From 41008d7385f9b12a5215bbc4a50e5534018d91a2 Mon Sep 17 00:00:00 2001 From: ca333 Date: Fri, 27 Jan 2017 01:22:56 +0100 Subject: [PATCH 0001/2705] OSX release build instructions --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 02e8c4218..5d987b574 100755 --- a/README.md +++ b/README.md @@ -222,3 +222,33 @@ sudo service ntp start Now things should be ready. To update and run notary node: pkill iguana; ./m_LP; tests/notaryinit + +##Building for OSX distribution## +Get OSX SDK 10.6 from https://github.com/ca333/MacOSX-SDKs/releases/tag/10.6 + +Unpack & move the .sdk folder to Xcodes SDK folder: + +```cd DownloadDirectory``` + +```mv MacOSX10.6.sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/.``` + +If you are using Xcode > 7.3 add the new SDK to XCode by changing MinimumSDKVersion in your Info.plist: + +```vi /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Info.plist``` + +Change the value to: + +``` +MinimumSDKVersion +10.6 +``` +Build crypto777 library and agents with OSX release makefile: + +```./m_onetime m_osx_release``` + +Execute the OSX deploy script: + +``` +./osx_deploy.sh +``` +The iguana binary and its linked libraries are in ```/tmp/iguana```. From 32f7758570344251fda8d7e3bd8a9465e2e937d6 Mon Sep 17 00:00:00 2001 From: ca333 Date: Fri, 27 Jan 2017 01:28:59 +0100 Subject: [PATCH 0002/2705] OSX release build instructions update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d987b574..e0b8c4163 100755 --- a/README.md +++ b/README.md @@ -223,7 +223,7 @@ Now things should be ready. To update and run notary node: pkill iguana; ./m_LP; tests/notaryinit -##Building for OSX distribution## +##Build for OSX distribution## Get OSX SDK 10.6 from https://github.com/ca333/MacOSX-SDKs/releases/tag/10.6 Unpack & move the .sdk folder to Xcodes SDK folder: From df485aca3ae9fc2d36f6ffa84b635d720726667a Mon Sep 17 00:00:00 2001 From: ca333 Date: Fri, 27 Jan 2017 02:19:55 +0100 Subject: [PATCH 0003/2705] updated iguana deploy path --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0b8c4163..3aa7e99dd 100755 --- a/README.md +++ b/README.md @@ -251,4 +251,4 @@ Execute the OSX deploy script: ``` ./osx_deploy.sh ``` -The iguana binary and its linked libraries are in ```/tmp/iguana```. +The iguana binary and its linked libraries are in ```$HOME/tmp/iguana```. From d4e01f4b8d1cedfa5f89877cb2dc55972707cd20 Mon Sep 17 00:00:00 2001 From: fadedreamz Date: Wed, 15 Mar 2017 04:26:16 -0500 Subject: [PATCH 0004/2705] libcurl+openssl for x86 built (MSVC-14/VS2015), updated makefile and bitcoind_RPC for header/library Signed-off-by: fadedreamz --- OSlibs/win/libcrypto-1_1.dll | Bin 0 -> 2105856 bytes OSlibs/win/libcurl.dll | Bin 0 -> 320512 bytes OSlibs/win/libcurl.exp | Bin 0 -> 8337 bytes OSlibs/win/libcurl.lib | Bin 0 -> 14376 bytes OSlibs/win/libssl-1_1.dll | Bin 0 -> 430592 bytes crypto777/bitcoind_RPC.c | 5 - iguana.vcxproj | 8 +- includes/curl/.gitignore | 4 + includes/curl/Makefile.am | 53 + includes/curl/curl.h | 2551 +++++++++++++++++++++++++++++++ includes/curl/curlbuild.h.cmake | 197 +++ includes/curl/curlbuild.h.dist | 586 +++++++ includes/curl/curlbuild.h.in | 197 +++ includes/curl/curlrules.h | 262 ++++ includes/curl/curlver.h | 77 + includes/curl/easy.h | 102 ++ includes/curl/mprintf.h | 50 + includes/curl/multi.h | 439 ++++++ includes/curl/stdcheaders.h | 33 + includes/curl/typecheck-gcc.h | 624 ++++++++ 20 files changed, 5181 insertions(+), 7 deletions(-) create mode 100644 OSlibs/win/libcrypto-1_1.dll create mode 100644 OSlibs/win/libcurl.dll create mode 100644 OSlibs/win/libcurl.exp create mode 100644 OSlibs/win/libcurl.lib create mode 100644 OSlibs/win/libssl-1_1.dll create mode 100644 includes/curl/.gitignore create mode 100644 includes/curl/Makefile.am create mode 100644 includes/curl/curl.h create mode 100644 includes/curl/curlbuild.h.cmake create mode 100644 includes/curl/curlbuild.h.dist create mode 100644 includes/curl/curlbuild.h.in create mode 100644 includes/curl/curlrules.h create mode 100644 includes/curl/curlver.h create mode 100644 includes/curl/easy.h create mode 100644 includes/curl/mprintf.h create mode 100644 includes/curl/multi.h create mode 100644 includes/curl/stdcheaders.h create mode 100644 includes/curl/typecheck-gcc.h diff --git a/OSlibs/win/libcrypto-1_1.dll b/OSlibs/win/libcrypto-1_1.dll new file mode 100644 index 0000000000000000000000000000000000000000..4b16b67beb62ca7cd458589d695c35515d73e4ef GIT binary patch literal 2105856 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 z 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

jq&F_vBpHyIHfqQGl)LKMJ1 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˿|emJ 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�fP?c7=+wdUZ~%97Ktd5=Do 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\iG zK)krK*`qC%9hv5m&ba6?!&Y|zVAW7zSdDmV1)j3tL_#^fnPb zJxFh2SzgBI_IawOYtau1Zs;ikpkEk12U=bk}D>UoFtrOkJo& zpfCR7%j zb3`?zz%~^l7p1DRm8#l`JEsg%)s&LXwymkE5~^CsA@B5xDuHnvja!_mncx4|UfS^=6A9hJbE8f0Icu{Xs=Xk0)x|n!msCkCnYUIY z3CmM!DC{g{r)w(9dsc9`b6fVaLdc4ZL)D3m70*nS%PSx?eXVBy4VEDcxmIaw2DBx5 zmB!DLzeRKa=a}EWrIH;i%vZcgluF$RnqD?{I=|V-&u)BMR7)ReL%9o4YTgr}G1*F1Of+{W_*o*Q|F4UPXRKka&Fe~z9(CKYM}g}o`r z4Y4c{Yy1k_KQb{ z)O@7>ZnpA}Vhn3as#05NYt$?uYIKMwV~v{SMU9%DPODLKL$>&hnhiA@Rg2r*0EsW| zc~3^$Oze|i4v|{ylrfHV-&9s2Oad+@>Mw&yq%v#NY~RX_^B^0avKhf`f;A85=&#~S z-2UPs(}xl*A0W6XD@oRZ3vt8Gh7zN+ zGRmI{bN?pAjLf@OO$KTnWq?b?s3LgV#>!0h{ zDEc9EpRf*e(5yfj*yXvfEDqNXtN)zwY<9v_D*UJLqOK|NLrOC1rc&ev|K0YTz|wL< zS76iLP@>*SdGY9rI-9G+G@x7WNfU#S4;OFlI8P=QSN_8ZXF6NhfdOzsVS|wDrqhbw zbe{D8{7Gk}|K}@zi}fYsPo5~_4i54+nb$NxHkIH2K1Wlnc6rqZPj=_^6C5SIcS^y>>Z}xY5T_7_HhFGC>MRHvgHi+ z>`ZY#gxkfET)8v*@C>>$Jm%n(!x>OMV&<71NWTm+=8iZh+<*5-ne}?%tcAjM<)w)I zLVfW_6uO*KOUl>vz7#0`qa0xI)U00gqMv^?y}d7bYMyb{_P(@7&DupT6%=qT_~G9E zJ!&3y9w(B}$F~Y4?IY{@C3_qHYI=(wB4l-Mzqf|7Fj)@6)I39lH5`rEHkC6#r3D3> zdN=wO{bdtx<^3pcdN%?hbH$>UidT zsJv|~8lc7dtur=YzjYhS`!$EN#R0N{f}VnPuRCu$YZv_$x+$XpsPW3*So9Yub=_+= zO@I*RF-cuo(ED1jeBGkI6#!H3E4xd4j}Tn=u9lTR^G@&UrOxW|@bxVZh63pqPjcQ` z_gZ=Q-j)@ifb&#&xLe4OIu0PmqgrF>q8Ar3;~|1zxLQEvy|0u}*`vMvezNzzwwF_P zeamVH``3^64g|{U?rM3MYU;XM9-_oYNh0s7cz+C-@Bk$Ed7kcjWVCR;-iHt98r5|s zH}r_&Tg_kPiWHEw=$%fm=U=+YomI9W@f<1rkNg5Vbc;fNp>TjsUK;Wr@+OSjM#)

xL;*EZ~t;(4?~hH@1)PoRVNSXFESC?*>6R| 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%0DnA|6la{%b&+|%;giguWA6y4eeN;@QKId z+@Be$y&sBypB!;;u$m~kU(5nRI{#phk*dq5Z9jA|u#x7m6f{mE;!pVX(M5Asl0ySA z?jWmseb_-$Su7)$RCpD@C5oaL+x8? zgs}o+rdirE(mpyB0~Uum(7HDFO3+zTA(k;zXvw9&2Xo-$1_~#$fk$5F8Khmi|4{qb zrhh~bCh{^f{Z;#Ra5U;JH?KeQT~V~ML!n@=ptYoUq%Lm&`$Ct8pCcAX)#We|XpcT` z&!^_}U?!`@|6qzv`WJH3P7A1e#QCyTP<$jbVjgN$MU5DbG4@C_Y6cNa1<#bWET4q? zTk*~9@n>%nq{Ts9M4)X}w(26aTHJs^OXCP#gpqW#^1Pme)tpN)y5HvMD@`eIT@%W; z`mtoWOT5VrCekkB5Djr11|wn60>7992AN!M*pPFw2P=P79KVmFC!z!2yK$H$8)ol# zzqo@TSg>sR1PP7V8**^Y*7qDR!~T9hERG96I|~-<&xP&ol&HhLsGE!pi}>;^X3xyB zp;AL#kzWMimiN+z*Rk+pvM{Ja?Dx-Lq0y9AeDDmnk`^K8P>&h%SP}VucigjiGx3j= zE_Z|6rJmu{?Bf)QK#&@)Ja9Q^e)&GC0H?4HdxIYMh|n3W7$kH;7fn!Ye(^ac!DI?5 zw7ueO7(jk;;X90(A0C?VVl(D4%0n^Ga|kqg&H~^*VS~@es}$X5qx0ilgs=>)&nM3M zBcy$-M)8r1(TZgA0Vg0qVrutIO`FQ&hZ)(b?uET-4P34WsAZ+_Si42MwT-byH;wg+ zF><#-Th0|EH^v)l(9-j9paHw9w7oTc3R&8WbOa&E?5<{nUd?C?^k=YveBmISq-~@6 zD{lXw+5+XuS`-4I4ST6ZIvMpAd5uFC7Zm1D&eGI*} z5?L4!c8}P^S&R`by<%5F0P-Eah#KK%*1_#eSbfOdorNYKuz&)B271LUPiuf7GwY1) zr=dvb*f(c!%q*@Y9FHLvaB>Yk@fL(EWQo?Wv{e26K0=sk`+elPmj2!+Q_UoCrLUjW z(l8hTeW2}yGKv=5Y z+20&mUuf>1WA5)EyU*iDU54wjfjT~i`$QhtI!3fVu+ORU_BSm*U+}_wXC%H;cqVEB z9tT3g7iX+Cbi2-2gE}$RA22}zV|9H}vuu)1-$=P!V~f2rwK2avTlNROnD`@mxwDW5 z3LpbHup!eR_GwF35YVnY5cU=P^$uz~t9Y14VClZq6zxZz4tsTtnD+v;9mZANbiCQ% zapAY1%To#ow)An}WW#y8(UG@`M`4WPkpxZ^&M_{$6?^D$FJHuTD_cuIQ^QAG&t^Lg z7vXFB=*~E#z+T7@Z#)kxBvN6GAolb!&V?(mzmLoPKu01SE^anA90#J%WXTsCsg9!i z2W@gc2{q%-;&X^{w1I9P+^HNx3e*d}qDj=zA5e-(q4L^Cljw(!ybm1Wz}(P;M&L5= zH5yF~p^i+N%$dVCAfcw3df`NxK{LI3V_l^%gq}JIoiSmpLMJp!xFi26{)R9K4{F2x zVDEPvhYZ72!(U5V=Nn3&S~x&CP0#8T*C8YF(M4iANFymFdKy>v1ba)cdNW7nlNede zkt-pnW)VWCZ{-HhP)^qiBCcL${+I6A2bak8;L^OMxwyPdvNP^x!VXwN7#!CJA1Ry? zktb|Y-p;NTEbo)`iLVJ`Bi$p97ZMV*DZXS(eF^PqFKfyO79eCwH8dsh`VmO1j*e^+ zr^-sunX7(-S}ID%EN$cB<$7^fn&QLs;_fYA2MyGR?8hK|GmyYMiGVZM8+yoE-8pCo zD4u~6I!+~j5{gY_{BS{7C;ZGh(8U-bGz6o|pOab+%iy!IZx>TA504>e%$S=n9a#?f zo1Aa#gs@MHKZcjWmVvP=&TK`?w-L9~Y~xLQQs{fNc=i9W_b%{JRoDLbBpH$c24;{! z2M7>!)M%nc0~!cu0wF{N9SoVE^02L?#}O4_Mq&*RoX`>ugSORH`_y7@ZELNq)*G$b zgdjodt7w&8eBi6yaY{woBEFda_q+Bv^CAe^-ut`#{BQC(XU=}_z4qE`uf6u#Yj4vv z#_)Iy9^qpJ$HOJ+O<8MN+^VOYie^CI3Go(p+;DaHduOnl9gwM%_Tu0ei{P;0VwYD< zd)ikpxAORe?=es^4M8SVuHsg{GaQUHhp|r9!D?Bm$N-Otc-kuw3Szj^vymrpVjns^ z*RR6|>QQ3OcElS$iuHU{@W+B@(5~X@9#(IKv-a2dJ^?h@tBVJo@YwWdx0^Eew z{Xu^BYfddy`59B>OS24BYAOV!W+N}AY@0IK5qD4aw4a0ckYo;Mn|w^G*xA?02N_Jcg%3aSLB)JIxBasAJ)DdL$x(9 z!K#1T2Lq!6Abp+JP`PuRx9x-Zo|}4VY8fs124S@oS1v`kNu4VSEAGT8$e^~S`n{FEV$%A=kHVK*F;1Yy2G^oE zF<*PIKZge zi?QM!Y@H%Qi(%*LDXpvXnFsB^Q9`|+8OIq!=yHRsh?Kq==}) zV9j$l@K(z^^J*#YEPJZp{b|+Dw(g2MuLD|9jMO0A!rhH)aVJ9McH{whl9hhUddN^C zM=ic_%D^ZV$@A+y_vh8FE3Bt?G_kdC;Iw+=wtZ`TauE20vOOV=rV4fZZ)FfvZ;c+y z6*C5~x2E8)tUHjl9If_NV@!B9OvW?~mw(~K&FUJGSj0dh7cGb##0>Oj?(x1cPh{_} zy@jbNBe%XwvC_$O4}wr9(>*>X{0$J6%7u2`qRs-36c%8Sdo7eGoCL z`}7zAe=y3RM^OC%GJoSnd}4p%F_HiGYi3PYXHctA;V&7g6f4K+SVWhqC!wVPSVD-y zOOY?vK_#jIt4V7~5Sa>XCZGb&fQdm3>(1TYLP+6pkG&gj@RLqQbhP>zkg-E<$o7QP zPH1hAlf+$~i+U`s#j>^6TkmHoVZi@j>4R}je?Fvsq*Fn@^iOhM2Wjt1!o?oY-gy{z zhiWgGvF!H#2J>mEy$SGThtb|QLHDR%VYTjdy(8GVjMTE8qmJD)SI0Tos-u##U7yU~aDGOP=jP^^T_Js* zcqOE8Y5A@X(@-%PTgZ6xDCLFxrG}bE?#8A$IMA`D?`8DS?T!L~tam`c`^F0J2C?3J8BfjXeJ&2Q=q7SIrOh0O znZ_A*2s+oRu0?EE2M^&!X9v7D_Z*u9U!^|}UaeG!E$=zq zhS);P7y3LL$umT`zl4z12-3RhvcPDu5CFKI-^6!UJ#~oK!%4N9=`UP=HiZFM$oWRy3<_D1(E zMtK+XTb|P{uj~-zq3^g7!3F|kJkVn|=Efq?KTVv6c+`X{F{sETxD!<0U_1yeu;Gk&CCrbyf&s)^Y48}474LG! zgAB?IN^+@DY6qarSE9`eh1>QSJToc@Lh5nI4YlxtebKBQq`T4%Z&W{}dxGu8B!4SB zVp}RWWpfJ#om0*Sgg>tdrsD8DLA@->ssV|R-B152SE|2HGoA(Ul*Y_aSLj_6;MZv5 z54Jbj{w1{i^TP2{Yo_11#zM0RU?{RCnuAn0Req)Mwq4L1wHxPTh3o*o-?6<>ei-Gy z_6oxUzX7AHsg7<;PF59uIruQDV2|HZja`@fykxY$16+^SyFva2tFLXLP}rv~!)cT7 z9IK~yJ^Kkm7r5k%RTV_UK32v#1H1VQ&pe+XqMfySuPruiO5w(r!k43+AINqJ;EbbH zqEtU_MBlc~>I2iLNY>R}AoQ_j$m#X$a+}7k7q= zZFc>9J*59OZ26lV?(IK3CqImRwAFV&TbUp0SKN2iKQim5;~xkcyL=t)>^DEwPlx*t z5$-)ixU2tgnJ*)QP!4RMag=65NVjJTwu4z)z$+_051o1sp54r-qT?vD&*93OS|f5n)?o?5J}wE@Ue# zdK`CSxMtFkZbc->@#q5`35Yyn+Vl@W2g)}*jk>X)Sg6}kXj6t?Z)bckM%cMI#mb{s zHrXlb?>W>qiw1r_Z!!1pe%K3^7Pl;bQUF1 zh79jjKCgO5%IA4ss6afU&kI22eyUj*YjHUuBgLZIazbrrFoc_mm@5Rkt4>3Tnd%2R z0kj*QX2In7PSgd%v{3}?d35x{4Z8Hi=N_J5eKr3U+)^?Tq*xg9cT&wum0K4i{m?!%4zyGHzkx1 z`pL0r?WbvbWedO}r`Ja%q6%NZsbPxwGKv3`__=x3`lMhwcTjsJm}GPbY4v-WfF!M+u`Y>;stq_=&izyp$`wlf``_BsZR+441gU#91gLTp|6 zlF!Dll>b%tfi1C_e)D`xDC->y*5yGD!wTM>3ikCE ze6JM@%c@u+1&m!E9_0-W391|J$2_~jm*saI{4gS`7kO7+U{sXc$4|BA*f+vb)`SxFLvaEx0)&DG39e#S@XLyHkbeMV_ zLtSiZMF#)^3o&0DxZIHVd+UqyA~Rtdjex*lR3Brn9Mmm#WF#Stf(wGLb5-uv0C(cu`MUs`#$f=>c^fUHMo?i*pjR;5sTiH+Of; zb9XcplN59`xR@rhrw{L2@R9eSi7G(mZ%CD3rpfMw(JBe?uI>d-vpVHt=>>EFI9>EX z0DXX;QtZX!r@UjP?u!$iO!vj}km`ISsiZFsS>w(Upo022cnUPL910pN#xo2y_(1s0 zJkKx)pKuKN!MK$IbRlRs zPXwuvV$@}jpk-&`qwS(=b2H&Sy5?B^vsrx^t1upBYY@?dYrSjoQ0rdhhP=t=SvNdy z&2P`XS2+?e{ON-CyqH@snYTqf+Emt}9=oj*g^~dPBM6G@s^WIIX7!Yeh*W!h>Wi2` zP}R>e0x~-9Fg^iYm--=ez+zn=p*x^LxT4gmAan-Qb=b|2Uh1#rqS2Cp8~qgr^mfAL zuTOoAVywBi%H5a`0QL?D0zrT{j^v0bfQdP=M)&?EA`Tb{cQ~Ku;uN=01JCf@qITBVAlJ9V78u(f9XL1<6!`-^P%dj6>e-QTjq$2xt%bGZNu5fy_@Rr znF7XK0OQ~p=cM2D;ipU=N>22nG;`v8-#`}}nS4GuaTnI$VHdxi;g^$N+xUeZOHTX? zzXtQ`BYt_}v5z_WHxMiG?Pg*DmKK7HPZkH?dgTHFy(?wq2f0EMAJ- z#NrQLuHDt0+{spB!0y}pb9=xIFS9-1$B!r}KNJYyvvM!DUb%_TJ76wq2i$dZOq_== zbp|Jvy8`7*H-7IzANhkpYFT zMmb5&h;@h=hBgP-RbSAcT7#$k$4C=z50oM;IyT7+=OG%k3YH=Q@Xrg@ep%__*h6)G zL>dwu!_QIp927m`0f+~&-?2f08o2LK&^6ToD(Q)BM(WDP=FAcG6-05e2w{}NNfcPY z0_PZgA9Dcvzs3@IM8@3eId30=ixF%vqoCS3{9RBGS7NbFtm`=6sv|XB?K=9~TAibY zM2F#L^q}aVt#!^(gQQMVsixtHRiH-jEOsQ0NlxToM1~~-1~hu9rXFH#=*w8}_;i%y zh*^4^f?9mR_6nxFx}Rrs*X_g&#ArPc5ssU5k|4*} z1ID+F99Hza)&c4&a2hOLIwh#uj(C?x%ZZ%GHnkPB5y*^_Kk)5QA7X>uM)iNo-%f5U ztCe80?eSR$fxkJ19S+*Tej`g#%)K$tq97NZ6g?adx0_u{o&)YzY;`cOT`sIcFVmY( zVgZ?}Fdo%uviv>`pn$#3P3(1R9^^{H3w`+5hj}Xt7lK=(UEH!ezy{GU@jOw_2SX#G z?{Y9Y=pV|U{A>5NoQA!m5=Vp*X)m?-!NbZM>icz_#GGOt|7jTvO?eSvJIy`KYK^RN zAy-?wcai5jSSUWke4N|1PA3MJ8Use%hHra-Sd1zlEHydjvU45RoVI|jg-EiCb{Yl$cIF1e0AwXz&%oI1mSR7NX$SUo8C;o>QYwFBDV6FIIqIq?ll*detQ9VwXC zas&w))B*70?kEzw^&$0DaODP#_DMsU)r-Gjbciz#L!_SDWm)drnV;()FE2le_`1e?o%gsLn??h!ze5Osj%J2)YW@D z=M(WuLqW5M>$H+ZxTs{6A6~8?)Wv`B!$h+3F~JSbt=(of3Uwiwh<#qiBE%{-8*GQ| z%7q66;8|%qY1Ktdg>*U%pDK90H=tq-d6+hyt*n6uk5V?^7iTCh^{jmfx~AZL;_ZPg z=os_evOVz)fi`@`r=8US)4AXkBJo9Dgwqpxp@Fi^=G*YS)a)(mMqDO?bC#7unKCz* zbyF)7o-OaaVzvk7v9Q*F0gok%A)IVS3gmz8DV1IE`*iwQf!6AGfY7BYM#S$5&`4DL z+&$HO)bm`v7%{DQP-+j`%r>xQj&pK#ja>oz#s5TPcvucmcZ;tMFbC4Q4sxZs8O zLsJ-5fWyPOJ=9W3<>B$VM|!-@6FkEPno!d#*tXd7cDH9(yOU{RT_p$~>hVGd;2wsM zZTOwULVnYE&uLgP)dl8~Ujw}6iE$Gs?AJi?G%_4ggvFlWb%FV)$|X?9nV%S7dd;QI zxD)Id65QnEl|rZme+ssB+~?#OVdN8pzENyf5t={WbAS7mM-ka{KY9=7sp)+5KKvj~ zLwx3b9jA_Qz!V)ArzSr0V;yG-f=}Ozycuxjc7)O?6dvcfW}gNM=5Xu0zN+UGl50%B__Y5zzy6 z?}kSYJSyl>Sr@3H$1LatYiEsiPO+Q~+F3^@KYwpNP1sd#!>kkpbetTYl^SN18fFNY zf2#M?22Nb_Vo8^0!)*|UdA#j{HV<-}1}G@He>`Umv=y9(Ul4X@9E|7(TG9VG%T2Wh zy5F$eBs_Hgoo=m<9iNs5B%6=UWKXU^zyX+3Zf@3yBZzT*e^DmHr&)+x#cX2z#hDVH zW+8G7<8XN9AmB7XV&VwG*D^c{0prsIfr(N;MaKCG<76QoVCRo@5s?}G)pQx?LO+p* zh>=FWDvfUwEL5t|&M8^glY@SBIq27bG>1k%3;Fy^T)FQM=!dEjXNZ0cL?9Un7WxTB zQJM}EoT8De#=^M?+F4~e%e7PRm7hSt%58v3aT}nLje4ivR7}!z>V{$xCKytPEeQnk zNXg_xKT7kgeKrFb1w*?SYc7bTH3tD}GjWhyBi%L*-e$RN9K46_wfBC2mHU#w(s;WN z{mSj}*=JR&6@%e!Lxk#W%ZH({f$AlJ))lA4r|+rWwv5{Nv&=uh`_e~h5GU>&wccG6 zzaa0lbCRdI)}52Yp{eLwOqB>SDkdS;#eA~tADB;2^-DqG3%Wt;i-gE~9h%k;^muX0 zwAVd6wz)(HIEU(xvtci%B=$i~>t^I<#CmE_q+GA71`YQ1xJKjL(u_vueE=Yq$-8XAlT3n%nI_#x5+*)@)&^*^KQ$x{U)vSFy@PhGyA&#ik3|Nq-?Ck~oF^s<)&))k z$q2;H$-`Z=OdA8apB3<}+0T{vvQbp_Q%aOi+?a}K4bQRWPZSO!naBax!)N{6K*fN(>ERS`}!+buXUgx3|Nof?QhbB)udXkU#U8p{)?QZDYQ-0jAG_e2$WG3);2``7=G)!7 z2d>>6Dd7>}(nj?F5_i8j5cTZdU69AD|4e`-=07abj;G50+TB-B{qeFB%RY`TuR)x+ zbEqT@s^P!NcOXRtt_EvVSIb7ezjAM)*zE0A1(XVw#;4a5bO+U2zodyHcfosL)dj$) z)mol5<%T~34hxwNg5&=$y(wRCn;Y8zU-S1saSWo!kWMVjq-T zQ-L{axxcdpfn^XB)z=hkCJp$*Jp!6=9(;l!Rfe5yL77B8BA4VuzEekTj-R*sw?yFh zH)Z_h$It#~U9B^IfwNn=*3}lsJ73;;vA6T0FWb34$-P=KWtiH4k(C~Aq0pp|XBgOn zdaq|#4JO_C68vKMRbPQ$983E69aPD_KC?fyhtJ#vQn-lq-0F#62p~Fvdnw|k@3)C} zY4iqW`>EmJpNc46&-HI3Y9m$8i$kP0%{YJc>ox>&!P=Jhuz=>}*y~);`M?DDCyCec z@tUr!C0&a-grLD%jSw_!YlCxuZiJ_uOS>C6crGIKco~BnbZgnd_2YTs0Tm%l0ugf6 zjj4&xt^pkau^K)d^{|PNA49WAU5pLo^_K?5u}^nuQl!ZM$s9?ZZ{4M1YC5Fei5u4s zD|k;b-@IKRSC@0-^mTIs!_$NXISyowbFCaJ_eyT@88v0h@HLPWp=W-bV_!AK7#s0D zvz+#@PM(Ks2)8cY62}W{Hb_BP8JYvX@D|KU{Wv z*@y9H4PwQeM>gWRmEm_|{Nq?G#($H#8d=3~v)SInNIm{hsW}Ckaklg4slm_6>6(!M zT#3pN+`!0kgp{6yN_y9H^9?dr9(yYfwI~Hh!SEgpQU*XZxCDHuJ31di4=NtxM*9bc!=5Ze9Nkr|){p=Ut? zj>lewt%*4ze37wZ0))L^!s&p)YQnDwV=+5H@(P<=9}EyiwSRS_1DX_q9*bm$y=)Gu zJwQuX&l#;Yt%c$TlPmbG`Nx6sg{6MLDsh+Yu=V~76g$7XD_Ridw;|_ z6(2O$&Hx6hTJTUNKgLrD;Kz7a0P3LkY3_eF=TVzOpsRJ!?loSpnWbde6fSKiIiC zlvbtAY6rv>cDaUWEqv*SqP~BSKbq;L-DsbBW)Psa=dI$k!(f!OC`SM}4Dw_8VHJDAao{*lg?>@G6o=ci7o_j z&o>qTSM-2$sX-4TAAMHF(|(&Sz~52OvD^ux94_@5wu~g3$U-21*FrQ7g1c{(iY3NO zTIyU`(6Q9Xa0c9L1&9X;C>Ze;EQ)ysnnJ+}HBx#H*2_E_dLc3ByE&s>%}8w+b_E+% zGbHmMqd;4cY9*G~fH|2FFR>%axs}1{r$1+Ge=7EwAmkNh9^HuP=*WkO(2i-&#Bm0B zSq+2QgxmN_%C!_UZLs>hbyfDSV&FIuJ{FBm)UwEr3(P23Fjn|+N~F?eC1*0FwuV@h?z)ecK00}+nx zmzRLc-uP_Jw1Ki6p7wXqKNxk`T72mdK|5^TG=k^y%KAZ0!mI`&lO*7HU%Y_{{p(#d z&^jjXFCVws{cQ`QWFnOL<)f9f&u0A=2xrCQL zMixsOB3NhZ(Ka2B3ji)NC=?`Mc7W4>wx!KixO}-MimjY++{;6b&NSG%;XJFFn zbwmN$V*0z7$MBJe7nKOw2i3>lN8M^rQ4ZSmXtcgjg7hEuzYrLcqY`#XQQeiv;c6-F zEL|Lx9RFW0ltiC2-89V9<1^cKH#@s!*ro5U8ci?gz*}^DcdtT zXXj3j^zfGjq?jh$>c`(B;IbjocP8fQ45HBI2P=^2cB6)w?j<04neI(cP0MtDZe6zf zdJv<`@P~5pFV4xYF(0v!MNe*254l|c zp)E_l_cAz`5zr$KOa#|RYukg>ewkW?Yot*`za$eFZof^ETGuV5{awP#yDk6RUDON! zOj*vp>1itDJgXpJ~cXooWAL1!k_9xb*o!kR;>>ns)yJlnLM=$uf;BKBGnezmJ85Qk%`*lrMhzm zCeDY#SM>BS^bn2(@-jIQU~qW3jxZ!~GJ64aB=Oz8-2Uz!*gZnm%m zC({S3qhxV_HPIwguTeezGvth1kT*GrLtUNm={pB0bpP!B#bNZ%6~OeMdJpTHRR8=b z-9MeEESN9$4+XxcxAYHgaN&QWDqg9<)L;MHB!p1Yrr>r37{t&0`l$V%a-^@OBpsHCTk*OA}JPheu&FZwF+b@tU*OmY9+eZ>y$b78%Z(bIh&<+wLtg_{ws?eh+~8+Eko^BVI& zSDV#NctN5L@#*uM*%EgU!)e7)I4;GNpwTXo?nfjvGBI3x-X@;6iziow-XLCnSX@5x zUUnDgVM(*PF3vR2h$H0h5SAP&H-G&$yC9_V>5_adL_Xm&j2bvX>O0@W#49B~CxKHC z*ryI5@(VF(PGYFxIGqiBR|tno6gQjI z8`>3iv3B_w>!372!zD3)a3jl%gZ|M{@DBjU*cKQTSXE>cBRny{sFG;6>ntjFHmU0* z4pvpGqSpEq3PR%n3}YUnLbWJ@$RRajnN)2uD4elWGMO*_-vnx-$^lf_s$ZRCUd8%_ z)D|KCsNao}CW)18({xoRh5BKZ`0Jd3_%y2lLS(eaLW`u+XRb5Q;eY(IS)G0t+NioP z;c>C=ggu60TnNct4;LAH8xwwA)-X7xohU*pt+KmbCsQ)D#MK0Mge z)TaRBj8^u21Ee&=O|(RwUOs9RXcA~v<}9bzBQF7!0 zaPH!&q{K60&)VH0-}Th(!PqaqGcP(JJi^!_omCtWG$cJd0rHgaAY+&KJJbHd;4kSY zU<*WRgKGR*jgX*R>7lqs(v=B)O$|lw8N}@)(?oX*g)po{jb0f&P=b2uDtA)N$TOoG z)|4gHE*UitM0hrCWGd_~H(~qZ1<-enhGz8yV5VvLx+@SNoM$0t!}3&{nylim-dIN? zgW>T;gJd2^$2k>o^q5^LK}NdVBN5c7ehbnWWRHN1RBpZIh3lXj-@{P~Iw^4b%C3S|VV!STtMk#6kPk=9K_?;BPuz9#2jJE)Xy=YuMgaH85 z6g2QB4s1b0&($eACFK^R1Tkc}%cO*Rh1y|=d)CHS5us5}NZeb}aqAI8=>Nol56@bv zw!v`uMp6>uJS^7#1whh?omK3*i;=hq99@+_UFJ<*m%`qyZkiCF_&@j)&JJ?A?`wCb?-vPQK z9SoLL8dN3Gdl9`+T?L^SGQYWnaj*wq!T#KHA0BTmdgYJ$hfqR z%bm`Vc$ICXPWP&@fLax9A8A%2mNJ$bbE{|Vcw}`R&U?OQR7lv3VTOrNv=BkD4~IvN zjD6^f42yl}j<{nV9vLYz-T(?D#sR!O-0HO4g)<6QNru%p*8O|5+UlGc$Z7`if?`YQ z%F*21^r-;mA$Xa7SPdXZ`YvKeVRM$9Rp0lYvL9h-&Z3H$R4{{J{@>@PfZz(3+e|n^oI2dcx}!=}+JjCcK>5^(jmV z8Gd~)V*1T=$3TQL+?|&KYt?Qrv$p<6UEmTf)s|9Hva|^@CBM2uMhaufOMv83OD`SZZxDCiXK0E*3ygB04WbBwkZf_xkS7>@U>_b$^ z6h=0SLONgjPFyZO3&SI%uKtqXZzBJ+oj60bC&fAn^uBJQ_~$gM_~iO3t;K3!9}ETk+;eyqCb2L#naGI|<^| zRi`{G^TxP3Q0x1h)oYW%PEsgO-J?OnkoZ4G{F#Vejp(gAtvMm2&HxsGbS$DZ1-S(Y z7i2)-{i4VwFa39*D59XCc4P3R@gFAQ(Z3ayJLMjT3C0qjOtbna*7+8-uEs3Wq>8b6 zF!#Wm-)m&}6U4R}OrxA?%GJy02!h^^5hAvui}WPu1-AZ56K0sQx%3v$3SoZ&6kP=x z)i)u`K`IV48rrJd>$$&ffS#FbR`XXyghGcK#%dqqd<|)_+TnV63cM8LWD^S!~S|$`!gY3FQW}_Zj zzc;Ho-;x4QomJ&hmDjAZ>|#iOzqEa@>koaYIvMzx7R#MT$ENYC(y z_dP3K2ATRF`^;J&d<_g7kUkTS_4?pph=s9TlD%T1R z^E>oN3ErL=G#_1zy#{aPV-l!W4m0}JZuitFkXbiwEroTBA;x?FCZt{zk|kZe-kDlI zU`?3zUj~1!L;|?SG+NuN775jGVj-WidI+iABFD~JJ%rQ_@f6ncIApcA$LU#{kFE(H zX)KXC%uAOwfMuzZ!2=3M%Xtu{MjcAMMvti?7zO1!eOcBHfZIsDsqde+^ECgZ~8 zMM4kL3&Jt*u$Gn~^_bvUfS|et$z(z^xU>wZA?cc2Y}F*Bmabw&gumwc%;E(`Axq1b zN07myOD)0OMEyETt|3F}K}?<@^)#5Z#9&!ELTbOBNxkp&@Dggz+BK*%sAoAjl5$M9 z+p(MlDUP)OHmoL0+w1_Sl2C=`2hl>xsv)Rk#G1A1sxbYmS<`!^dd}Mc%`s4v}-d3 z4U_yZ3|EyPGKP8-Cj)V7w5jKJ@EN?g(T{>0i;U;-7V3=&?2YSXxR;<6|K56#|6>!( zr!1&h?In+(+8`82uO~`0{ENcZU_J4w%-p%cv(lS1-^xMBr&;xURj(DxkNp2OTn@pJz5uXWB2i0leiR z4vYlZE|DE?980VtbKVY5tjZ^Ce7)+uzv4Oyb91*ESFkzm?lQL)JXY2nJ;tI(uzqui zH4ayOz6nIT%N|`=l0bD&CL)yXEqK0Qb9Ikqjc4HKOa7doaS!IFX0=hoP$2HB#`E@y z^{JeX)HyeB9}=8U4X)qC5A36T*3BF(&!38EMNS4AoifntFJc2g=~fqEpAlbTBGjKe zBcv{u#xTf5Q=kmPWv(ADVFJ*+$P6eRx#r;Ig*v2vp#_M@$-o)Npw;h$7voB!*sPh$ z1qV8HAOZt0N&5_zv5O>2fQKe{j|dM8hSVtRmw_PY5R2;GaiP=@lXaKp2i=RzZb|kj z2SY#6`}TqIXZZJR0>#X5qhh4&c|FvtdO~Ii%W|ZSBr9;WA2Wr;7)Qq$zXaYGOR?_3 z-EUmfVvMZ>UoC5P7+*!>Q&wh~yjcAfFy`RIMGnz{nCih50k}NykjXk`)GGZcOAHt( zjue__U<0vC-E$eMg3l6TOR65VqOpK_`~&Q=)B{<|;x%$MR2Yg-AS&WhV}OS+!Bwc| zx0}0h^x%Z7>Z&gYMF*xvc-df4>?}t#zvB$r8|#7FS$#$X4fwDBkOqk9*mPA7>r3>> zo4I+>K2HM$7V)De8Ly|>vcjNH0Btz|Z3!8!?J)V5ul^Qckr20|VVN}+Xsd-Snskko ziuvUb{$W)|^fN+e?ODjwO&o~bs=FH7wXkQYJ`lWgPQvhxj5E%}45xek%c2E>TE;-R zte(dm>WA#m6uy~S1w7?O`Md~R6`*_$LaX|kzFh&bh?p)KzQ(1UGAZ2otg{7Rmd`cytyb`mzw_#GXW(9Y}$M_j)4xAws2I>Q-MHwWk5>-f1*k*N) zENe-!M(N5uwOmt!O36>|On_0AV|DH!^}c3;rI>>?^RWFP`X6hzu3w7$g;*L8RBJ^) z1<|+&DiKoguN|s!dUco4xObN6#)Y(~M@Stm>-ns0BE)FGGWCE~`~dT_JzeGFei#ka z7OUWwM0f+J_PfVwkB{*owd!VM1BwJ{P~E-CyY{gb_Z(b*@g>5;b+D14?dbqe?qRy{w>kjlcf4EUXi${h&5*D)SG0e*m)OP!D10W=Hbval1oILRJx zyskbon-kK-l1JtYOpC9JXaf_vtu$xUmDlV!dyjgMpn#ati96ZGfra)1-#>>MG+~k% zD||gsa|oH*H@U!*Ot#|dp!@Fza?EIP-@F|6L!c~~;eW#r$#i=`-ZI@0EY~yLW5N1n zy7!^BnQltiGu_|F&i_5EB49Mb5iNjDAix20eopoF=OCFE4jAC|DFZQL*$%cgsy7sB|l+2}@nmkl%7032FRH6XVC zqsZy&^U#LlWBWgjlvxcK72Cf*GS+I%kl6lYWSDMJWZ**FM2!Y5;)HonsuUFW_du#0 zDDd1rE0Ev4%Qd*0UwPJ-J0Krcf_y8%!7G>(V%`4+RySQ=uP}8OX*bHuBAmeyASxsV zsMPmOAvd^AqfvbobAK4Sz6&m-AA~Y$B&IpYnw|l_2bzh&ISW@$Co6!)&BEJi&oe}X zMs<+(o+@UW>v*+6&qpIn3Y&^biD_<9GkE%;qj1QH$G@PkUBLPM+y5uDT90o_rWWby{XP+7PidK_ptSwd#ptmdB2TtN8qBks;BWK_AgZ!3OMDcW@k zzz-MJ_EENm0~{jmheE;1g-}aq#suC3!djw&sFJy_StZYtPC%ww!8x;DpR?;FC2(eI z#LeDPE8yFS(3m*i&b{@A5~o?IkW>;H5qpcQn30oX`>J7odEb=iC`?#+=kd#n{wRGA zn+A?*V2EeNX1I&7w9D@})o!u0G4bca>XLsdk}wNyWrAXw`*2OXYSH}#(Z@L2F9KGN z#~2B!??O+Zxn5l;!CojBzuE747+66m#FfdVn=ds_bF`uyk+o;(}2ep&QArjP9bipb4&F)D%cR8PRg^Nri^ixGz_MHa!AaX^}uVO6_kOBWnH zu)>1Qpuue#buH)lA3Y|4nr8tm*8{uE9T&t z>?#H7eqSdC>UM(+W|sO97Hw9ks0u4)_V6st6Y8~eNPn$8w4as-EV!Qfhn&`+$OH~| zxZM)Z#^19v*pIUHO+)IJA`{}7K(E1(6~_T@dmvz;!H|q>jkZPujksLe`$(*hybnaqFx=}S{l*oXRl`*^(*_Sv8ceNKag zWznI@Yl@RAiq)58j&}7YF4X+P?6&my0EjI90Vsane9~c_kG~b2+Y|~Bjjz9g1-MNG z<#b>)n1CNb<4!XMk?ac(=Rh1Y8yvC@Y{u0!B$-XheHmmP%bm&P?q+q8gky6kqPYqm zGW@GdW+|>>IN69J$W?e#T*a_7SFxa3T?h$J4qI_QkQ_ui1*!u(?=XA-fAHfxfX^RQ zfz<&yfK*EM4+ADmV?er}?Fe>wvCQrLh9l!roqwr%Mh}m6o9wB0+VBEV7+bf5&~j(@{An7$ze_ zr;f%}cBH7Y8tHI~9lc@Zf#1q^M2kA7h~KeE+-BH;3tATTO#K1Mh?dxii>8i3;;1YU z-$UFyN91>mCOhf)nI!3LupRbq-{&sOUXL|^LT04y`x{7qhFiu9IG-~0G2~iQigBxV zK5sYu9L%hFAzbLDZV>_kTLgL0i6U-{oTdiW+bMpVO2Kmod1S}J`9bxCRH6t(Y>;^G zjqDS4;n3?WyNYVDRV|mg$Sy?Ik|+mPw6ba+gC47uGjv^wRi#AZ?#LglIH<`Vg=YKI zl|UQKu-FCU{C2*9@t8)pCpvxA+3s~Y?pZnRTXNiYX6FZc*f{W}CTR4;WH`#8M^H7P zhK8C-6Xoh`scpYj>Gl0#znErsB0Ee53w~o=#XF12r zW`|#|*}<&v%jaQ7j?zby;Abb7Q!=*Q`EnD2q~0r`8a_R5(8p*1y( zo7rpWW)oh%zSZbJ=|@~M+$N=vslvp&4( z;6+R@2ZyImg=KA+POstRQ-#69g_lnalzu-rysG-n2SodWS5;75h?NK`XdU!S1KRqM z`UrkisXM2961=L^(UMih3<&Da59cGr8+vCt$PU6=wXe}vMSKO+H?R$bU={uJt4;=-lIlIhgtnRh{|!uGwf4e!i-EYGVRX@gMj1u`hvc(_9b-?X%t&kco1?- z#O1WZ&DH}D)y7x5|G=`s8b}(z{WYHT0e?w3_5@t&2TRxKfm% zYZZn$mg@vYvdaH{%D-0Z=U|n;4@{|ES7-Ub+g;|X@6yW)saki6Qd!Yf#?vxncmkXhuw*-_8mnfTDT17J}rm#5b=+PpCB6750|7QOcc{(=v) zpc$&uKAiONCYLs-qajW*3!sFijk81ob4|mE#XJw|mf*KI*rcwRse21|Ik#NiB=W=f zb$RM}oD)DrtM{$EXz`8c)HNdLq4kf)%b-ORtwVp5u|I~hKgI(^in%G!^F@G~ihAPu z`x3iHMl{vWRM*>iw%(nf@tOeCkUFRqo`ugdT2LWwZ9#5<3+)cXXniihmniIo01$0P zgUtdqxAg+4GxpTSa3c%`8DXAKn0{|Fu)?FhGg%^3cJ+-#wrT^MI_3LV{0X2+;P22t zssNC@gr5+S8e3p<}!kbi&N()%#n2pU!wPGNubX4;jrHfCU8$5Ye0kO_McS zh=yG2Sk-VNc9YtCHF(}l=Q+s96{{agona6x@yMqgHUE3!ciw@9sv$UqmX@#G1~1UL zyTq<5r0)-jsaIM!kkdX70k;K>%^iBGb73HssFo-Is;9gDk@-R(Kn#b)3-y)uJpRLr zM|ptU(yMGRUDT1JoUd%6K*E?f}aMMDeTNWA%fw`e-nKn>njaVWdXJa;o738?kosGL5wX z^}u`q6tH$o{q*Yh1Z%B4+mR;{`+>EIaJr}~;0?kBqG05mCg@qB3WWZ86WrK7VD=9o zs-FG-DpQFwbM`-_ndQ41m0v23?M94{dr*06gp9#3ShIzQ^O>iO|F!|p`5daHrh>?& z@%b5easJ>SCtB~qFQ*ZO-{wq$3_K2~d(aOyQ9hk2JoWMK3=7(NpoZG4CIEQ zKY)a$IS45PX{vh3iVKdw+pG#F60m@0-()1j1Z~y_8ig06r0mo%?zDBnKq`cJoD;et z<4ni{J7zf4RUu@mdM7YIADijh$I7ew;AIx->mfKsMjLd;aasXveJLhqKYr)J9hd`T z!`Lb3a8OIIUXmdKzQxnN5nkp{lF;8_-sM!dW93Rqery&t5=*bJfZ~dsl^0!rYN|6E zwE)AfUcBC_Z?sM~iPSOGsDnzjQ;PZUBZB$X z7pSL!4Df}A1c>jyW{8I}$EWg<%d_T~as7?We+Z+AExd(tcGjn-8nj=`V5sv%x9MmWmrf-62=GYXN`cKgg!ZeZrQ)V_>XZEj$sa~H#O?a=l5_%yY z5O~lK)&yhR;v2EidAnY!RL^roR$?3T1wEoc2wqRiE`CN{%aUD$Iu^Rj>0I>>P01~s z;o?L^$CX}~&vL1OsU>C+6~(cd{6t~PGhkMLxZErL^b1c*Urn3-0vdzob7R}A4pWRO z5^kS|wp|X-4cq~4G#9xVG3`J%8nfPRG#r%83t(VZd_K%Y);M5W{%clSU8!1&SVgxr z<=3Css1PklVr|)|zOJ(_0fnvJ*80f{MF}Gt3W4!Byvx9q@lM^c&10uhhiE!a=I!;=XTVS zMLSW9+M`>a(^w6!qm=6+1~=e)aBqDbQ&Xfz9kZt}fl-?C$m#rbsr&J3{LHRVNZkjP zCk7Man7`~E`*gq3evxOp)k{L*v*lO^E^T)>Su$`+t{6GeKikQ{)Im zx7L6&&+~(>ta9yM&y?R{FLMx)r<#k>Ar$frrgMFrV5>p%Kte-8>I%RYB(@(U>Z`+w z!Ok4NeSZb6XS$!jkjQkG1FtjP&Ybjj=cHc;DO6_szkr-&x{m=PoauhGGTVJej{Du5 z_@z1d7w6QsHK)9LA*RbLZ$H-XnQoq=&vZ}8PS5@eL9~Tw#vEi;nB8TC(TcKdkrQKm zd65x#MUO@wB$qkWy~0#LvE6dNHcznWV2bWmnVoY%9#kBBX?ndHgqPVKn2#SWTltH{ zq?3Y}CHRghho_x~Y{{38BD;7pWB+@T904CH5_5l1J8N*#qxR)#c}tf zLo&MQU-sGAj`pe{V9C?)Z-W;BeN_j(Dc^2u}MeYPmw5j#(7|BijkG0awjC+_|v9?^s_jy}c{?KAKYYN3&`TOrLwfYrVn_YjKV?4HxXQ_Z|yPk+y3GG{m-j zR1-CLIS{Pp&ka=J98V-L0oheR2v+K$J(()s3D}hDj_oSwt!w9bdq-{c)2)3tS6cyPGQjC&C#RrUB!mucY^g>!QVuQ9Sgsb5o0hFeyjLf`B>$4lv^UD#ai1d zpyIaPdBU_QCCi*sR$WsN+g!l1cTsABOWw?PV%_-#+aN#juX$fL^Y6$7i+FT%WE2cZ zK-TzfX{v`GW8e&DVknew1D+csF2>S?Jjzm1uqUK?&d#SDxCsS+16(V&Z!Mf! zk1auS9*$tFnoWL`cOMq$%He85H;UO6+qZDVfOSLb6UUp~i+c;_w{-7w#$NTrc0pIW zZ5>c#U46di{x$lm09u^Ws$XdRPb?VAxnHog&@mn8;R7D*7GV@OpEkS+Tlr|k1wcE^ zerU{_2+=7jmN?V+6Pv&KQq6653u zOlr>RXE5E>I&oGC0DKqxf7a?q?}sCV_6U5cT#uX#ba;Ym5#|Gl_yBWS03uqP)S)9j zt+*pEGp4RJ>jx#7R6u5ZD+Q9-^(7i24#x+M!~0cSn2NN#AUFK>FyU;9Jn63 zo#05-2Kp%^ZM1K2nmLg{)Rl>y>4+R-?LS~oV1(hL3IjN6Wo|| zVzl67KtMfhG4HDaI6IMCW#DS7pS!j9IJmMJv#yiE2_IALohmdI>p)dP2knR=wYm@RN~NxT}FOc?E~NG zc0`YYO@=%n{!YESB3Z&73TVb)HRnjpHAS8xDMQrlBLtZbf~ahd$ZziH1WLxbE)fyV z_kfk8GKUu7AiYb|IP;9^J(1BtWnjrb8s!9ya)T=$ST3m2aRz|CxBpJeXfN_}$F})t z+{2>LUbT)j%g|}gh)#TS$9DZWEB?Gsh);OZygG~%1Wske+#Mi)ndDns;%}-X2#(PU$tNv9dD;o61EF$S2F4xyf5L3x42+7A=;pCG-|KI>cX!+f4;^*D5ge_6&ossgwz^bHDD_F zMGbSo(u1voIGWcZvfmRYtxaA_uJ2gf6uQzKcdm|4c=S%p+6iBL=DuKZBCDlpFOWKz zd-m2l^CKg~hQAa*0r<0I4Y#-r-qWT%BekdmF2A zEoSoAuDp)1gCC7;%ZI2Qm_C6TwvZKc)Kg$r(^2nZ<5vl^0I4xXMbQYax=rfm+{DVl zx5)T0^BWFJ;5C^1WL}G&qgTb*b+|>iWuIOfGl&h!M}v%ek%P1*q}~Zn(BNA(UMB+!EX*5rUA#_6?`RLAzYRt}CkYvNAn^PX5&s>{#Q z3(9_)$Mn#fPK9Xv{vOCPCV=92EpARKT2aJbKu4psJHTFn{EuF7cK~Spkgyd*>&TyD zU9L}nq}|trqKMHGRQsfAIK!9C=h}eR^-J@q;?4ksuJ3Npds4_~tKA;U{()UzjPS82zBIPY#f4$OAX!z-AHbSCwg&{j87(?KqeY%}N@=WCO(~Xv z!PZ=Dwdyip1((mIm0ip@2tJbb-gKr!6g0uLWNF~VKoq3V+J4sO=LC>Tp>Ka*uxb?jV#H*0HQhW6`KeN2pz6Q@%sltMV z`O<+Syq&ipRZr&~^4=kD#|-)eC2#lnj9DS?x$hPR{Cx|D6XFi_K<1z4Di6?^R%Xr%Gd69-~LnEqr4Jp25SuwE!J0$wE`Q$SA>^fI@tqppRjM*7$vDRZknSe z@;(Uaxa5OvM{0e&t-0WS4R2VGO37!m{mD{wBj}fiAI2CzBpH%&YfrFM2nzS9+v>8-<6$*01+)AE*h8XeV;`>|(tMns_G(=5dYJh5mdvLVF?@nO z%Drwj*!fxPQF1E9!t1d};iOt;Kb!ERmtaTo!0iYFk#gJi8<8HD5(|H{E%~6;7U&<% z*xXU8)g-g#XqIQiC(+jptwlrcmMQjtbBZ?o&#*T*3CkM*)T_?NZq28*H>huUgBqKd z6)FoGx(BD@Ce6X>eoR)toJMuWU@$z&?~`fY($uod4L*F1Mu12)Ze^Q^Zx{m-oA1?6 zt}em_y$w&AeS&PSFe3Eup$-@Mc@wrBUKJS^`Z7AyXiMWxqCLYH;iuIIv*81Kb3=7y zz#wGWo7?4=HXLjlJ|q285TKzkIq8?nuE#;`)uE*>^$M2sY-hH;wQfi=4xl%d{@TIp zt)0U<5M~+n*51Lmp}n=cp*SW&hfiZ~jjKpp?;+(uFAr;Z+q_#N?YsRKTBkejA1jZ8 zB-W3;{xv8Ms~|b5xQe#nMsRZhLMNDc`$y}`SlM9IVzmt6-l2OdHC{w`b2*C321#EH zBxM<1eRmAYcHfl~ekNGk%=rH7Ec<#eC^EwJ{>e#Tu(_0Whhi%)f#HN#vET(*Ur@&ey+mhVqxVA*hVY_7j6PW-!WQ7wIF)5|f$$n@fX?B| zFoGfykGpm-&KkZ5Crw687U>L-W2|wFogjRr#IDbbZRCSDM}j_>QUH^S1mle_+X-aA zNSY%u((xZtsZZzP9-4&FG*ez8HQCUVni{9e6b7MsGe~#5wGQHe-?ou zT)gw^JbGdLtvUg_Pa}%38Nlo>9FU3$D;K;rbc2qF3xHn0O&P!>u~7v@4!?Rv&bkm3 zv!NrqvX)`kCn#w~=etEjha#inV9UEu3IjgVnnRe>2-pXOT;?43E6Y1C8b_xOs|-kCufs{< z>{^t3$gLuKJ{bw4OqfHB6)uZJ;5wD@%*dO)DkFUarA_e&+8xYsFUfHmIqtL^K&NlX z37?zePRl~9@_^cTv=Zvq|CIa#-FxJqzz*dKd3mXvgN@g14XE{gJcPYI~yQbUT zBz^EMr+2wkEfiU*y({Ql(RG>~yIgxup!WoCx$Rw{y{qV5<*2p2Cur{}^q%ta47=V{ z+Pj9{HQ#P%Fm-Vn;NT|jN$y>{%II?YvgJK z^?8{a(PBv7FSmoxP@XwNLuUx*49+Aq;Bson@wK+g8esc9GhoXsVl=BglL;V5vXU@A zUX#lATCJWoSnZbWS=qsW4EPcf1MaJUFzI5UuV>S{ex`XOT9S0+sCh~`vOPz9X zACAb$A$5Hqqr8h!<+a%5t;{G-s>~79;Ei4DhaOzVwaf)O?HXMQI+hkM($e6AwK@j~ zpWqaFB>L%E#-4JoYXgK2%wOgwqH`Va8j%G%>(i4G*cI-ixH@Wmy|pD>7mo1u)=sIw zsJF68<=>#^5Xn!^qSpk~4S+0S;84A*qdu5D)9FT})9X1e?bdUEtfvNG;Gn-`Qqnt@ zOTDUD#!hH@xc7*`pHiYZ(@TKWqQ>- z;R|ihNCxyr85Cv1E`?Whh+3KM8%AJV!O!aS{sYse>!;_Ov|GP%jXRuN48K{_PjGmGjQz}NoSJl|y&wYBCYFNzFWxWLW<)fFxm!faeB3nR*8 zlM_dZ!cB5S;AZSyK$#d>0ncF07ni5afgVm6YdngxXqO$PI1w8*IB`}vs0I#YmvXK- zeiF7rTZ{4bwjLRZ{Vu7V(NZ6n)`TiKTO;~qxcn;DUjXwjdT|vAeffy5N$nTLkXTwI zqj`Z`#^DV$Vq^Mx5rrX4Up~}~W%Y>@IYDegfOWb&(%h^bwDW+in0hr!rviANj%`i0 zz+kQe3Ex3qV`w3)IjEMF5g@+UU-Pbg1JxJ=`x^_y3)UeowyI&&rx^bwSZEGbuN*Cj zWENS_W1N=?zFdO4?BInL|I_C?t@F>&B#Aq5XQkccBs1v5v-j4xYogQ5250R3qoSiZ zNc4ch7pCAvqQ6P%(Gz>$e_;62;Lh22gy$wbUY4E`^r?E91@o~+H!LZtaIgkJ7VITOHd6NMSy|f@w9U@ljo5(qbu;+TR#h_ zv8carv@Op#9h+Ddhl^3;23r+W!%ve8I_fVq>x)BSaKM*LV@A(NuF(Qi22=h~JVkku zY^?*2R=Gmz^^-Ag7vc)KGnqR)SD!{{PPBXxa$vy=dyJz})vuM7zA#Sk2N8xLf^O-j z!j?lv?j(1s9>&a}?ek7)Ht%kO7n+I#BE{-5G?!;7lDK~&sE&jzC+sly(Kz(4hahD2 zQmpX1-yRbCa~_T@$O#WfCu;CL0h#b9LxuJ0C3g>Z3Ei;|^P&SLEu0lO%J~1-dl&eq zs;l8UmjMPCm_Y}P7$s_ySfXNsatUg;w6(Pt zZELlyw$<8NDL%CdMhz-n+oz>PTdi%~FLD?~MI2iLFVOD5?vXR8@YCi9}yYJXAUvupt%ONZ5Y7_K4bQHI1%qvr0L zIAly0swi1xsKDWxe20w)3RMBaU z=RU%K*R8C;Kk<~dA)R&lpfISYqhSfvwEk|OtLIZ_SCuxdP$gUqMnRdjo1{A9bflj3 zQDB<$KyWtYc&u)3v=e(0Jp%0VX$nyvf>%9FZ=AM>u(h(zdTU+48MQ+9%+qbMsICl3 zqgUTXPGB*)D7gMM1`IK&sx@s8lr}%sr8*YF!SNq@0FPJ9XOho*=S3k;6KOH^{F~$+ z>%2XF@Ay~XAJW~SVudq-S3jAWEg=AJW-SE}3l)lb_}{9Fw+R?llRH0D9tC7Bdf{ zh$*TEEUF8NcVEf`mYeUt`C=wM-y5EbPh+vvur6GDvfB|Hk?xps!JOm_p{o3wV7|Wl zMRJMmHB!EruW_nX^6bCQ=Dsv=$ZL&mA6X?EN&O28zA~6a~t2hz*S;8ZA?Al)3{a@0tjjfuK&G28t_fUWM}R37s%os5%3oGRnpCi z-qLQi&lU|8*+RuhEcU?-8z?V`*SZFIh1h3UqsGf91S3VEk7L#RI95m?QZ7a7mAxQm z1=q{@XocUugR~8zWa{VGY1<#>$h6V*M&>O7jf&FYh0ZJHcR{IK!iP~s+aWRxM%R|? z-cLaC4m%o;lz`I{i-NPnV7%c6Z)Gywawv)jw?|P$`t}Cg@J(Uw13_N#$+T zxa!GVr0bWMDad8%9JWTNL1k+i!CcUn9yDYih0Qu|viv5~p;B&YSzTV#np@RB;3v6N zP481xCb3j{Gt5>+1VTDOC!{aQ!_934<@YNrZ>}oHv43HX-hshqRv&H_7Zeca3o*-% z&P*xDA#^k^2aG`_R)qIngWY?x*#AGr|3wh6@+ZqO1c&XZ3x|@Gdm0+$zTw2dS%I(8 z#SCb-hSbq39>cIoy`TmH0pWsZNuW2v!g_>y4WdXSIIqjx`O1rI?u)?UyY(6*x#0EO z)|s4;Zd=0M9jB+d16uEI6*^d3dd26NIiNTbVi<-$5U+6>^lWaK(lfw(tX7m9sg-=u zR^sfm;7l()7rHA3Vpj@J?B7uPcJQhiC?2swUDFj$a>V3A#zm`dtwvC{@-qeuXgjo@ z^B}1HY<3Fp{{-veMDxxN<)@$i`?T1WcHq*kOg{L&(o}>L*Y_ly+gQ>#rnRSO|E(*g1_6Y*0fP;TF+m4*jazR)FCcC;=0|Bh3Lbbur1PM^C+7} zcD^cN3_~SmZ#Xhvm*|G453S+RjA#w1wv|PR{m3CJU$mIA!Tfd~C{lQ1cw5)t)N{oM zP?b)j#IFMfHauko<4sLc-JdbV>)PWQsGjN2l%w}FELWOR;bHKSbekaY;Z*A)ad7?T zg?G2orp+(7QkY+KjBNhX$R9J`R=L^dY)`$NNmRqL4@M0-5e(y?LV4>@OV%n93lR*v z4^q|0dRLf#}l+$57|YW?ZI|3gNE20+D11w zMcCZF3XKXAh~VgtC6VQg^4E4kPs8#G&IN{&$2kpg%;Jf0bzDYmIPI=zLyHz52T{md z)t{3B&b;OAvx|GSRRm{0z)A`4*`|wVqSJ7`RC7e_6K$*>LA`7pN9ELUv=cjj2C)&S zse6!yMVpBrR35yliHiqw7<@?l;ML5SXDH9Am` z_VfJRBQOtC&{a9UQS&mF!(8=GQ9&>S?S%wrd&x20U=gZ4TuUBymh51)^)`#d?Yb0 zupc%b{18xCs}T7n0Nr>Mj@rohZo)LfrwV6p)I8&U+r&5S>{$(9Nf9&rHK`cBnj9`RH#eWt5KyO7 zu9brBl$kr&V#Auia~0(S5kiGjr0=fO_Ri?Rz_D9qx~FYFnBKz73OX!?8>BU7x3m{A zH|j)kE8$YFi4Ooo@s2|82Sg!p)#KX1L}_~I`7DHfR)NEKSp`kza)dQq1^@KSp~=H2 zc>pV37J*%B9{wF*DPc$32(r9J7Fi12yPC{5_V@7rW7O%`H}F4OXB7qRYr(<)(=1wx z_jmA#4Q^%nS#sO4s!P|%^CW(`CD8rY2LOay#PzSaVl91SiOfcXACx#nz{6h6Bu?)| z%zU-Zh}~selv!yREqy~?UzL^8+eUI;CfzVcmkOx0Y{27#eL8C8!Ovkul9|DIG3Lyi zPx&EuTW$RtI5uQGmJvSQ~5i4fj4B}R(5l^lvdYfmmoj$PYUT%0^; zZ5tOK?avu55URp_FC$YZ^fKH~i@MS(5|s8+#i&d&WIE`DaO2L|DyMa(*3%1QgrfB9 zvUD;)Z_Gwuq3zUOGN)~f*x&e==3~Tcp!8f?AZ1NgcB=UBACV5#U)1o88#DgiqG_ep zEGbH0@@de`3?FlHlKW&P*u5f_;t4HhLKar5I3dav`vM4-d}_&l!Y=}8`)qU9E*CUy z67Lk{Og=9$-?N`<9zq!T&bDQ8+j*bqd(RK8)j zjp=3umKJO6>YNS4S$7gh`>0J^XjW|=$FaCMbIAm@6Pe3ubKr~8VJygNM%5EPdzT(( zUV2vW8Yp%a^840V&$p*7IcI8e&bRUMY_t%ane$H0spPIZr2JlOoH12D^N} zK|ECI*?3wpO?)KP!vG?=MvnS)T0bD>$?lT8Y`vJ%IcnZ1y;UY|bsFlZjO(v5D`rvI zEZyjk$|m(w*?0R^R@YluaQzZS_fhdR#n*oN6zJ^}#GkR0rt8nnp_>EYmgR3EL)Gpf zf{rTkpM4!}k)y~%aZpaUl&+M;X=IVV9Nh2)M$Fx?-2EcCC1??s1lcpriP5rZ@6{gZ z-Qa_`&loxxXxHlTgD#?W>p;UNvX_ zIcr+D(={y&xOhGM2f$Wh;?78R>>Hr6Vp8RHh$PpGs`TsOY{s=JOi=+270pf~`bT={ z*~$dp#hJQLdmE{~>v8@- zQ^Mxkr1MbKzOvYSnP;Kooe4J=Qn8u~U`etI^$MF95pybJfY)*dHL7x=`J;ZEsI;N1 zwlg_I8|c1>#7grsF=$|6@X>eG!vY9a{+FmC({MX9RX7kCi5y&Bnia_|$stTr$~SzmOUt?ez=rAy6y`gEMaR zgaVD2u{uwj)kuzu*YvIY_qrL}TRB8c4#=NNQN1R^JYr?e+RotBzo0+JFFO4fs+Wp? zPu=n&KSq=Cw8w@pA|k(jjI7?QE~2gmlXC0X+j_5Oi%n(TNxG=lS${4iWTzi}%9hlg z6elX;XJmUlEAE2iFxzVtJpjg@y0G@bs>da6WnTM#@Y?H-SbhZGM1BdYm?)k>degir z4rOd1wH|=lPx9TvT0l&UN2iFW(NpqG5Q=AkA6J#vH!5)o*QvHf|a*wDl*LY&I_C7rV> z#atnl+%hwUfed8B4Q`Nwbn1WB$9`LtYrhR!Ke4Fsp=Vhxo@>9Y{IKk|RR#9jN)u+b zn#@T4=Gbp5-O+`Z)_t_!R+@)jlA7-4FFeIn;xiM+2LhOH{=3s@bQc*l^~C_H|8KeDMRqt`stYMcpR#zA>h{#D=#N1*_IuYI24(0Ol`;N12CifZMT>n{MH}f(oaa< zn6sC})0JSJEWSLL40b~EFCskr{>t^`Hrn9&`voFg4tJ5Lnc>#QU6KY(3vRfXG$kf1 z;l&-v*L%|vrY56RKOd0(v6u5t^lXgM_lH<;VT{Y2WQI|c&o|#!fm764S}aM{nPE(i z$QH792#iXTDxlyN=Bn3~MJgQXl+!8usMi6`qb*Ycgp z0nTBvZ@qd5z$i=4E{C?wE?XA7j+1bU+kLa414aK4W%^)vt@j~>qPR&;f$@r5#ERll z?TE8tiFq0zAoKYN%v4;jwu}wK#gZ@w0GsRoAgCx-t1;rx;S}FokqD)>6J?J9mIIq~ z*`tR8(&a3vrY zzr3KGle1}C6w4S*h0L@+z*9&DCF4t%$@i3B?sWMmPabIaKc`{A&7lMajAiOV8^8!2 zN({Z(ml(+w<1%45gY)_^Q=B*Ki>@p12C0rzc!l{ zAYV#0O%i3!ya;RMa4a$q=xR z4knpH=qK`@3Dk0e0z+KPD9M z@BdO_>Fn(;sSy=6+)Ncs=2oc!H8((5@57tbSvT_8h5hd zEcP};HDlCrhx;4PDB`F+SWV`x&HH^V#3tbiA#=CrUSgU;LEVY#I9u5xK(O#OGiVuG z?c9wialz(TGZk}5I4_l&?fpitDE;!MCi{}a!zRx7c}n4A;T)hiEuKkKEsoPm#TC6{ zsTBj?8*?rH8iCX;SJVgGAgdySO%oYxZ2ZZgp39Z^RJD8-O=OdTj>9F3I@-nk7Yn;N z@&R}GosUG&JtF)4JkKd@g+H z3`Arve)+7*gtNYKEuZfi#vk_hTAP|7dJ}&owo2zmlHznkYkGtb@-MVy5MRWaFUsA9 zjKmWU&f2E3niSYBOfdCaDc{R#KR<_`3Bftr`Kffa@wYtn>|0ZkWx+YysH<+n>~LcL z3|wKI%W{al?QHKJOqhZ>#Q)wZ{ixj*Z2vbkM$Ct{qW9}^<& zO9+4C!*#-HIlHwn;b>s>O>fds#pZ5fDx~Hldx>8s{^<6-S$cOLLZa=uE zUS_;@+oiaul@+b70nr3$;-3WS3iC`dB*yU70rTSDS@E+f8@azOWPbXBtd5WrmR94R z_3}r}eUi_{2!~`*LRhPW3jd|5eJejOW!={m^wH*1dw`s`x?EjKG3?sC1Mgs{y4Z5C z5|eADKO3hjpT?YTuNACl^JOjxnW@x;r~FJ?)yx1XyxFQ|YE}5(N6oXiC<-GWUVZYQ zo|)l6_=wLeYaPk?du4opx#^V4tNTNqE-xI)%iNe{c4+eqE_k&Nd)4h>!OK|;bZKU#@Up5V8K=k+bDYH? z=M`tBZjPrq{M|#bpj8wl>uYwwqHCXb8N#1&&eq|sI*`xb{GI!GyZ3p`0m8aPG9_@p zX|@M2vMVq-b4dmwv;5uXQCt1}BxGIH$EqMI7E6S3@*nROT@cdc-JB-oZ!Cm1+5x*^ z&fJ6$s&b)Q`XGPwsRG64Zgnf*ly9=$sjrLmIzT1;kPhMNC(8M)3Mr(Axb#n@t%&_5 zvFphdr7`m<9jXvHx&3_tE1#puaehMS`sG3g()9^`kWJH4b-89JRyF}jcZfMie)kzN z{bzLfKc2!_`%QVw`CO4+sR=9=^lU3hun4&4Z;=Y8WzI}bGEa`^*>-l~2qsEXd$!f# z`~AS4CpOeCOpfrrPH8(kd34nL3b8=Mb1K9ZbM|q|0tzd4j z1&8+3tFvTs*t*As@yRDayFN&_0HlkWcb;&ut3~(9L_lg>Qy(>_s9+(hwwheW+qa0B z<>dmlWr@RA?cY;}_sN*l<8{(b_bB=7y@(5R8CrU1K0~O8M$GsA33btZlMumCgX^b5 z!I<>Q2yQQ8?>_u>S?1_Z2;Jh!C4ku$Tt9|v!@Jf!vX%i-WktG*2pCX}eGNe0|1|FN z*DV5AbI2Y{E;UJOlpL-C2`E8Mstf=4+qbk1V$d{OPclBcj=QA>`H znXPsYA6s{|?h~aa%BqD%2Aiwb%Nf#&|8zaR*F?&M`JLIi1ewajxz6l! z8AsTuTRwbx<1MN%M}%;fM`Lmj^9@CDX07cQJq(^P3$~icwEjNm{y=b3|BVpCMaNtr)Fx#VIWj}0=h70jXvB5lVrr;mcLz+N;&xq7PEG}!uNUuz>X$mG5PPo#kA zh>Jm7n!sS6k*jyjZ)_S^^4BK5m^P~8pp&d7nz~a{QIXrmi+#sumXR#5tT1QaEtSgB z#JEC~>W$e(en&ks&F9_sovlA)RMIFv3OqQw`H&vY-zu{#cNp6PlT2yV!%sp)jR5?)S@lv7kD zW^tLLaMnTe0&%&;Ea~m(An(n?=%^hSFSw0iLwu;Oe26@?&m`fmp*_>XMRhFX%bLwk zbP`#s$q85@YP*vqPA9tt%=mEU0csW}zV7MjWcdsPoVvV^)ez3-Jp1sPK2GvK&F1Fh zb5S&1FV6BO-2$8-LIhqtP8=<_>qVW#6I0eq-fapZoO#j8DfC zknVE2fYYC+X8U}W(rdi8!sZnO7BR^_jPNY$uFAyK3@xs;M-i=KxT#{DNmRc6ody&AzZxBQb2<-dpT%YVOz z3D3>{^@94ZD|l}$=%GlL>JF}# zO>)R}d)pE$qhT!(GdDv?h1lYrlNg(sB((a+=p2^tsVo24Le+$CO?2wZqWtT;UTr?zeJAy`m`Lx31S`b=16UW1X;v{=jdv%Mo*)bXU*wKnGS1#+p76RG6eY z={YAazN%tbo~zyn0P2$bWG$igglR)UClnSvvu{z%xn9x41N7$B2i@N6`iDHwlQl=t zlONHOLv#1^gSIMXFZ^sIb#x!P>f^cTuUI3preir{zV$qYYjP18XMwPz#U4QR1+X75 zPrT@&(V><`h_HsHkYDo&)jE6c*vYM0*F&nUswg?qq*&U724nR2rcpAGxwOjc_`QP0 z?l|TMqHZNO?6kKu92hUUaCFH0RUzTK(fxW-ho~d?et+xNLjM7A>YYsDuxRE4$zXm7 z5=6|IP$2KiQ&2OkH(KjbiXyh3p4)-TwYpQ;+vY}a*2uN`%m)vS@(6a`I@|* z@4nWVE9CWa`WiK#=OuN2U0(?1H81h%aA_PQ7ddPtD*slFkrUeZP44bch;6Wlnlm2q zyP=M?A}R0G6~+Us%ocFxD={Ks+JHXvBDHl;hi)-s^W^r(*4L{x+V@^uvhTeB#?J0@ zX84^?xFMBv{}B7(AlbX>aOQ;s;R3_whI+Pz#4%otUp?FW9<^YHvDx{9)0KL@IQ6%Z zLQSDfe>WyxVgKOm$X=F(tlO?i=*P%a6WqsmFZxw;~g2vcHks;wd;DHX)b zvniF?luAvhB-S1&gL~@3B`A;$&>26+9#WqUzs*%AJ==WJLp94e4dJ2nVe-ETo zLsiML%!(>5)%v3@5n1QL0LVr6@I*e{W~)xl$l}jPVD3iPV=*`l)e!FrO^q)H#W=Rw zA$4JClaxhH!-RDG1Y64uPb@hL^Q^oqjE@r1s4 zG_Za8v`G7O(BnW(4&+h6-mZFi(YAzMt}e{UtccdhZRWlNvk*#1Bz0*-n8!6<~76E=zci`KcQMwW#25=cyLhR&E7%El2=5@Ru!Y_)~Z3wNxW z7hVgLbtR)8QLVWXRt{~KojUr}FC_Z^$kg}%sz2Rmc}DNMT9=>HQ+PXHH z7_#nE?Lyy{ddpAH#NPK%Kiqf64vF_y*7Z7z&Gyf0FLi3TL@q=G9n;f$!}V$Y@~$7< z>E(~VdM0e!GRqqjME=e}!a4y^QQz*#eVu_OJR!Njg&iK*=yKj@j}>nm(jeDpkNTV*j_KrX~nVov4nA2Io`UlwtjAcgO{w2L)hiVT|A)hRVJA2ya7Tf#8Hx91Xj=xIr zz}nVH87^s?3tj7xs4BW+7D^sy*%1eG)_`iDXy;6I`xJFWj?Brndy3zdX;yZLnaj5` zB*Zs4RQBoAWz|K*ENRBKJUtUOl{}yY28ToxHD4tk!)8Mg!l*}o+LdgAw8@Dr4Q{Rr z$tA~v-qsb1l9Sv|UQfG2an|jORbgCX+Z& z68mkOUpzI!9xAtr<5jo*spMawbO&#R;P!(y*{Zwdf@ImZ9XqSNZP~f1dyTC#Ebn{}ymE_x&dY?FS0lTmH-Z{KW~ z@|oNI^N{+S_m)HKvVd8b7yhEykq6F}!+X#Y8$(k^x$_k%o;qLV zYikKpwy*Q`5!8pgofmJK_g+S*Jw5H-y!n;#Zo0%0^>y7k zV7eUL@pYZ@&%E-=k1-MI=}3D6=sfx&_ogRaQsLx8^TZ9(Ij;D~!7K04m5;b%_#VhE zcMZc&zpr=(&1pMC_5;eyJWfuhmsixw^OY6};hTR|nhZ03Hz7{O$F8a`bG!JvrMAw} z`$bRst@H@WwMN9DnynC5UvWRT(|GsYzKgy@{kh}Hg9nYv{jwo@AME4MN6%!%{jwo* zAxk+WZo?rxK-us8vf23o&-{6pxjyvc7c+fXu;lNotAd>s>2w|b{k-Yg(bWhnJ>c`( z)c`TieSeZCwDvyw0&}uFyr-=TOvgPJs z2wu$DZT^BtmAb!7j*sU8ET=7bwD_cxu=sS~7px}cu} zy~_LtIKjt>iR&%QM7lgC{uUErVYVW!ym`2}1r z4igd>ep}Cj0mFAg`Mj?6;*Y%qq4(WNQ}WK$g4r1n^~v8Hl^BiRqswgJm5HE_R!VGu z;D)RDCL%MER@=w+bn15S;h7q9%x%cLF)mW|HAl=5x<62sb#lk!wP#h(`4>XYrmTDu zxu&A_ybZda)Qi&tvC{r01wcL#tu5-E%(!o_v?G2@x!4KQHcjP2}GHghap;aQ_oq8@bpeYD6ETdH!J;0m$DkdE24zM1_Dp%C3=98#50A z9)T%Kzjk+<&)MBQ2+%g}2EWTQ&7Cv#D%j*$i0Y7HcoXsrvQ#nFh&k$h$;g=0Z5}`Wqbw;i*OH^D4FOX^i=gl$jCu?i_l!5x|@i)!(*mOZ9IgOjG7UYmsT;5DV3lU zMyg8nWGge}JMFUFbDy^VK9+43g_*}o1z+fJaQ!-2kzgkCzL3suLX^YZ?{|GVFRr+~ zRM$PsV^;U;0g zR$_TZ4$xj;JkqKAwz)uiSAL=EOUadnN3Jn(jCsIF&PUZg*ml{5o|P+_S$4qj#Ggq#Fwiv+rdmF5f~dAeJJG*FO)Z#m z&s^kZ)o}6`6noHja*?e6_qqMOqigLgdE@MQtKfYlqsf`It|RDV&U+T0I_u;LFeG3r z=CAA@e7*WYHosLH8uQi0Yzx`?Wun|NndJfV^j8&DS-HY1VC5qMCxlp}0VIN~K+tkj zdwp?yJ7Q(TR6J#8jW~bFLt4h^S5B%6{eu-PSNdx&ACdhjoL%ozOhb-X^|6*}oBdKR z`*gCm9HSrcviPO+%gR||j|}6985RfaJv7Q-$Uy)=uY@|lo zGBfpuG<7nkC}glrrbf1zPH7Ju?CjPr^UYy88eE1UN+-anju-1V&i%wH5$65xA82jn z@|!4ls+NhGKW^56$rjY+F|T*Sj+L)VD2K@Tb>w}+MB??Y5BLi$KNxHv3FPAbG-Z< za?e8fIpC!6n8*{u1|9PjJMnvqR}8u*!uOcjb)8m7kHlU+ADuD4)ft2px<Y7-hQ5fc z{+s=0-(e0D)lhWP?J~8=WB1fG3P2J^3THx)8r)edTL{5WU7Rn0;HYA!Ze@D9Yd!Xw zi_AB#v`a%fzcD~VE?~@d$wo2hUBKLTqh#+jr-(f`Xa8hk=X6zt=d;UE%|C{J9AYYa zr^t)>fO6}1%lqfIPxlJFi5@L{6{j&D^pu>w2PP~ZRO@)_Zb!W#rnqW^x3@QH1DDPkD?%d#JmCFz!MR6 z(I2`n|A=V-&71#;62wC0e>@-a=6~&XK?6Q23aq`Im;SI|`_?m^VsJ%* zPmTOT73xG4ikM^XmKt&wp4(Hmyx@~pxVNmMWv@}6ngQ@h_0w2;J%Je78e=AWm9&GF zlE~^Cq4xTS#DzOqE4%Gx$q*jUKEU9GcKGAZR~LoiAx=P>*6XE6uL&{_#{J}f;Vb)+ z|K&2T{_=gQzc>FC`&9p;1E_!7RQi9nQttQae{cSA`&9pFCwuiT*{Aw@^LKuEAK+u& zVckT`#4VCHA76ET%%3!U6V$5T^ms)b{rlTQ8UMHTp}m~^`VRTLCmialThKQ zzxn%tra$q=0p`zSFw8Rl1D5}@rf(XkeEgq_7~iJjWd4=6ychg>^N)kWyytp1XJ0P; zyM~R~e(}%LY5Hzd!T!^4OH26$1D3y9({CTJ{JmF7`S5_{zoY5P2Pz-GwhGV;Q_$p0 z&yFlT)AToB9(mpGO`p3T8l1V|EF=3KW*Uhnm%Q~ z^5)yf0ud8b+Lbc^Z~UfB)0e9ln3Hbp{oh2?_U!#)p^>j}3jygbVa;Nm`KMh~?_tj0 zVe30>;QB6wH%oor+qe3>{@c!cOyz`}?)T20cJ?4;{Qagcs9-QJer>?{*YrOqyY099 zVCbXy(ZJ<3{Tl<9ubD*omVwJ_`l12Ln|ib+q*;YpP6s{sn4>g(lge%VrLRF!ikMdl z7f81JGEI*RR6c%TvyA_%1HwDj?O!-x`_HbE^e0rC?63cGH|Y2WEPt$~ zZyK=tvh_Ot!UdKc|0$XtDJ&n22Nslv%y-2=;o6&VwzXJ3S!FL@da$XXakViY#n~L6 zY1CCFQriL4ua3PjGmJdY9yJPUrBQP=cDb0Drltp+Fa{LjawIhB^Vu%VRNb$4C&y;e zG#QjRp2`s&3pBnhGMt=mwytezfXKHz=GW&bi6Jvl+x6=3+EanqOan~$^tEdmd@-m0 zTdv7(f6IdAy#D0K&m7l8iHl1H)2T9LU-fmzmP*8PbN$`GpI{IoJy*wqAp$Iw1xL+7 zK^Xj?^hi{J!!ny?OV~7S!5nyLnK_w`xu4oB)l}y;NxB}6Dddo?Jc2Ik!RSh?p_23l z$`thxxnAx?nzf1fE;HXjX9DJpa;E0#lw=SS##qjdnK>M?0wTPQA!mcR%PZgd0G?lN z)pUIt$WoH#GWyhI<^Ho4vwO3wj`P@+Ia8Gb#eIJiT~KW=mRQtG2jm2f zEz$tUQPcLY00gJr2+a>8{TB7{)>~U!&LrkM>5{!=AqUCkn0fANT%r;2Wr;aSE5Nb# zY$_O$YFkp29I|e1<66?OP+w49v#Xh_0J$-mSIm( zcZq2SoEgGJZ{RmROugIBHLJB7Wo}hB+*CI<)LAbUt=>z~#Y3031@>p5+7;( ztw23~Ra8vOKZ3vIlO`Qw{AXU4mazE-Bva1h;NXMhK&oORT2Q~&laaR&b_{1*XE6o) zdMK*?o@(QoYNU0RnE8T|OCN6V91NmoV;LM*vmW^a>5gClcgL&E%AJAuv}}i_$2pi& z)H1?csQhHWJ?GrXqIO^Wej%Ah+@&oPz(~^+zN1vsE`+b1{0TVAT2q$=iV`0qXV|Rx znL=BvE@kFh8+%`znOvIm1d9saN@!VsyI(@jo#`OFSX4(@uVv~X>VcH&Yc&?2J8Rcw zLAyo9k~0Q7wo#90Cvv`fFp%0m=f$sxAyv8q|+fsnEJ;=<$1jmp;Z5-G1~Wb&IYv8=&>+|GIF=6EG} z{qbY9mvg@f2zIpH8cq&g#zu-g0Az0Zk&@tV?2x(xdioowLN-n1h=tta7&2?glVTrl zr}e%Xhho4h-d7W4e^Y#}9=D={#s}l{cau3)>$3vQin4n18vK?r_#{03ANqaT`?a6J zy04vNC$Gs|290xeb2LyRszlicsi=9`tkE{))u-V$vFyL4wy3!)yZ3Ma&Pa44V(!=F=08bB$i>EVB4(1g z6|~+9J33w25%^Fxn_xsbd%ju|yy`dkfuI8tFp_oJ4;=*cK9c`DdebXEzRq0B(znfd z^u9O!xB2O^mIQ6Rf94nY=|Ue!v-0QNol`mn>R-=<&JH{Gq@rnmM<7kW^$Rd+E{ zr!FX-QtxXU%7ag_Db?mLY8zC?I{|yc?xRFIztqRKl2lu$s7;H`Eo zY#WLM5ZsJKe4&0QZX2N=>Wa5Li>v;^b>}GCo^O5&n~1Q-zw8S-u>O6H-fiN#mV&7{ z8M>x{Yq{^&eJB6D47QP*-T@iQecy}tock_hF8BQ$)STS+4F&C8Tu}bzg7-i{e^Tg$ zx%FL9kbXpd`&*uc+vm{KEumQ6JE-D|OCD4Db6uJ_d8HXmBa`2}dh3Ac=1bV#p??Ks zbIbSQt54hU`V^P`c(^RT=C8_Kv+2?|zFT~JN!!W8XScjf-_a+1%TMyhYw7E19KD2& z-BpClJB6s9qQFjYCd)pvJO$@+E=L|@cU*oUzOsu~6b~#c53&1!-vghj4$Z zDtPrggcTv&WvSYt#PF7)Ci5%yKB0KcQI|HGVSIoxalArFss`hu_VJwrp75LE)e2=H zwjES1og~Gn_Y->8Xa0J9v25RzL;lyQI0#p6J4Y`7G#^8LadvV5%>0)oAz-u}zX|ps zf=whH_p@y7y-sQuR(>9bF`CTh$l283T48b1ZGD2;L$l2hS_34r^+pC$5jBH2dh8m+ z6351u|B%z9A_-;42Suo6ES>f2_qyDnhTyfuPUqrfLVMW59~qwo*w}YR#UyKdtylhD z%Euq0So|e2v`meEn`Z>PtCi&t;#ZCXr3&;?{Zu{+OousJ#4OJVF(WmP{nw&nRTpQ zQLexDUmY5!OCQ;!O!O>ZtXVz}V{zvU^!+lyV)7pvcW)@I?ORL*hgEm&#DM3++ z2Jm7N1P5CD$ifS;O)oUy5oE!drxa7~V!0Fr=RWLg>xa7R*s^8)p{^{8kApki&(e?zpO@}Haed?1mZSQAl9V<*%{YaOG_)G`3 zO1rGwHCA`FXDj@IU3ES^Yav_8L*%_EZDZBF2MgRH?dSAYn=;So_J4o$x>-yQ^fzqo zz7}+}2l$dDXLYPyjleY~{x8wS1ecmk{43g7#lo{Xnquv%i=975HwM?faa^)uV?*(@ z>8%G%J9EwGjSVH!PD<>@>o8siuU%7mQo^_Xp=7PIXZ&kX_0=>NT%vW=KA4=n_LQRb zWyOh#mXi3K+YS`im794sS)z>}NqVBRq5InS7%;=_$}?Z??aI<+#I=ea;w82WX-VQU zHSOEr?4jPrX7gh$fghA+?~C^z^o!0X3uT&MG%I%El);H{v4{oxchNLlJ6d9teqsfE z!)m_ilhGKb3|`792(-WfXH_LHv8lGHAndy(dNlJgTHL?_W-|*D`s&3x;GSSS^TN^g z3;mr9z5we;3_}&B;WoO#F+hKMZ0b$%*Rwb6I>{nu#ExrF6?e5YY#h9P>&k|7a&}R}?AkY5e-3cVmW{9CCzP(T2)KAa zkbTgp)N*!~gfhAR%q*oF-kMTc3smxDz*T0ods#RyplV4nVWYYtE($&9Lw7{AS zCxaYjP9fKJl9=H{KW#F{L+D!gUtCBb{#$arVHL*^maLM@<%B2Muc>rzy_stZqoh78 z3~ApyF}o7rR1O3!-52^@g%VZI^_nF6)KOlQ0M-WRQos^60Mej2^03_2U^5go^B0o}qkdX+H z=380@TSV~cp9mWqtBK|m`lJh37QmF5e#C_O|*y^h0e~@ zzP_Tuov(JMjR#3urO3av#HFM#9*tX9PKht|fTdxZr)Yz6t`00s9GspV0CmfWwKmum z5@1q*yZ9DsucPLCL>o_htTt-_4u(drk6+=yJws$~Fz zFARXEu;7LH6Zj?5ATWNFB-U|-geEI8w^=(BV*9y7B`Y$EASB)_hwUuiKw&uy7F;j4 z=L*pen{I1#llrca`gE4VgeiNfH$gUfsItMFX4^p0zfMVpNHYR+@u90m%*5)FN&3xY z%U#luIK!Fk&*l^%1aMQJQdJ;s#@g0Gq# zLk@Z4VGkW})P00LBKm*jYudC#cZNhs>5p{w=n?U1N|OijfKVmgaPuu9D_g;*bx`tn zNyE@M0pYj3&2J`~l(7VY%<%wg~)lKI?p#ZFeZT=6v^{k{>T4YO{Zt>@G1)d{&4e8vzis z)9n`H6njs%0A@Ju>N){!-IMIhPcq*?Cr?jmN-y=BOO>St6!VDV+0k-_&E48Pv}L}1 zys%{@Gj{<@D|LTZtB9HyH897_AZ5Ic?&Gi05J3`|3H^7X`P-+YKH*fdwJ(P|@WDTU zOEu#QWxdJ(WSzvXVAS;-PYk42`klF=!&Lx&zMLJ{EkBI`Zs-;I{Vt*zg7ZOGQ7$A)4lQiK_@%p;bZ}wJh^(SH#i3^Uw`3HeOrI=4W6Ppu z+-2aqv)3$Fwj<|Ky=%4sKsY^~tN{e_bc+=9rB6Of4-;S`?td$%UkJZ@fBpIWy&u^n z+utvJv#`JOSK9t=b@#>w>Mttzf7V|MUVvNXlmcF{?UxC77eSI-@Fq*y(}LcO%I)%> zzTtK`IoMu{0Y?xf=UbZxa=rRNC4FS|xR~tfgLW@GW_HkH5z~?t@d|G( z!TW?V!~3rNq7-!x_QcH3fwfEu7yG5Hli22)G{d_bq%3G}NpE`%IqltP+Z&hP-ZuDw zZSOj^-enEdzh`@v9~=YjGVfXbqpoAO@N4Y}e|MW!#&yogwU!79(8Y_VJindf^jr zg^OI`-aVD=4=zLmRF!h~fkKV+R-3-MdkjzxEX$hy;%l>mZjHN*e!?~yHEA`XVn`Zr zaQ%Q-++pMbGI4Stq~ZhsBoXVB74%2Tw^W>&&p+iIAp4DA6a6os=y6Fm=UBa_AWgbM zQD1zM&J*Qq<*Q-{f%lYmNUDK(rcm1BL?Rs@+fAi93<)^#- zvG_4Z$CWFxdgX0;b)WRE$IxiJ&hWcs_u{<%yHg=Q>Ti@{!f`W7u4u16Hxg|rHEm#1 zX7exjY^!5FL}I5zSgr$Gn=oJ$De|=na!Kz@eT}=nazSdW-vP$ z@l|5k-TZZV9}Br{c@;Dl_%L zCrLL?ss!3s`f%~_>?P!RUKNu*6$q6$ChH3biH5w2qj$7>6|>hdrFAlR)i7sE5d9izJv|IdR<2kPq+w z0H=o^IqP5PiZ^}_J}&)N8-DKkR(q@{;z~?7!3{`sJdw^iJuYS@ z_Q~fhTYH~CSWsxJb25U_!OF)J0`UsKU|#x+4n|^IBF2XmsGMSd4$0Dk>CqB_BbvEW zLAv%V7o@9(1L_cVbuo4Fr?i8sC*@&Z&My@7;L`9%sDFT$i~w9&=QsZi198lDq>ESZn8ruQAS+V zkQ3_IBJR!WW=f?-Us_i*B~NfPot)z({?KsqM_`&BLdwB(Js3q#ILh{uPg#{QYHt4k z0*uD*)vNQUtHSz~9^{$`2*C#Z)kG5bKlYBCsnS_S{_z*7keU2Aog3$Pus+1rbpU5g zF9!5 zIT)G$DC^HzE7QUFF^Ci%M9)hvCGv6s2nyjRc8q@EhnV_);U{$gzZVctbKs|(#1$+0 zf!~Q13Hpa$K;ZXF07bZCD$jvmz|669<9)(Ur@nX6Z9r5!FGdRkb0?iR4{G4-kBsJ* zKiHO^V15Tv=`Ai8Gk{S<ixP_l?O^j=vX%4k5 z;o<(xUx`pt)6=~l%O{+AB(tt@IrnK7!IO4H&Duo>&8N&NVoUrLEdrZgb71_ya>Qs_ z*`?oP2bMZSNZ~%RKGT{5vG@0A@8i35Bf~}#6YP*Xy8MU;L^x*rf3X6FjByB*Uknra z{VlsW@Sa!Px%kHQLxi1M$Ut>iRP19|@!J?tylSa-7xEprxS zT!|XIma!%G?^ZvyGV=m0=vd@fhhl1zdHm~gw(3+AJW{labX9@;{t)gz%&qv8QWPjk zj?HY|LRZZLDbT|_37FguZ(G{!=)4x9R9+9jdRearuUqMpyQXvtCStbC1vu;r2sN~B zG6StRDKFbTdaOYo%nzoR=gWT|0DrAb?`yT>kG4Cx0#~XE({^CMO3=a%a zfrmZwAm&n0IxyP;;Qb<|4mm|ulaJLjh_BGTmKv?MC1n2S5?&Eo4>xZ>U6ds!%UdS9 zO;4d|j)Q@QtQu=B25rlVM4yvQQX*CjN-y0{BnMe`oyeendp#Ec>}pTP__fb?)mpb-uV@b}&%D+dp>Lcr!q)xTC3N z*OZ0gwiW!Uz;AfOJf;>DU+K9S`7JUxDv*`y|5FmU2y9dK)75wLiT&*wVDK*^caC4AQ_u9W-@0+Wy!g7OrbZUi2XTHp$4gHf>2iApS3WapeoIfuE3Of< zpmCm+BtGK^maMpm{F1=|$ujyS`YA>YUL>3FI8WGkA_t5g+GE#Gmgmh+S5^Leb(I&) zXUCQK`OnWUA8nZxk3(u&0;Ur>>H<@=McLU2%TAmP51&4k#m@R}6v+Mq$pQdbDQ$Ra z4SLby^a_9X_|zKI+EBdWQKZ2}=nt8Y1|bQ|+mvX;{6p!PaDegbJylTOR4vV3DyuEs zz!fEuI1+cL4lir+z?KWNk5Tje7O7H>8gr9K2Nb9@Gt+t zYZt(x%W&^gWD8Qy6A|@wjX(x<-#_I-Uvjh)6geStk~7r- zTF5Tsdpd4`IPkL^j%Inr8$XRrL>*uvo3vHHne%%;EGo ze)f|bp;$rSUi#@ws@Vk*|NXD?^53s6Sby~)MV+h@aJ#4ZnW0~y72Bthrw+D#0xYM_@g zTWM$3H9M!p{72+9++E;hWk{WaoFN2S<&O#|gkv<1 z?HF<&m<0&Lkb8s}aW6&dvZGIy%lrJezFT+nYK9AY$=`HGvJ z@j{b?oCL4dt&|6RdOxc(TU-w18l&~1H)l9q`aq~AW7aV(ma{HZXUS?fgAxrP1yg4F zk~Q`+h9jhhOj2TL6Z7-iGqOG0U*3QEnVcSSRl2xHjGP zUiCQ$7GJ7rUrin-(Y#q5MK~!krX_rQEg8a%c7`_M>x7J959l2=w3fH*!3`~zKlvZQ zo8<@XE5+ZT717HyDhq`!uNh{UD>G(gGr1(!o9$WK_sZm$F<$Pr`vu=Cx2&=n2s|^pSUXhTw4lJ(`6ws3a?-V zq-Tn3aX5kYL*@Y`ULsl@M?YtJ{S039S!R@I)xEGtogOZ+Ygdk*`8!BNK9r}AV0w0l zm#|EXS{R*4sRu*C1{%Q4zoWkpuOn)PdR#d%bx(aj;%p>?F}@cgY+0Zj4pcwI2|ZnW z#mSK~sYbZOU3OIN{?|Tvv27^>rsk|mML(0hscLhe$P#lZC$if1Y?H7Z_mZRN*Yc-5 zk`en&QTv(2=>?VL!C7zO30^@i`WT$m!2?}nmIExxs^F|{!4eexr;@{#oz*_0gcVTM z5pBOXJ-$F+w zIu9!3XauL3m6vT|FLY2(M@jM`!LW&DG!;b@&x9=kEuPD75!-EW!#4UtrZUs2b^Dwr zdOC^|fz;=HMY^tovvzXJ!@)h2sAz9MPU&>^Ix_;!<1{p=c3W`HUWOIMD?=Jzb-B}# z+KxgKoZZ2D+0Dd;*-8WPAIKkJ%`Ii-PNCjNHUYp?E>}#5D+HBP#Bb-J4z*l!M$A=Y zlx$+9tcr`_Q4^ZX>$&01n3S>8ve4R0u8{y*0BZF5T z$C^=oihKX-CIdTwRye!&%zjHi7~Jqvnc9W+pOpZRAF}8{+_5R>`Jy?Pz zW^iw{YKe)NpHiQ*H^#2~0}u}88f=<_{cw;o*jef0kJ56&f1BT9B5`prxL!Q|nFYD2 zp(5(|W6jX@RM3~6=Qq!bocaRDn~-f%10}D>rY%b zK;2h(bth(lA!PuhUcq&&Tl?N%^Hhu7OLlV~BT*};UPGCQ0yvEmYLg;>nqW}Y%hVxBa` z%saYsBR+>?Ij|##$t%sL6hnl4o@VLmlFCrGkM$#Jc)cmrWHC(q3}bLP-^;9_g@`th z<|b2_Ej~O4QXd9@tUU8;Y&q6*gro2=4mENyxzBt~r36(u9}?7JwF3#ll=;jE8Se@o zmtKHxq_LT2PWFU~HVcz3EbksnUSvTj9%o@vW#(yqfyuf3!Q>T1{al!o=fNbDEq)|u zSHX;gXL~)r!!2u8?=QXXYJ^x>Xo=jB1>r{^gs2tPY8>S*HAt>-#`csJCzd;l15KvP zc5O<7Kk;93*{9#WW6z1o{wwDXe+FNP#G0YhRptQ?ZiIJZkiueQc~>@@BVLnpV1i{A za{K3fz#4o6f$qtUu0t$$iDA9(R{P1W?QdaO@pK=Ft}RB5ikLGrs&r$dFFn_9eysHh zH`@|5FVyC&%MVF<^H$lOnQH8EF7qYoW9Btst=Nryu$z@9B8^?IYs&BVdx}eOLutgP z6$)&*d*)QXsgA-RW9G(sMKemRdRP$R)0>>jUQcxs)8>ZU8c!hW>9)qyN^GNAA)z30 zD%^$IOs-G#R`>`f!GLzPmN*LYJTIl0Mt}S!uVCg9zqyfehy-GTYP8d`A2#1Y^r(L+^R#=^())1tdjCg5R>`flxGh*ST=4G zqtSHv85!I>Ik=e^F)#Rs?^XY>PNcEKaq?$OEI#+gdV0Jne)~DHLEUn`!n%8$mrxnM ziG=Qvz3*SwjMFt^$SF-tE(uB$CwLHNh*s#HZlqwOgLYgj2cU8h+y2 zwd5(sNfZ9AHDrkI)KAs+Q}=~&qwnSJ`?9$2lhUhz`#vuo()YKH)hfDAiI?m9OYZw| z@hW|P+I=4zpRDgY-1p%8ctk&>KC2VTHDPc?BT;rtadK*Wr6zux+@wf+3Ygji<`#Qf zx=J($@$ufDwYRt<9@o4V+nR;8&nAe7E^G~=bRNvHcafsgeeEx!L$~nnF8)2lzd!J= zi+^wMZz#|?h<`=JC8hok{-1Bq;16Dyl0!aBp8HYOwZ*?IZ+&c;Q}Dj2;QhA+?{mOC zb3K-q-utQ>#b~u8KH=rjAq1Ujleth(MC>Z!YH>__EtZOSE0fMilTp;VUCKF%(DbAy}R#x$^ zn*9v3^;6QW5a&VdD~h|%j9*0tN%)~A$daBOzsCLc74I9zrCTex(4?4Z%Daz@f7i`$ zv6msZ;cv*Wl1XyhgJQu=Lkv_@vqVtPe?Pc>MKy${TRfC2DtO{1a#9bHKg0M|Nui={ z$)|>K%~wgSMd(TwtK&sD0=dkL{_dB@hT>n}cCZ-UDxBTvNtyovLYzPjm#SW}?wt&! zf>#s+k&VS_IGQ#!xZ$7lN{h|c{AKZ9kY2i7p*|mdrqXPL>M%`J)YLsXzS)}+q0tvA zK?*o#!^^?-e<0aZEpx~{JTk)eX~%M3vwSFhusL|o#Hu>Bu*A0CGAvU1uc(C~CAk1FQ2SVLeT*z? zr@(mT@*qcsritz@;g>4-S7okKi37=3&ID7{5Jvd@A#HqB^+wwBq3A`eHs* zaGhh~U_O-ap@a`Xx#W@Dr`IPrk>8s5R(@IroAWTMr|zFn^K$pb`2E@Pa-z#Czx-XxA8pHboyu6^&v+HIB)rle zf7jC8*o$esYq*s5dxLICbbma)r?;-|%J{3ib?+bVmY?h6CFJa`kN?KYV$D7-G2I$_ zxACrWTl@xWHGY>@K`$x(0;QS%u2qtLZ8rT9Z#EAGBpQE|Z1MlIb;pI@vnKuKBDLfdTA?-FjM7El-~K(b?c?S(Tmtl9t}|7f z1Dx$nS?!x5)e=|h6MpCT)IWR|A7J-ehSmDnV}ZVHMVW!VrQUffF>&Ltss7}+)H`n{ zj^21$@zloRnrou>{}BcQT3K#?wltHkKxaD9b?{-wMg{jepY~qTbgD zjEg*@<6URZaTFk@rklgij-bs2Y0}0PgjwXDWx4WCrO3Lf=uSj-f%FL@3$Vw4H|qF~ z#6<`J!3|GP&YA6Vs+`p@{os|~gzDA46a3m$3zZ_L>OT-Gl8B>h?w~ph*TU4uD_LTwU^u8 zjVBOUCh4Be6lhJe~N2Mz@KeCL7`s!DV|#5 z;m`EqsWYMtSL+yjP5l;4n8@S9`i%}y_woas&_d%fW-1j8GEfq$$D8CFA!ZCqYe+lU5-o%_!zWg-{gaq*cgCGbBe)s0wn@ zD&(XYU^A=oi|f3WDrpJh{zuo+fnG}sJOt;u+qxnh*N2AR!SwA+OM6ph!&3xX8#@b~ zVNSRbJHwT;!j*)`8~oaKm~gSpa+ZM!U>b2vA3Fw9BkT z0P5eU%Pe_Tb~5M4j8<{y-l17~Fos@%0OjCH8Msm}2*N7{rdMka{#+cNV4gwt@ZRdo z<0`3Co-r3ov31)C*UuJ3%>0IB3o@$tpcOZ7lEYE+YxxQ$E!X9XE*e}fL?$&Ea=ey@ zCNOHU+(bENe#G2(K(=?Sq`Am8G1Xm&0^K5%_oUubWIJAvZ8ymFrXt%#7TI=#Y;P*E zU1X7MH^}y;BHKk4**MR?rYvjZfcPwc%xqv)rtV)TCr;0mQ}s%Fmb)K6Gz#*6S4DBL zS17%EQZ0#n=$)jSi>!{(4}lh~RLbi=(*{lPOuVNOQU*Vy8BQ?)q?3aszEJW6M2f(a z>Au7WyF=fhUxRk9e6HM1fDIu;?3tx@t66j5==?4YF9qPX`zdFE$zr><5pe{AeJl=d z^K>RD5`so9szV;QWsG2^I46jgoG)e;sRknE413UG*`f|_k@(Gz7ARW)fA(poNW>K` z6_E8Je@yEk+8AB=hwuRY_-Y>N4%}sVz+J)vFj>r)Pv#1`s5bJ5>CrAis}ohSGFiuW zs$QUd^kVdAA8|LZ9aMLr0^s!Xs@@CudB)5uDz7mCZD&ybb-FD4PQ;g*TAVyauUzRh z+hR_|Z2O#l_;%#PhvsK4_LC@u7w`tWG410hdItup6&xC)K5$_+BtgLu!OhT(QzaJp@NETd^W^tO zbNF#jcie?UAV*&$2W`F@k4H9A0*hGj1<*9^Mf{HjX zWCqJitKxBd6m{aPpGlRFE7 zK%Ooez>M|~4~pJIv!wax$XJ{bnP7)%z;5{Pdntb7r;alOEG@-Fd2&1iCG(!lB zQFQQ0=o{1ZQ0)2C3K<9L^Q@o>Nb6$|#QJd5X1;(C0+Peb0zq;)A2`sn%7JM88OF)# z=pS+X5??=~9m<;|ml6K$!b&y2o9Qb3zM*J;6D&vj$p2yXYtmfCt{SdWGL3 zBfw>1o+|@TMb4X}36s5Qi|X~N#UefhWQ&G*o7C2m^vezs{{MdM1q5tgKTl!{(E&7l z>{p(|Cj6#-+7tK=t92y=F{xWK9e#1*-|^xWyl4o?9$l~AKLEQkXy3cS3IY?CEC4HT zH8zi6J?MQv%^1R;YAN2(=F<;b&zTKs?LevDv5T%r6^kKqsz~@TTHwIC*~MeaDg3Xf zs?a=_ANyHU+M_kW%DHp&)<3Hqzi9EO|H%gTU7Ta1C%A7uy&xD=4{#gEjZZ548hp!& z=Xl^1(p9eoWoI2>_sz57 zWD=xkz_9K6$a?zKb68{{P>>NMBQrrp`ir$GwrfvfhLEREWNq>kp_PX;aLfOhRYpk9 zRFrueiZaeQ%Jf1O5FIiAWtzrQ?I_18mfA6+E*OJNynIJSU2ritv8nlZVXF%+h6FdY z055EH!Nri^s;T_KC~#k4w@Jyl(B+f-p~b1+-;T0$G^rVx^jZPxn;1X(a1K@u3EG2D zzt6MmjP1!7F@)hinYjjY(GfMQSnroelrQRjeW}%AOe(cg?Eqh5n6vE*rfQ@;W zGn$_7)1VH9e~yql1abHeF!A~TYYU}|QwB4Mr)MQFh;9A^<*@bwWNS$sxl+rdN8$%alpO8S_N`1kBIJmAq1IQ?;QW=^{BSO?JsV2xnf3%quMQF@rT;)EsRuOi zfjo$qJ)XoAHp8BL3xGU{LCh(T=JbV0xZqoIknR*P_8{J$^P;RWOMdb+e~A`xXHK5g z^X-kV3m20$taoI!in^;@k6F+4$JwLkqeqeHL828zg3fsXw1HC$T?@LlB8r5nrym9~Kp2KvJFo=$)Im2N8Ft10g;q?77sby%I8-Jzsd>nFM`_M}wb_jfcg~O$yhn)&`bP9z^T53*D z{)nI#1%#*hHe@qTB(SuS(WKYX?i3OZp>P*Yq?Y^#6&4q4r@{hbh~ds3PvQkItQJtL z_V)ysJCQr(K}H|VW&bWiE3TiSek;EOaoz`DlDA`2d%?~9zpVCoX@^enI?=}2Aq(vD z#g6o7cDkk8?ns}Joo?wnJJLsFrE~jpGn(B}tRt#?7J)kWzyki*>{ic%xba|fW3wsr z;8rhJeY&zvZ4^wx4he&F1li_RSPvwFU415@+;&{0qZy*y)WfK`PF{LU)k-jy6Q<(O!7}a)nA?qe{xZ-TQszVu5Dy4MJee1rg%#{+zMO@yUMr~$ zg$MClc(!EUEAZ2px`_ps7oni6YJnlLR)!R1W8qb!ryApM3sFd&hHN0OsUu-VE;l5h z!mI2Gq2NPQ0-TKI@nrO^!t%92W2M-8em;T4iV;rgd32j}6+s|If-q$c7iiwyb^c|~ zvxoC4|66v~k{ey0`Af2~R?c90YGTu79tMb;e?8xQPvKC}5{{Ha;IudoS&6u-EnK z)#xN~3tDj?8KFgHv>%%d43Pi(%Kws}VMqtk z;t=9Tp;F;dQ3q8OQ>@b8HizG3I_A~I$?VO4g$VX1a&^0i)sAJIX%c;Qn``UWDtE&b zlflSi&aRji=o1QqI_@#We^_67y;n6X30$x1o>{ zV|1Xw(|e7`F9Vy^ggyd?upEl2MlB)0B@=vZf*yD{e~I-~Ljf)LS-0f#wI8oxksn`- z)6IU$Z6)y>)06lbjhH(@`HGtwho|#mMJK|$^>fw zjmmuocvD4&7hkZS?;+y_WH!*g8 zU4U3bO{hE1EEwA@W6zwV=|nodLrf>2c;@Cem zex?m!2AN;9x_(gpPqBw-8dr&k!A+wO3}-5hVLl%FOyhzjP?65DOrU4AFE2TC`H0cW zHy`neXVto?@$E|%oe1xo+Xf7vcTN+&+Cbj&Qe|xn8=g9_4RK`hQu_&ENcC&uh6Zgj zXaQ`f1osl3#(EF=>zKdB7>ldbwNZjc)5*FW`_Ty0Hx{3X_#BH*5T7tUbMcAclh-}J zd-v`I`0%e#e`Wr=GQT?iQPlbCF2C)zH>mNw}OZb z^GP}NU6J$LcuaQr*Rel2>tCLee^R&X^jfIIocZ6uR^fck^JG6C0Orz}zCCArvvb<- znbUqdtG}#9oOnw>2Ktw3p?Ny zZAb+!-^H~~KJGzV!H*+!sc{a&j_=qX(HMpqt~2PccEKR7F}>P2_XvDs%+{!Hd|c^aDl#c z#Xkr1S@g#y%CVAyb_A+rOppuO`=Ta923r_Xe+Jhb zRF6X9Hn-4OEucPk@lEv(c7T_pmLj+qcjezX8xZiSU}SU&7AnxYOquvm zuSR^4mHU``{Sy%G1;aGr%uHqu8Vn1C)2gn^%>i_P~ zTA2NO09J%E|2ZIDj%VX^ASTcTM6ZHVl4}py#`F&Iyh-w_x=GC2nLW5&Ux&VNJ&+7I zY}H|>Ykk@#smB?jEv(KZVdIr!gN@!;Eyl((#nJO;z#y!<0Ja|@JgmU%fC>m{KJ+N* z50?50k6vLmzX<=%wIhh-#y#^fPzZk?94h_6S{g55TB4&?zl$a;{<2H-4`mC3sS`6* z{#2^OvWU&qRfbo8C{=*D8q3Z5yP(c*Mfrw)g9rOQP|EyQ{0zpk& zl!N)(z*TR}-%Wb{P8TT<^EazqVyi-L3ImMOFh$n(MpX>-5XIObp)2Khtf0vOiBX) zQ%s^CCtc;n~prvkb^ME@!X1`VLpn}poEq3H6O?)VP3=klE>oDQ_U z8yMgPv*ZmLQ7i}}fq!aaUyi3Z`5Lk~(pEC<9xIK9&W^O3nYPkOy8~&EiD9$gMa*e9 zN;2{OVqNKFIf)N3@meeKtenI)CN8uRryuIK97pzPG z@b#=Z0pSv+XnS9_R%dKPLy@AOIt0a_?W+JiYdyEX{1o_CFfp+vwgcYWf$~>Q#B*&v z?uL(TH=kLXEcon~<}>lP3qQLv{#Ey=pLtG1dh61B&^nsbL`g6<;hj$CXC)j81qbt6BkKWvACESO6zfo4PK6)T0a1y7 zF@E)_5M`kd&*R8$4lIBMsn38$Fzqm}6pVuccrvzxW$THN?RZ&AK;w>Ns)m2ikurbf z^+N`DllXKSI>7q?zN_*5EWU^0dp zO+MXDuF6Se}c;#KvF|$09Yzuh3F8_ah?b*u+|X#oNBm+YPg1K zxQ4m~jm5f&QuV?iSp~6vVq#*g5wl+1FX?Vk%XwBI>Pd}WOLfL|sG?r2l=R}(g$2|m zy&(ry_3HN@a7nrmtalc{c%yF3tA3aW}u<<$I3TfsB=o}#2Cdq%b44VV>Ikb6TKVS%0mKTn8R~unulPXecWPd~i zSE_%T8M0n$m}SdfXjgr{v+A){)eKXERZgd*v{)*POs@iyv7D)-4~q4WjF*EB2uX+wwJG<%P}} z(qLY+4>J539DZ0`qxY}r=*Mf(6V**00-eG3M<s8OsGM#dhU4MxUqgw@=C3dSM= zFd+(PZO4~IG9s4%BAfaPMDzieK|?{Ex&_%fzj18;0AVQCH`R;Md%7Lml<2P?@LOyDWAhC4XK0v zE&veRQfJ7{=jP>#07X9hpFoD@QB1T>MxN*SdCU0-JjI5Oa%SJl@o9Z!WGo`ntiPI} zYOuwDW*0(nSg&f57!l4o)2AyG}Fvkw6_n>aU84cE!_7p5JeDt2Q(gKlHYYxNP# zCp+YmV!Q%>=;v1=P=c=(SD=A@kl3;c&40fm(#YqAQ*70&1NVB?(6=jD{2np1vUAiMm{J+hxS zL&4&xPfWiu$~fpWw!TR$_u1N@u=)miRMEGU7-tjn^`;qF2x|JUY$zFi)Yl-6lB+NR zZbxgD90kVI5C6z{Xp@0dNqNykt29A1atTyZUxDx-f@YJHD#mv7oTZPlG+bwkM$gu8 zIlA7ZpTH=%2b+uCRPU!_gN*kxV`z-TFow_MB$s2D+b)WUkW#W=Q3<3&$|q?TXOISj ztbLGa-SzqFLW7heq#n!^>aGu8=NMm$6!J4i0u2*VlZ`xsC6+l7Ct{4B{RT4&uM)qWG;g3-N%Lf4lKzW{@!%WN!>IWS>QB`I0kSDkJU^4EH8e zTO)dEBM%C;t;v2CdD)m95gFK@9?5a2f%}ugCu1_yXta}X2Nl!4%D8%W7v5wZj!yQV zt88Ss}rz`h7Bg+G>uXB^VF@-SO^;htr;<8h_Qn}9EI+{o!|~+0kS+* zOw=Z_pu12o1Ha2)+euf5QuVkTevoxraTGQ+Z7&A<&Qq}&Lce_7xfnB;x8?m<2L=lt z=Z{i@j2o@@7sz{HmZ!NIhxm`7bsm68Y&`fD_;r0<)fX>9n2Tf~Tap@0j%5J%dk)Bu z=wsHHKE>t*KNcOm3@26+z3eDEdfD9~%2ZZu6KI9iAAOqtP|t(u4ymVw_4aD@Ght$! z^EINBE<|KOiM&V85DcR5$)-_xR)Fk5Opq{l!SrSd^yA8qqiNiz!#vGTqMNlk1YYr| zy7cBk7+JXsH%O((ZBEAnT4@@WpXX@~aZJb9W2#er2%Q##=1KHNB4WZndmd{JnZZs6qWJyAWEJDjb+J@^9T}ma((ay*9*aTRV(KNwx>|~ zcvDox`GO(!6Rlfk$urSv)i!Z_=aLMoIiSWe*`7o>(tvHWXXO!J#Uzb2SIGIZXxd(Y zrVZDOFe0MRPfwy5+IgzCpXzvZK}KOO;6A|~2SU0P8w>@QgR=b~m!Z4h3Vg{?C~H*j zn&)He5q6%w%ro51BZzNf|3+lnJ*F&!sDw(Ylh0xp#=)5yeu44YHC(pG8phi-n5=;T z4s*s*i{c!|0;Z4IHT@7PeLB;7X3{TAdhud!sM!DAyyUR3ACBU_Xjalr0+wC1uGlbI zcJA_EhK7R`Bzz8*tOV$!;x|rr8cJ)8kVqQAG90S_oY1x-3G1L0uAC( z<_Dxv^S)&x-owk#qy94mY9j$;Z^SEY?)oK667=vB zalDM=H>j^Z$-G*it1N9$1+U0Uv6=vwY1)T&yg`+hX{ed%MMTVogUeu8n#ZQWXpx}% z3n&bJVs0_&l9s71#L>JL|hOu>fXY8SD95?+0rHg%0>yj5$(ge z`$0^!ZeUM!-!Oq3UtXPB0qqztWJHJ)c)VV9Cr%f0iAubxtx?l4jhJpRX6et30vX5f z9U}X>R7!Y7YBCR{{w~luEl^2s=Q4OM{~AmXMm!Fm5vtd#ga!_Zmsa3#7Gpt`SX2Xz zzu4n4rg0WWK+lAg4~(FN5zCjVXTZBRC_h$$-ah5FPwb+Il!`pC02NKL#Y5eWQsAL} zB3y|t^|*1p-2m)gti&^{#M_PYc1@hB6X9A6laG>i>&6QHv{%>vy>Em3EMV?ZqwyvLKQ*wqLNLRUeTZr8lGk3`uZ3iNE2OkP_;$Nh$jXdI%|@Q8O>msM?0p zV88kT93Ih%RD`-3xnJWJ;I+9GlU!0AL{@6gRSVy32R@WyVyU3%pd+L#NYF%u*Wiw0 z7B#%LJGeux8i3nl9VtT!ckMygQ3N? z%~r09=A(lZgxH%LE&wD;4k!EXa>?QS2E50T!>`5qxZAnpD!AkVSaKr}rvx1zg-@lr zQEKOsWBl#_fQ*1BOT;W|6J{A;#tE|9z7ok`00Ns6`UQtEL>(=PDqm{jJo;MUl&*bV zW;ytCP~_jbCLc6otJ02S}X3{o$bfs z-v~7_?@=lyxp$K!_eL~qvN+Kmba9x$;1zlxi*-eE17DIH5}YP@?T_B=66c_;;G z^rg_S;M&kmrs%(fKNfr$&ucE7@;YGr4@Mlvv(hh5-< zA+f+9iLX`!ckE~}EM4%1yl||W6oSTLw|#Q9UkTp}NBalbk9%rAbAAMGjYfp0_#*m4 zoC5{T18`_o6d#)xog$}6_zj+ZbXYz33}J{4#wyJ2;1h@%TL3R7L&ckejn?m z&wVn-LtRG+!pDj)b2wO5ER1YWaQrwK+%>+;0@2G6k{$77wmofkUdNZ=!2oIm*6!9j zxQ*H!H3t|DuFHo@?7?wkd*qFEIK}iNDp3Xc$dLaD5@G6%gb=s)IH`iS}cATzW^_uNVf!lQ@mCUv>0#DPl0!MY%1dV5usA!<4X{4W}xvxrehM(B=#4LFDPqw3yyH<__K(bl$?iO z0Hz-cAP<*2;Y5Fs7EtJB8|woB1!a74iwIdlax!I8)UyBtRt1BdFwC8tH&GI+Q0Gxh z%7AERrY8cTlt@{{rUOK=@uM-7v7Y$v^CTYUIs`NtP%ZmjQ@h~WP?zuB}AxG8IRWHf1o)Pdv zR>Oa*IuMrV$rQw9;JVPUVyt-TSL`rWW~`i}rS33<7z!mDYEJ2Nuv3vC)nC_F^)y=X zBl5i_Cz(F`L~E1jbiZ%y^k)F8)oCB^Je5wDSoO(9R>fWqL$7_(>$_!FA~T+t2@W`u zQ}+a_abOC?dEm#r!jVbv4~AHg$}Kf%SZXdWWolV zEuVIze=ed)CY^^Yc3FO_m$TC?{ymdNJ(QJBs$VQjg0_s?76sXbr%M_XE@#WVRwP2G zCb{MMNw@}aN6c#}^|&W0 z522v2^Z^4M#48OJGOY$d!nC-U0Z0{kjcXuW>IupVv^;^Rl0?}i5Cw@i@*;i!U<~SV zoaPy@x+UV>!%Tr*D=2+{O?{m)1Nz~5wHX$4k(si@(Zvy}FO+|*VgcAdRfI~|5ZCGA zkgs1;gLo_&#vq$C$F7w6Z z`;9rk@^hS+KcD`A?k5i0DF2-Cs29q2L*gBqdyu;S*$+Wr~W+WPK_K!?5US1%0a|ZCH^dk#z*nJwa zLNX5EUR|ZlyC75Q08F(1#WDF>5>7I!n57cPg+6n^2#MA2NvtH5yTpYk1Ot{<_2wl)iwVkXbq-&<4+aCu=X18c(D14BkWQErkP>^lmRP zyAwP+FtAz;ky=J{)Z&<%|Bj!cFEJO65GYh~X1(d7!m3%+8eD;WL5t|ZO%0A$D~teF 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

4bWe?C8ej@d?k|Y!gH}!up9!cy_L=TpNrm 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�aP*i%edaEi<$%o9X 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≠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 Kz*gY9EASt4h;2#$ literal 0 HcmV?d00001 diff --git a/OSlibs/win/libcurl.dll b/OSlibs/win/libcurl.dll new file mode 100644 index 0000000000000000000000000000000000000000..8c80e23eb22667f7d5b517faa204f9c30d73a13c GIT binary patch literal 320512 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
R_ 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

lVAY&&AxLX&?GI{l=sbD%XWl8?o+Ju*YEb3){IK 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ⅈ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 X`G6-JO)!vYDEuGx{`d8NXaxQj(%IsO literal 0 HcmV?d00001 diff --git a/OSlibs/win/libcurl.exp b/OSlibs/win/libcurl.exp new file mode 100644 index 0000000000000000000000000000000000000000..a2b9da9892721907d902a3dc7c86e7ec0ef9b217 GIT binary patch literal 8337 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⪼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

NIicB9=nAyUph2p zmYr!+=6As~G*&2tS*u68Hd+as|q_s`QDXJ$u^5eF7DE{B6aE{0vgn}buj0P z6L|5V#*L4vD?^YwdUb&-GS14HB)7fK(CUVfEO(Ie5UWY{IEtZ#)huk9vBhgOKZz@o z>1O~p_b$e;YiA(Or>@pz^6cAvR7Y#>llVmBqM5F{ULKy8sS(IXjMLT+{PaI;dRFDY z2&v=d(*H|fxMn3kmU8G?7OT`TL`jh{lU1lvwDtGfWScK!Tc;+GK1H^2Ge?7HV&(FT z@97e1J}U|2pkX-maJ7v1a)(gZgrI!te93`fMK~%)0?)|!yqxCysohX8ST;}{ra#=Q zB>8LA^?X2yr#jh(PfPU}$$YYtdBp0SX4ZmcF14+87!zZ}W{Ly_{is?~P`!E(Qqqmy zpia|NQTlzBbIZ)}UI;{eM{tLrrN?{m893f+ zD;AK<;#2D2i0DigD0flTI8s{pga-8*H3_L-^DF&9wBz{=2s&@g5k$}-A|o5rk2Fr* zV%X7@vN!oeWZ&~w5@wKGPw$}brw4sMGw?g3zNf1D1;MGh<_)Z;lSNM{rFK4e_lz0z z{Uu;zhA$fQ{chF3@Z5pr={ast{09fc&lwcHZP2%1H8cPCp!D%U@iz~O|Gk0V`T!>N z)?<481^p2l#PsG=Zpe})!T3gqTDFeq(P}y!_$66>D}7TR5yZeTeH<4~_c^`5ly0d{ zZKEUHHCuOt9@zlcx7}^D2rTtE$|vmCXt@*rFA&(*13 zorBO~gSz|>pbi@VO0>x;A5gu=S@%9bW{ei2HEx=Om2!nV%Z--l?c1IO%bhC=lYX^? zEcBQy)0sl^7$Q1j%RGB**)YpS$Pf7x7C^!3)f`s4H5E0RIq>aoNqzQ+@uh?I3nYy(hos9+B&^)hW6#MLmBY0aAgE@VstiPaipFhfixzv-P*M zC7j_@K57ty%Xo*>pLG7ddtHTSX^jT;y7s+UC-7j&poVCtq&*onoFq5lzk2PI3RI}z zHpmnys37`&R^*h1YV~VfAZg{NDRhBtpna7`J+A#d@l|4)ze2)k1OI)zr-hA&Ef|gGyF%P(U97#V~NMFQMxK;@~RKItM}vKQa3pilRUM%S`i&>Svn_>?E2J^pAa!%T(>fHQ@X9$9_#74_*_ro>wastcghp>@wwi_vV5dMA6dxRub4l5Kr&wl z<+{3++-2~AeTyC_JRMuDdbChN3eT{Lfe z4ipf+*y57&vpIFei#{o&@-CFrvMb9MeZ(J(KI*3!zUaGo*Ouew@A(R%b>qrG6@R)y z68Rg{kOzgZ#31KlyV`mww0BqZm!i*fh0n60dcG{DEaY@(C?WNGotkqIBn~BNw=9X2 z^VoUG`^5|W0}IP`N{SX=BcZIF==eBY(O=#sukg86^iJNUe5IkUaiEK@tOM0k1Iv<# zItTF%DMRNVo;n9{NDdkq_1(_HvK}wp4?yy7kOP$pp zI#JhSH=&enyeV2eQ!36qO%8VLK(5qgA&JIEToyUMM;ST4fKsU2)fcpoo~*5sxeajM@y<)Op=>~O4P4$awJa5u24Px^8?95o891B zahtLLkSc^UsamL^>=EZ8lA1%D@Om|ypy-ak$Mfn>(#rLX`;w!x!0`+$O{?zTJAM7l%vz+i9{P zZVyiQ_i>G941((cZsVESvtC_B5j6ismHjccg@>x2R+6BUl5=~z#6rMZ`dEE})4CqD z^_|o6v6xtaiQ}okXonyEy7JA2(qwcMh9-W^-AC4j)curKchGRbTsUzwnYZ#cOoIjF zLPi8VTwi=)*P?hNWsu9qp$c;dKPjI_%7qk&028I^E(DlX&4^@~Mx=ur;MvMJPBl`^ z8tsfStEMd8fE>D9&?RzcU9H-tnMDC2PUIxy&w4v5^5^r2jsCR!d8YOk`BRr&ru1F5 z&4Xqq`g}$jc=f4LZ@uaIlhMVR!^wc4$bQY$Nf|LYX6vohw-h+99;wiP8Ppkr~!VEz?YS zs$Y&ljH%4o&iQ!Pjjo7jkizBw+T=x(&Aq=G4 zt&gqFZ^pPtjTR*l*V{hhLpb%SOC<0@2?WB*^TokYfDq#T?Bz43&ky)l%1MC*eU(0UIXH_0w*^wh88I8yBb;HSXrLV8jn->`-aCGXvPfED`P4cN+n!nXyU(4}B zAHrs9)fda8)50E%mN)Q_#_?Hg(!y4gj6$LeppT768T?i1%g!6rd8g0;&{0Mvm=?(# zmi#m+-~^GWnVg`JY_iCvR;Ip14Qf1TqjC{(WQuu1I`MEbm3W$+xIw*b7tL0ocQvT7 zlIQMv4)iNjp)CiJoJM_&c-f_OGzkr=SEtLbS6BU*NDZn>f5Rzk1MI{d>nJ7svmm)? z11_})-GN5IDlseGrek}if30Bi-4Iy&jr=98Y@p$+OD9l_ne;o>Lbw0Z2NT>y!<{fb}p8>-*H zIEY*R)F_?62mBJwy4D|V_VW`A0*^L3(+CVY2;5gzMN@}j4-7Wk|se#=A&y`;ce z;Z<+_L+8LE+ihcb)o05zl@e|Iwi(K*l9;+FWQZZRePNn7&et7wbPdHfa)>&PujG~_MwK})Z9 zi!NO577h7;tb7}5{vG&6%Q4V)^g!YA`tX_OL=PCongTqGO>OsFp)=jUYx4>~^@#b& z<`!|~iED$nL)s6W3wAg{C9tK?PH zULvmyN6sl4!sda$u(0+n&v~+ufagq}**qumoWfJV zqr-9s{$&mPJm@R?AfHd?k@M-I|HEUu!Oz{){R*CCJlF6v^Tc>==DD8dcAg*exU#Z` z<_sM=)XgJ*x%Mmlo0oPS+A-wN-v2OP4|RE!a`y84l_$wF^ztmVG*u0}RlUWh19Yw$N10(|ZCkhdXV5wPi(iuCMelmU0$v zn4TT>2BX_O(RYU~eVb+b=(|b18_;t9$4X)iNGrva`4=M6C^_c~bH`jOI8DxSEIZWM z3OYXbHzEN%%kK8`{hN!ja(&ZBg}s&0PAupBc8+Y9%@KnE_answ56V&Mvt=j#Qr`T` z@_GlC_sN4(r|iut`-glDuP9Z2ZzjB9gW(k)vi_6@$qwYYyV`Goe;%T|$On0Lm{nPz z=PP_)0gvuN1aSB4`N4r?y5*%jRE&L*Y>6BMOCqJ#ztJ2r@*%|^FYH(g|0Q_n*+C+D zI;z&_{+Y&_J_fdW44{r7nmHK@IW5REdR5P4BwrLgvNm`eD`_7dM}*_j5rXFTNy$9m ztHeX(N>pbpyl_!h{1`L{>No_VyLKaeQSW6;?{Cm?P-m`~X`bwWs8_d5LQRpaz9*2& z9B=a!O6dUi>4f@nXqSL@fF1+TSq{*!Ec7h|2-RekMKp7o1Fc?t&dy|}WOAD0&0SEp znd6-=d*vrppWBI#hC@%%0Hxob;&zC1Gks!*-Jb4rOPWi-Ky!W@FUl;!H3*Erm~Z9u@V#DXlsSaU9E9BSS-AWRYwFouBk0Rj00WXoa+8<2e5 zV*NpK`1W|v*DKbvek;j5SSRhIZ70aGC}+A{VX(4Bb}L;~^cov0g2 z8zpr$zb6F^PnUN#yTat1bdSb39%>S7j|{$&Et#n ze*w<pMfZtAtT8onp(r8a0f zrzOJYMQ4bQD_m1=zAC*$<{Wg@nP4HMlMNR)&;h$eMCN>WQr0I=ku>b#QKN`vf2rd& zOy5E}&Lr(jT`vAf>a65g@bCF1IizIIhZfy)AlWDf@rrS)?3eIT0$0d!s6Xp&CAEC=85q9*=wFI1RUYR6?NY0q8oYH5ga)dT;r#aD`TFl#h%s z$oS%U)|F_f+0cc%+Gkw}CzB6vyxMDJFO1jttn7Hu+Z{x3XJ$U^qv{TPS#^uV0kn@lLKQsmdDDTa?p^bN2~^P zIj6AWUd+x;zzkKb2Z+AsrnIm1%~hlExeg!rWjdOt5RbhGp(eC2|r8kA@AET1(qJ|EkBIe_Fbl=N@$ zm5-ACPx$1c7RYC2djb!}!71N>Nd=WL*`l^p@Ltph0smf)ITzME#s>-=Mx%GK+ z>Dfw71hFZ8lqjIeFYxe^IV*wq7uo(rtrvK;e~Vl>hkvo{U)*|u%+4x}7P$)m{}S83 zr1b*7?Z4FaFSGs2S}(}A{l(yc_|rt~RjKoyR(?T&4r`rB*gfOIqpe`^MCx zUQ)Mv3d4ruU1+q(UJ@~MIYCxSjMiK}>E-(NBR?bd&*gY>EVJm(a&$|4p}PlePYM*N zIz`KKd}gL-8knL-jJ0T&$jNr}y9Y)8PdOg3KZBGBL(jE3RbFJGUc_0NnZdS!DSGRo z?`KCs<-d*$wd%dn#JxkUb9`1cCj)!S4@8Dot8}BYGM@rYo90>7J~}$_><@|CU9I_F zceQ3NnhcyfO8(MR@K9yl|3Z-?{ z8`0PI>RY|lt#`3VF{iM$zG1QPwT{x478^@CIF7|QjTooGA9ivUan;I@{M;YrQKIsP@-CV0S^U z6)EhNK$gMxi;6_P)-$1_|;s?0Qc)P{#SLFwc zbzX`9lFQ$__L#)ES?uZYUZ3!;PXu3%XK_qQJorK441e@bS&=sr?r$f&ZHeG+@zZW= zPM|xu9}Kyooo~cTtT{z-xg)~*{og~U|11swlVZNnv>|$MAoU@m@`Rtyou*}0- zI#h4m4a+RkgQ+!)(Ay<5*b;cb z(hSjP{gFAYZplN&c-#I)I-xTmoTBe%4yj}FwGhBeb95*r>o$(nUhyHlc{Tu`7s__2 z>5Q{R>tE;siMbq0t+TenjFy-2W%LWkBHAu-*W0Ry(vA&iBSxjQ5jMo$337s$C-rf7 zbboGSi24&H?j2&eTk{c><3p_a{B~O_Q8(Qe9?r5Z8Wc1Vy(~;7BPW36;%>bjB&^Tw z(Qwfc;R-fyD}6J%D!L6Rfxe&E%jNrq~hOk1Ulpeu75TXo{M$1crUl9Y0)-IeBpwJpBC;QQqdRf(I z{W1RbnU2P~?@07jT*^0wqGfUC&pSuv`qVy+a5q!OYY42=ft*HSx|x5e7t?_kH?Q(H z0U#Y-DB)Yu;WN^SeI%}sz}wS-g-+se6{Q2A1M+` zJN{X{>hI4twF}E%`dH~prEiw@S#$mOx=O&~kb7Mn=<0`U%?GPJxAQ|AGXch5Rt|=3 z6pebwa9AcOaRk?Fp$5{hCzhX#VJGe_{B{2DSTk ziQ5Mah15vmI{S%!-k@G0Hlv6k)FtK)-)TrJNUFE+m4gspxFNoa??)^50@@nzJ2LC`e44yMD1l@ zNL_y`{7D#5rM?KaL~q!Wd*;>-X`w&OLLE_8Z;Y#QxhhVGjN2kTm$@!8DVJ+54yHg% z8IX*6ZpBeCB~q}36grB$brf+(l-{c=#uF~QRY1sFhl@jpUrt0u9y*V&z;lzYnkWB?X}VO za*Y<*sYbnrQ=AGZ&Ro4|y#kla9Ogs2edIEY9fOrj**<6Owesp%NjfiixM-p1t?-ZG zRvuc@rV6G#g_3A?wBi=6J4%$@5)u3PN_e!72CnHnncw+(?||k1Kb%+w0e=~CD}#St zI8g+cvPgqOroRxK5I=mbFxP06bNNgAq91yUR*{kF%rKlJvlK?_8vId6h-pJeeHF9` z4e#w)k2lCFvu63o?Fe8Bw;rZ*D+zzI*G*uFHOo)nkpvbKI8q0K{3~IoIzq8E3#A7U z5Nr`}M^4-gR*H<4kQ1TEIlzmxV|7M%?$I%Qd`Cu<_Vr9Az9ngW z1nwyeAJx}Y81_XUdu8Ga;wfJ*^yUrMF`}or!sD!2vI%6GU;|84!2CH4RL`Dzvc)m0 zfMUHW!Soz=`7RE<*ab<|^gcsw*z!o!8l0?yC(Y5&vaOxV2Pt|_ING`MeJCUQP^QYZ z(78QPVn#n47AZ$5*fa>qk;$~L-`H9?G^$D%KbIR|Y(XNjFW$This_wX{+KM-zV@?2 z=A;Z^R4lP`vd0`@C_K_p!$&UOP;pw=UjZ&E%ER7@;;?7!+^o55kXKEoyTVI*7c;*o zm4+q%VtH#NR!Qyo;!z_%A^BM#KbM5m({IToQpLU7HS|)M-vIvs;BN%}eZarRflq>b z(Lh9Zly%M3T%+|F`}qE}_ac2cX4xTxq)dkN|8uu3FDAdm%nZd$ZRtzaP;**^JnzWg!^`3u9_l4>ZB2jJlML)d|u|D6U_UGV=GUC<{ya& zt^R;Wnu2UG5Ms1EWOLNw4LT!_&M4`=&d#Qn#`SYbR#@~z75~Sz>PwU@U`<2)La!KN<&`fei;UHZh|!sfh?{$bu)O7eg|7(^K+wTtTr3pO z@oDknqPHy5#?OV$mYDdFQe$U#L4*>z~1xI&!3B+`mfJ zpKp7CgrECOZ68zYN*$2MFd$6=oB29+jAb{64$38!dpIc^kNZ($c51`t?fSv%5U#KY!s4qNogY^pV1k!4; zOmy2t3QLjFknUAZk)+AWe;YX%QZhW(7}q4hx@1#z$@W$HMH0=ZWg6tBG{{sfcOF!@ zWVlM}iv)4~@I-VyL}eHMo$xw3at;aah))7vbB+#n4oW&?s4p8Z$|KKG#@RDTKx-b0qb{b?Y04poNjf3SJlp=&WC zlYSg@U^IIObXo%DpZQ^TQQIG?Jg-JWjVk@xeVK@BVsgTX2Z6LZF0I5jvd!b)lANm*btbRD@ z<~<_~=UED)rzOHRq&~pOAP{Xkd?*M*{w9P9U7Ztkb;SBOJno}Pvh8)JMo%81BnQ#E zZy=v&wo^mz!U&+&=Nur6TLJSsP9spcd=x@5N1=`dA@zURdl&F1t80CHW->_z7??qW zL<|rlN)!|{s6apiLJ}2aFk}WrE^V#-OsPef;i6m;CM21BMybcPw)Ip!+8)}{inR^Y zRs@3#SX8{UrKLw{Ydt%Sws=EOVE*sB_V>+9CJCUm=l`7FbCPFf_WiQ<+H0@9_S$RT zl>;J-Yq2yAa*6S$*F%V-Ua+LvNKrZoJ5HRwQLiK(ZK-ifZ-H~S=uDyIh#7UF47nm== zu1}hMujj&pGIHZtigyS;WHY!uleMNwJ?j>PgNSLc@su50t$w0|Q(aKEp|hf3J=oZp zO4pE?4n5*I<8W)f2=CxaTpChk$S(*F{9VcmId2$$NR@Lr%7GmR59+YgIFQ9DS)e9i z!_jytmBTAJUX%Kvgli|k-eYW{MD0X)tQ32D_{W)9*d5>|#N(3KZMe^H_=B+$wHxDv zw9n}|hr4FhoGaPJ1w6$h{GaRpAYefNq#{%Q47kMuQZHmzI8BMTI%%|E61vr+F#G9i z1yVuMQ7!RYQw&U!8 z8i-kfeS@A}Iv5FhnH5KSN&e_gH_khv#{-L>jc1bsWr0tNbobEu#4@+~Ev7|4y)Tmk z<+5!kptqUZOOkht3aE#jngqhw?uvoNJ=`{n3i(^m=}?Oi$qmbQDZ{mE8?*S)=p+^e z)8}&{1C9HVdGaWBy!U zu|--kRjZDuUttyI3emOR4T$N!-uoD1)$8!u_14?<_O6q9p(TWSp8^KE>Rp|xp4?;A z7xY;5nUcpHomd1@%5{AS&WF&cjCx+}RL}2SJ$3O}#B|@q$0bjvdTP7Y^G2t7Ztt<4 zxjoi%6=Gz=#W^OO>dSf_VaLvS2(F0_VRrT<8bMmu-A3^L5enyPB|`N~WrQB(-EllY z8?Zavq)I&}223!lLhtan%VdAe=Yij+2h?=r7xUqA_vOKDZHe2x>a0~6f!#v1b9uMu z@{X>^$jb75y)q;46w13vm$$LI^6vcf<=xa>c_UA$JW2`hs*3P<>gNd;h=d!&^)x*D zmGtPRfUvhl2)Q5LE0xPOW+kLV;l6mNp~gK^J$WbYCZ2}FO>`1E=m-m_XO;sL84J8lx@v^dgIG&G}P3?tws9roy81(Qum(~vrqTlACaS)L8H7lv6 za-kX9gH4XZJ$Ei0#>;;f3H0*-7=yrS^+s2nqd3mu*!>j<(TV4Ld6O`Z3P5IwF zweoRbgMxFmKy4<$`%~@|G-d)68-@rddJ_~oj-3z`(qhb)6P8ywRLbL)MuktIJkd|X z0h6GmU?sGJ0OA2vGu5-TK&I=wVr0yeTgO^Uh;dt%YD9xE8NXRO4x_OyvAPPFG2>89 zS@>$xgNF!d0Y&Z#3xgnrPqf{Wu?@ze5zx|Iny-R~T@Hh$NF}67-Sv@+7Ff$+jfCoy zQ;!gT@n-UaC((oJX?#=od?=?7c3&aIPw>($al5}fqe~k&pkF{0!S3|%zpu5ziQa5O zk7$&vo+GTMPnkV^Fi&E)_cTv5{w<=ar^jsFgkgg+@gnY+t}t5(*63E=>UKo>tFHhw z+GafnhD#pw_2M41w!g6QW5P{14&Q@fw^r)~pRC27p#Haybgp0Q5aE4Zwoe_Ear>9l zFG?Bgztm4(=l(N9t^C*5|29xn8_L)9+x?gNkD_s(2L6Jd(bbhS&r|@rZn5%8v%C@{ z7ABM+B6hb=z+NGVU3>PVr+@2%Zqm2bbxN;|o?@3!^7i;;UYLqs=8xd)yk(jb1~=8w z4_)B&|MouC8OSrh%!g-_L~CQFJ`|6Y1a=v&)H=^qssO#T_TwPJ^0a`gJXrxXDnb;8 z@kz5Hxga6TOPHoCur@Mbmn(*8|eP4__MQG1Kl5*ok-_ z6>CDsoCoO)rqp+=DK(GwC?=WT5lXc`TtX^!VM(Ipw)|*YK3>*-e961UooNNH1INu@f3fihsQ!luj{C1)XaZzmcsqnDkdX1ZFUD@#ugdgBQ~>v>!F zECU8zb>RW^b)q0x9m;_~+T<3HHXSDm1vaG@=(1wV$PEo{xz4uFpHohI;UnJ>n8lXy z)$MqN?8qeKWPA_#PqwL-(-hrp@k8e#Hq+L9#{u$1Eo+TGqZLj&Ut(4~k== zxmKt&v??c$X<55T0>`$+C+86-;*-beAJH6$PadOv)Y0e$cWoR_|4p^W*7euzc>pCy zdma@B+Ot6%Xb&--TApmrHVOO;+XKM{Ovw#1HbcKdaLTCT;(Z-ArLb!Jj&LxLcnF=s zCe@4iktdXxcck%ZGVj{7yp>33<#MTqC0F5mi<3wntIxtM_nG{7<0IUU=6WJIqU+VR z`Y<4tZ|0f+NBAwo_KIHaT;nczxg*OA@B)ed`l^|xGkV}ybeA*cRHGM>;(!BLeR_*` z9gx5Q%Oi)vr=N%N<`81x|BUWVkipu1k_nyBDasvq!0A!2Entn^neRUn%=T?A z>(`A$i*xOQCNQbn4`W;EUrY^5uwi4L-8T#j;n-*Y$R7}JMX5a26Pd*61SF$9C=ah$ zkz@5}EAn3}lDgq@T*MomB?xYll4!TWx+ljsN12e75YfN`^O z!n(w45?;yk4Xx*>I!x~e2DT7p+>)<1_n+X84629rdh<-@gn%>BFS^|o-R7!)Ir0W9 z`DCB94G4l}dCQ~6J&U)`7X>oY{lP*Maxz-Up0+Q0+tum*%!_~TdkiSKV@}{Tu^2F!K4irMs5SK9u7OpN4li+}GR3K}4|0hjLuu0er1v zsXK95Vt|p&Nj&dR+&3etJs9l;_pG>2MS}qA%b|udyhZa8-K3H;|A7 z@6@fr+0g6ytNwk-@kBiP0E%RPyO3D5s#APCo0T)AMawcX#IxCrR08#-4sIF$if{FK zasGkMTgCYzo!5(V2c6f7^A~hpC(fVHd6hUHp>wJ@@2B$`akkJ|F3z=djuz)KIwy*A zA)Tj-^K*0-iZe*(FmbXRRUpnXe8VQC$`jwkjPQwb1f9Lb$&@Nvoc-x^h%<-Ik1<98 z`BpFgH=TzNV9+j&;j9IUxq)J8EW*?!lJa+S{zOvlVM>~=(JB2**_&YnaOtpOh8=2W z3oF$}_zkFUuz(N5Y0`O6oV9dzh%-Xxq+5?C)Ma19*ORxwu;u}vsoH>O2vOtNul6+V zT`}cf6QcG*(D?`_iAE@Een!rTPGZ{}@odgl;u9>UZ^k2sI22^KZ{0r3%&rTn@diY% z#$EucW{UAFvSF98EZ&syMSu))d-w7IWGqTciw92GWtAuZLCY3AhzI( zQo-WKe$%XUmp-?IO>p{0J{POhrKHl?qlNamqjx~#>I~C`hcuDhV?E84a3!vGV>R!b z2dBnd@Qe)rxv?H#OkAe^{AX;oaXkplMSj1&_@ghJn2Wf*9%ejlClA7m*t-I6+yVl5 z#^c9x+F~X4y_C+C*^Ny5W&gw!q(B$8vC^B|O>S!dyyGXk1sZ|GMWoJZr$Y`KGs%;j zFVHrLT_xbd8r;#3e7M}}fzm7$#ogxQMTr9_+Z$`5xUNevc6KQbn0){}WIb^Z04x@5#vRGDkEf+Q`X@VWvdR-WY=r!9 z@9;X=^UHU#yK)|fJx<+G)PYS-D#9w2_yVnAGHI|tb5nRo^zi4yaNQzz-$aCo$0Ak5 z0@;4ZZiK=a_wA1Oz8*m1Hy8Rp2U1-Ps)o|I(n>VtASmnQObPgFU= z6JVPbbbon&o4~yaR5N%<2n4R;zigrf)0YQ)E(%M$YS`=)iSX3m1p5^U;C}gR!H!--OR!uV1xK)3%N?myU zaR{?lR2p|AOXv&ywM%H!B^V#tu~5yn3SX$Bg6ef4Uf6~6B*9o^r!ctsC>(HUoZ;tk}G9P6E^a2s9tQ`^9^#pJPT-jN@QJ&bXn*ab7b=ehi< zSf-~3rlaHnJtEZwYy%Y^eD&{wMyPu*qhk%6DhzrZL7MvDoo>-A546m4Lsq12y@5mx z7eRgXJm!Id^os&C;Jxo|-i}o(FsS;WdM5fhO46I-$E6W423;?eMDmP{b_WgGyluw; zYQm7+af6+-$xgZ{ne;s-y@pNx=(nuseo5l1ABCVaQhTS6XX)Q*h%qZ@ea(Zn^ZEc) zVnQcd8j8{0xIAp{C+a@cWMM&7KZ}qeT@8-!~3JSIy!SWMO>p6*L`Ju#F>j1Xa{WX6ONz6VWcCXJ>G-h zw#;sECwjYya8v!NHJ_F$B+aGA1JD|PsbvpFInJT1G|BoV-z=3)HtZOkfbj`=o~&iE z5cvSi%3#y3N~Bg$jqpgkxr~EVnHbnZkFo(G4|p1+(}2kvFAGetgbG+XSCZLYiZnRp z7nAFpd!6uHsAzZ(TxXMAHXw{nYvH4mW90mkuqwuh_ZX&U{2ILF;+e{u(>Q9T`n*l|X?TsEOTsq9y z3ixYgu0L98&^Qm~`Oz2bdCrn%l3c}_$n9nC!dF1OrcYqH4xH6Ufj@+LNtzSuZ!s$% zJJ+kH0v4}Awe;e>7S&m8S$s0GlWoGOjKlb$Zj+I0Q#vHNceB-mZ%s}Q<7>rR>&Y@9 z_37|W((i4k9Hjw&QrxwMf7>XIMj!&(%0aL$?Nwgoe5Fr&|wo`Tg|Loq9^tF6Sb zW4HRMoPSg{ogfzkZ&}~$oGkiN&($5NMT3@}ZRFxGRF4~<4KOIH$GA;}S`F4L3adzc zy+&_4nc2uyCb4NBzE$HMCSwI9hSyFJRIPxpc@NVeGFHc=I$LxL-Hylr;qG-x zJYUeD8!FKK*mM`l{z97;*Pk%m=5e=2332IScgxitU&Uf~kSLg^zJ!w%G_C84Ttcs4 zrO6TL6;!_}7yd4&4poVxo0btjM5^jdY$7YG8bM@HvQ269eXf7Zg!VK}%jVNq182Z z@$=e(>I;=JuwW+g6RjJvFn+(EE+N?H!Nults`vPlW%)=TI*jeheL;Tn*Uc#kw#l=KEdrnCY^1I#jkV1*m71E_4^g@120 zQo9rc9~+bd7?JEh;!8;WXbgNpZV0G$yt1hi#^j}`mc}MzN^GvjH){PV<}oA*AMQJA z+lTw+qt;V_lbwd};`!2gj9L%pOEhRI$3t%eeesG*!OQaa&8sircnH+OtUZdnB)epU zz2;haW6e5{@jNtYsztvvU6K*1Q)qjisj@o4WuMD>Ic$u=qA9^r{`=ybg>~)a64-@!J z37fT*Soc}p=_oJeG#NAUu#;)c@brVJTKy} zJ;{ZBY0_M~MNTWQ5SC%|^g{TbNGk8+VIllno3$Q8rF!dnL{MdEYBDKHwUb_&o-_~0 z?}(HFQ@o&O*s@**5;j#1AAxDZwHiN9S&ThtMZEWn)FxPG-=qJPj0sXHy;L` z^6<9%f~-hi*qgeM+%;zU>f34(LG=-r9S#QuV{Bq?P_4u&f%E_l5_Rt>*ecU ztl57rYO-k*3~Yg-1(nZks;?fR0Y@m&O1h+e$wd!0U16!0N+~x0XNBlhg}pGRe?V9k zPsfcoV1ua>L{{bOp4h-ftyn)oQMt++D;aDT#Y&LL3f`#9lSR-9# zgDi)Q{5H#1#wu2t4YepE*2r&Mu0tA#=_7Q!3vf;e(aazk5UnMeH*8-25am&ftUyjfllt0*A;hR=wuE^vgxxvF72 z?kQ(0FMg27EH92#6q~{`#~SO=NweXtzU&3R&4z>G=C|fc6Ptx9oQ)osa@Zk&4i5~d z!7`okiaGa{9F2KgVH-G2&>18+Dl-KMbdaxpk|g*eV1oo-4ygS|U|q2G)faL--OR`! zlydzj#i8Cr*SP?r-KD!$!Jv?1W>Ec(f%~ddHFC>tEvWu1P02^81qm$PLG|PGj4Pkx zyX8R9Ds}oc0vjkfN@KMR$5u~2Ik@%&TJAo8Ce%1*s%s^!AA8bI#<6vX`Na!}5Xy`1M-jesg+%eZDSWL(= znYF3@r>U+ zpv{DFdWy=*ZZ^wCB@QIB2tOnG9vG{HJ#D;!mIj$NQ299HDWPX_QO$P`S!3&w+23PM zwg|6)Q@u-)R1%gG)O18)Z4^b0!8|*fj{vA`;J8%1{0qk6cBYU7MpjCsN0rI%&FcCm zxfLT7QuD=0dZT8+$uccoJTItn#&MnDDy5<_{XIc-4XC-bzke7Ry6o@olE5*@!#``4 zI$Q$vkhc&fOdPa5fX>Q`b|zXMqVsgD4aPrG@nsBr3mXK3e7lvYl7YWtVDkfR$lyoO z@05`(Ge-S8gNhmScj?mobY6iD8;4Ux6fp2U7V%Lka0~<2F!1A4-~tBLFpyhos|B?T ztY+Y`R3N8@DnlUjqAe8|(q#1|G$ZXTVikfP{Ec3@dg%=`D61`B*ff@K-NT&OSa@*a zh!sUm#9C$aMGaO93|98aW&-X}Iv+y48mZK7)^~=T6cin)U_19;z%nLr`(NR}{PK_| z)mHeiTjUyL){X*TV!Q|D=LWKg_yx+~jmZwr}{y_wDCn=?*$`2J8nXI-QpOft-eBIKJFN>C@bTl6{!aG`(E ztq&ljBXUtty)}xgCt$rCoBgLp+8%87FTTL`oCet*(t~z`h2lg$fk_nBXGyMqj~RfX zJ2gkIpJMOh1o~06dok!bAIqzf3*Wwas@s|O3%9mEGQhl_vy)F$tYP>ZS|3s00?5%za;Dq};_me*Q! z_cm)O+3(WGRB{V{^K@H#$?$v$ls(x_JwEyA@fBU;xm8IYZ*Eu8{Ctacfo58CdCM{B zbiA-7t0|>ar=whR7l3_c$+o&bq1}nPBlvdt?&JG2oUK}#7s68_S&=d3YEO+bq_#h9 zjbr568dpgDH0d2tgKfnlNpCrFxgxiktG!HS+Tmf({4MAlNB|29rw4;mVlYaXn+!e= zI~90n+{+z3;)2||WpXy;Lr1c<;H<{+qz7N~eN&&IkUuYa*d56NN#qMMs0Ml-C@*?A zhaPA-i6@sHXpzEmsJz&P$J)xn(JcoM;MkIbuW+^$j8f7D?K5;z{<04MX#XPS1IpF% zhxwOcGd;D)V~|K<_vfatDY3|-25+)wP5%~e(M;@^Z^b>Z#~A20-9=qDW-{KDVT>x@ z1MvpU$7@k!=}uq8&HzNvaC6HDT@E=<71U1RUU%Kp_`@Mf!>?MN>ZJRr>yYk$qf>g! z%Km1pHAgTr9|fGd&P-i9>kA^oFmsb+I20aew(?{MbOmywul$rF?%IDh z+Gh8k8gN$s^+B;NsGD-^l6C*bp+9I;5Bj>9{k!iZ{mV?h{v_$mvZ7=Qr9Bz%D_bWV z(qxTKK5(B%*%hCj|8Y0?^nD3D0X|vl?H;z%28{Kaf{)pgKJQ8BEjc%f-hNIFa8F2Y zg?`E1A*s1ZkYqRB>e!;iz`3SY(KBo5&upzlukBm|bt=&7-Z~pbhNO`jz>I#{Ue*c| zKNfQO>RZuzvvmi)DXHYfkl4)!2%^XEL>yTTxd0bbgMK2Yi^?D_gz=+b$$ph%hpi4+ z_7h+h|3f`SJkWTjCFpFnEX=%%N1{ugT{AW?Go;4h@Ga{&nmKakl@J&dW~t!L+zAz` zRgYxpzLlHN(EK?&D-tkwI+t2!`7JXNrHAMEroM=PolXZ?j!$Dizy?J6_^0jgWmM9H z3gWM&6j4Kzev7|L2yN?@zuVL)JvhBiew+q*M~X17>nKTmVx+GZ_wVh0{vlS6G<|tJ zKmIXB&ksDWKtijn`t_NqeumT_FSvGJ<`r5TP~VXtaDm}83LKWe?q^JA0By+!$x&-i z-^2F}&+(V+h}9SInBBZf9vw38ljnv)=C9Nf+flxXCXSVq>6N~(6(?$f{!!+i>#N+v(hU(W$ zbyv|ilnP~02%-+*Xm#FvRCga5YE{>{AE)Y*{XyN%!>BH({&u#E5@45WiKv1qA6nA@ zad)(vby)Z#a+fjNRaWLJ?K(bX3|s1h9)LMnw5@&X>N)+Klia|Vm3K~(H?70AzUDd6 zgfm=d+?#7{z-yKpS%3#5N`KwJfrok#7XF~x2=a+GVyYGz-%KW6VJF^_mbk_VW>=DX zVq3W^N=H$OahILZpbX#6yVB0v697&EXm$lJec}+!kCuxV!DvI5jVJMijuhDC&u@!f zL8X(tWU@EXl6~->c7NM~25~}{&u`Nr5xii#cr<2RBNy|SoKBdHUgU_$-2$`mQ3-zw^_h*- z5P?F!xE~U?5;uACn4Dn5McxL$A~m@WXw#y3iOnJfI}KPIg`$^eBTzCwNODsw22~df zlG(V0?(&spBN_HsLoL3|#%pIZVIaI6`~!Tmr=t zQj?2u9bqfCZ1Dy!Qt}USzocuNNq>C~;oqbHwHP&*e-;ZED zBs{3rY~~-R}MHh?Y;AasSYq%Mi;thL|n1AsGu37vuD;7ev7#lRRVi9nf zj$EkOq*SA9g&WYDaM;W(*&VD~p8v=&hu`=0?Xl|$)PEFN)F>RZ4%R3#?)w92Eb^2A zo23OiP$Ljp+`Hh8H@uJ9_?OsBd`N6Q3O8&$70UEL)@<;<^Fi>2fKVHc+Tch{>lYqj zC0LP=>Li5e|Dpu~Sf9Y}t~lHHId+qpM)&}FqaVINo>%<`0h&h!6AQF=CO0EIsqm}! z#&Dkaf&Md4M32z6)7!u5m&iwhVa!>%y-Pl>mjTg@nU&c43-CH?u&|YG_f6Slc1?^P zB-?*+=k~u2%t8B~dbp?d{}5E=6xy%lhd7zV8Gpd80;VA4FqC zhNOk+CCf2cU0h4^BNKUZCLggB5zrY_uYq!jJ@IwBVI*yLhigp^v>f_`F%giCa)ouf z=R>_27vstoP?(@iSU~IxX~d^o*sb|vkE{Kwu18x=G`?VR&6#dgWKP!fIq8f6OUk$U>(beswd)DM3rC|8%?l z-nxF-O?6uXDmaxISU&at*tYKU|F*F4YUnu-+0tB9X#7GvOWg2X7LF$gOK4)S{!aSv z7;o0|=#Rg7JYtHQ3vwrX9GP9_YyB`Qj;Cs(e|Im=!}+?|yVMi$N1t&=x499vu~AHqEU;fqF3l^br(;|Ql)I&+Rt;#0j+Am7o^U|E^mIUe={G!#OsE0n)*XC z6Es0s$&S~$f%>Tjp>mw})&l~XG|2qpZSO3Qc0|hMw{lMsX(hd_1=!tvH#E#6=al_; z6uDXG8PrDQ#@l1?!8|P}42tpct|zR;Luq>EzZ2WQ#H8+Z_0$8_-${RcyVQ^*h>XYF zfI2F9CN=&cDLF;<#OfI*w%2Ur!j0Dr>(2%@!vI>2`5>8*VB!g365j^SSjra>_q_RY z+AM9Hvjz(7h>31a^yzvOLZ0txu$P*ikGTyzUq9)R*WAoXxb0t0B)f;HOYhzRw{P8Q zeAn&Vh3}ScHX*z^+U{Q5-*lDcXavJEDD6bBBS*s*G`l9`L}o;f91EY_JjFSo+!>h? zJ#suepm~aGLb)q)30}Fz+nZCeCX{DIip?l1fbt3o^}%o$YwIsMxA1AEvyn{a+{6=P z?Xh3P8(h~cpiak%@8W<_+N^F9BAOR_kUcQl2!Wmk<(~)_e1kSQ?_}Bf>FW960KI4$ z=fl#vii5$i&Y%ZB(9IdN2Z2~x;tgZaQvM~ewQIwqzL3$!zSWv&B{QeK`fXq)?@M~^ z2z_7jn^H9HOKO%6+JgP;1mJ>ZqtPIiyO0@+w!O29Z6&LBiuWankA61FOQg&zUG0es z#_1z?uRZ}aO$w&Cq1;=#&sYBl`i5(TeM>)%;5uoRjzt!1VC^iYb;<&%e7V2cyv?J_ z``}w_s8ybt8$OK_eUOlPcWgB*+5*WD;z@?2Ci35b7|3c(%|<__wn^TkG~J%giFrw&gnrCale!D*Oof&-42n3{iDu?|`TYp9i{YbkGlO_E+8cZVlx4|j~+ z$EWpon1)U&U8=qMj3Vi8q7WjL&c*?)FQIMp_YJ5kzb<6QJO~=NjMw%iLj(6d37eFS z6TZkrIP$`wS5P@6rN0#86)6a+H<5_ipA%)adti9oMrSn|L9pnK1U5ny8m(yv^^8WS zccmIF@GvdyyQkO0A_Q_P@PPa=gmvMTmYNXGYZUS=FX2@myflk^vn5R zx+=KF&z(QdeCAXb47P{(hWoAE<9p}%_f4UC>GO~CL1u!8@xX?H^yS3re%38^>-mv} z-`9325A|t!_iDE#Xnq4{;~>|QLh8(W({T3!jk_T=O+q#9=7-ez@WS}~yTWMdp~0?E zEdzxMsQ>yJ@Yd2RFEk!b!`mHt#3x8$o$)rLiiJG-Qw#cF39uLR0q|K1`f6Fwq37~T z)C5Y0HT|Es=c?}yJczCk5~6t>>2KVY+;s97qhnD}t?n;eHCE+WX$t?BsVQg}0xtwR zhyye?HJ^d!4&$LBmmiv!IPb^@|LTGK^5t_VAn}T_zh)js$&Ee4s-`Nz0%k{T0|3=_pT|LQ-XTcAwX<}ZNGm7i_<>rg>I_gx1 zBlG_AaAS~tZP}3f&z$U-=Tq0SK0WHD$hD2Zc0%j!vw07bcu{_dG1QI=sV9k0cawuc zq;>aM3dp$oEMcGN-DlDmp)Y9^jq4Tn^OQ_>x1X2vWvS=5;0L}!p5{&tu*lO$CjpiV zq|e>S({A(-;V?iamZ!=1m=HA`?&WLb48x5yPcLW>7p;5WY1Dq%CokNIo~$jD-E#wn*OWS<%9o*!4h|L zw{vDmM#ae01F-fk%)_Zg6ETbD#vP+MUfbq?{zvrvR z(J)kwd36pS$f)PUgwFc6?O@-!#SohrzeAVWi?smFuYH5y1JN4+;Epj~Pj-2#)n(mN zm4$-Zz05ehs0a8>2S>8V*5~tK%&mQ-`Lb)&Fm9 zp*NF?Y zJm;fywGlqP2c8e%YJQ+vIb@~s0xd~=b+n3uPFq|}xH_b^3fabNSzQS%ZWSMgeiS(- z<4F*{fcieOD70c!O;+~(sH{4mX#b5bg%zyZzr0_lTrJh*lpb8Ug(z381|uM(ZpU{} zzR_os?_p_lKG^YJ|Lj2N^`fCbIv<{ZUgEithC+Bl1cD!T*3>4DTJvy=s5(Q-F`%>- z&_T6EXmEkK6YL)8e>aV>%HIGG03M}gEsx9Lx+o-|*({)GZ%M1bg$gc3qL6t|4Uq~8 zPgFrhos>^`@JL%pVti@jLUm>n2nt>&haha6EoK1mxIr@^Pd5^axY`n=ZKQnFsvl6x z+GvF@UXR&?-Pr?ZASN@8qa)`AVX*I2$%qkNJ+Qh${V|rz5qXg}(@+++e!YX$>PI>u zf>6n+>=!b+vnO*$E%M-C2)f;UtJF8qyXX#F8trfqoAF}gpkS41L})<$Lx`U@de{{{ zue|ibm2Voqu>oLErfSU9F!*JIz<@-OFRe*^Cuk^_2Tybr&YQIg3>3dYH7m4i19yAY z!2re`+LvV>R?oms{N{TfH-e@Gp}B501fXO96u2Oueg(({)F1GzN#!74>)q248*|@d zxtbfUg}=#tW^^Z>*v?;$;kmzLc{R7o;Sk+KMn-or}iF z{&YJLEySv7hWxgEf8;!@uDC&Rw((!cE-g2HOjk^U>3h<6u;+8ytOo!m%=7pf?nM$` z>&M2McBYmJ=k^1x0IXVmnUg?~Lwy^kmcm*W*?oR;aJli_#f{5zRnuPQ+QGqhIyA z!<8mZ>O9LXFflm0O?ML}*RX)PR;qKC9t;;7CCR+onD+wYH7-bo@x-P5OoVZE7h?cN z7?&j@e~n1H2Y0WP9zfG_o^&B(l-lWP{OZ*@3@x_$-WWJH=yaWHOiad3wu`t%7s27R z3TXyI)s&0xBI8P=Z>n&@JxahAY^rdnuSgDWtb*LAKcspMMuWvplgL7~zt#%zNrQ4oy~MP4*lCU3=ui8f z@Rfu@5pYIU1AzifOW9EP9^4uV$oRw(k6I&bMv!maCL}bzYBx32t$s*?!)UkW&-L4W(JcicaL^nE zuK9zf!*S!sEi;_!n{z8@Uk`{`H1Y_^Rbke%L1TcuOKNdX0~vE<#lb_a1~tM7jF%fo zY#)akXV|HLQ14@SAw_sBV6VSBY)kT)iTG~H1*5`>Ul5g!;-|#oWk;TZ^JAX zcE{_X_%JkJti+LdP_0F)D^Njnr>peX;=iIXP|&bapN-VTSg+F4U!ReFdQrj79NAk2 z^`)?xW-WW3*lUcmn~JT_N@=1@sL%ANu(VN0IRRLa4?8{QRc5HNOQQDC0Bb7wp7zaX zUb;UkBmU_O|F<&I{~jZdp8qQu@r{^q>G9WQ#9x--k7ks2UPk<_8S(Qo`~x%U``w+L z>mQzxerSe&L}&bNKax>@V@7$eWW>Li;lDK_{SPwYpUPY}0GSYuF!+%3(KUPHA zDFKnS#YrmrlL)7bLtsetVl>5g2vZT0Z1x@2BkgUI+)xt5Taws& zJX-dYgA#$Mqp*3KXUm@EQtt6QNvo9G%g~$0?bFV|6heVIN7GH9USpgj`*DWzu zG@iv)NUg4pK8ziRFhoY5ae=Pw!YhhG9OPO|q0wabL<@?L*XmE{@^1Ts?5QphB4}<) z-E_1RdI@YWWFR?T=W~T%3nKRd?1j2yWc*C7+@#I!Pwqr>JTM4n*7BI;P?_Ho=KEG| zH3(z}TjTm|%ZC|b(mU)LaJAppNv~kqqKrqBS2bRSZ;s znF~1M4GiF)Ivs&vPvZ>?=iiC;k@iSQd$9c*E6}v|zG)e^aDS?196cuQcjmW5?}DF9 z_6PV)Jh7g!dv#uf-c7Y!7MUMv*~*k5Y$fvXvNXh;(T(t8U(v zri{0o%8Ff=MvynluFFSDH2P?}E@>#xse3#xgR~m=;mMg}v^w2~2lJnKAATzC&r%l3 zN#1lba9oR5P{x_&OjxK4pN1}ZV}4kEjOn@Aqb!mQVgD%wE(@0&3Yi-y39DA;g(-#_ zjBjpVJth0sC6-TwvTMPzOVtd9(hR~#m_e8Y4-#N<4X(nNLo#@sgn%-x?t`KWe+g`J z#Kr|xk%YUou(o?r(FrcL2Zcb)n7wRRi?^0-)s}ywE1UB0k}iH=2+X2D-CuL&k*p`W z1`jA{?wPkC_AF-iX5rhGYw{%DSrZAW?K1T!jT@9$h7B~h+Az|gkJ#U8mQ(IiAj~*~ zBThZ5at#V6Ktoqc+D~$yg5z&a_L}{v3qO#LWSzz@u~7uGmx%Kx4z#R2in;=c+dcH& zj%S*&e5T&Kuwlhtim^OPh8UOGs~!vlzo)1CpKiCNyqrs7xbkYKrY9#v#-e;Ey{>tW zGdBN3!-EWdw3!+GHL%PZ&L$ZOP%))IUC}ka)*qPv;juLRfpd*-KqRPFAnFeoy@AGn zUYTwnwy$!UFZcIzv9$zO)0U=GP^I1mdBe=Onixh2J${SuOY@Mnk^vfJD;Y4#Rx8qQS9nQBX=xNjD>LHDEt@&WaC zC^w=PFlhZA}^kef0P|^i@HiPUF+hvMOy2lbp0W zwYGHhaIQWc;>%^fMh%!nordvTtU;$fj2vlu7{3pIp3*QDrVXRf-|iJo&8;pyf15QY z{^^0XV4Ph41y;7~dk}oF98i@4w3=G;&_paO8IIwtM0vh{F;)M+$n z?}v4Isdt{dhHGA3S$bV%CtDVN1>OVZ{0udRy}>JsHcyhdir^mdio%$rx#f2 z>3yl5?$he&;aqv_`-F>1S__H)ErIEHE)v!|mYfy1o*ODiA-$ZS0X0L;UA;I*hL~>( zM1EJhwjc2H*$xK;>Eh@uzdg|;%}*t;P@^V)$TD!e90oFc^&>!AqAMVP&ZEJ-NWbU` zuNdE8)nN}B;pXaOHiFM{;2v^SwfPuUDKZQG=wF>?BbY^oM^`L&1c`jKJ+l%E$yR2= z5z`^_x7*)zZ~t>{bj8h%urIp8a6oC~1%KUhwMYTedNDFUO<;n*&^%en4t z-_)Hr1NyZKq#ExMPu&MuN>=nar}=L51%~Az3{E$kSlrG{+&)pw#jM^SSvTh&_QgZ8Sf*Q}ah#X|M?6pay`%<1HrmF!8fVN!mg+vH}4w z_*>Ajm8wGlZBQ+wjxOQ^%_m{J0)%nwC_F&+2M}?+dVC!{>?oNJ8iXLcmX6}+!93R< z;DlG--NK2i@!xhntckRLgNNHKllVJpY|4go>t7k^^1p-68~7Z@=act3l_QfYF*<P6cpQj8xsOhs`DN5-gA846HZWgwd9fpWv1Kx_?H$Y^3DyDN35!J; z86(xtN;B#$VTcc5GSo&c#x;fub&f-APTVyun@Gb7l@k+@fsmLCcmQfU7)Ms5e*fRh z=*1Qp4ftmeO}{toFWHYv~khaE|*vvZB;af#!Utk`rR+l0>PQ@=_ zDRP}DAx}Ml14l?mDL^ftHokc*@vZA2br>Xp=l&JrbP&wtp;hTVyaM+?v;hx(f!CRS3>ze5kS z{#`5g`A9>8pnMB){*5dm4?qA+Xv+T1;_FWhD>c7#52|BJwLa{*#>+NmVF*9#)s0isN6liUi$OAQ@+c{F1%c^m3ELN}sm*8t7?-_0t0+U*MbzXdX)kWRqZ+`-C zO?7uq`wu$%tExo_xnw_7xe|C!<))&%$Y|r=*yDQChsSgpHEnw33o<@cs$NJlly`ki|m+y@hD4osXt4xh3(WKQ`3Q( z=02KWY=9T~E?)DiZrED<%b$-WI{G4CexS-MR+l3guRwe1R@rtDTD;GH9$C!o(OvGk zRRv-#Ve0lkm70sJ$XHO4fGt8~8Nb}KbQnfBacPzM_FoVO*_9WPs|%1QuL4RkrOQ2w zU$0VqK}0dBOf|1c-K*VcJ&qnb4z2db?fw~5_3iK(Pb33s0W`bM-}<~j4wV{P(CNgb z#y0$*zEJ_=enKHf{ZWz>bljUZQvWl~kU8n-IXO^5_tpOdt)~*}V8^*ReqX~K@Ky&) z-mV!bn2;DdT8;l4EE66Az{ZD1dzN0}8(N0J9PO^Tz)EpY4MYkFx=;s&54u$r!pgyu zl_JyP7i-2?F{9n8eF0KS{a2#U=(FBZseAEV^XArEEXhLZS)@T^Je$o#lN|AEwvVnk zpTY=*rpF14D5O~W&gbn|BOvt|V;+R=;cR+THFY1DubRvWZSf~DrC($Ku19#fa{pxbCT=0>slh9=RrCT(6@wK@xhn+IzurIZ%;QmO%| zm*)e(yB}d!A+U*E!k+SuI!{V?oL}-XWITB@TMAs&F`TBVKN8#rafdUc9t5Q_4^!Sd zMm;T6;{eEa_n*<&nvhgNy7rWA6jl0s^;G`|se4(5s+nUoV?1M0^}o55gZm4U6RaM#=_B?i=0NL*7B z%hHX&U8-@?hKh*2u}#&b*vhs zed^0VkAS-2Ce(e9Jl3Je`C^(x*PUx@(sj2YL39Vy(=QQ++kAH3T)aksZs5(-g^+to zFe%CT#u>?`yX@@C?Cgi;upBEpdXdkaT3(2Hvu7oiEP@Ckj~6=Fui7}<&Qi0| zZsg07AdhKhq^Io}mY*hu{21IU*o5`qqp2>%^VyaNN&~eDo5;~dQLBgC&A)WJ2gK0 z4p{j79dst3VmGAY^9#xPbA^Ke^xi}Q!RIfEqYFOQOR&c0SCZLXcJ}|Yv!9!uJsqE2 zkpb!WI#GJ%=@>#xzrHJ`kCk}8h0lMnYfR#^@ruUhjY7=@pMNwvZ7LbB+gX6mnb=cdmQg!?3-Ry5Petz}8us;rge0fkWI1Tk4iVvti1vSm*n@WYooyqp) zimo-t zM;ewl7by1-hA^aZ*g+&mu21?9Vh_k^$-BtUzY3sm`QUzvC;FhQ`D7%21vl`lN-aQd zIr!TmdB#i#KBToqJ;2=lDAUVBMkaVO>~*T`_?oHhyy0WqUfw*d~1e!cOcIq{c7Vg-DA!2H4sFZN{~B z3|Nf-S_?$Dq}oPQ+`{MqG@mMX%UHBmz4(V?Nqeo>z54vw`}7uW95zfC??O@XuPk{R zD2y)POaQk8@X5y~51#^jibB5r$V+zmGOVr~iP88~9-t#^cvk@!)T00|*WXy1>|t*E z8Auc)8&R$L&ax4^ztNCP;%euCE#|b;qSdkCE2gUmV!#f)n6Tn+BO%ei{B6tCPT$a} z&^2~Vp*|>*jv4t<%W`M4r>uT=0aO38B7Nl7p zxqWw?P7eqQRXu#IWm((*o>J|w8v!DWMJYi=;_$amcddOpbo)%OFh)*QM)dP&;eJDX=q-In= zqUsQZX3RoYrn5hlh^b@@J+mwLJqsJB1pwAop=(pw%U5J$5x%vG@{O_ToEJqTjnOVP zkGFpfxs8o>ZP*&l1Q>vb8&MS~cSqRZnWLUj4T$Qv$oOtDfFhNSLgQP>0B#{6Ke#s; zz~ctH$QyL)i&*SnW2K!2$Zyp-PS;tIFt*x}XmO!xo(YINofb4!Eo0EOPC+*_XuBO0 zQnTQ%RtxcsJs7n2#$s@bu@jmDbHMBN5e8#F(;4=ursZdr37ymXmp3_}7Q0E+evIXT zfJId7{mVE&N!36b4)nSQ7@)lF_b-z%%~SiA!5m+yt*^n`D5!0*U0Z7ZBK3U)161Vv z3T2c}w&LpbbSU@-*}wbAG``U+cOLApy`Us3PL%!tdQD!J6Ou zD4E@5XWwjRzcf8NK#{h88J2j07JxAG^cLm`+6%%mq~__>x|?0hD2cImF=92DAOmje zUCjJln(NB}u7Wa=ll%E~bXx5tC)>$zestNtgixJaRFeJ6?~(}7*LYs{?fchSGbg!!DF*dq8+uE#Plm-QAZmP` z0sda_c|W=kP`jt6<1;x58=qg$^`EQj5327WWfC8NIM#lAhXiYU=JKPny9_J)e@isr zdP{otbbQX(zpTXS4VutVM2>NGPndq2q_TH0&)W4S@!9=?#^*QnOec>1^_sNy8{6$H z*u_{)ov542w7*DCn}XnH>q_BszKzd2HOzl1)n{yGz*8%8cXBgRP%~I^1q>_GDm#}$kz1N$fIvNzTF&uOGQUC`x} zkP?GspVvH`BkXhMg+Sx$gL^afGs96sK=r>`&l~P%219Bt3qY=@+hU^Mj#v=k_8*|R zHmbsckc1Ld2SFw-Ib3#*D|C*YcQUWZn&RmgO1zw)@sgVvi};4rOzFAa&-BJ&9Luln zI1`(Lqadyr1=-Bx*G$qiue57^_9|&BcQU^PSVL+e0x&^7!<~#CUzC|g8E0O68o+|} zL%vCsAg;U(Oej@YZxJzBFogR;(T`ki#zdcz;7*^_QUF6b%Suo|g z{Y_8SJEiX~D=Pgs+&63I$lpdF-Vu=}j8~xaqNK$Kh(D?Fyel!6&wza5JI~s_8Mk8; zQ-b#vmiH03tEzc^g6jyrwJq@aT8H{taU1wAo~(UnKmoc}Y1Wdq;cmnR*}paIfDaOQ zpKr6XbYJ+qDbei(rN3GH4ooB*oZ*6s7#smOs9HN#8F3CE%ejbm9dPa8JYVY!7u={v zbLpioEE^DwyR(jrd`FwpfMO3`6`9wDUkcge>z|_^S|8<}=Z_^?+(lUYF}F3_E&5dA zA+D>LJK0+7F2a|?pP%;8207k8hI8g!m>y6qi}3KQAnv#r+52n5-~d4cAvJG7#|F~w#^4DO0LU_ICsxvWZQ$}n2yAvw_^qavA5u3K1zSJ{Qr zFl&puwPox&LQm#K)(3d|51^Zk1JBpdP<0a$Czj@`pULU~BL+E<0rYQzKcMcFP|pTu zWCQ|3>QNz#tb8C7ZLW|t2Y2FGf$~dPdC{GDssk}0bp)4M(5cwvv52-LF!x_%E0%*O z>kaMOU%yT05wur^!a{+-o^X^k5wIUS&4T^BHt6LoNT^BZAojxrAV-CA%3iUMbRG{9bUSnYupsv3X*(@1Fp#e#9 zlI{8pdPdO2+@~f2UAdj7%$1_B?=f+pX0}eB z-KNu@Dd>epY8*i$k`1{4owtM);R!&+nj3W1=TJpQFQgo$_CL+qkUM-udd~NNGFHyW zPW29byXyXg`t{3ty&{9oN%+7-99|gls|{0Jj*dP-)gajCF4<2&sO9igtJfyWluMbe zImxL1>!Q)9PWHPD$5%lGcjr0$>S>`18MgsWkUrX7dM;x6-vVTTt^ubpe)R>(k$U_L z-LzASjG050o_<8v^yCyM|K|DN6MmpvphYf5)i?ucAM8cZN%*gzbB0+AEW+vqnm-DDY12p?HVICFF#GQ2vtV}cy$BX} z9ydhwlBf_b(%ns&Qnk6P0QYB5(OUS%&#Mft3bG9!0XsPNJf(k+3}T4flu;ufv6npCi)%W;sUzH*?YFy*xv+VY`I<@D0L1nh*p4(vy zWv&K>s4%NXG-~oFY)+ei<_l;ROT_$2KwM_N7gXbPl_iHPFy5A)>0gJKR>@kwd+4)d z>{mkex)N7nDtP!t)}ji_d_E3LIJ~5AY7a)1(0vO-4GdZaMp(TGHxML0U=%KfRT(M< z#1SN;@Ejagx4tQ~r+D6cjQb~`)@T79;|wQrh`;te444k0ALI@%(d$S4pazPw6Mj^G z5sqh6rpp`Cxx6m#uZ`*)PkY0aI*;TRf3c)V`E{O@U$<1NE>Fe1DR)g7Wb7iDcShqs2~ZT!WN$@?}UKRObkh<7FtG!+K(ys2i#8P$ipx zQv6A^cX>vCQudP}*Mz<56wK2L#g4+g?&XLm?oBC@lvk${9QGgloKM~)f`v6Sk<G-A)m5mCJ;s3ouytvugR-!DaA?^K{-;MWis-7(eh zroy>msufJ^O9j4xz<2|r_!n>3ryULzV8Xmq!u1l(tY*76Oy#`P5*>Obaqutdl_#?0O zYMj%4g4*)W!tlS04TIdnTNs0lq(x$CIl668cUY?PKaieZ9>Xx3-$EGP+XgPK+YP1k zwH&#aGqVhxe@iky?WGf&+Ajf`q4~hqwDwf8J=3lBOwTNfz18I%O_nGAbbG9%Pqha- z#cO(0`?F+V8rYcMisxRnOO=c-*8JU4eTTN=idc?L9oxhbI!3oF%P-v-@yGg^ zYZ;&$)R7;nW07XFeCwDx#?Oz72QEikYNhLxnw=a0F5-s6QRq;)PYMqrgAuIxoJ=#B zLuw_?8_B;=ucn~p3z}9>Hl9Ldpw%BC788tQw+2&t141!1;o6vVZGvkI0`(n@DDRLH z8PsS@-&g}_AZk6Y<|`Q`KZKHNZj->EI(8|mDP%Qi^e`l|8*6i9s6_<+G#;74R;FE& z$uCR7&QAuIB!oIUFyAcu=~I$~=6-a*_)mNR8gEIBfQC#WVn?j9GP-Sg>E3Xknb!x@ z3tE1iE+XhuL8^Q?-6N$o`m_9Ty8OGkDSshohh6?{Cn-NU|3`z!qGr+|*ld&aii@UP z3s0M5UE(>GJ+@xc2W{V)!z!0`#lCf59EXpaI964%4a=L`3H|T1sss*t&LlR|I=1=} z@Wb4^0e}Y1K*_!!xnTMOEq4>Y_y)}ff`EQ2&lR#H;6>-|<-eMKu}EFBtjE!<3~+=m z#T8&@WK2*M{+x4xglRYqm^Rs-Gr&!?GO2aT=xOkQm=^l!KGRWJ?hg9{u(_Z7b85-+lmJdl-uSbwK3%j~YK=+L1mN9ws1x>d^>i7( z*=|r0a2&C^o8am)k^+yq%bn@J`c#G>C`Qd)nj^%YBJ#N{^{78nF z()~OvSOuvK?1gCT?$sXra2Iy4zsyrq}iS0;=5hAs}9NiCr*`$8i%0kxm^f=D{a2fpg1x3q)pR%waNM=09FRo+( zwF=M&#RR28GVc11;n#Q=3EH#pRb>(J+c0Rl@76oia~bg9Ml_Rzb${dx9sA3JU%;~t zwQuRdrtRyL=MvFVs{V3OR~jq! zIXjkd?qlALE-kNIc7Ck9l3Qt5oZcrGff!$XKZrRDLRx3L5U!3gt=lKdH}x+&MvJ{) zoq|2>7?OllJ$r?BfQyYE*@fW3FprhNPdsoTx3)!68@9GEV{=0r){iFS3AB_i0z@H< z$IH3`89b4<5RbtMPGE3^7eg_4DK-pQHx{dKZuD-RI5_88PjuYyDW_H1jQXE-ZW)E< zt2My))cfbf2&yt4C>n=fDAN6`h@0k;xA_Qq8C>zHxc81fD2L_aUQV7l!+za6GRJ<| z`}#@bTEo`_t6`YP0HkWlYGCR#PvDL-Fkk&9KsY`2jF37cjDf^b^UAzu1HO6LqYXjFQddLJjkYaL-Ya6q6EVc}H~=3u zMy_n%10>>vj2Z!z`@q<$OKUT)dhgA2Q}aXQdr$$2yWQbbHkH+*=eJUxPGvF3^p&VV z9^gx3oj60kprB<^QI$|`(N{-dQ%xQ-K$7xcpaA11s5&&g(qTKw!o*GNFd?W)edAZ8 zWtclPk>TF0EQkK>HMe)Gl!fPwC$4^2M?&fu`B!YOOCqn=7I2%3UQiCA~v;PR_ zU@Sj%j6gWQn`vMg#{niNcw(FsRj{Smn_36vgjxg=!KH^$uaj+ zF~uTT9!P5E1MC|YSe-w^M|YzPbqxOK1U>v?6ZEbN$rAL0+-i+OwdxA$vViVDXk=Fm zV#u5XJ-aS*)1IF(Zh~gqU~U0&#&X?xXep*f5KQ7wLgpgV`_uLDd8dKP!-Smq7FMdW zkWycig#-2&oj^0)H z!iIY%cCM1x*B@P%6{I`ab^l(f^}kaZcKPh(0G*zxC_zJ%Q>3s0s9UbvC_~2j5-J9|3h~Fq*e0w+^NK%4JN})2TTgqvs6dh{!sObUi1<2Y86b|GL`{nHKY+>h1H`kwxrIcT-0X9$-;Fd0sveeQE zorC$mQm>DyWPKD-eSR#g|3?)L&@wyBjx4ZNK7?X%Io0+B*rdvDUW}i%yclhNh2@zq z&jNWC$+K9VW8^tjo)hF*CeO+8td!?ec~;5uJb6x+=L~sXB+uFMwB3uZE&x_y#e17tRlrS!I~Q&`+)TLHaCLC=;5;MDpVz#M$jbJ)@4Zrf zy>tA1`t}R-A7BLs8qY!IWyIi+c^zV2Mhs284NJY{9y0vUyu0e0f%9CfYJg3TYwmg^0^G10FCNbt+^1e}?Pswwe zJl~e5XA$G%%CktGmGYb+&xRU?&XxC7@?0y=jq+6T^e<+de0hplyWP>OU>4fphnoy{ zCfoqH5ZrLMFdS^i1&iQLgc}QYDqIy@1a1c0C2%&}m2gqGtKb^oR=`~ccLUr_aJRtS z4)+tdb#Se4o{{FyYhFeIkKFfODZflSGM$TK9*JbC8Jvq+v}bFMt2@?0v^zk>|7Wd{LgS$ny<( zZs&8(n%5SA=D{sR%XZ>-FWj?mK799u3&Q;g-(&DQ9`0Sd55;dD+~IJrR2dw-652ol|*k#`_a+%!~Q#)1ja9hwlF$Nl#1v=Rx1d z?f-A5`+t+}|E8qdF?pWrelsuT^Er2ODtj%@uBAA8308>Qe6g!Q;%n7n*d)+$ zh1IhV0^^s%z6Wz>_C*ppM?xVUu~wHe-HHc+5#VZ%byjc0o3rUiVhC2Bo~+n_#+M-S z^Hkf5k+f^Db>F5c`$oR<3Q2pNhJ=5VJv56<-)@;r;eCf zWxps<{wz@>VH=`MDxFz5|1b6{5_WGo`OR+fxjOkgll+!+@+CU?TqO4_Ap{ntlV9j2 z_vz$*lYCY>Irh<5x(~^7CHcwe6F_fjx?Ua2m3rpxjvop4oRuk1J>zVYupmorqjhG2A3EZ z?!&6=xst`obc9O~A-qOBD@~>Qe<3zmv$C-xzBWV%I;Cl$6NCdbvG}+38_7*8~`$)ng&@~uHlPtECc>Yy9 zr6iH($l^dZ#D5k0aJ^1NyrPLVN7fBGLcT=!emcTp7B*RYuNGf!NX@Y;#pm*r&w1E! zL`-$gp-|G*@3t**swEDpUSHh3LWD{8FGfIH6b}pLvFxQ1?HE&JeV^1JYcaRJ@6??d zqyI0zfX*C3UFSJNAvA%B4j$FXgUzZk4B)yPdp!V+W$~j3h4>HZ++zGJ0KBQIRae3n z^HsQ3{pA*Yu;?g>hYKDLY9&FR*T-#NRuj*G#+T7j=SF$+;f*2+Xsib9+tE`sDtcII z3{ps9-zB~?)4tSZFXWD4WFz2-oo#Oe9qSquZ@bHfszy)MQ5Y$9qK;B%ze!Su@oP`6hbqRo82DAv(ILrSkxoH4AHd1`=e1xtK=yhxAGvr)nXw~hb*wP8 zz{V0Pmxt|ioB-AD3BN@9IHo01?Q^Z<$J@%-%1Cs6yln#C7GCbGTgw^tTOzi4CVIZp zx)uIV?>HypB9VYE)?2O<8IN12yQ8=iwB=lH)5d78^3o^fzYB$`!|hX$i|&>0Bfb5q z^osh*V7EVJ>JIss8Ud#M5GpswrY5q^>>s^9j9a{;195c+8U#)tDG^}sce<%jvb7jN z>Wo3G3vbC~%kkH-g16lA&rNbrJTU>R55UsVP=LHs3DbmC>SNC}1v?eEZKeoc>URS{ zfGTkQ9=GSvgMaw$Xef3+cojLUdsRg3c_wvo-54glAtNb0Qc1_UA0M^yXoNmL@+4So z)-;H@($DN3ot&S8%gysZqR42u8Z@hJB2Gh(j`NWdiN+t0;<1m7@8r6hHBR?S{)!bz z{)&Oz1Iq=HLs@|OeM{LMF>S%&>Vo2-U>506{$P70QV7aak@O(xPgPL8Yg)}(1n~J=y9OnosA64; zdqceocs04d3vwQ)W47r64vIVfi2&j&#}oO5wP+CkGBI7VDV2=oR2p23jWzqF$Lsx4 zJ&0ZeI5jZl+3&dccLnlOCkI?$eE1;Z)&=gjA>kH;#QGYqyO2wKg9kdBo`}`Nou&AO zCOi?e1y5IpbNx>7YQ7&o@nskJt!AESj&E4Xc3DmTCm$|?Qy0ytjXKwo-j=RrSypoc zJh5kTo^yjx>sBI19G6WDJm4)8$I2}e=kS(^!`)jZCi0evA?_^`U*IhhetpYCtf21V z+K!crQ4`WqwI@M5@&k_!0cdk)&N4GWyN-l{J^FU3SsG@az?AF((MdWoLk*tvQfAI^ z^L_I}2n{%WUAD}7;^_Ilp7&x)Xlv5wG`U%|A-6eGXWyLFAf%P6doN zdHX$-(5z*=cUHW@x3_2Y_G>dJ1hCduiiRyPO2|$hw}ocX$Vince*r9(LUWW?PiNF& z=024;Kzf01S^8#8$W(QpRhKZ!4qLT=W#+S1x&_{Hj`Yim*EDilE(u=|YA_Rp)6;v65r17speT zTE1KlH(%2WOTxluO-nAyt5r=a=&zZv?;?FC$cfaIbzc80(7+kc{M+bUPO}(~R|cW+ zdu7O(<#Q&@cB+cwFZ-jtx;Ob^Q{1ZK!yg@wp*Y&f7X96&0X^*_AQ&5kfS?I*^|el6 z=XY-kN6*0wH%7ogEwV?$x@m<5L0YnV{`bBhlydyAYO?=sIutL=NalRD*Hv+lNQ8@L2w~~#?MLWk; z*kb@z_DK9Ra7b&Au!DBlJ@Gxm7F1Rz7wn9v++Bur%#}sI&*=w@ zI*aNjN3n}rrflbr>k87V=~DoBfc^Y-!^8Jx`q)t@HLrUUw524;qMfJ`>XTfE`xvhW zWTc<#+Zl@$J3ZbJinoVLm9=~Xa0;U|T=K$(H`wAw{4}c(9oBq~iVl*@VxDS!(FeR6 zC&eEL#XG|B4~8uuEz9eAI)yp^F2!XwK-+L>32eaqkA6=}-l~{it53sB3xyiaYU!!R zqKBn=YJrbERl<&1fFnU7o`_!^aC-=u=5|ctD%S(bz2K}(fA7`U@e}}31u#aGy~Fg^ z9OtvvqhL{HRODBP9hT$vL+zMsgZLEvkOcs_!)qUm#f_L-FTW&tZa_gUFTY zcS$cz9{iS^Q?4e-Fx-#R)9AA>w3K0BB%+22b;F7h3*-41Wu3=@8mT`qDU6?6O%Ueu zWIqSD%Ej71reJGzmUy?&9%!w49I;*h*IE6Rru^&BwVWI|xWd(kkML4r0njP~A!BrCz)61^Mk6uwvw%(Rx!{9;Y zzt=rEKY%ki4iEvNSpLa+isuDGwU`-4Iam4a=M!MZSbJE0K%r zX}s+ttp6zl3XQAx&Cjb%oBC9keeoY`0OTQG<7wbS9WTIDmhiSzBym<$Py@k%nTdf&c94A^ zmM1v(5#=dv|5W&#p_qM-v|7hkPAu)1pXWTD{d{3ZVrT*(?4ZTIS#G@#(r_0$B)`v4 ze&W`z-bZ22(ar#Lx7Awim5y#H&jLJfEqBY5y{M-EXcjIYK5)5QO7cNWfrqfUtEvb6ZuwE@&pW+pn6ocjrCE{ z%wkgb@d@Qyss3YnSc3k9eRxoP1Huc`F;!*x{ulDA&IRbq3>@gZyvKJje3$h2 z9=-23%a5=FqXn`*K_NJpo9HO3^~5tKVy`$i`?u!Cx;XqeiK~RGy_8Ue8ZTXilli zO192M9?4eb1PzgE7({OV@LJV>K0kc;7=p|(S4qJvLF(CVlM%KXz~^Fl{0!c~W31dR zJO)KI?!HB;KQci5kzPe#E&xTeTbfX}SnruFle`zm;o}gRRaC295&o0SI+e|uBz0%A zj%Tx&DB0Q|&AM%=X%=|plfGt}<#JSq+N;4cn}+Zh5gM}oJ!y!2qY2V^si62{7$*0{KM(CY3Np!d_40oQ~$ zN7SzmBjX7CiS^Z)0qNSo=lZz(fcl5J4{^ETL3hGB;1FpOC7~sCSrHYzn$2LF@?}ep z`*}g=uU$oNVrc(}`pQ?`rp9iu8&GG{hridz_&&Ch!0=+mWy$+h_(MEUt6@SAm&RBM zfju04;Z5NX*qMZHEEOFWv*^sVEXsO zx-4Yr=lT{V(nrWZBB~9C2Q=aMR6mpLS=W-n`Rz8fWlcY9)ooq=mchGEBMa);KRv(o ze7fN-QXdyA(AlHZ2VLbwvm@#u0SqyBB8Su{nFlzeN^tZRqiWrYsC+Lf>|!)76>`ev z4vDCNbKQ{@^_$JaxZyekd=+E+xLl+tx^RjS3d`Xk+i8LnvYkszIsx zrtxa8kZZI7`{q1AZ7M;X2N18JrVhds5iBOI~cgT13e;u{oT;)w>`JXLsoGd1wFa@phuhbu0-`7nn_*y}Fd@_(0Sw7i zZ%b>4(MRi~nEsOMSO|jiRGSbX!rPUDV#fP30u5ka)PQ}d%LVL5J)77AvhNQ2jns#aT%|v0!2~{Rke~Y{~WC!)r|hWUyDTuBbR}HfLo3 zjLXanXEjCX#S7onD?+0s-YhrXY3X>Bo5Fm|-32J8B&k+NXM!24zuX$xfX?=~VQM}? z>O57DX@=Dx%+j>Q8^jIRtK*0y6JkLXw5WoYvsT0>n%2mdIa0kWGo8Qmk=XgVq$%n! zT~O)HrME=X(-o-5lgrv!DHp z-vEDA;h=r_@e2XxcBi=#;6vy808KwRb3b}wnmR;A54s!b%+zr;z}cpOb1PIGg*Heg zMCn{&Z~z$Gw?>_5hMv{Lb>(q2>=#HGH_<_j%6%f(OI2c9i5 zP4!Amw2(pehBfON^?C{iPN({i_&t~MI{|tJ)bb0>e-Jkpe%Zyq=%^Z1n)<-TttNd^ zf4O}USn#X;8`=uxZD}YH=(zv4f26OQNN${eOPA~Zw!Y%pg9hYbnENTA?Lrf{>A}Te zq0m)<{5E=Fa>-45v47G%FLUfp=@*W$QTB6YTvXXF>7Kvi6$22Wk92xzG~d5;Y+aUC zLW&(?4_ZcH!empI*bp0uJY5x-mX0@`(W0}N?wZZm8M)Z>5tgstPJIk=IZu{jgB)|5 zVw9&)(XCL(REP$v5%Z~Zl+Gzw0eoJa!HL$d3NV+L+cSElBoq|945(ETWulSZ*yQ%c z_l0OnZ~WZ#x;E`aCSV$_sM(4($$bPR-OX>-A0zT3cy~xsk(h!U@KCjC+Z=+9eKo$K z^q)&#s8zKW8DJhyMzvP`CKY8wts0jK9XQjqv~@wdy+Q+bbsBQ^%XkM7ybr&c2e=U1 zxc1WhV|>%ZK=@}0YL}nF3UmS(CQobt77%&RcDxcFkiCm|DCErai3*n3gz70`ZaHgj zqBk}uN*}kHuSF`VB`?RX)tXxd(Q|ncqUX}~*nBL8WRFs4oU55%0PM2A0n#X*H7X0u zbk2c7K1|*gp*~3C$ms=8NM72KKl6gLCT0zmQ&;@mY?Ti}+?k1+ijhjVC~#A$1XQu= zxsmV*q3F_o^tRZ0%uQ{y)E;o7rQF#h8!h7!7FNr=l-$ql7Hl-NG*Y5f)zU~27iR>R zzIscU*7T8kbU4z`hywePUM`62ThSD`0-OqVY?rzUlZ8t=8UJIp3)%aH`{xxlxv48` zD5i+tk5z%ki_Ovdn^2GkT7`{k0p56<=<&va9gU2Db*JxiY1doLHC6G*aVcdx>mC17dnW5S7AA^BE2Yu^$WpR->PI;37(_zl$iV z0-$7CANXK+NkrSx_zK$Y@%TNlQOL__VE@Gz=axkW#TSS4zEu<}UYU{Cv&8Sp%A2%;bP(y# zskps>%E?JGRLPY+vuSB?ed@QK@HhJCU=*E6QK#1DtP2Cw*&-Bceg@a+pejzznbWM+ zf|g2e!b;ToO8*c&-oDZd2f3oz-iT-z(k&3$pyd-Vq+tqEtJzY6sq`PwzV<>S=`3V^ zC`k$^ea>1=3w(voQAw!9cLH)xj2*YZtD<>LR~2?B3v7EA(e^2HzW!2>1% z_tGSwcRURK{T{%I@1;q=a_{(wFbVjOc+ezZdDi%ei1ADDph>{;?C}#}67UD`NZ!kq zqQ7&Y^U?&90RS~vh^TXQlyiY|p9Ft0ykWd@qeQ6=%vqa(+`O2Y7(9fdBLhw}oVv1aUA_$Pm`JL4il{P;Xy%a?SIK3~r zz*P*4o#hGx+o%ubfwrnvuF+JaU0*WI^>?*;nmwDAH!}XdX&;usF1M{vKW82y9DL$G zNNc3NGI2U9s#t04L?v6#!<&#xqYE0dP*2h1aVr{8bzd?pcy4?dTF8C4u}GJ~d#RYD zahchJRAC=)&PTQJ`*T@==xnFjhdDjK!y#JO7;GHx!!TItZye8(V!fs42_XJQJ6T%y zdW6=!9tL?-E{>g}qw{L3)pswHCB&@uj>i1VN(z^n!EoFEBd78xTjPkG)*l!9}70u{J}tb zeJY2`khrU~wxnBKfGw*y_buxW!-BO&zWn2+`=Y1RR;W{TVCmaS|7JgvN_=rf@lDu` zL-DDJK=U+E{b*i`_y{SG`2lUvL=g1r7YEF!RA*$`Ve&Zu=sy=P)YR8F)&rap4HS^8 zDs@~HSGzT8EI|w)`msJu){i#p)1%=H&+f87Q*1cT$j3sBi}Q$<*Yv9>-LVuDg!KBO z(Ghq2{m9nuHnNqwFuD?n~5kUT-vV>jH*x-65QV)_Vx3NDt#)8y0ENTSX10d5i87@g;9RFclmqF@z5FET#K+K=d-rML>VK!coX{icNB%eKzkvpg ztJ3;>niehkCwkNG;QlS?zx~OO=|0(?&(xn|djs|(oY_SC@gx;`LT0v*y*cGc15s)V zM6M-|C3?rjuGBX-Ihzh7%Mg0=uk`U&BKuTrwruJAE08Didr6P*yL*J++2i}xeZPC! zyG_d%DbL$qB>>7s%d3So0{+kB*40Z9ep38;4nLnseU`cE6cq7k`C&vIE1}#kI~y~Z+5ug#F%w|O0ZSJwpg-9TWE+=9>aBCr=UuSU2Qn0O z`11ECPZ;|`zTy$Zysg^byZ158kZ<5Mke!v)2fx8$c;Yv7OmlV?esi;iO4K|?#djF- zhG}^S5oL^1=06ga=RBu0pwwv2DUAf_+12VtUvyi(q`Z!ITKFLvy-579;*1?@Q%+|Z z{;+QNq%Ef5sBJz@9CV@$@rMg|Y^y*s_V9ex^~}JKkM~M^jJL7;ETeoSC=by+u2NZf z4$I`K_z3p(Yv=KkT@S^e?UinuqDG}c-xTTgAI$u)|CavNG$V7?J$M~8{nw@ndg}Ak z9fyt2vrUc0u}0^mYIF>Y!re!;z=(P}6$g0s#Z)!Zc*avK2Ha3&Vm+UI+|={q;aM9X zhx6a$2uWd#bPUX&F_2^#sjLSrAE+?fM4J!h%1mX_7pJ!S2kqe3Oa@>5`UxSEto7woN!gJ4{1T?bef10LWT3JYr%G5DrSzhR z5i`Qssj$PLh&Rc!5Y1hc`bZP8FJyEXh!?xe`q<6gj}YtmKzG;7c-wV=sW&!FZ|THc znG}bVR)M|j41;m$Ays4ipaOe(MjbH`u#R5=Dbho#=g`=%F7)6i@yFMXMLj%G=n{rf z?i>N1!M{Km+lu-xFsjS1_F~@4OXxB0+WbTUFKWt#T^`VT& zAP3}FDJxX5VaBr004-+9(PF0Oh*#VX?^UZ#G?j}^qh`X_g+3B_Dl+mJVe%QG^BDl8 zpOO?_^{-X2au+{hIrb0H#IFAOkT7)pZpvse?O>tB{{%ZFE&jB+e(rdt5XZDXrEgm| zAfl$Fa9EhddxXBSabOlXRKAc3KNSNUxyTlNL>-p$KT2zs22vix|1vWe()iz%(Ms^d zg8!zKpO9GuzO@C>FkE%7^@nnu(~a)8yB`JZmmv0|X5@#{MtrR0&mqx)4Eb2gA4G^Y z{CkX@GV1AK0pt21TA?GC#AT5pDmIZXkn-MzLcOp9BO4X+ON7LhEkZ9uycTkP*}8CukLudq3|JUbI2y#-7pVDXUF`FNqS4tPw~b( zvhfn{ z@Ilzlo~LnWo}H)phRJHwc#<3p603=Nj`5vds|kW#y!dc%0P!8UMLapLSp8uFxOeRS z`nZXSyfgBJu+k)7H(HYNukhGpw+R$|qs< zOGxpZVaU>1CR^D!J!&mK8PToQzG7i%qBs7K+x%VD^22mSW1NSwpDx^mGtCea26djqT5@Ol;%K%^HWdo*zXzU$-`S4mn<)VTXe{N@+6{r-!W1b4i; z>Gj^F&&Nizv@opnkBdSr@!-*T+cY0`18Hs!?ZLS<4pFrk<)W+*;VXLbDaBQy7(yo7 zyV1>NJ+})ihb+dk${A327A#`h1c> z|6iPDKl%XKIA*%}IGqVgn&=fL>ujraEL8#eCg%G}cW5=67T>tS9f>S}IRM`pXL{7R zn>+ZWd!xR(Bf6?uzVWYj@~6uV`qA7$|DwBtKAbz~W$q4of9{}{=pFQEVO^p0w#}__ z(R2idGZ=;;P(1gEsDq|=#b@F+EAsI~Cu!LQ;D2z0hcXJSw?I8fr2fMLlG;^8(kfC1 z65oC7p40rqSHZuCK3dr5qgl(BqT~bVq*==^L5S8%vzjA#htdUf(lFe}Dv(hqm!#MZ zgkQ_VBvoE8%$tvaHz=9tFGKNV;A@=7z>$^TEw#)%Sh?O@?Gg13mbszkBhM^J#9Cdf;_d z0~SAIK9zFJd>U+b?OUUIF8|HKbso+dW&$e`ljKx`s}JoSEh>C+9K`dnf@+$R3#uQW zCXiEc<0!rnH`PdA&q|2xY-sreanfCX=m7CDjW+XlkBe+Rc29q@1e9kuUzeSASdv1W z{K;R+?mA`4)yZd2c|gup{?l;#mnv4S{^KbwzKQ0fHTHB zvGIvv8pr&Y!vf8ZMMtA5p>gY)&;_wUxTw@$U8Sxa!x@0ge810(58~b%>^Eusz34)a z7U=FhIsXdi?R6AB8N0N$x<)kiQk#Q-Mip7VV1`g$8%e&p61s5Q(8G8Qq4hcj5;y!RBSjGkFoHbybg3f!Q zO^ka*L7*%_nkin|lGxlbC9CuuYx$oMQut2G1i$kavKLR_6Evs*2eU3V|XEV1eG=I+=^B!+n{Xx*suMHPzyi_y;^EPqN_H~ZR~ z*;bx&K_!dTqi7$6sAE{-rFx=IG&2|}Pi^s?JPy@~eIa8ts@wh#vP=b2Hw1 zj{PX?ddI#>*xO4DXQgR!a@{M4uLj0AqLD=~GpNP>3gaYS-&us3PMS&;98zUztl|^QXt8|LVNI@PW zBf&vC?Q;ykeDksOQ=GE2$_UyHdo*R97}WNPpkF5R8tjFcG#KubRhmzI-g|MS#4qz6 zAU@~+#y0S%z{r3jmIs`M8-X&ZEcSthV5(fw?M#{NEV8Q#=lRqUkbWVhv0h@-X&lJh z{C_e+nJ@d%#1z|Qdk&B#>)TN_7Uk&z^>=aVTU(t_LwaN7dms^qhDVVnI?k!YUU{Q=CT#UCGRfrAUGEQ{|tAzBdM zRg7CSUV*T6k(=XN^Ud6GTjL{Deubv>2m9by-!hw&2!ow-6N+m=6vCNDwDe}VBWXd<)Pz~>*R5ji2eJWBGN>>D2 zhMxn_7xm%7@%Ch8x+uw%L4;YNQsbb`&u!7gAsONo+lWupGt{oabiY(UUX>3ikplblWL-<~Ll*<8IO;;f`==g9psLqS?w%#zvW-r?t1VhE+ z101BGh-(JgYMO-j*n5jOZGOzD$@4fB_)2$LE59QFru^7A*doBKFSA=8s)_+Ajb8`h=hU}+Svf@DZHb3 zo{owM#H2ZE7~Xjq0@Brr_K7Hu)Cl}nhUx3NDsB)IpRgy13tBN5ZPtn)oQ^Q@l>C%5 zF5FQeV?`UjrTj&wdcPQ{ic+a^WD-NFJwK6Dw8W&1X6xv`W%ROC^vNdr6Z=KSPAX1o zGdeB|)OFG)f!%7|+%pB{^p38q;1akhIKCU#W9a-p@u~N-uRk99B@vumu5~4Wuu=i^ zj{lCbi9o!*$Q#Ras-rWN-m_iAWxnJp-`Y1S567hYt`vKr9{Lk^*N_^yDKw)aLO(fEqm& zmb77>8@WVFY>qU8prj)}wHwy5_My%h_(U=o-SJ=ufH0f_kFIARTZVucsJ{~}M?6gT zN7y6^l8t>G-`t!k-JAx&Z(RNCSb_Qye6+n=igImF8BZ2hOEj#LtR@BDME&dtOdR|{ zvIl=_H9Z4gkeo#Q+(<$Wrm0)>uw&r82#l!1k1#;*O*4 zS&b9hYM59nrlM{bmf{20vhAf4abOo5pAb6rqm^6xfu{(alB1@9VvvFMKoF5a|K6Kzw zm=W_l)1rgztS~7r%j75dHqw1|8@p^qb4#JA+Xuw;U0*pzI9% z1Z~F8gyc4S)`hCg>*YwJoP1#r)6MX zAVjSQ5%$6W^pJ}7)F*7qXZmG@h94MH>#Ua%oJ@`2whTU?PS5|LSwlR*-~42xO!&dO z4i`S)3z+gT|A&@?5BN>-ARSg3_F%Ry1_D_tVT7I&__p`5c=^LYX5#13`GOTbnY{$% zaL3+I;R~)svohwOe6+NfE$yg~{nXAnd?Xi+k@*~a!x-=liw2;`w^1ab5>}vKWA(yT z&zhJq!vZ?1iIf1?IW`#^jK~}*CSQ*1 zHij0&0}S7TJixJW?L3%~v@Lca0WULXzocVRNgvX6#rpe6Gv=+PpXo#feXMx>3~+xD z^@gUUPK6-eP$J$yWRAMbCf1=kzOE7Qs0-0c?C|EO$!JGcFSP}IFN=}-Is3L+04aP= zCMf;e1(c`=sxSSzq5$lInc(wrPU1pdwClk_J)d%EwBVHjp<190?5uQD(4Xhu!QJog zW(5bKhpvYEJ>0M0&V(P|GadcE*~9ODjXt>N=ghXkXKqjUk~o z5ljxd_(S^x+4GAJVt=5eJezA6o`&1=Q4J@%1KZU9-(^1;xcj-EFIoP5aEBk`e8~;B z%IyA$?J;Xp?;T}i&3Xz*M4qtt-*2yZs0i*qKYPvDJ?u4qIL;qf2Q7tvJ@WgQHoOm< zIdGitC(ZsG&%b<6B*6Qhe*qSLr1LNSB=2#GSiaI$H~$ zhuoyvm+&?wxvX0_)c!G0+TI4a!+NR!*f+wr>tt}q!P=VS!o}*BDA1``jA<;<#uQRM z_K@1`AEXjezOAjmEJqBi3$OYv8wo}U;vfnW&Ix0$Mm=^oS(qRN6Q9arko0$%3n!;6 zaO96r>c2QZ>8>X#<2#SCRz8ZlTCEMc_hbdZ)V_!xiWhMxnS5bKc^O$&4P*M_K1g2j z0so`Y{;uhn5F>w2A8Sg|i42&zDC zkj?^fUHJA%`NntViVr(UX8}>=oHf5d15Sqf9^8#^BjL`0n-2FpoF~Vdm6Ma5gFhc1 z2mI^R`!i($HT|Dh27nh^E4k8rQVWo_ZJ!CzMR zy>s?M(v*ic8?VIWPl2%LY3?89$ovK2sIT+#+&vlA`Go&<#qC^vyLjB2&1`L`^a*T= z@dIiZ$c{lbe(w-j3`2;9gLtIaAO@)|0N%rFwn^gk7lE`>Aw9lct^&4J`~n|!I92iU zLGGH}YQ7m>9PO~wJXA7<+@X1;n{8C@>gyAaiALrHsi4z9Q91;ggNzbD8v^*(HNZ{a zNi@dWtaPY7n4|M)c#n=>Sd$b_r%g_0DWJCllT7%GurJ z#s1h<$D_@CJgLu5Y<9|nHpMPtu>^(0TG_@;Ap<}}_*yGt0bYT&@5j5{HVB_fQ z?BE2r&2aqz`c3%t^z!xsy7W5epYI?D|2caL{s3_}-zF5X0}8AG8N_Q28>4I z_jEYeeKvnyykwb=gZz3j&pLk+Q0+rctd(R~0E8{Q1qj#ShmzCIHE5^2jPC2c+;|-1 z*bF+Wzw2|>VE5&#=H+z^2#J$pxi5#Apr?(`#U^=8o*U-{j4er3j$LMX*?1_m=iArx zMRmMzd2q+UoeWn7cLv-AaOc9!hFb`CB-|BngW;CJt%7sucaFc0by^)T<`u_Z^W)xSuO4Yf=#fUrW#C-(jen-JPhl*^uo#YTLdRPxaZ-mJ zb5|drB{U8(IWOhwCW`$7;5|slV4HGgJJi31QQF)5b)-N5`5wc@?Cfnda~~Gog=ue{ z$;+9U#2;uvxFuV5cxO2^)#Gj4hVewhI-6K-$8wg6ymT(85OWk>O;b>;YtD-e zi|^{E)$b93`ME`cnZJ|FeC(7vH{%ED6T1S@lj6Jj#|}ML{o!3g7rQ*sYmh3%T!XdS zH6T_8FF!JBDSwY1f!O)*fC7ifIsSkgUxVVruA#za_DY9=kJNSRT#A;)cZFhkNKEdg zrTk6w#$(buqvhKRUFyDdS?8*y7zXyYP)S)k+1n9n--b`DewMay^%EBU@ig>scTRTD zhu<*VMt^p28{A=V$Km@HgeBqr26qm=J^h41>DN1_pT8gf`pENOkG}h3>wmwGrq||v zbKGqnJJcAe8l=Y)4us$Lp7b_}G6eEiM}z@fjGlskkhQn_fgOP3D5mgZfP69(tmYi#7ExDf52D2( zrI-1=q{sJ{dwieY<9i?mbY}X~dW8Qmv2XZ&J-)3T@$c*r-nnmm#hzNAb_3ZKVKr%c z)R`W1Dg&5HgWc^Q<0F6>xMJICrYT9yg2vl^fCO2w!box*Ia(FR1g)9N=C|-|C$Zet z)QTH^oe#jTyWJlR*}bvI)&bWr;5G!fS=6rfda8^btYms8Rv}<~oTs|my}0i1@%T#v z8+Hwh4zz=*On!p&U9-B|v!c22ZG$EZLg3I;;2jK{$i?8=a$G?2@~DRQM3V<*~2ng|=J;DI}=mh%VazgLN<30JH~l#($b*TsKSTVomB`iWnK zp799ws6J+lo-B30h;%7hsIS`IQN{%+rs2B1viFSmMbbe~i%6Lh;Q;>7dbs+}Xe{-6 zgHS?oeoZ}wlI|L4iRY@-$QF9HxT_F5*|^W4sQ|s&oSbHTb7Oa00iF$5I_`#&M@!{i zYx3q2vT7kUQviwS)mpt3)rN`o;DWPir>Uv%ca)92Eb93lFRLbMavbJNl1*DVJ_z-{ zY3{abv^pEwyC^?AWt!@vGsT?{zu;l2WylzdxDeHX^J6EO9H!YX9uBpavMM)=Sf2fu z>F&D8T^HE*Wqf_nZ9}vmojmu5eUcBbpUFs&m$BOoEAbmlkWI;y4ZRzp(dK4BBcn96 zk9_t+JLF?V5PT_lOsfcvTSYyCXmNEl0ZB#@7cBoUxtsJIBX0}33*(t_)EJNO zR$<-$=H8?mXnOQwxsW=qYMOcha{}lrHveHlfrmuG>IQmk%t3D7iNBna{m`bJ*$gO9 zS7w{^atxO^q`rp8Fv}sZ(py9r2E1-Y{SXcqCcw&dyXQUGJHVJ;G6Li^xHH0BQ#Oy57CZboT zq6ba%Tiod5>b!)0uJph-^t1FJ(nL~eCYv;MZkk@$u>;&^m>5j2?rUIA4T-bVpo5F= z+0qY1!cP&QZ7gb`o&?g}b|VO9$-{}J{4wytmERNi)0AI^9}4Os+<&?!zY?ENbR_d( zs6z0_2DAimLfX`m(?IS3gZC7>-n7m>6X|4)gu}_b$<3&X(N^7^Gf^4~g+Z_E9NsI= zO10PUE})l%7DG8QhZwn)eepu9)NVHU)|IC+B`=@?CQ~ZBrE>il+UMpv&0dpA8&)SE zItO3?r$+|b-$;d&cXEMVqwZYEI?6=IwP;;1fLGL1Rt=a$&hLt3%>il(n+k*sk$r|-LDI>3WDW8(@D!Tzsgife(n%AO$b* zrz3|%rSl8$0fiW7uQJi>zrw%k*%lnFY&qL|ZSM+R%~<$O z+aRUm^afP6e_+BAs~ARuHOL+bJ&BuU(8Fy$nFjS^CKL~(EyB7cv5Nkv%w!Ii$w)eZ zN!7zL?H2&{1ME9Y3E-E9B1SG?f@PHb?UaAHf!v>we@70-28IP%z7}t2c^&|YGK!?j zs#Je`+P^TVdF4@&dhco(nq%yB#y?W6{zA{|^0%VE_`}q4Aop+q22hcg1Bkfxxz1*v zeuU}u)CTa}vYv_ne15nSHrv`o!yN7$Q9!-0rA!~#TIy+r5>R&LPN^tV?DRpC*{ zkQyR1mm4oR_7h0i^>D5I`&16a>c>b*;~@cXKgZdBNQIP}yia5V_qLc!LmfD29p81MR=1%ADN! zKAJ2?y|98L3W9C*lWnD;r-=H7v_)pcM;NiV7RZv1bI1`@FF{xnTC0D8Ao$CvW)Rqk z?{gi)iK}UOMj}oKxVq9LtG^ugrJ_Vo{E}{6+xkPNsg?hfMUbF(ce|b zO{S-jrS$cuN4?J_2hDH4wR^X=w+M8mh#gX*t@veMw6ZUl8QIk#Ot3C?=yj?hTktf$bcWIWrn4?e6#;^ zsFqiUXul1Zm#fa$R}0zm4@tR0y&+DhTm6Fh^D8aOeP0-YV_5^z{rp+2cDAVlN23plb)Fs>EAU5l;~>9 z-2q&=Uh@x^B1HS!*+4`+H+MaSlMqKIPmZX@HyMuXAb4Dc^T&P6{l<8?2|)5hEz+x5 z7#TX+9R%~)(Z)@8A<%3P4=CB#Fah^IAf5>iTz>NO<_U5V^yIUn^@| zqiUrMLgS9&R9+FS3v0%{M$OyKL=uK8k8!3a3|!YRaBo~5Mi1SC5z4_{OQ=$`3KwMjxwD7ro6gK$xQsX6#=VL1)id1$4n#M?Mz~ ztn*eQ=^9|QG$Yp6zJw(vP$KW-+$#a>ioW*c448+28W=CsFvq&Mxr;k8(wI7isn_0e zOGXl!LF+t)d7i6sRNvsfba*M z>&g(O2X?e?25LqRm9BsY@XNC2Cm6Ph0}|1@+smUPOn6PVi-FO(DVgs1?K|4Dm`f_w zg>RTx6&bO*+ndr+>fSU_=Ij$C7(K+4_545FD6j*CdUT!A-5!qeOmwgcHT}-cWU}iw z*gc7Ds4F0{Tmk&CLn+ET*;c3%DDS+l3bMra;36)VK8>i!8XW-!JI_Q(aLbfi z6wAxZE}rzp&cS-s&s`|M7r7pR#M^}qbDkUsc>5!&^Hsu&#D7#tvg|rYrNJhSxwOfG(U&dZIm!(2w7%AKvc=i=pxRRxkkUe2V0K zWZ!Tfz;xXdG?;g432!x<(bQiA0ol3Wuml1A1s;+%25=1_&D`w<1aS4B)e1{@Ik*`x zz6+)t{tnMb{QYceIWY`(eL9=1)-vxVS`w8DO8J5VLa^5}aS!bEz?QCExe)S9=K=Gt$WNOk2}>fcomfoSo_#|#BLPNHo$(L~i>TeXpE znL*|fb%Gn9JUFG1xO)t;m!Zl}Bo5h~`y_Ug={(d_lUPR%+J8$$J_E?NZ{(3C^2fWg z;9z}wApbUsx707dDq#MqwHrRbX-$Y+;fbTz%6A3eNCT#jQ2Ah%0~U+0e%S(vf#ws+ z?aMVeis2U$md>|15YpDN7n!xgm71NujKuy~lRUXD4}(Dc5Tg$M=&uQhHu~Tr(H6!F zu&)SwoV}Ty1762!rXbe-lgU7z!*HwcF0x@2E@u^Hpw4IcoWV3-RtyiT^_Vjzmj2FK zegs1w!sMJ^_&dlg!r6aFoaIXl24mdP$Rc6NidE1eXLaS{1}(yNrzsUg*e!CITV%IX zn&-B0R5r_Mx(BsH-NUH+?hfWaY7?qEk#k}(=)Juid3F9+QlY6)^Rn2yEHy6;=B3HJ ztip@r9Z`RJ#So7XI`3z(Cb0LKdI~k`JPYx0HOuRaN@{herZaakYPP|>y7JB=Ouo2H zzGt16GIBpe?tBm3O(RsGfy*dmStEvP&xEhldb&p}*Iww2KawR^+?9S{EkB+K9x41l zVBLi$Z*9%3p-s2b!7gx%mx>;=Z`rgJV8Z|kXSa_-9IN@e{07oh*QhUFrb+L{=xoT3 zu9f~xp_$dZlQF%brf6N)g%3eDeXpL|5epu5JHl#y91%3Ye)t9&HpW1~{viTnFU>A6 zepsTroqfX`RCg(@NQ6535bLEoFJ=z;Cbk_%4kp3HI>DIEXH(^sF!o_4c3poH^&}JZ z&Qw%CqlQe>eK6gR*m2DG$iYCsr{+*B5klP0a3<6h7UGD5l0umr5PjJrVVytVMBA zdlNF2QfpKW%YZPPv!B>z$^CauV+SI2{}X=Np6o~rSIQIegvks$3t(ZJEM^sY0KY-} z;6_}SjJ_5x2Qo4{Kk8n5K9|B-41qv|BrP}5ugdo5k)EGe;H#>I$=PBxMR-sw2%}$S z)T)RWrIU!*&{HHG46Lvh7)BHvK(2cI65>Fhr6OBogu!|1v9WVLneW9QE(CWsB@l|Uh9by+@fXaVOXshr5?W+6bjIR%`xwc<; zJjxNxlw9&hytGQMCT97>Qs+~E-hm7jPTG4eIG{+!iU!PT9O7!6)RWw9u00$o!7@!F zyMhXYR(0NjCwdsmI`zX1W?~v>hfPe|LM~kkL@^_u2onOjfWN^TF3naWL6bBpTqZu0 zC;&XU5+|Z|2xm=9skDzVSt2~7HeMu{;;v}KB%>WPF$DamV-b#Rzu4dkCl7ba+JlH8tn=?_RNv7-BV_196`8!becOJ7D|ULM(6@dRogn z@@4i2AloGPL*CaA1qK(PI~mdAGzLL!lE17(@ldY7-U?qSsz{VY?FFL9GZ z0*V7kx)m-+Z8O$(o!DV1O;y`BTIJ|CZOrVIn@?flqZrmA%C19P`frl1{@sW;QRNM!dM2=DCVw zsMf0azhUtraQZQTJ8l*O-JyITc`eldMP5Y(j-FXLV zW?F-$O>bNrT!Ws8odcrNTdeTaku(>mhS`GrxXAcW1SQ2LRGrpTy3_=rkn0XmNSQ7q zEyKR*LZMU0>q-<3|Lf3t)b^5;e`Fd8Ev`{jDWA#k2-DT56Qn$V80FoPSzZZ&cy%Y~ zc#Y~KNyRoE8brG{p?3S*nb8I2y*qD1s6EF72$}5U?vy>*_@zKRxoZ)CbclUoW(dfI zM-FRreMvycp@<_XlVgR@20A*TPL=fo`rK;zF>u=cX=Y;G?_FWyNmCUt-oD2K+f)NU z(Ro6!u|%ZsZ@~r94H%k`7(oCi#{MP=YT`1x2mS_vp{yB<<2Q<@q0e+?KOnjKpZC=E zH?3`k-WHQVCl}C>`d$^vtmC?uh?l~l9n=Wf50rCnz&Peg5}1Soj@tKp!B`w%yzHN z7W8KfkCIgt$6xlxf+lm=+4JD`_P*n0jjE3BN0#vWBXLfdrNuFrDhaDktlIs-S z)ibpqhT>s=-9)SDXkZxsbWlgb8~W3uuA7edl5PCqyhJ18={Sz0L3P9SH%vyD`yqzp zi1Q*DXh-L5_^d$}UEJytc-Yl*@x#6e$vP3wWH=Q|fVFR@3P`Nlo_@cH70N(`nCXwX zx<4*;QQ`7?T~vrp6h<*bMllbJVo(@GPIcWf?#T&`M3}yMha^(s)T$={+&GsM(8{45TtOT zyfWP`tNDHqJGX7tb$8)I+6OHs62T6WDe9Z2a*$u0w^lv3TdzygPB4gEpb>c# zs2AnWH#2H)5kG@sB|)(ug=$^_UqR@Idh4DP(c_*kc)C(xy4Cz;d_aT<1h$&aMe%dy z%&|r`0p$>fgb~7PIaM$q{?HyF!b^k*?-U~ZcR!53M|>1vBeMi9O0t%7GaX-Hu~-u! zUB*W(g=7z&kH%v=7z(`lek$N|UUmmrF$l;wu+diCPFG-N#9$l(E@CgoD{{;SS;%80 zK`dt9oobqo0A#ofqoLd1roDHC7(}4B4=PP zFuj8~`RZXn2=(vsF)@?ns&CfN3mmJ}#A~Uh;J$I*`2dmMZ?JhT3~7zpxs|#4p_=t; zE?zuV(+Q|3l(eoNjo;+m&yuSD2$AgTO?mbT7OxQk;4Dyok+O43-t2r15Vq%;h*Gga z1fr}kD%W`*gD*G1vJ7_f0nG9_)v6nG^ny-GVC_XFF6gm~fnReYkR~r=oLMH0P5TNx z^P6b$8_T%oo461P>ik&nF)a8H6VYPCY7_B*nZ8*qZK9A8jeZG$Qb8n-@AcM?wr?~^ zBc{sh5gk!cRImU=A<55?L~8=#JVB!Ec2?jdbeE$_lGD@}&TPj2b0sG*p40CJ+)-(8Z7q76t30c$=b9*hN%?giRpJHE6Z_+QYh&;)A!@){|F^Z;_Nle)tkL?f1^mbUzGvp%O^9f%_4W1rJ`cUwd*{!YnKNh3 zoH=vmOm?G)tm-&Dl_RIFIIi;b#IdQJg}5@`H3UELy8?-WQ@i|$1MLTPFXm_|28(B3 z=26~EgVGznk$ZQK{5=b98kCauY3oPmEq#j^_gB2?I5N*WDIv3T%Po>KH`0>RJdQHi zaFmLU)JoFDnyNZdQ{<&yZTy9hFDuIAX!}=Q=b*mRS06}tuv2S1d zWG_ncX<=KdU|o94i|NjTmYHbk)vvXH6XIZ;nyH6Qph3Mu|Jot6z>Vr6-PIxIA#eKn z1kCyWvi!psF#D;eKdq(7kls^mOsxp`^vO{nOpm+OQTx;!0NJas4FL7RER$D6c)5`N-X}Ceg(8b#dqI7Q^jlAf zUak07npTYofqV7SN9^H#6cUVo;01s+`XT%SuPm7&3`XdlU%g0iT*c;OJR68&GtcUr zt*6Mxv6o8ZqNdoJcugmI7SH?%RJNQb4n3^PrEq7%TteEmB`)#Ia%ElNOMEfg zc@_~JbF}(BDq&~PusK?4Dyfps)Mkc}n7rsFO{WUz35$>!H%yXueN$d~hFmU1MUx}N zZlVN9YnxO(WNd=dE%yKkx8@6-Yh-?@{OpY6na;bZEi;{8q+Saw9p&Uz<|o6c?m%iw zfPiJMrLylOj?}j&9+S$xpBU%fo>-E~?n>Z8jYX0Q9{3M=NI4bs_PT`+ihf5V%)!A{cS0Jq- zJv)b~VJ1fL_B1b!opqPg4>{S8x-gB*@g#ChsxO}5yXX*PY-g%bSA52Ercq|d=aAGU z*$d7lijDpqYnyDYBJm7DbT^4^@S5+}Qx2WHT%mfB@LD|J9oUSRuCgEXdFzTySM z(=FHXuI_+=ikP*TQm^;`kRgIP(a6SC{?FM&i>VXXKhWtfF1D}TbNW9Djp|Fg97BYg z6GNSOi21I377s<$f z-v{!GJ|e>^nS-!a+tsAvd^nKWtAMoI@Mi!`h^ueVM0d=U>q0$iajWf4GP@Sz*5$YI zp{c-X6*0-F4r)Vj) z5rlo2tE3oxY`xJO=TbK#^@&YGP*#$M2|If916lLP+V@%eeJ_Gm7OR_JCv>1zZ5auz zq{rS4L&{Bgy4W(wd!Q{$jdOsHc=39gfGCYd)*VAHXppj}fP9FP8PFJ4$2`h{DWADR z!zHdv9jw#oEi}DDo_M-%x|Ig!$J=oWovyA*!R`DE{b(@{NfHOMvHbw_;Fix$` z$*D~4wo%b(R6b^{`86@)9}}Ab|F6@h1=6E=jp{u2>OA@6!88a_A?#jMI+Rx?%y8va zYmMw@k)e3}R{!JVh80B9qmd)JzU9sEt+K9G57%(>C6c6aFg%j2I_GsU9~wfOtV`c# zjMO(m+7s0oB#`5LQIg9(O}VOaL#iCbca_r@Zqc<|DZeP7+Xb3> zpZQ2L1K67!l)M1RQ;(pgMfSHzk-L$4F{@%$)S0gn*dRyp)lQvN7J|d<1lcl`MA0_1 z6144U9jjF#e}kK_%ZL_4ESMTF)ZeBfnFVkfC8f6HO7$D##mujTRaHDk+BVYC5K&mi z>_Rr}8`T9`@`#ZAXq~;?%Wkiy3TDgNt-ZRVTG!ioH}gjU*`%FwsL9^6qOB(<+8aCw zO$Dy?RHR^ey#itIk`BfxFlN0Sr zbD$Tw=9UJpYK&X6_xnz>&m$43rx?`xbEp@_t=?ce57hS^rs2)Y!K>aq*~2CocNwXZ zXkLSw#9vNJ@Hei`gS4QF61CLyqqkM%R`LuFsFBNe>-nWFT|P!Vq*D8_9HhwuA!%y(!-*~=?*Jn? zq9y(*`N^|Xny!LpY)=$(P^TTb6rh_EBO%}PMxo=(w;(88#4}zIY&v^2)$mimkE>I4 zr*od(E2YV&FWgio>LLU#97$&UxH?%EB-^bUUI%=Wufc3%7w8;uwXcCC@sCUKb%`NT z7nsC8UKOnkvRI9)KWQ`xhYX`?nsKAIvKwW;=G9kIXkQt`908L2WOdWjtwz#-D;#U@ z$fZ7(D$?KyxkhUB!%Zg)Mxr;sovJWiZvwaE4I1TpP1B3@QWEja!SeZz0d+s#BQKTzZBJx|2bCngQA&&ZYl{*+E& zb0lKtc~~{_x+}nrW_B_G4B6i1E6E}MT&0lPj}fQ&7ASLw#L8kn6jOJ6-J`*$rF^*w zHb$)6Hm|$B*nT}%BazNs9{*iE_|2#axsga&2}tBubfoOE6sra=@^KxRxKyuEwW*4lAi}FvH}&c7;bEy@kRI>}9m1Pb~O%o8q3Y%&%6jX{=_6L;3$x1? zXO{%()l2TSsT5ti0{zBO727zeB;@#&?v4=3VV}?6Ucyi1X^Rub*)Qg5J&{`X9pE%e zTxxTuvUV|z`eQEod1=(|O?80GEsu>REgD<-zO%WMjEmBBLHX)zj`G!B*jpDe6#$4Hrt+l{jnF2r7MNRX#9F7g@imDT!Ej)&>2W$Ja%~ zD@0An7^|}`n7{dmx(FX~#4-|7lkfFN`M^eXyryf8ri*aqVsC{`5bB9hP1oz(6B`jR zX3CaeP>ZLM8a$uoru+o-@@Z$$NAg;B<$+V}3NNH)nx-*`FV*q@V?V5XU2fwOix^_z z6VODgzGxm6i$OPUv}49!ovACZ_XiR$v>L7BU(@Yc#X^?!)WyA1mq?e%2HSr4;@5@Z zi$8XTT7Q=ZzEI<7KEC=tnMJAL&qv?Q{0FBi5`QG381$)KbcJ4VC4=1c$+QseX>?Yt zh^rg#(Gio@6_ak+&;?$s3_fwWR+2m{_5SGOIA@(pzmuTfNYiRFBBKmTb>i1nG=H(R_Ey%h(t^XC z+9lL!97A`X)XtE#_9BVk!hqVvp>*w%zM;^qbFFBE^vUiK-0!GOw5d*S-gU z@sByH7FWJ))x9mX8=uOCtTitYp8lHDp`-4v=`}__#~p$Jf9(eWESmGVe;qK-ZOTC-%1sh%qG4DkN~AL6n>jq%~ICcO>nq6{-7W z-4A4$NU5$d=J z!VlZ04q24`Y(e{Hg9Mn2LwPe9hw)}I4wnk|6{NO=7>%>Jy5Tg9ijWL%iE?TeS8h#I zk`5~4~&S@*z_1Hh#*-RYW z6Nm3DWTt4y9*0W-b~TFUoz3A|J>>PE?lqS}>!C-KH_mjb2*e_%Z^J!&GWO-|(`I%5 zE8sC=P)D!e2Ti(+1KvXE7U_dMB1G>1HC&0gHxjU6eiz5;}$SQwzPc+%86@^l2d?psK0Eyolj$MEK)!XX{QH z#LP;2bp55itYH(_=tO*py|c^l;RpxIE-zNqG?KyH^m#q3vdhcVZ;rxRZjt+0t{#@p z^YkaX&wQjFDEWK!KuFKYNO(PcRb6;ASi+hFlar*_O!sKL13d9aS75^2L6X2y#kJJF zuD}#mGj)MDNS3>Td(x}QM7NfxYC64RT4A^H>uSYRlvJLB#FD1jIk zEJ`(?c?;4PlsgXr@)OagrkD1=G81&ooGwh+s_PyI$=vtJl0EFN3$YmFc=Ng+FxF7E zgf~eJCncFHyREvdm2X($Wr%+9Hf0 zRzG;8^hQLVE|43_Ft$l=49W~JZAE%xOz3!8!s@ir?I8&~b;bI^_Li9veCmotPF-+O zxCk-DidC!u*EcvR2haY1j0qQ&*avUdjkQ(zuWgi-(^q=Z~sH3>aN6Zm4Bn zeS>UfO+t3G+S+*&46qCOx7%fE73J9S0rT+Ll?%hIT*4P>sPAR5N$+?W_m_yK-6}@qNx#3m5aCIdx_JX(0xVN3s2YE+84hCStWMY)`ayU5FwhMnQY&9z#S)ey+^hGsr{#vy zZ8DTDMQmg!F>EWIa~jJ#W@LfU{kC6Zz4grrycw?#jhejG`bv-U*5s|p(M&Dj)aLAp z5zSNbv&loa0R7^>Id3rp$Jn(Vs7>0L_SB?$n2zhpD7E?LNJH{hGy8GngmDwRHx;{)ejZA01B0P+8-O8bjo%?M)3=mA6%QX?Z ztl{fF{I_Hc14iY?f9;w;M=0yI{_zXn)UL&=*j<5kbRWr#r@r}pecn$ySb%eTJ!Z8& zCX`$i^k%w=_lqXRx^qU*zis@Ch|}FZv*e_1B}4W^2w|e>b`A1|ejsNGkh#J8`0=qH zT$H+$n+>J~tePGEhsd!oyR3}Ggt|cV|I-5Sk>rZ>^u^AlVOalqzjbGQFug$-4U3rK z^nEfRx3856dQtisSswMS72#R_b!-x&J*P!h%Ltz(&i5nocAaRP;T@$;i`Ep$NzxWk z3@vg*F;s&a-Rc!6tbrncoZ6za0a4458p+|*;*L>+sx85wmk{gDS~;w;`R4byu4__l z#N0C|28v?3RjTS?SX8&nd7Ys(k)T-G)FtDBrcjJ`baieNfGPfB6O=YA>*wbY-(r4Zmz;HFe2#u}kQ z2=jPoJmhNUMtPT6>vf41};IJ=U-yJyg7WRwBR-IvGiw%mPAKE37cqkJ@~%=H4SG_xFOIJK(WmnbkRCTHs+ zr$vfgR9PEL_BplThV1Pk^NVn#YN#k@3ZM{{haaDE86*gji=gCkIm9A%AyF z`Sd0?=W82p5MLUX=;CC5d@ndw5nU8X2Ro+AKJ2_6Jo4eKQp;eW-f4@aFU_{~e`}Y? zeS*>_VdoUk-7-wtY`o&OyemtjM60j;=@Q2TXKLVp3hdxHEW&7gst zxS2d5HA`bx1odmQe(Y0O!U}$b-$hVw?Ee8A4QS07E7sSPgseN)2dR1c8mYeseCaiM zQl+=kKam-9QF^_g%BW)hp0b5O1Psw%0Xx{P(M|yRD*>u^4qV(38p-Lmm|121-Xq;W zb8^daz=^T-qifl+Me5ovx~+otYWW$`UM-emf%aC|w0_3)1BkLl_|>#vONHaQbjX;Z#O9(t!rkg5IK zsg+)DCl9f|#9Z#p#>+^-Z2T2e=*Dx_g__`^ngsqng1ea5ng7V6_XxwH`g1N=(emI- z;5Mk~7_Mk>fIs44rGwCv*q0~A!@^`eBSQVoUEB`2^Zn#PQfaS<5t5#(lL~o0CwsDU z#Q8?EXlv5>4vOp37CS4nDSA4{eU_wU$zQvY)cY6>aGYbUO%ZgzKCJ;*Fkd(5>@$1j z!xhf#5qDno&e;LysrEwW=j{vp-7kmR8}qs|!S>VXyy-*RQKEEC54P70S=3v{l>1O! z(AVBLwEgs9?F)vddPAjDAf~^OOIN$xGp2LKs0G*a@(QQhmDbDa1^g^Y#N=b zj-aVQ9meJ_ea7&n(}Z2puz3sEL||7kU2B^z0MLg`2A@KB*IenpDRl5lX%FPOV%dCQ6v55Gokn&yhnD<+C~EkWQ#94o<^Fga~X2~KQfI`^ntSR~YqT#Ch&-(Q|G{Bk1_op0PdmK6XuVWUn2P0^u*}-UX?$0?rifs24uZ_*w3Iow z2MDEPy&K=S#Bjk}kd)~>v->UyC%OskGLKzoXB(O4sGghosF%t73|X-xZ4*5o*fr`%P#}b3WrYWN+z^yu=yyi(Yus zd3WnWQ%gw?TfA&vEpyk4fqDE!Eo4R+t}f>Fc6%==G4yn?>vzj%Mh#Qhx$Y*EIu3m` zT_XE&Gw2p@1Zt`n?S1)PGmZHdFI&hW`ql@BjH(AnwVGXCM@=yZW#RBX2= zE=b1$?kp!;e0xS5sRPacQ9$IG)FpT%9PKboh$s+D8(WHOe)g0Ab^^P@@#LTIq@{tS z(wiY?n42N**u$3w23r>B`g2}9f9au40e#DkSGfDdV0x4szpdcPt^u? z4bJ|7o|F2^dCa6=e7m8`99ZSutE%%-BB=$kUm%6Wf-4u!SA3t z&)==md&sZxTNTK~XfJUHi-`u9SP|P`v(VP^Gew&|EV|O_#O+IMp626|X0pdH2HT9?GwLcj+T%SH8Po|IPDvJTp%w|Bn`H`{~DXI`9X^ntO=P zy8KssxMy&FF5%2vO;t_NMs*hEadNw{xV1VgF*dcc6vNRGt!VW+8mq=Xu|BWkeW z^h7?msK@K1Z0Ab&L&w@F{EbO&wFz;SG{U)@4HCJhT*&CKALea;cH`5uO`WtCxj5?+ zW*|Ac7x4iy`@{jj{pkCDuikt2`*_p4e;fJpvHvvoHQJxEY*9os-(9{qXTMUVEjEzS zu4E;N76rqMLcQgGW=|?RnxzT00_+641{|Cwx=xab^!XbRH5mn!-N_@J_)50N4luJa z<|}a)sgiR^pix^HJjq^D?tF1x?UM0Z7o<;H%)t1>GMs7OYuC8;vyuB^bWM|AUr?z= zYtck@ua1RSf+FY_%fXOhC5IfO=MX;|)vyiH7FpO8F6gMeoyxEv3))vf2=>G^L&6+O zlv8R{UQA>m)->hMY7d$ z5CEK`<*>`X^0qo?w${;BI;lr!ywi0#Da{qM!MN4-1*#!O_C6;wacZKZ*m#G)+MXQc z=2)UVLsXGKMP+z!Z(#CBdsYsU)%FzPz+?>q2Uui?mVnUke74mQt&ruB`?>k@wNVls zZe%jvk0S6Jd!HFw64immwqDB#j99lFxE@Xy>II})u zvnjD(ZROuq{-#kybferkb>0FR+o*hm(FU=X-@Oggm;Kr+!xJa!IdF zHmNILU-=~6p=VL5n0v{Q)W6k>JN`kFv7hJ2l?vrptDZ1 zo1jxznU^#crLxU^UYe15g^n8P46O_%3-6oTf@yM*nzw#X%;EQagP7EbzQkCkmIh)Q z`#Al16N(9;gUyK%sfR*DCtpCq!A-w~1;@zwZ20`6p7mR(?p~`=SLluY`vSDwn$B8= zjbjcX%idGs0IY5Kp@>bQhpaq)fi=B*eovRw5HF$91c&p%iM_0`RldqM5_@siJqisD zX1vKg5#&HjtdiO2jnw_kg5X5BWtS9`2rlRni1T}}+HjuX8fZCNt=pFzl3ox(cLt zY*KsxeRrHxEL5?rZS!4HWoyR6te%~2eM;wkgNge!Cek(})zV!?qDf~4tyY<2T;NvQ zS$yA@X*H;vCV&$aKQ+wM&V6XtE}F#PdL}SLhm{|ow11ZHI>iOr4*>IxiDS& z><7BEN4iwsWxJ;?#kF`n^V86{dg5|DH^Jr>IBQ?06yB^D2br4=)T{$1y0y;Qmn5Pt zn5^7h7syXo<{F|MRbecceaS=F=o$&zD#oRB9<7x_E2xk#^wa0H()wU|-w27hSLlXO zS0tKazEdmSL%BE#8eTAu_@Yhs6My#nG`<+&EH&MqY%=}?G^N+`Ae|+dvsNQ}tcQrt z9pEBjMI?u{>*;tc z)3>HK$ZP}uV#xpf$qX>iD=QXF>{@7*!)5`)A`j7HBDuf07traxOZc5tv*m>MclmrP z1C?7=aRFjaM~m-$^us#?7ri+U%*SfIlrd3go-`9c2W$)AD$3I}{h2LAbcAFFvENF=L`V50+LciGONhV2wF z?=zQ18q}?0G}-QWX8+Aq3(oEtIN8Ii>*H3dIEE4Jm2El9lS;YkscCJ$UoG=MiZyIM0pxW&sf}BwFLZ{E2%_A z|H$GV>3V>)>c?&U`&+Fgn+bASOCI4z%&6tJ0j61mjcB4`yQo%*un-lY_m*=YB#~W2 ziBQM8)4Y(sBJqeXWyDyN36fQP*))Xr5^XKnx|f?y?g~{eGc4smKK_6oqBNs*sm|mP zN3)BCgOtf1aY=fKzM2!&4gNHwYMG}&mov?!pZvr@)}7P2oy?eU-Kv3N#(Soszm-LCq-pl>wQ=0~a;dw>f?v&Zq0PdXz0H0}t?5d3UCV_0lgf z@&vu4D?H(8SaH&#Rbg3Je^*zE%UcA4qDU)KWov~NrN}~CCYHXFZ_A|&mzO*aAeJ0*eDjKw*nSU zlIh19`v(SFFLC%ykU}R#)jcheHYy8tVm}fKu71B3y->2Sw|0)Cm))Y-3%5_jJ^WN> zXv^CHid#96IaOA>Tbf7O4|`qKbbj9jKudKm)N0SXM9_&v zofV?+j1@U6P4MvCw{&;J#9l;Fq?Uciv1=+E}FCxYWbPk@gF@ z@@nk!c!zqPM#hDDj0wkW%{r~wDCqa0IM_Y?Sl2Vc66_6vF?$ZGU@qs-c!%HUAm`M&m>UXk`flBxT3aUpcIjYt>7aj)DB;3uYL6`}i)ySGB=uHO=(dxT}X0kdOw zFe~-|=6MaKU;vmX{o#T6R}-nG7p%8BH?pi1wxB9Brx(IJ+%BN59$|`mCOYC&$j0=- zp&FA=<@}!BwK_ZVm~O{MC^4{w2GXP zV);(3!nB}OCIK!?x{cb(zuwxY`I#d>YRYn*LpnBbfb41ihLK}DyfNWst7i1p7M**L zFWh&eoX#-AD(Lyn8)_0}tLB;)(%!$HFPyEK;;a=#85jwh7^nFwlm-b6V>m~(-AAau zF$oU-uBg}+U&P@n$UzJ$*zeB02|ra&nTqz-o+I@Z0}&sJGcb&DNX`c}!Sbl_-^1oV zPc1ILSe0nGUu=&=bYU}qxrSY#{w+7>e%Y_DcjnvUS1slwl6LMDW@~6M(~6%H_~smt zX92V7bb*jpyLkN0Kh^zf`tnom5 z1s&bj2)M{R*DhdzG1U>W(??>hRmXv=`87NP7uxG7V{;x)QR{3f}0v!Q~~!dSxw+_XBrLSDs*lOezcZ*b(^`^qj+E|X{;#bOr1E;Vuh_o(Q9+w z9m}QlLYO;8CliE7Ukc2n8)ax&Z961xm011Afwtz82zp6gR_F2dtbWVqP3G|C)qdVY zD#YZ+9m*nKo+&cFu^ej(3^X0foJ52j_PWPzBWvGh4{ z;~8%emZk6g)?1eDuU!B&stp%tQsdGktMzA)2;8aozGDT1TrkTfK@>95%SEg8t3pC` z1MUcW=R$pEs8o;U26dB$E^~LpJ~!8ZuM03aLdM!ZQmtJyaidk`hmuyUXXDCw1^|6JQM2Gx5(oz$j%^w3QsT#orqcJjL-|6 zM1iQ_`;NEe1dgVR2KD;uIw##L67ev59Z{KwP#5W&EMn>^p$YNnjp>MoSVr$z-gRZ7 z?c8n6_XNBT65G>tWu0Es>Qn8ncvT>`+wf6TMPDJ-a*_|?;i@Km!A)-cCuFG3(JeLW zvFm}+cUObpsiCHk++N$$zBxJaD7zH?;6 z(b2xXxV^sm0a z;Dx0~E^3};arz=9tjaxAA|gCedIc$9e{TJUi8yVH$rp%Fj=cO&;m*iU7fLO({KSyZ z_BDD5F>nFx-bHkpw~06X1igGd(Gz7ieBNz#V!VB)*KAwdJ=%+Pvw>VJ2v$Q;?a=(p z0i=?pxeIyl>h*ZtNrF}%DuVlRAiuT;kez)7q%73QhE_3RdPH(dK$jRBRbCuOl-j)> zq^1i8)J!HEb)gGJB%;P4+G;6#jQWEPh4Ij`N4?Cp=$i)Q*X-wLH$P`cwXJyKM6)W^ zm-h%A+24`H^|=P1SzPN>;;VQ~$)vE$j_45}rO| z;r8nCpw;$sL4?n}Vf;QmboZJ2i*#RCIMreMAS$jGF?wtFKc$Houk@z#-R7zpFKcY~ zvGH{aCCMUyn+DdtNAehEiNIh%6w+{*Cs3@t4vfCLsF97q#$X@jh4$Yh`g&$Ux#i>6 z=WB8&-~RB#pa`S)GReo)@p>HSG2&VE{CkOhA8Q;M-jrQCK@fMJ{EaT(&mQ9;Su+~D z6-;I}@W&fm$DHd8uF-Z$F0E!)GQ#>k55T#_#v$SdJuDKy}%j3&S9rw5Mn_8lYHAlpzI&AFC40T z*jRwqU~XIGO(01z6MERXadSstx-2()%syh5*+txHEE%kt$91Zka;ZGnd-|2KTJU$l z1;W~VT+GQCxUSVY1}lT6BkHFO12KN7B~v->q18 zE@yjr(yG8xtY42KLy_twL*9vGIee9|M??du)uFp(=7Y+y)z@Dsw?3gs)d6j6Cfh6_ znEb9k3QdRfu3vv@H~$=PEb9YpF`pM6|1h_t?4hnwHu(APKRi=3!mW z$%NsLSH81U>=Gi*qy9I?zmvW+kggETn0LD3qc_`i|9y(*9kjh27ykH{e#R*j;9-4$ zBAg!WaNu%=J~;3&`|^BLGoqE}d$&sh?{YU&{Sb}xB6TdvliE`YnH3t`u|5S!N{9iR*T=(7$|2cds6%YL%VLTZy&r$kiy69^NkAGP*8 zEnm?%!_Pk4E<*5Yf0L%q=9Cx8H~ieovD~0cY`IPtP(j@v)m4}P9c`_iV&w!(c@GjifJ(^5s~=e$@#?ZpNp5UNb(fIqPZ|fJFH1{-9U&h z@jFRkB@ZLX0l6fpi_aNm02U=j5OY*6MpV+X)ty+hm{pf_l|J8T|IGB(oxhXblKtT; z-|6y)f6aqwclg^pSMWq=h;PV;{mUDYZ=(GAC!qiO2cYPmdX@Rand;&fS`qy2yi4Qv z0e(_Z!Y$Wlq?1goKZltkb*GQ>!|vf89gsLvpE8ceV2FO9+gT zT<95`=n$*~q~}x5=chLBOJ>u9B-}TbkPlHa=VJOn5K}%d=Ahh%TWzaN#7dIU4K4ub zgV(_Ka2j_g&r+Vx^IXUCQ=ZFtDtK1&4B@$%XETp4^nrhQp?rTRV1kDfghGYEP-tjq zSg0U0JT&Z|>XeVj?2d=j=2tnRXRYg|W%Sq$_v#*-%MZh9)2aLT!mhbj7la?Srf-FV zW30;Gu-TGvhYF#+zMqaFxsH+k92mo=@P6{hzkxB0!b zPZ!TOiGPyc0=oG)exv+O=6QwpIsE##q(}1 zBH4$lQcw3{wcSCgxcbooolj(gxQh0tz29{iG9s?N>E%g0-n(`u*d?RSHE)o$o2Qlg z55jX=Ik{2L)ykbJ;nhJc(#S&NYSEp23mCiK|7W#c#E?ndw}Nq)Z?$r4%%|smQV&Yl z#-10dVj`Nx4T@?#0vJ*$W4~&(K1x#2k=!*;+8K1K9ao>3o5NSz<1CCMkJk`U%H|r< z!H3(BH4^@Dw1igcZGg1L(S!^Zx#*N0YV0rWbHt$=e5n4tY-YSvw_k01u&0n7ql--J z9aop8R+7Izr3)!>vZv27=rx_YQNmCq{UVE5BEgHP%-H zE@E5!;fr{_$+Mm3Zl3pfP9#pgeFMzQ&1+sTUnn79zJ>%1F}TV8B^2TD!_At1$3+%- zKzHs6el!yt9do(i)id3fqd|_2Ds6CIuJ@w0&2~fPz&drBr_L7dkv&HO?l_*4cxLd- z=J_nofAB2kN%FY(G5p;{g8BLQs4(=}KYYu);d`(dzG8ulKe*4o<(dg#mJLhLl7z6Y zs?^RBYuyBbz{G72X-r(s4-1M=p4GNL5xuqjYZbDH)`s1_x5LTPyj9Cm7&ScEYGWe` z?zEBj)bsu+{^XfPIXnygp{=d;qREXTSr^X2{!XtnFnBa;AWkb2pL%<^)pjE< zlrAfwj_U2Cpi;P_UTcDj`SIFeIHJ26+CQ~wu8(_%No^(10>AqvgzY^~??*g`%-R3c7j(?Cb z!}AEwA9*YgJ%i^kp0jy;?u5VFRIkJOMS#HnFrPH^rY~G}W|XI12;vGN-<*Wr%TU~K zybr!9)P}DXLtq!31aUQQ)5JA{pVX?Fy_5TZ%Dp{Q_SV+$%9O$ldS7 z@r}FJgGisQt@0>~y-x1}%Q?FHa|=DG>}ga=^H5z>PC}NbKTsp0^lEYQn0|<<`$|O0 z*BQq3*NvN-KOEM78dxxRY0-ZDx%e8>|K+v_&r(e9AJrR4@m1(0CDFi zXm?vL=Z|%V;}r4s?t$qm3FxIYT=qq1x_>S&xKoxqE%B&0b+=@)&W4j&g${g^> z?%)6Mi`~D^9P~YH(D$T4-v!I~&ho7&+}{$zYOO6T3iG>M!~F{Wjh?)a~cH(dxW7Kh+)3UhH(FY!6$VqllAp z-+H5_zT?dN$~TuT_dh%SO-=w^ApTMsRUUKyAwF3rV4)}TUUEdEdgWBjcATx;;k2y< zALTHey?}U^3~_7Lmde*T)_;0J-x<>0QY9V9X~vlS4E784>WPP`^XYO1K<}5C1f1QM zGy`z=NnW9+pvXME`Aet?sz#5Ug`$b^sZH8kB{43w=>cI%$xv_pGJf^2@8L*r(1horfJ8j{P?FX2i<}=QqCx8}ZeoknJqTbaF%C?4H;>uxjc})8EQJ2T7(vYV(^f$^&fxZ>^6#%a zZ?6A?)8u|gF>homum8mT2b_Me`G9I!3;`^uL{BiT z1KykNV#jLjkPvl^4nP{WT31R=@BCvv2Sy<5SW{kudJ7_BA?fT?vot`AK@vxcNz*#2 zt8tx($|LRaS&|O%Dn`U(62XBk{A@<2GMsQzDE=NI z9N#~`z9Oq8Zxb9+!&UQfL~|@(t|!C9xpKto1^A468}EwQP5D$B^VGO{tj_D7DY_l? zs*8kFw(`N`5p3E;>gv_=x_1JVJ6GNe%8TPFT_c$&3cJ}qQ?0%)+0XOi?I|Rr_7OD- zL6Y?4eTxQk(FdF&H04Y8{OA;cDBBZ-_GeDT<2+8gvtXVwLQKH19+wTytwTVgBmhow|w#lcCvSS|8G@E+r zz#g5_KBGUpoIKf$l2cVd2c|rBQ`7oDoB5n{ov7xLQMl}EhE;g`&u8plx}&CYH_I6bnd;?P=u0pa-{fTvbMah&26qYpLhE_ub2iE*Wl%J zF?nD?p6Ih(#KKVK!#Zf!`H1<<&RL?zp_9nef?Kr72_g zQb?jvJ)}8(2)2K!Fuq3hvs}Pr`|BRE7;?pGO1H53cVKMwsvH4?uF<1Km>Lqp5)R5P z(nAdk-5b1|OsQ^fUQKrC&6RYb)xMm+4a&bo!UD9gD$_#k)Ndc8>Z(BniI6iBGibOS zQ`I^hwX`-&A|rw4#5z)QX)m}n{>#*|Z5qBHU?0+e^Gbk`Y$C}(M^RIh!{3+nr+N#9 z27b$}u)c5B8dbxE1nwFyIzYiW*e+I#Q9@=EIL#ZWwMOJ+dJ2*%wk{FC{Ti0TJPpf% zX1%*_QviHUY*eT8XE}i^V!i%d&06)ue*{4^G)5;CP0JCM+?&`GCOkp-iJEY9nPOlE z)GA^Y5>wJ2^P)5#(t;XFW~VksiJe$0@N~WhOg`}nT_TKCbcE#%s?5kg(i%~`5L+rS zC5`Hae#q?t8K{-GpR?L7G3mJd1yKHOj+(s6eCrl-_5dJL8dYOIkZA&h8~}>?yK##O zsH08TM1MD-WvT8c*Oy%}#(RUY*~cAK+yd!2mzR8pwx%8^F%k>|-B3HlF7d$hv+Y|=P5Z907v>^!T%f~5X5>PPe=ou3 z|7!DzFre38*h6CCzYyNkTZ5|}h=t{E)Gis&|1UFq5ePf()-)-E#Oc}G*@F^~NA7=u zKGhJBMG^#Aqz*aBuX%qp18akVd|}ko4My9wtF&T9}hbrjh!x$f|L2Uf=0i9qY|8ep6DXUYW=+MPTUMfhlub<+B%EmE?i?UG)iK#((%khLs`n9a z!w5A@1eyv+pJ*D8b}+iMggKs6XNik^MS>U z>J~i#g`6FIhsV{XyXeBUTzzW1`urIYniXzleF6EG2dMTjPMegVy)h=fs8^S9?r@B$ zrx{+J%b#KPRlv%;iz3|F5f@ULqX{AqvkO^|HmCzMLCA6=W`ENw)?QBoypqq?B}cSp zuS}TY?XTt1{eYhH(oG+jPRW8~IxI=ws-1}1H+y*y23!(#F*l^uIGpPKI-( zos7KcEU)B+szvP|=CT)f*?;*n(~D`c$JF&8u@U@s&~H#e4e|^>Gq4c&Gco$(EIw*9 zu0^y9>jI=#w^xO0xVuyOuPP)Kw^o~2abi*roMNN1O+L#M5FE3xm;l{*G+D&GsvY6tZ)xt<`w8; zdv`Rk&}rLBIQ-{$=c|v%+mmbv{Ooag+nzXh(!Edfme?Qo6P-4BN5MLUL03gcP3Bgh z*nM7+_M!nzEpzt z#R3M+d2*<KC+POe z+rjcyCS*^OS`*6=Yy2F5KQ1>V|AaP+tW&S1^atLk11YbhULDdOyw(erL+MfOchihl zRJIq|b0|npMiQmIe7jI)h(0YMk90#s4%Le{9R?yd@EJF29ClEXOatMP+{SwuNEgTM za%vtlm4l5P6&`nw*cVD`<`ZYnmbW>)IsJNP?RTUp-@3CZK)&;}NTjE7Ss8M~b`vel zXXundzGbsXGW93{4L7t}-=~%$S(Q^Nw-a#%lDb~APKn(h>o-13!DA7w~wClOhaayk(mGCl1Qlnb>YZ$GGvTiI+Tw;HfO7(^8)$%jMUYM(5 zj&px@qjYAZBC9W3*9zq_LlliF1pV0G_VQ3niTdh~^=O%*UNreo&zLKRCbDjOP-mPX z_Y>e|ZZj#MjhPU5Ze2;DZ@7v6X<6g{0Q~=lfvzyaMcofq(ED9c{7gYiQ6#kpkCxb+ zo7$PIdZ+thGRD?E!bH&Mv=_kz+O{PQ&2B8_ts$O$!j<&TgezTaiH{qkKcC(q31bM7 z;QH>McfvC~t;jv)nX2?9N}N*zxDjA;ObX~`b5-=+6l1k@5Mms__Ady`g+=II(U1qEl{)q(P%PyPQF)hXg0B-f$I6UIBhlr#m z$0BHTsRW3HRAvc(?B@|>WmyfZJ8tv-i=dlnqnN37MQc4I4M0r7A!cK#hdL0 zapkSu^xA**;KXckj>2lA8qNit;0@l%+~Ll&Kzi+aU?N>WO=_jUclhI+w!+yYP%AH; zX|;WgkdFFT>b1bqy{>ffahV@ZZNaBrfRJUcrLylOj$EHVIWL(^W#3PXTR$~#a&=zP zPGxr`_E|qQe{ywxa$YLSt!(S3`X^WWxq!2ldy_>G$Nz%VmWk55WEB{Hc)W}8#Ig2h z4@bEMG$YYEyH~gGRC^@pGCxMTX^@3l|JF?Qr{d|I+ki&WlSd2OVx)~_c8Leqev$G$ z2^HrsdM z9%vA^eXF9rM94ewOnX1mK!a~H!UHzV$zWRVD)p6X&pOLQWM%8s%FU-mnFVgxy9lGm z6EYEsi`a&2MaSJSkjWbLaE(B{W=&~&)u1*p}^tS9)5)Tt^{68p2)CHYRX~RYC)q)(HD%z2>y*;nA^X0+p>d_Qlk53klcv{qG=DSi;#y2VQw7nnaKrQ^&c0q(uGC9LLq{4$Pxi6K>$-Amu# zIZ#*V+8i+SPgF=&GMOeaZ`TLos}jQ?kxPE3O)F8}lp>iTo4RxzS3Anw-o$&-cXFWq zAV3b08uY7mgp!UpR8k9RY#2?fhv~M7)U4&iJgC6Byo`5e!(3=r_?PVBXFJd03;HQV zIuur=&*RCR?>eAL0?g)y_^i}yPLr36Eo6ma;B5Gnyqg_De7tzuh+#8S1uyBA2XaYz zo57|2NA?m5l?jCEB&#qdIGFXDft1}SS>h@N3)YunF`JZ-YK;Aahl$=o&04!jm)VCw z?N*_kWf;vumhq`2-}7o_;HfkulkH@&66XGpdhnfXBqLda>Gv$)@QXT(#6%7s5>I)#82|3*FR3ow z2&(XQt_lrOh2P;iz`0se@-~*6dvV`e>u{mv$_Eoes=3JTHT)H<*&(f$5f&(Pxuh+J zBis>o9WZj#CY>8shm6g!f&Y}ex)IKmQc1aJBPC(|m>aAlJnsxO!n8!z(p*Qkc~#6B z+e#*~=>|8t4SwZjLUi@P35Ro8;5enUV+_bM>2vK-iNkbz>MGG=t?ZKFR?8b)c3R#^axA{U?7#Mq2HB?$+8*jlR9h&9wi2DH21Y9dsyo& zjFGjeCbI|^+i_@LFR|5?hKcI6@=2u4oItcNMYZuenuivt@9|>SdT=-(OxdVeH!Ur_);?p>=*m!ZkTrG_Q2_We?- zYbCtImynxTop#wYVoIH7E|TB`r)C}5jm@NSnkA*SSU@;Rl%#h06C)XJq50<4E9?UM zi|7)dVx=vnerO6!j0Czd9}jJ2Kjy!fTcx1hfSx0zQK3ePPaecXDPEHPrY+XB$aXVj zT)da-42;_jcLuCBvF^|Dn!iv7(>$kLlnpd@dUoSR-t_bekYuraqc^N&h7_)0Ukr@Q zWC0$Q#gVj1R}PCKJ_(2KKCu4>CQ$1zs_y!{j@Uo&z}nqp$n^0?<_Yb4&27rH2MO=i zO?ghDH~f{NsN>k}b)f=beLm}}n?(}vI9@Q_a;+rP5(dE`*q=wvM;0kS-n~!K9kM^QOHlSJM(Yk&&rG+IgnE0A@~Mb z;!Au+PwP+1J64X1L$uCynIJ=jMjnewE3Uq*rNScFdDJRaf~xj&J6H~GeM!e-!-8W4 zI^`pFCe3&;_N|X0s9_n*{a$hBvs_z<7Mk(!F80!Lv4Jzp>cr{Q#d+P&bH{f_b$-XG zyO^4z>HPF5fy&3MHtjQ0t^%8uaBk7t46h=Z>=@>@!A9EmWu^cLfiGgezk7IzlmN8x zkNJCnm(Ewi=uWxq!DJqzTH8QxWq&hs~-@k zbr6a3kf*uPuv&|5NYtEBA(y@H@Enp2!^wOL=rlscD7C`6O&X)tf_Xxb1>(JW7lkNf zQ3++rC)mu!!5-V{hiG391iI}~x)<7Hld7>%{Y5tNWVs`Bx;;isPpNh@f4@~|_2Q>u#RwA)j`BRv&ntKoQRT4Yz` z8mk@Q-k_0Xnx|%5uTd6PBWRaMU|cuEB}I9sG+3RbvO7|wuWqaSrM2c4AjbdT_+RP( zb1}U7IcPED^G#x9$r@MR=hZO54WjoI=d9Qj-%o#Q3ef~nY|r#6)r7}@QqpDC@(1FP znNpQHp`5b^lFnyz$GPpY>vCWU5LN~7 zR4>G4B)IEL+n`8|N4*0*ogG)NX*9V|KK-8DGeon${B_m?1NN7xbWO!J*=4SwcY+L` zq9_$_ko#a>#bSPC$=uwzm)6Y}k9IGI6|Gxxv@^rz$Lbq)OEfXmi<#5po2?==(7mTK zd7S-I4=I=;-Dt=~i{EO$>oi7$(Q8XZQH0;47c5gacQs4*JQ|GEBkisnh?>5;os>*s z*^TstPhHA*q?eFF_Gb3qq;U+tSv^F(!TbknjL2P|`9i|}?sUG>Jswvf0j9Fz*`ln8 z${&3LO*E!%|AwwlYG>4Hlab71RuoQNItf$uWD-h>l2*2OB9dtW#cebhD2_`ksA3cszdF)w0iEmMkIPl<_jlvih#FZB*{*)ral$x<(Kq~}b1l_T@nGjchkXpx+5 zIo;s@x%Bb)r_!^0+>hAuZZnu#9(Oy2&{HE%@ap`O2z?Bxv`wq1OUIN3;3N-cIL^GKl z&!S|gPhZJXM375&?;-fMJRp7jKTLXhQ%?POOh3J0jjFds&Js~>VWYc|zOrO7zUCvs z`oM}WyQD}REbL28&Cnl{>{%WXTs4;{R%|)_0}>kPVvPisgUw{*y+e_y2Vyr`B@xt4#T`BDzislu|2oHERAcKMf$G7pzH#Dhhs!V%mkF$ zS$^5R_UHRkYjwto%tF)^_7}Y1di6&$)5KIh6%~%mE#Bxs7JDgNc2uo>M+o&amB-X# z-6#>-HXIKzuraQu(FS#+h9U=iTn!=BOQTbVFATfXU(x$t21&eC6t&9 z+WXtMtxlWlz-<4`xZgNiyWb90JZyDtmdsY?oMZDUwn&XSVs2$#9y{*wft7hySLX2@ zZ7&J$@HLCgM`>abo$S!4%@y#T?stL}gNy8#n%(iFH16fGl)Ht}N@>&9VNX!u;&IPf zojny#u75^2*Y>Bz1&**fXGY4#{e0Ng_7Lwiks}E>B5zy|Zr{Sgwi0qgKEB_=?F35F zqa-PzCE;;3NB9YaKhBIC?S>u^aMSuFwA>3F;)Vt!^cV?+_ypvT)RuzOJLRxjsEFyQ zTnx{m4XPcUozfH8!S+*LZ)3n@#(*IqHS5c|tNXMJL3jJ?-*`#m>T6d*eKSjJ=#R3B zTvqYKzGk5OH%>bL#-JeuaW8sF0Oz9CnsY&!Gc47+Yw&f&!_t=oDtB3Hs)gbBIs(Ux z-xZ(D`t6c{I!#!*IbxMw`%Hl8Lu|yBc@jgD-~NVVim2PK(0!u~ZL^(X+7wgwYvDl# zd3qDQmF*M&>a}YmCDN4D_H9DVLf5|31DV|@Gq(CUN?LnmF0fOMoT~Svk6qPk5qFwM zgIq;~yvtFdRbCbZLAPq72UIPtX6OYm#gjOdOI+h67SGQvx6K(0Lr)QVg_qVANx@BS zl;Y}+0hx5-3v-F*4NNTjR;?S5_+LyrU1d^%?B23}A8(X}tnhSxWjW(hhf_0#V-;4O zbU9r70J}Y>YN)nX(iD2Smu>dU!DwR~&bnfm<++eQ)Y}p{KyQg8M#JkxfbG4-or|p2 zhv-CS71Zdr*4!oUBayf|&V+Z&*6IVeT(xm~n?A6k?tR?pa;fv0D@o~kJr1#2D6iPY zTB5A4(0ON*bh>PAollay(c`y}!)iN+584!!HicMJ=)BCKSlN^%z zp-H5)^gf*6#~5*2ZQrCWE`F@bMP@VGMy+XH1y9tsm{%m#FuyCKsjzDQ5VnKbR^r$pw`Qk}3teLd`@sk86#dXxAPWjoY~wg|@* zgi3ElL~dd6Th2mQFNqVgvY-+)w%yOJd`8Bxy=gZv2MHK1RTnUjO=bj>m;Dnj2@NaK zVul5V`cAetdl8IJm!Os#0HqAO%;WTxeT$bSmw6qeF(WTm|h*mfAnh<=7}KG&Q4mJu=kO>w!`(P}(+<-uSC2 zwV%vo>g~^@zDHuonUJF26}k}X+^6~SB_b8iaV7a}L!?Wz#_D;AZyT`IY@>#8)y-cA zSwbT0&~<@ux?NVHPKN|w56a(kiwKEc-tX|Po)BE23uH8f-f8SUY3J#dOU{f z)%CPS_ibDi@e22tzz`C-CG|kr|M0@*Upz1UyA;8Nlr-J-7GYi9B*!`-dlXF2dmPBECSMX7{=jN#@?67 z+1($=bdcJ9pK^2nP>W<(Xa~NT$;9E!9nmnxn}*c=LNLuGQhwLI6#yrqXvy7Xdq|_0h>Sqq4F{ql7IpcA#sQZF?j~CMNB#gWO#_B zE$z~+t+d)*y6aZ9wHRB4V35QX6<=zp+AVFVy=kyTr4S2s{@?F;o@X+d1SE>x{rrCf z<~;ZPo_p@O=brnH%iBK;-fVN#Z2{KkW0G;4=X>9cbWnVi3$7lxZs~I6qzPPk;&e@y zs~q^mFe>;D9xM7R@N9nsq(uu!ZrsRSPY8ZWg0p?s9RsRGjnmWNdhf%`P+VmP3Pue~ zz6f3ix+44x5l|xR$6&WfRSX;NL(|iwVzZTN$aIHmhSCp=c`n$TR>WzSG#?z3)le&W zt(Z0Ncignn_(M)pupWRHcQo>^H6Nrz$u@EZ&F2q`c@fP>E8V9ye}`y7aJcHZpW6Q| z7O|P8qOMBu(+ir^{dGqAB>8gRM;1SpbB zg*K!iFkuzVl_E(m!-d4g>1jSjkcr4tpE~kw3)4E8jk4arcHmNPquvHv2|x%|upFH% z?W$Qt#w^rypIPQ_SScagy$p8<;R@ADcFIuma;-~(=xPIlAl+o%2O`ef5~=aO3I4zo z3DhzHDC`#Vgd%=P{!J|P8rH8-H?F$!53yseL_J{za@F4n7ynlna5l!x>~HjZJ3i@+ z8@bwS%(OLbAqOby!4WB<(U`UK z*VI$aUECty%s+H58%01I)x1=GsM!{4+ulc3u${rC*&oL{_Ct5 z;awDr=HzgHFeZG9TWe&-7ip=1(gHAR`%gdlXzWiP1)QaRy{um^_nr;sAh8C>xprSR zb87Z4s@CeyVkqZMcom|-Ip!C5x@C@CyVJEh9=>f=3&*r291^$s=hw~xO;df1oBR+9 zhWJpAe#>NsKypcF(@J=#;YlLxq|m5yyr_y;hF=pqY|w(v{woJZ%M$+s2Fa^87$jFO ziQ5Kg6i(K@KmF_hkI? z{BhBNR&@n>&IrV<87cnw=s+{O0_`vY@oLi4?txORKpP&QCw}SO10+NOETJcU6S@cZ zy^tLUZkD_0}bzVOIrw$|fi{ zxIufJYZEDnYcriGc6T_nzG0*tJ6l?s2EetY$s=%>z~KU~5cnB^V+5uP94qj8f!t2r z(v%@^oIv(@Elr$rZ;^H0mZs@qo*~dD@HTzt`}41HU8qy^Y^`6zog*9fSEj{5tXb5I;NI2H@w$Z#aG__+5ox z8h+Q~Hvzv%_*LSUgWq)gX5n`$ehcthg5PrdD)3u_AM>zzt-m>ra3X<)=#dY zcMcltau2Z_hgt^jB_7K-Obo*TM_5kY-Tl3$KX_`Ka_d~Uv!lYe6Z^V>!=*c$lVVO6VM&#J2^jsoyrsShKYu0f-XCfxqJC! z3$A(p2Vw^IXb=`Q%~9)M{EmLL-Y_(_NZ)&kk6y&twEn>dn-DIpBPsZAG<+D`a|Wq$ zYaf()#I$v!sAs-_95>RPg9R_NC7*g6Zjf}k1aI8vhA6{r_mMjxNZi+a+e!! z4WyjA4H3|eQV^+iBVG81e)GC;r9*wzNG&8D&`&*b54?y^Kc*pU?N1`1uA@W&m-S}g zU1T zt4MtnzAOd0ZEU(fJyg3sc=}51I^>g#Wt0@?1M`tLm+w4N;mDmH*!UsN?u3^+=*2^@ z$qbetOMXZS>xI0@3ULZp%MZzJgzT+pD8QN_GK@02;`UW=Lhq7{AA7P1>Q2lO7pYg) z5G$Tt@!A42k$ze@1Kt^Osu^#FOV8~_7GBo;7L*o~)CiDc2DsJe+R?+UhO1W{HcDBf z?nA;RsX&Z=fiEC!Pw)@%+^6GBXaPIma;*~ebIBh)q{c%o?t~V0foT;(OVpzVX2`aF zEO^_`*+8o>--Q{$y*}kfetzB@VtUEV-q10>6kxfM+xb{_kvb+eyMYgIK<&8dA4Oq6 zG((v-H1nboz0yJ8H@MZQTs>MJT%$?`IzN<9t6ip-?js$yo_f-lEsRre?MxqQc z?)x@$uJ(FF!A)wI9R{~ay=v)*nWnQnT?Oi<`zl71sC)~Xz+mGh10#9|Z#i6Fk>gX} zK!C=&)cr_~)=jix_W>?CQ(rX9IN$73t0f(;jJi7t{r(8@xmH!2LRTEz&&2~t_vY^D z-Vl}U)lun=Fw&K+8SEO&_12|-KaH&!>_+~1TF|+Aw2OYx6o7#BqBBPe$MPS>MyZXf zbF{?ZbMXlsehO7-q(v$VDw;L9d6hq4d0@qc6G>>j`=QB!WpGc&*WkcGMk+?In6-fr z^fu1*2KPIWRfbKUii5o7Gp+WUVSE~lfxGr@b{jsFSFR!Uaq!{t27Jc3aYuX0KILf0 z8|P)SXjnAv%HY1MFmA!PLmOP^!}7FG37h5on^7k^~wZ6^Q9TxwzLNwV#u!?TyfkK-&~-Yhb^S zV!Y!PuC()Xo*@^zU{Ucr<&=X7ll4yjIx8h?kS>?na_g;ZqyMLxWm5qtrdI#0OW(x0 zCizpgPt7NbF5*PW7ym4Z33ZFoCB}sYdDsPY0uh7z3tAw$oW^8cGS-{5V|1mIf7RF= zP~j}>g=Qe=1Vo(d3qO&%6=+}%<^{~71ouxy%x}V%cZFb6-u0EJR9pZEm7>Xsa2S{) z>-)^Cqgz+s&CCT&hIe2)^)KzDn)G=s7FTa$?PJK7lee`-2S3P9PP$cHZs2?NDs5^Y zeO=H+t^K%lsdaFoKEEAbs_{@WpvFI)x)Wc6UMFj~wGIk9HC!GxJ)Tpd0Jqm{c0;;pb*OWRPz`ZWafDQZRwg^^f)8s~GNQODa}V|0=A{ zD?oid^&c2Z2KVQ6WaCr`(!d5XD;1%Lk&f4B5)pC@^0VdQVC`R|R`o4X&C(IJCSjCe z*5u>wM~cw*3jBx|#(dP5-#Z;HBrm7P1;0*Y9T`bsyJXgOs)Jhp(#C0VGDj4Cl4B&H zB7mE7PRRsb0u=p8GK$JL$x2BtHA152 ztKZ{@F9bZ8XW6MuM^RqxdI;RA&%gx(Jl*`j41{g1IS3ErVeX|h4jduQXM*cI-avmQ zx1B+Z&9a6!yzEh4-0FdQCrb4eA<{=w=mqvhC+QeU&Ts^vo=%l!#%_-De=Q)mSKqV? z=+TtOu9Jr7pHF=rv;Y^Jo8TeA13G4MzL#7w(9I-Yz*g35F#$e~rwb)!( zvu&)*N^QX>*g0mcQyUrVyjmL`>`d!$PSG%-qz#x77siKgnoIj^!CuTDg4f_@i^HD* zfE{W(E`q*QjL266v>Nr-({f%3Qrp9QPWn$LqRjQrW746OWWcz)mDJ39Cu_CcwQ)2! z09_6a2y?)ue>UMbrWoAJ3*TgZ5!G{Yx*Zbn1=xZc95z>73rzYP2fVHeuW_Sca)L60 zEi}dFda|GIR^AbUag(coYm&yhUvS5bjfHBC^iW`KR~@AV#gX)*nsY5&C0-lPsehuQzUk9Kz_{kN{;2e9rKF3M) zfg^HfYD_Yn$nj0>)F6tSlApcWUVSC<^iY3m|9}%R7+xF4R-iPX$3<#5XA@bxbDq7= ziB!e~Fp!^wKP&CJqdQ9uvRG2yS1&!w`^V4o@%dp zw?`q+9-VTfv?qWY#MulNw{SxgdXZqHaV7>o92#)&adHge6QPbQZlTKJ&U{54avzAp zT*FzkSK#9_9YHRYmzF;|cCE4YHMKNg`=F5=CC&jTA_fg$tT|2Q}gcg(8XlG-$Nsl^apHWjs;(d5Cys{iM1(h6i6^cXu z8_%b!>_A3H+^b+T35=rI{cQ4*9G)5f<1%TeR)x@Cj~Y1>9|tz@$5&m0{rR|I$+g>! z$7Vu9^nS8II6UFrO!X)DPPMpKSWSwDgizV5xB#R}5md&~L1_tvQmPA-Kl8cuZ zX@3+syWvU;%ZCR(Q9v%@>$|vZh%1jlAWDG&EWd~_ko@abXCJtKHM4GX<{G)j2`a?P zz8Pk;6`#sZMKUN;5c2*NZ4g*JQ7>@w*`Uw>&;b|wnT|dO9A5!rfG^=V1R?wDIXDWb zA0Ss)-*a+DkK!DpYT|yXGC2{0M~<&IyC)3^TvmsxLpJ;3Ce4cr3=THO2lvI-y%IQz zi}4fj)^!_O1b5&&N?UFHQ0|te4sPyaeB%|=rw&WJ^UTv2+duVIU*bgY)CA9DDd&0S z7m2$aeM(DliK<+VszOUZRfYP21_MjfXIHRw!@8tY*c=qu3hwH?ZSmrl zca8Vhr$Z%SLrMcuLm?o@HyFA-iBOP{Ey0^pw02f>S}=Tx>&qdeP(n4v?Nh&%$zyC8 z@VJ6?aEGhoK;C4B&8He5xY%2PEd$rk9W#wlPL~)?H$e|ELur}%&6&@mZ*($)6Ye@Y)TRn6noQ zag!OMnAA@8se9KOO52BNuHZm06`ykQ9LSsCu~m%mg@@H;;CYtgL2Mg787RvP@9Bi1 zr-RYZQ=vkQ{q38FOmds;b6(seAKT|XygeV=KDEnd1P^$F;h|M~tmzaY^nH{wxPL;6 zUhLM_I65XC=x3W=bF)o*lZX&W6DS}aE{0tOq?lv=B^R;gLzjDk|;?u4@TsGcnq zet9FV@-y_IEZ>=cJu5>C30e+R|2rTTuC@J{J)EE?lr9O)51P!7z*&|{OpMfw|G99L z-iKz@UcIDiu!MN+D`M=0G4`3=?Ktbs&QVpCp&dZS(GQnoo>W&L5bLpd!_|-*!(qdi z;K!wO!-(Q}-J8EP^jx zd9BuMg)e3ATYrWA`830>OAJ@uOXeMht=VlG`bQAI6)RFz++u-yZHN9rlmvOduFpzZ zRQ-W@?0PMG?BF_Qd?2y?Z`4OI?oy7G_XD1D7w zJ|o&2X57@jFA|FD$7?@i!1Z4&R26q3vBQ{oPPlzZONpAtw0WQSKt9$o6E;+01^V@7 zhEGz{;L?$(ZelRBQ#+c#NQ54Nd)|t1moO4D>bD=~8kV#as)?xiV%516Otaq&fSU?GQi|PZd3z2e$;t@6Bwt$2(%E=*EiQ2JH>L>fSs}bG1&7e6> zC#PV}1>$HEym48|3*iz~CqjsGaHv+ggQ<0eJa|EdiC2Mz*VPtY8r!&+n5cJ|`7I$oti7RP>@R&7VI-$y<^&zV2|CzRyHRfAvEiiB#_936dZOF3``RVQ*tv66xVn|BCjG8T-as zb~(PrT6QQ{82B05EmVczp8W|39~gny!3M@~!&KYAbh!KW$sNV3syE_(4BycJKo&u-ur>SS(X* zg=%*axr?=V3z)&!yp&u2PGE}Z|BZSDNvIl3|;tVWkjE8{Y*MSBnQ+ct3`j~cOedF<8L;s`j zn+6fa$$uO}2?zQOY)0E}!IljONPV?k&tIBtjT4B$^fX!9+3{3v*k$}9+tepo<__E*#YU5D6(?^(`<*MVs zkKh9-I2Z)4OX!c65Y$MQ8Gt+2x~Ju4rkkh_oXSD(lwi~5G$o+Hm1iH;JWUCShG~HR zKM4dX!?nYxiGVATMjWw8^0y(IjyuC^oa!qtp^+-;RPW%l)eDjAE0KN2 z=k=C`MXAGN&w!kP#Z$5>^;Q<#4pZGcG3~?LoqrG{SBct&CU58-Y5reF(u(G}qdvy* zEV&(%%ffYBN!nEjMv~SCcX9ogt>*tuw8EmyH+csWp1Ab7Hhz`$h{o!A(v{gPjjB8g zyW$5%+EeDqV*fypP#XIYP{WjJt|ybQt^rrCs(w}K8a2HFbu|v1l1Ili!RE=!6zk;W zB}Nl;1~<6-X#=GpCW`Ev2C0hnn!CmJ$d`3l>dKGi*%jZWy`s;fn07~^eP1wP>ZLOnO7 zI6E)Z8Ms3K(L?aXXo532?ofs?;K3B-4(6zTbsIkP!LZvMaz}i()3?>uhR&-AQox2u zY9!ZcQ*@A$8TLQZE@h1J7yCyLuNQAq{{atVzC!8j!DdK%*8J4uHFxozk5ti$z+VH; z&R3F$biwi2FI2q`Y2psHup>;33;a76L4TI# zT;MttS-Ua(`d#R=!B%_68@*ur(N5HN(487@-%=1cenIxOgT2?VUvuhnBfLG_;_a^P z#jR;>EWD|&%dMAK84U*#Wx0w;J@fO^c)sZES?J1k&q-{6aK+b-@8wVeQ|5)&I4H8v zsPOLQ@1<3xK0-Z35|12p3pQJ)x=JWWvv*x6@^7cWy+lhsG9yY;aw}F1QOBPT> zQfwvKV*MM^-ApyRn{w2v8_x+%t~oOzkhJ$QG>eV_HD{6oWA=_@6ZsM6_fhXBvG4h- zkHXCN3f3h{*J00o5m&Fj80cSmyIBqyRTJ$P8hjF~abLzuhYbC30@sqi#v));w?5UE z`3^Kltg%7sGFvlv4r_2Y#|?d`8gC{9y!vHLca@iy>%SQD^I*H@RQtZaC+L6Q_t#Mg ze+QE$cl76ypuMIs7{fk47Wq>U?pX3J71YXB6;+r$G2#om0G}rxCWuaj-iF)Idr9+pc8P!u#AClFDEv1 zpt;V1dP=nbSHLteef=J{WLyhX2pA#zQ@Z>c%^Som z8ujlKl4V_a&*=)cW#GYe{O(WzVKFdHVBj7GBjGv*Gl48E)#s}FI*5vRIqJ6OPlxfO z2RDDURJm@w*v*bWWi2mJpo5SZxzSqzyMxjpN^22VtCPA7<|!-cOkwy)69IsG>rf8bk-&~AmRe1kf!dI*d8=^ zci{|GW(3BK^RIV!m>REA3BLW?jwHxtB$|Qu9*ukpR4v8?hWJhlzL?V?4{|?_;8IT* zrUutRS9R3BSOfe!7J`L}3JnX8`bU9<)I?zPH`p+Tgp_@1jHGJe^GhQf@HyNunE1>= z2DNWL0QQN_##MhM+}Q>$#TV&JRNtH}Ik3yWie3J2qsvd)n?rOwwJ-8WTSv)W@={0Q zUPKebv6#)py%ad>HC{kc9K^Z8TJPT-m)(lpGP&9FQ+*g8_A?SXb%4onOM$EIKh30= zP*W*K8ftU826(o0Qu=mD0bEVm`sVS4>dO@xa$867AkK}V@HQI zIviI6G0VQfI3u0o2n?DsrWp^x46NA@KSCSIez;{yI$ch{B{}dHs0FfO;i7oere1JWWE9sdFAHvxW-j+U>FbhVA7QV$L8sHWhhQ_VUtLF_OGgrmEx*Vr0nm9 z_JC`eFME;6IN{n?WvCZ&82aj8+t4NE@n&Ms0M}k=H|Y&KDbK(17DxfL`WiiS7$$lC z#ku*4Nh$Hh+b<^}g!^$t4=N{mPO7-c;CDx3e%xX{`ikdNq071F0i@0=@hK%Oh9sCr z^(h#R!>0C=S{5jAQX92-F?$g2#7jYg+_*{kahgMD@OsrT^dH{r*YN-d778giwSF@Y zdBgWg7n_SXxWjz0fk-cP?I@3+QKPyw;KC-5pR5?P#cih zoc&>`Ya18>`V*!U3?&gh!wePC&=3bK6DD#`eD&=Qj2wZ)#-~JS* zaddN(mbVWp`Q1`!@}^*r)m0`C3tE2M`YVH-m#<9$hK@#O4j8DvZf~5wDUsVy?2WTv zILkm0G4R%AW^>lo1qh^JcZD-|3MYN4-T^fmbK|1&Vy=R3#cCNHhj-6HC!@ahIW8(q z7gfpK9ovHk(cT?=K@HiM+szw}vgzmH?KX$yas)0NtGif1&xsnUYBP*s>J7#)^-9)) zUR!{iQMOPXzUXeox5hU$-~yEbN5{2t0uQf;B8#Wc<>0>RXW`Z15(`~hZOw2vxi3yj z^CzIF#!x@c&uil`)L)45AQ;w`J)9e3E0o6ea(k~khPvwFd`wbEFt7fV9Af^8=E49P zIO(CuERh4_=O=)iF{Z{`Fa2tN#{v4OUypn~xGw=g&Xo_+cLYC3TIcL5WPUQwe z$qY94@5IbsgOpZC<7@K&>sDsw);4Tua&tpnj}2}d5J3em(bsDF;~W^(9^gPlok%h@ zk^pbNZ^?YV6`BR=embbikHh%Lx=8DE308Zc} zVgd)Ro!h@dZ3Lz8tz zm*6H~SKW8u%)`?4UuVJdHGeuNCr#qzj_@vyZPb5f!{vH7H`+&v4|d~BMqs|^jP3lg z^Ncsn83Q4XQn#<9viGKzRU(%!##h}S7cWL`UBsgep?-}sKE!oTU{nuP(;CJu4|)9g z*&S8SLyTs3EV&(WcX11jzW{dUoAb39^2$8)QLKtvPUBfT;|K^Y=A78iV28nlCthnoe7W0?o5o#28K>$JwT#ZKcSD*SjXb4N@E4ZsZt5)PM zPI@_~)_x!Y_?T!Rjkm>NS|d@+6b58}&jFjQVL=>}nJLA}Kdp=Np`jG3#fAgs{R7Se zNyhv!*Z3Rlx1Y4vvr|aGZu$?K8?fj1y!$DuV21v3Lo?blW%adKlN-+~`td zBeJ$6B-?AH)?(VJ!7t%wFdvBMPXG0g$09CX_aUV$9!``%GD!SAAjqbE-0pp5DZ%Q_W=G?F9X^bC?)`o>~bgvnxB|{Rt z1ug$g?RD3abL{0?%d=##%*Thm2?~Wf8tM5N$Mh%Sf&#~x< zqq1|s+R$IVc@t)bu$+Y2_u%>FVs(#nuGr~=HF=ZDO+sSL*Z~b^f031re;pf$nbaI6 zbwgBAS4Aat-aPba1~lfIA4YX?0O_WB@MHFL{^Qmfj=str-p%6H{*h{wIyymGed|Uc z0o+?RQUTy!@Qaus8m{ko2xbUZCr4KLgF9gBNZ0q6Q*5Ryr`bAq;V@{7vF52JFbvK* zlVRFU1&^|`wdHV5H6?H<(iz5a>{jV1cd~E9EUTwuBpuuJUtvDRqc_l5mp+uS=9Ls- z|5_m?EYsA8KXH`9<2h6O{m~6$n%?Y&<8DM8EK>?n#`K1R`z}&Akl_IZF9xuO*IGf*_NL>a!8_&ZP%y(M_$L$fS5qGC8t z>;yR++&)kWnOy{B0(1GrXd$?E?$C58d&CL_q44gWLYViz`absA54P_vaHrF2q)lpCg?`FlTmhr+MAz_1;JA_K1 z@9cmV4-lfQ42ncR0&1HP9IeanO^o>NCdVkvN{+Tja%3MP!Y83_&$#kDn)))hvFrRT zGe#G*10S;sqH&(zJ+Z6nNrsC}O+|Z$)IirWdcc2 z6DMTZlF%lc;5 zVeD|wrETw1!-GfSu!(ll6O_fAVBwy0^WTL5i{k`eim=tJli&Da3Ftke%z$#ae*my&j-d&j;p$H^5tvC;eCdp zMte?pLOsX#`1tVgC!(7G^(QJXC@poVC1J5WUCW%t&>)Ba7JZYe zbYz+its8S8i$MaOP4(bPx!G7N%#XtztpnR|(`(g;;0Kql9a_4$(LPhROTJ4apfMN3 zDCbd!7cz(`|IwL>KI#en0vq8n!x+benz-Fo40q5Fbv63uQSp&$si(jKt(*^}kB4z! z3#BpDRxF#;vn#bY(HMC zex1RMKQ90l1Fdv*Kb0kL2-uE$dj^0{jU8UYB_UvM3k=j}K<(B>VxQ3nBh~3FMz&Fm zFX2J>u;FaF)Hjnv(8{@vH<->a3BgP4pqR`UakENq8f88cTU+P*08aZ)L6D=yBEk6&9G1U3J{ArANlvcuigG zT9$O;uDb6M;YKEYD%VZjLmP!e!dh*z`ZmrW`&1aD^r`oSpicb|R>^)IHX`5%>3@^s zFwK~$huCGC>pgl_R;ed2Ao%yNc3D`!~Wo;t;j`l5BsLa6(4|02E>iKk$lb;^t6{Du z*V@tXVyo5oZdert^Lvv##*Owv;epCDBMOFxM}zL z{Z=Z*fnn7A5^i`n9fkiQIQT1jgu4mOW;445M`J^c&IXDIc^4K2gZjo!eVkyU6ru0{ zvx^!4S@-FwN*7Wr{;#D45#*@Jifr=7vI4rR&!D@y2Hn-X9^DmsDr%`7RrTM}Tb*T= zx~n)%E5RY^@yEOLo4iy%GOYw}Xb_J)jJ%$z!FpIy^*R}4^QyLVy>DnHZ}yKwkQ%&N3}1|jeWD0Z=g+j$=ZGV&l)vc7d4 znhIue$6%X!abvFAHxDJ69DYSKc2~nM!9T9Lp92Ov;{#tn@8a#y8n>n)(leZnJE&!kEO#8+COJ?kqg*JZ=8Sp5ZUj^#iq3HuI*Bi(LRRyQl3w3L;C2diqRc;)fixgJY-a` zq>Ieo{vm6BWs6$Mz(C|Vc6F)hR#>0Hl`~-+Tz8|hNcgoV>V>L5k%q{^JEpF>EaXmH zy~q&PkQb|If|<~W+i2mOP6BxnT0xa`18v~*K!*Aji0r@A8Y-5k)@uaWSp5DW-S|o_ z17yS@A+-$gkRz`!OGSWg7%bGl3F49W(aKYe&zs@9+V1}gCYf)RIoei?12Lw!8T~${7$%Zp_;Wq@7~rXm zGC`07dp*aT#;kJ1fMQi4RFmczga>%QZ5-_mK2-y|O{>)Bt;gPSywNRbvXUC7Ch#Hh z1%S(4T(s(RE$9?N3vFE%8iT?^&gKA zlT-|R2l(xvNBidhkXv%0YD$H4kwlu1$mqyjpGkq68W$vDo3<`GFM5U{(U<<<+Q^Os zeT{i{6VJ9@++o{wfw)Bqnc>$3V+Z@E=mH%E?d43!GBwx4rMSmoAhxrw) zMD9C21Q*VjE!WK}hqW<2l_PYt>pwgLx*C`NLT|}v{2>JmcSufD;~v7%y>jJ7Nb9oV zz)SvRkvhrsvkp-wtGrSt?W^pljL2=i4anA~4qs_7sW_tu8I2pg$N{Da)|JEG{#RB$ zUVIK78Co)VsH<)hV$ycyxtYXnLG-iNvhYtNbQ4AKy?eyh+H&WzY4m5|6U~2J|3pVA97&B@MjR7x$M=DQ2Rl+ zo@~i+)fK}K-p!pgY7Fw!6~d;BL>`SBSxJaN@!;8ef~!}!Z5`gJE0L5BlkRMg;a#sG zm`Vg%U|j^wf!1)fpRdvgulqUTvxs@65vrY3f)+WzzZIVC@39a+g_o}2=#{t9jdl{L z1$Bi{3x7gTv|f)Ihj!pob5VUb4G2h@gAu*q$_&+sazLFT+GxL+B1Q{;TylnnrcFis z9Q+E3)RKtfSQd@im=9rRN1VAsqJXNgS6w5H_V#a~wEjn|(%}&edg2s*O5!9?=C_SuPj~etXB42|TNO~fgcjLy%hyc<`?e29ORqfr%Dg(Vcu0sH% zg8<$p!_B=n1A!Vho`ExiFz%H=4RsorS*-pOYzJqqj9{%sugO62uuo72wv#rb!=)%K z#;7^?%!khRsxT@99%|(`NK}qBQB|!ClVJkGc*F^h%SetswGivwNT)VTw(Rm`F??#W z3l5yjx}2>mqNq{1NeR-<;a7%U;f168)YpW4y;1a!3Lnu!y239zSNMo} z(-l6mM|k6X>zAOlcIkh!z!P_vZ(Ns9V5O*?-!Mb~4wHq|qRYTQ$IxW19@P+2(FJTYyuouZ-Ovy7mGocsd<5)H# zLXj#~_rp(;+i(NZLMC2t{pm|ZPC&Dwym7Pn;33OXmaA(nRwPT*uYexr58z52mMqTm zW90CE6Xo0&Mcz-$i!%Oz97C%iIv%5=qY3y{Nh@W0ohyV-?y1#tz2Bi`A|R)pe~M)x z#s%W3R0Uy94aG4`s&X227n6i}{s$@&pLKCUuTXzr$<1qI66JIbR@#w-SKW@}k#xGQ zP%|0zd}K9k?;%J|9Of|l<_uf|mA?;lj^nuXZx-V^1ND8OFQ(945B>{^3B2O`Nl>OD zkHTz_091Itz-)j=LbP{j#QS!5yYb8LCq@UjITBzJHb~{4E-CWkQpm3KuZZ|xCQOGE zCKRj7#1);-20VIW?%>Cjv?wA(WbjlREtMU%Q`}w3HO7`r)h;y%V&V<>&Kz>=g0BY};4NCh4ks6s{HV7>ezJ z0lsNI^_cV}AfKy_H}u2NTY>Ay5~PW+vg=keQh#_%W`cRf*gj6{k9^7g0XMA`5{2ve~$mM+3gH)J{Vi|Og<-g%>7Nn#* zckYPz&IW3EB6R%yqWN<}B*d7;y41%|N(S;4tF_`m79Cm)x#<(D!J8e|70axs$~GLa zgx1Iihqy(E+Q1Nu48gL$7 zGhX@z^U8^XQ0>!jM(NFEU7>?HoJbXQE(HqDX#X*UGKK@2X?hC8!Psi(C9GwLEot+( zlmapiHyl%0H7t%L#!bl7u@Um)$pzy+^M|4MTJ0Y^flFdgxCNLAt@$#Q@%M*H257}@ zAaO@#IBR;!Gt>ZoO8wB4_veJa)Hj=hI&G-_ofLM5&09`~n>d!~aO>YWgK+ANM!0a4 z34xYy0O}=mY%1ZG`JaH$<}EF|SiEA@AK6kdM3dx{M6ntzH)5wlha3S`bR%XmI_Y<@ zwFr8)Fdm#d)CR|aZ0Hjffgr~9@sKYYM6WNn5Q5XVUu`uSau>ZaNUh00z>aIaRh~gC z4D`&a>v&Pw8EN?wTEe^ELYIc1yb)YI0*M&fXu7!RQjN&r-3JlIc#+-+uQH$l-~vT? z&RzxquCMRY_o0{*xF_OaGx3kZ{?gxL?g{&Pm$cw6^W;X%AniT`mQtr(#Nss?`vKAL z?!)2==>)83JTAr~H2zVHM`?URjEcsW#CVLx{bD>$<5MtVR{~wHe)OwC}-#W_&Jz zxm9Y<_@YBPE7&2qmA$9G8Go+$AJu!${}%W=Q-R-n(ViO7pHS|qvM4^qOk-mw|C?sUjH?bjwHj*$9EJPT8 zts5^aQS?o0K%tE!jlPLZD72Bp(KoU2ve)vdo1_}?<`|Knw)ZL!(Kj8A1Q=!oAZ`rs zBMHE!ZlrKRGy4J1%ahyyr_1$Clq)b@;ZvoSCz%G4ZD7R%(kLnt@b<+f${J$&-@w!# zBwz>QQ-2&NJ$Gm$*$M&bx6-f93V@kIF3Lg+at>fXk6*XE!n+woaUY1;*j5aQG`1yT zl*U#lMrmvXVq~$^6fsI;8!tv;t*#X#OQ%v`L}Qavc)IM{2?=vcOFPRQYTYIL|1BGI z1e}jFSPmBe*RuWS(xr5lyB5|)c!LAG!jnnQ6`p*Lx{svK)^M)yMy+>+C!3rlJX9q^ z=3?`*{vZqDtAAcgou`gq$O0vg8nnp>cR*q3YU3RPRSSX`?G4H#)n~9Q5@G4gM7|ZB z2;JrWsV?z=L^enw^fMCSv^f$XlbMMWM<*i8_xfOBLL>i>NR}i*2O|*--k1nk&P-%T zbRxovUy(#;G!r?2@`X0i0f_|nkQQ9vO)=yS&W`ONmNxCu;2z0Za|icGbj>)$g+<=B z@CBF97UvjWE;4%5B48@}_jvS(yK8aXbhz4~#?u`Ej7kYt+m#nC;oZctQE&~3WLEz` z*`bEQx%L2|u^6u2CQ15{9EghqOE{G@kw5htcm?;T@z8GYNPOv%g4=s%sP5<Nfl?@B;X4i{s4`JLvx%Fdsw{g>a}d)=4Q-^n%X~#n zssg+GpYxRoG-(b&?h|EbLW?ZN!)>CR>{({I#*pP>TaEGY+|Ari%XW(^2}`)J#)(#I zNFzddg`kY)>#F-L2o~*!kp_yPZjca>I}V>hC|&w-#^HjtQ5mQUbMqlCWr1sn(L)&A zqmF}+<^czdvw0ZYQ2G~HL?kYz_;{H?4|8JWO>J(WvayS5PWoo>_elxQ`sYDH?dwc1 zx-Sfb)71e;QYg1DQzBe}z1(l0uaf&j_@V=zmn)Z1Y_fiw*O!C~RT?rVQda@8zQfv8 z`b&-T;x@Bq8<*HT%N!2_k7)j-AlZv1$!dOwDgs4IY^G+pAv*MCh3oRy=U|9@i?8DM# zm#8i1)w^guCWhu|>Q-od2F)qTd0k*RVhGJSXNM`O_b|tRD#WF)>M2wQZmAXp0vCjk zc%S@`p7cdld8ES-oMlok#MwB@PnewhN2P7wx7whNdK9blklyIE78@becEcrG6vp+J z>7urhqay4rDLiluM7?uKt8E4{!7*qnAHm^mDiCd?@69SJ5JSI>HJSy;rz_$b*7WkULLjn&9Y!kR&V6(utCNTXP$!nd!9D$Ps zP7s(OFx@cU$na;z5!%KR+66iUIt97~dITm5OcCf6m?|($V7kBzffEEy6gXL6j=(&D z1p;RY^a-3VaDl)@0`CyGT%cdzN`aLEHG%5{t`}G%uufouz%2r|3fv}eyTFG8?hyE> zz?}jg6Szy@69StAJ}t0W;C_K^0uKs2B=9wXhXuYR@QA>p0+qmH0*?zkA+S^68G*J; zp}#rK##y=fhhvL0#gO12}~E5A#j4gi2^4J%n_I;ut4A}fj)ur1uhV{NZ=g; zmkaa@Tq&?ppeAsg!1V%a1l9>`5V%F)R)O0DZWs8Fz#Re~6}VI2V*+;xd_rK8z^4T^ z3*0ZTP2fR+hXlSR@UXzQ1RfE1RG<=gOyF^WCj@p1JR{I1ZO1OqAByfkoM+NQ__?W<50-q4rB=Bj0%>wreY!i4;;30vp2|O&Y zPGrjwF&`DE1RfK3T;K_TodVAYw23UT3v>u{3Umwf2uv23BG4-^RbZOHbb;$7_X%R2 zC~&gC9D#WP3k1#*=o2_!-~xe*1l}QVxj?_bl>#dTY68~@TraRjV4c7Qfm;M_6}U~{ zc7YEG+#&E$fjb30CUBR)Cj>SLd|F_$!2JT-1RfN4NZ@M%4-0%t;1PjG1uB8Z1RfW7 zLSU!BGXiZliTn}h5a<->7U&U}EHFi&S755ZG=b>?GXzc$I8oqafjI*61QrOKCD12u zzQ6?n7YV#W;BtX}fhz@83e*Iy6S!VrjlepA4Fb0a+$wOJ!0iGb61YR)qXKsdd`#dj zflml*68N;hW`X+!wh25a@Q}dQ1RfUnmcSzdj|x-*j|n_3@PxolfoBBTqzAVPbO>|` zbPMzdOct0T&?_)iV4A>mff)iP2%IQzvcMdHc>)Ur&JySoIA7obfr|v*A#k}szrd9O zD+Ou-*9lxNuts2=zy^U^1a1|$P2hHc4+-2M@KJ#~1wJNlm%t|kHVJ$hkXj&b_Og#@ z!*y4Ou5Q!!kGA1-M0VSIRRi^X3%BXEkUjOima#U>Mbz6m{uHG)W)IqSbwBref%x}Y z-fO?)fymo7xC#bqaRZwJ$rw_4V8)|@r{2{MQ(49L)s9@f4cjvKOe5D0oiDe){N~Gl ze);gg=L08By{{iXwH*8K+Ti0k^>)I`RfBO2p?j^PDv1{fuZf$3>kAJox&2x9IbIYg z(vJm4JFdYBcJNqQVdk6D`d|JKP^}oCHehO!W5s(gjtG_=ht?b%L@&HWR$LOgoN*fO zKV0bgp8o#rp`_4SduXmBRN~b059_m!hVnaW-(9h)Y^I)n~&lA6O{lAId)y%0IS#d_~d%T=gROHZDFKN(fckL$^3W zg+TeOAK=`sEtG#;&p)H}555#{Bv-oR2Y95wrrl$d+}@hVQX`}d?ly;3#E)B>lli)4kJ1SzP6M3$GwlxRT~;?^BV3r z0%8+49PHHp_;GLCiDJ6*GNS&mC^Re?k4=RGj_@!K4F3LhTXT3=3XFJ%%8O4lHi%Js zEET1w7@=;%d@lxDi52k+U%2j(4UbSZfN(X zVZvQ~Z4EYLec~!1sU7P2dryajoI*#g^@EN>DKhxh-)zS}n~q08$G%YyNaE3E5YQmb zn!v{=j?jR+96*D?n9KZMqQQ}mq(Sh0r)|xE;Qemg;T0@%+F&2N1|r5;5Xy)AaOONh z4l}vQqEE2wjI9HK&g4J@;gg;3tR9B1KKqPbTn_>}C?*g;z0 z6;w7YlZTGH1VadL0Z2|qhI(!-PAMd+$MM10(2h~z00n?bN26HS;buv3;0-=_=MNpg z!o|-zd+kLk-2TJc(M0Y8?l^__GqjY2n2^I|ENjTudZaLgVbCdp}ngM!+Uk@j~2CP9y zH6O^eY+n4QaNrN>v2}=XL8ccgoc>Ny^=hR4U1o*-FxX?#F}L6m+SEhHsUiPp7eV8N zpl_@Ibrzu}f}@4XRv|~CkdX4I-qDpnabf23bOkQ>vH-v> z`J2FP6Qb((J8^2=l{JM}J-|wT4Ot0VVcY>64CCTdeX$!`*cZDCONhV+@Yj!r0!O(h z{T)~g=Q%tWZaH%z&~W}Qwg@`&>eQ>S(dLRmA5-}{+zX3o8it65>0!jev~XfDoDe85 zqIaTQo2hCy8cz2~{vE0M>|=V|yl{s9&406l@$uiuC{_6NCEc4E;w)~z0R=gD5Jt$IxIm)%9;&em z=?dc-*64T$Dl0O2TV}o^_`6ZBwwYbHAq{O-|M_v(e-B2O zX^}2W!576vIWH za3Ccdz`aM9_g=U#Qe{F4WNkYUg*NQ~mz;zrUC94F^Pl+pajc;_5!=YZZyA6}1=5CucX~1jaP=YlX zEJ(H79a#L`$@tVZ(ITuk>nVd3@uVWWZ$^9J3Y&Y(K3t1T)s)?lc5QH7s%`z1rV!Z` z*D*@ZKc-_ZV(mmE+w9tgZHN>#W`Oa{DiN7SD(URFl2JyXWXQu+!+PtV+58mwd{bAI zAWY2^Rwm9`)Ifa+fSDYsdMPD`Lj_Uq3m0~;LBz0xMk2`$xq+asw(%X4BsCpNs2u~1 z8su%H3sGM(5YBh>!UmCqSUnno7(E6V`^a$1Wj`GI*6Bxf_VEm%zcV?1j z&V+}h!#a+JG{exCe++?A8EE$L#{4sxvyWxYK9kv&{Zb(5skunI!(IO(_FC*4Gz4o$ z`;NE=wuNN4aO&ld3=<4iJ9}Mq^I;Jv!iNT@up2{AA!aV z)-i?~nI{`%Fy%i8<*3*fx-lIQ6yLW9;xf4UE$CoFjSYlfuOs|+4dGAL6F##Juzbtc zAC*tzcKLi;lTUr6e7?U@KL6#%=bKM@|52kI0zE(o7`voU`sM1oP0%icsyf7oJ- zY8&%AQNJA4LgWu}?QY>7hbt3V$R!tWoGrYWSCQA4|1=JTs&9doKp8ety5-KG|xNL>k=rr>B2lKo0y@t%X*65T&L`1M40_WRYz zCHl?K#`^0oDGx+V_*cOL_U!ko{@nfbUqpKC8;JDUzr;rREqcbYM8ZO0jWHc}&_C`8 zyL)*US9O6&Fnh+m5{>wcIf9p%ML?jbXX53WG8GPBZsv?BX~`=2$Cp3Cc<;5K;V%zi zkbt&T3j9zv^WN)8N+~f27!IHhHuXjSzh7>1`>8ysRz!#9*d+?lo^hW}R^l%Bnsw8n z4=oU!k4Ud*7n$et;36JKSOn5YfR(Le!Sa>wW zT6i>NU3fI5Nq96RM|d<_NO&|kFg%*v6&}4sV1vLqfi(iR3*0Jjo4|);Rd%_+g9a4$ zm16b_oFMQuaX&2ZErCY_9u=qr9us(6;0b}90?!CM1PCQ4`ajx44}QDoaFGHRDR7Yj z7b$R&0v9Q8kpdSfaFGHRDR7Yj7b$R&0v9Q8kpdSfaFGI^1_d}dc=7Kd1ujzHA_Xo| z;35SsQs5#5E>htC_Y~m$yNeFn-5EFWPzN@Beb)H;vW)Lme7AlM<{X=Q2Y%56sjgmW z!*9`@D^{1{d;KzaemTYFUVxwOwYd-C_c^T2-#gUiPX4vsjqT62bo1->*xY#thka(Y z#qf7uZFAR5v$^{kA6G_qi~kmPGoeh_XmQTJWh+;dtZD^{(j_LnV}u+?Q%Ys#u( z+)%#d<4RYqxKoNJ<%Rv8>bnek;jQz1rMdZqBI~p>)!k_$9MC~ z&12+J#-1^4wu!MB&-5FA<4sY1q&M=fuF@(E1fmN12I%?Zl{WVw(DP1w_hN%_4d|bY zdbl3+z6bk@mtKNB#>qDKn{fLj!W_TM=DrH%#9=mfIhOjjA^abQqh5yC+>2pedX>$6 z81In&4dKqfylIrd19og$G5@@uR=&x2Z!R|9gsyxYpH{xTl{X&wlCALP{oxeEZ5*7b@Sr@D=m?-;h@q zGT*-N)rHKrFMM?&^X&^?UC4ZUo~e!_-E1iLgm|6 zI)AG9o`uf6wWAA3XR4Eyz7fq=pLV`yYeyF{-@erEr=71QG%kKGQs6>SfMdhTrOWOv z)4Im0mG=h90%cwHsB~9%c?Z*s=z&W zVl-?bx3n6gV{OIiRo?QYD^`{*pX6Oxw#qwsiWd7Jysm_d)C(0kj%+fmp<>h5n5pUZ~ef(S0$3H9RYQbztYOG_(P z2C7R*0WnlAUA}z9s=G{bc*kXopWywBe7cZ=sb^Y3!?I;nWf}`}m*yviB3r&$x7W<5phQFyaly}6Ti5qFbr zuuru3!1OolJ=5#q-YvYZ@D_`IBYBu^-STC+y@ic(?-ss$SObUd>2~4OTiBlI8sYP& z(Fd@rEk^K;@#}_9jGsyCUeoMGpZT*2$7Pa2V|!&gTbDnh^{9T+e_BB<{*TWX>zg}k z;ke9<8@n?-YO*UG6SbHSJ^d$k3lUvDOIDao#}@5p@=rwG#rUxhF@9|E-BUE;beACA z^Xe`oEWcbvj7iII>yA~#Eee|$JV~T(awEpyjM*hWdczrk1hsB{F)?G(?Ue~)!Z3v% zjLaM5jS>a?ypHrDMdXre7C7 zGM-guR*YyjD`XV@#IHvlQU1iQM?RK+Y+kYMR(?_C?KQtB|6cR6{A2Trb+_^}+C@() zS~8=Xe^idW`uB>l)vnAuqSCN%U|L=ISeP3*^mIo8X68Npx>78>)feeC%u111bSEv) zKBPy9^)q#lUi}y+3jH4G_2y@#7wgCRCmua|rfy|BR|tz{pu#!QA=S^F$GJindf&N1 zSbTN1Jf`K&&Yv}FW-eJHy2D`kNt<)|OX<%NpE}>!;#%&c`ML7!%|ANNSpVoeWBp?C zlv<1}qZudS*GpdF*GoR)ZslRpGLlX&bd2~#=Mfz*I*({~qfMDSbr#w)@!rCjTJEwH!oau8* z3#Szpn@quQ({pFdnwmT9mT32Bv*yfakiuJwZ{?SBTbQruwpRxB$X*$SiT>OFq1}DO zH~I9f@yB_LLosf+(#duNZbPHOdElmE+?YtG=@x>Sf64ec!baS$z|0l16#P7JOGSEg z<64IozmzC9ZZS#4FAZ+VW;o)OhF?ZhdWo>}Ho=0ZxVZbrmVw`bsBpOX$(DoP$|yIM zD-XZAC^znfBC~9ZN)I=Z*>EwF?TM&xcoV~hM?!4-qugl6)Tr%Hlp8Pnn1$bwsPym( zj*TNd73Ic#Sw8%1w!{csNKaO-2X3T2X-BuMm}eS}FaH+cmkNKee2M^@vZ^ujEIEM3 zN~7(|R#f^qeOz5u%`l}amK%uNv$R^n?DpMdoJ__a45dq}?h>=M;+`@Z_+1^)#I3T- zn1t?1r*zqBT7EtE?0=pc40Z=KtLX;#IFXwX8f$JXIwKVUtQ%jXyjeCbmhuBu?)cwk#v?}^}w3N zWgQy(?<5Gr03GhVGwh?QZy3!oU5lyKxxV~4#4m5=tswr=Z(a_96fe?X0>;8wfB~FQ$~-SSnbUX;5(t(o4;xq3|ZCQ*-L4dP|cRr^+*2Z zUP8(PwrM+lY~O6Bqwyn?Uxl9+KmO(5_Xr}@;QOD9jNe}w8NYY=MFQ7TkRXBn{33w| z`1RsqDt>bim){zjZ6m)(KBaZE z_}1Y2I^!eaA%5ZZD}M23lG*kM-1zrBe3||rWWYQI1JKKbZw(bwfHi<;rKG#2-80qU#5F0zFvGU!?y&&>MLtp>4m~ly~zW#0d1aTkw z1aWtmam_006WTjJLEK%RAa0Wxmpt0nzh*OTPG2J;{6RBr&Bus)*o-R;tdH@JnsL2- zjK|=|%(!glef>LO;f#oVZ4YOn;`X&Y*ps{DMqlGPqT=?Ir`=I;`^sC%pCGO`DsErv zDJ?3lw~rM(Au4W7ALHgk#of`zxCK#hbNU$9XT~L8;2ys7?oXJ_{7(>fff<)P)z^IQ z_ylqNW?bUWKd->^1C?f6w%xwAU(Jk5I`_35t&1veU*p!8ajgf_&#$CLs5&#Qw=a>* zunlHhD{5cl&eoW?eJS&{n7DnBJKJO8_C0r-pH=ve`0k8}>-~uE(cZga;@a%z zPpzhyxH-P_=j!H|xHUV@zlPgl;x->Q74qnUoyB}GCaz2}oF#0m^J}qjo6kSrw_@Yk z&Ofe-jeGuNwspqFJ%2LW9G7I!y2glv)JeN61V0oVPl;a^%7UYoCkj`KTBMm@A{~} zm7gH)y0gTMI!AZb?CZ`FH#S0VeA;lHaeL#nt>+oHw?1xrOx&~074*hyJIuH&PxLRg zyqs5#{d+npE}MWAKQ>%%abv?=v|psaMGE}ir2v+~Y}4k>_RY$loj+&(TrQ0Xve9mN z`O|ZYX3ZD(yRi^Q!`=TMd+!3LRaN$XuMIPZh zWbLDMV@x;UI^?sFLc5jMjXcy^|7v*|Eqo!h@=j6g@JB*piK?|qYDKn0Fa0b1Y+pU< zXOXjhNE9TXHrVFfGxk=!60dpB$X;R{E!m^R`@u>zy{ue^rE2aBRW)~-exHe$lJ}89 z^HzZbW9G%dUSv)6`(gHb$o^#ZENPzJ=ZHDn`{}$>7Ii8xYhlN%?d%Rjd6sR^>`TxQ zhw68<^2XML?@VkgPNdx;g(vFH8h3Q?fxc_lmr&p6_@V9~Yes`9e= zR}=P%`IqZ5FmHaPP7l&k@4X;-i5=-VCCx5)KO^tIg7+$gd&j$4+Vv*^ z?hgO7eed!HrlDzhzOyUWlJ9D4Yv{Z|Ub^u40O^yPU$*4U*)!jm4f0sR7W@kR>|d9p z^O2M-=VjUycG-*W;F--o+AA^3JNLkDTFKODIh(o04)X=ZF=cE@1z8vDahJV9vR6P} zpKHDZL~GS$DcnbtW|x!;%9H5iIi@qPTU^cibo&X+;_|r*%C9M3@J9SweD(b5^2^Y; zXyJnETr>4SexZHze6iT*rXjx1H`?1bD`6{vD%ja4+Gz)zHi zNLv-ynf4(RRl%OC^MhT@krn>V(QTZ_NV%0Xo3wDz!g7;5dQDBni)m8BTJjAWV1$sjZl0OfO-Qw~0G3%cX$E?5XE4%d;^nbr`d}0S?SX z6N@urFpGX!sho&8^dDCNRosaS8Lxgn0>OiSO2rd6^oX zS7|dTc(<2X%kzWQ+>3cT&wbWhiFp^#d#w2o=6yUL1VhPz4IlS1FYzpUgCs}xV;+7^ zu?SWW8uKL09&2b*^5-o{+)amZpvHQyH?NZ zs9oN|-k?q`rY`H&+ji7k_V%!;DBRz)Snq?W?8x(_Djx;r#r49rDz+V=gbhxMTC4J{ z`Q>e0O|@b)%J^GWv6wF&o3(rCt0R+ASGRW7F3T^-FR!g%ohHrJn2y!$UDb{GRyM~N zm6disR8^i2h&v?~^xZr+b!actA{(|=ee{<}3!d4AWYWk!=fo5|OX392B2j140G@1d zf}>RMkgsoOwt+{sBzIIjIo_%Dl{UTi&jmKsW)>Ul{rf8_S@}>B)ruy10 z!;rmS#{Z@j@UC?BOOR@b&7pX;nQtxtVdE-1dLVOmp8rh0b&p9E1g)VAhxY_rSdTWjlV zrf6PE*XnlE=teDYM~$zwyAAn{ze&6?A5iNZm#q!CrWIPLxNplfNCS~uNky@F4UZ(7 z9`Kh(?1|iKo;fH%nEZ?$J}mF3ZS8Dnl6iJ#CmS`5ZD6kx zCRf|uu6JujT7!N@XM0{+ebFb)85!A4eo_Tm+4X4)M`wH9HseWmjZARbWCN|)%o?@r zK^Sw(`SzXQbKFAgs!`_E7xZBfpXAdZF7!OC)&Gm>=kXP zwH=}5>sHe|yQQA1khNUYvN&8IUz;pZ zbav4cwb(j1b-Kj4A*XYv$?aGR-8!kB$io!3{b-Gc!E{bX7lx=KvpIi+Fj%+!h9Stt zFvXn)NDJvSl4BLv%xn{0SJp&nla#dCFMD}8u|YRT((LDIX#vO~(=}R0#!Xj;WQKiS zMSByO?NU@d9w+Ohc2A>`2trukwY@1E{N-#<3BK#^az+Uq1X#DObCh$<(vBA8(n+ht4p*t$0PTT234x0|6U-QhkPP?JC z?QTy5Hb^&PXSC?EO&s0E&NL{ddDE6!r{zkQB20(Zo^O?tGeSMmvZsYT;?pIeKF}TG zuQZ3z#O?H0$21&Ht#(SD4v*2}xTU!Zdq=`sV9%a-eJHA{NcuGie?wD;i9=_1-Hi=xZ??Jrz>wmLy0N0I!TPLCVzB!Zs^v7_RxK6exohpl=IX28N#*H-jtXATFP}WtO;anc7=YBU9{DF8-n|; zHsd;QD|X3%#_Y@-Mi&cGEbK2NEHQUoIR?W`e2gMr>%=}45vMV?{e6p5;EuA)kS3Z# z+cc4SBmr{gB0*RZcHws~uI{9pV1AHvQ)x=`mBGBm^&_&2c@f4_{BYd3Uc}t=_id5u zm#oz%f)djavyTVo2<~D*in%jwRugkKNs%b;Buc~^oM#TmA%fWn&zllEOWfAmy$gk2NX70!_ zYi7KZHB~qpO%NolB|eO#srQTo9hu;ZF>#}ZI4k9(cV{qxThXo4oT*KBM=LR|TOI!b z%;cYpF}vGwX-A4$j_F-|^~<53JnU*fof0)g%GoEOYH+-!x{G5iOg>taEV9QP zhWQ`3Cq=@%rVY*p-**aAhYOuD+mtUd_2d%1=r=0`Sy?dA@}f@$>SECLowZrkcV*o* zW}p06Q`}13)N72m4D`6+;+xQHtrJ}dm!1@)giGA&)hcJ*(C7>nPfd8Wzm$k<%S}yD zjWcoXtgof(c8YO4`*i%|f&!h$jJG9u?GPlJ9A|1>ZgEP})!EFY49)ow>AJKBONl+Le&oOEo_hsEMoE6Gx4@-}S@MsiC~Vof+=`e)L@%rAve zUz=?}ojJU)rKyvJminOWllZ2M_k?Koq#;9KI@8d?yh4y#z)XY1?C$G_+c?A?A@ zyGc)uqDwTDsf%d1dyQ{$-f*SOiq^6CTWL`fUkoAR~3Lp{Y{>VROgk zLl>*3eC@ruwLW)a8-+0;BN@S44$YT*>t=kxiU-Rb%eq^271vfVf0`O}6^))OM^6^IUwD_)2f!lph@!>Y2Rlktj>kQBa=~ zGO-b{t)p5-#-}vau{2BZGa9JqFt^>*l+UuF6pn`U$+T8ag`Y zD6{%~L3UZUX;O5a1pde7BHD&EZAoWo=^VdP-A7S3GE|n@tn^sP5)hS*n14=AX+P8C zv)%6Uye_A9;z~g?eL`GTkAmG{i;*!)?Gi9|`7aS}v*4L%UUa$EeHQ5x_e;0xtkXr~ zi=aH2rM+ks-X?8AzP-Dyxv5@S{lH%8v@2^?GmUNBZ*y=&n_VlB{IPO+pcJ`nCEK&X z6hfzkaTgzy=v1rAcdg7zO`)S;k{7>$iS|hrm}ObjE<-yht$UuR<A3_WGa0x#}uCh1X4(9kDF7slTsc&lv5(h1_mTKu-j#1M+YAW2LMVkRuXN|AZb zl(p{|bYj=(DY;Hht%E_V7(yk?nZr39qh;-oKgR8CnXKwp+|fu<_6q1}4x1AwJR+#yg}T#Z?SEy}JPA)epPm;oI7-P1 zB?|@2f{tQDYr`mmA3GU$3zQx2_t$Mp8j&S!ZL)l#%b`s?eYlCNB!q(~JFLap^tdR>}OGc}2%t+jMC^|c8b@Lz*i@(Gw)S=(jbqA$VI=ZwWUB7ZUd#JpP zo~itlX1s3d%IZN+5c3or=51*pYhNRiiDm|5X4%>{AscTC!Z%d1w;4~Rk;~TQDXn=7 zw0y>cgbo&O8yfABiE8ZXYVVYp)T-6GxCi@k3T3257%7o)9T&Ql-P6YJCbF9?C|SLt z;nrgt_d;124X}z;E3b;JBS@epSgkT`kg+e+!Agu31Tq;RO9npzz_6f(P&CtY4It{5MhTJ^|4QmlpUOEVMk zEUcMf*h5(oQm-d6c#FR;P1O}Em85wX23a)i<_)KGbHOQ5L46L>kL7*6)UQJk%67?2 z->%I&Lkrd+bKEZL>$C_Gt5n- z1LswlDPlBqNT$EY77TC#zxAktcPviSQ{@XbA~@mil$MJ9ZSI;-O8E0Z`3U?rO}?y$ zM}be1>oVI`!t|0g8RjD4nO>44DQRB8;hl?Yaz(O?F}h`X-PukZFqJSx_R8|>a^*|d zq`vU-D8qtqn|Z7BiJh?_XiC_nZwZzIbx@9?9hUrRZMS_(+JrU5AA5s?iLE2k*=XOx zrO9;KPA-@uvcFI(NO#LHgx6!t?SpPb1#-;R8G_hFo%D8D;^ZuR2DzfxM@JoIVBWxt z#13D=HDqy>5*D^)8Tmk#);m=?O;*1w%|-QGGzEHSSqo-FsXBDCW0x;XP+~glxJ9BR zt)_L69+%jLoJ3fTHa&udJ&1=LL&*d;Tu+xkq{T&7hs0QeY3XbARj&YC)8ornZv@C(4)t&)GnhbHEzLzci=?H zRGCKJE;ZM&-Kv455o4Xw23%8KHGkf9R$9t;G&qw6#Js)7o(|^Jts0~4rOK)C`%2yo%lGVD{xMl znK&nsJ)Uk>-WgvZ*PhqwTk+Xxs+=TyF#E9{i@aTY#P&$#lXbNEXk4V_%$8}^CE{zh z@%pv6dePkUF%deVeu5#H1St`2@l!8MF!Ghxt9JL5E-x}^(plk-p;P=W<7+YY9Jlr)cx$IxR2@^+JTiu=?tn8@iRLS_$o z)i<#vCME1r!rka8J?3QrFUy{732cf?)DZB7Iw)YFoUN7Zvg_A2NGUp)?3uJ^Yv!G# zovYZD2&{0ux&)31#$~!C>TV%9ktST;ZqMo7(fu zyccp`c8DLZwqJq3>u*!!{b{H3t}94uD=*{jg7WXam)AvQnGA(YA~}AGY*>axhPr3h zaO(97uY}uzvT9}Q_%T%`mY4DhCYyMX9QmR9n%EpzySE=VFxYLEhTmqjF6$-@v|PXK zupJDhP0Nxx3ewTa#@+)b!W*WalQ{atQ~V92DI-pJ9p@%S5kuA~7+=DhvT@pW{# zE3KxW>vklIJKOTvye*W8wH-nKKr0r!O6_JXpKmKzVY)d{u3cTux>nE*WLGva1jw>p z8obR;grVP+R^pyA8gXA9$Kvm-wnlRDKB1LF6HYJ%Hc9DpVez~`PqYHd`vy6jJS(rk zvt5nsGz_-j1jC|a7@`$f!Y_j$zNDecl}?Z~(KdNi6YQr6R22A6MJ-sFJ<=Ntw~sP4 zFp37AJ^yyz$wD?Gf zQuM_-NUg^yw5jb`P)_?@&DG&qF`aCpI`;EMIv$oI&8!JiOqXq+!`F^(oZ>U&csQI! zCfTjT(nTkTv>rAGUH@GjY+G%+DXPM$ItpjZ{fEiD-&eeL<7JzS;C0%v=BDM1!3vZc zKHk+jjj+30C9W^69e4FadoGWx!=2f?^1-_g8hP_=u1!lfPW{jB<7p)0lc-rYisE|W zvwJrj-HiBI8({S+@p3JZzIMP|;E(tg*Vh>=WfcZ0U8lXhS?dYjjWBO88*=nJRq=$M z8z&o{WZf)~m&VW;=EZfm?YNm1$qp9={^YDRTBz&g!nPWF1+VUy%pziIqx`!-$KwDdKv z$HP?6;V?4hy_NL!_NARW#L(_!0Ou4k*|NYF=i$~P8}3LCd;i&#U}}2O53_x;u*XWc zlPs6r8cwR2ve;iU@5GZY~oR!p_+eQmwWzbIp^(So9DFKraNqV#Y; zCklTO_WkWo3H`8pQesM69n^Z(tQjxzYZcdVx1D@l*i_#n%Y{_n zZa&`*7OLa!%rU~{LwzpNN;zm z#Eo$#Bjo4}rqR*e8nwX5Hz6{=moj{w1|uH%{6aQL1$}KOtyIEYwBaqqb>vpQJdwU(I-8m=$a2&M zyJYgA)--o4#7#{)boyRCr_Hu4OGbhWcihA_zc_qT%uO-EeSGp1ly5WA40gtg-kVz4 zChYdnv2k!{uUCgD1kP)pgk7jKg@d)d7!j7h_Mmg+0_9g;(}~y8#X4 zg7!d?A>c_n?KTe~-|n}grf}X3?YrF9my7k-LW(8^25}j&osNvq)G=%9(LRv^iNWU8W|IdKQ1q57xlLY{gei4 zmr@dxvUXtvjX9bXyPay%PL7;3sS@akVP>(ZYrvp~#e!HX?X4p!@vkQ>f4qCaK(0q|)-to?tm{Qy#xuL+h{(_~@}t2TPXh`NB0^ z)R~p-oN`I0e96GazjhUH_8avEJ=&qjE({P4`s}Kb^DY)%ioVX~{xwb_JfW>U&M;K{ znv!Wc_Cc6i>Z3Dp>^wl9g(DMxdBB}~fT0f)n4IOdKA4lU=ER&p2Wt>I-iynt*6V12;0h3-V0z#eRR2t(;Re=c@AR@~Xuqh`~S%H!G%}&l?-siufk-tm)W| zbJ>q=-RYgoR7o}>>dI~$*xh{MW!PBj1-D2(tj0RWaMj5P7reRBBS+aNAB?L+B&nXxAfySoKiaW zCNF}8{N#K&9@d!K)QClCVBJOvO;h7!P=Q;$4jFt57JXxz7KY?{O{B||!TwYw+{M%+ z?9z%$LAsgMT{{-Ec@^m~X^>W^l5U)w4|6=}CN05}ZX7)YB`E1Oz2vy%I2Qh>@DRdC zmr3tvUq*awH{D%YObT`OS9GMkWzZ;XjY)pphsF2wN+KF}CJsk(NEpkjs@OAFwXjm; zs;^yKZRlLx(p6UlG~gR|mGc+Qug>alFS-(1eeK)|EmyTTpmVMH%5omigD*lCmuY(K zTw{OjTw{OjTzzFQdbEet*Up>2(8w8cl{H^mVf9%5uC@MMyV&Ym9OyIduC@MES^ui6 ze^ti6vZ}ci;&B<_7kc%=E3aLcWgNk@f)#r>oFm1#05WyC7RW~cSA)3(PR``M43xpF z01FAhW#DQcv7JlA=i+!iDO(1wiXE79=WuQ`DNrVM*Kxih?ke$kKB+w)-qp~B@U9kn z++U49mtnq)RJ|HKS6|8Zc+G6{m$@1TaS;?}J`lW$6|VhOIPtm3k=8oH)fx8%EPB$` z5)-ps?Vmf2b?TzFbIg?9XbsrqyRR)>z8#}$J;A&(oVRH%_mY};#^&|G*k00He#teK zF%H6a}&d}p&QMdw-KJz#E@5=VK z(vZl@f|ZLP9XY}~_6@tFDP@C=_xc+k8I}Y|BUUmd)8pW-Rp$C$+L|eg&EAh$a(;4_ zUuE#_K0Aw>cg?-J!k=qq7CgZ(xv+VOu~LP0Gy1o4^jUwW%rBdjm9R0sTq1OsD2yzp zF!VJJ0=uj9WzbWu%&(5~-Ndjquj#b<+9^b4ni@9bjb1{ z@_6Cgzsx)=EAfl6P;PQY-pM!3;E%^mjr*)2dzQ+4V!XhH|Gn@{@?uX2LxIdMa^6Om$5+`YYEC%A8BM zuS4$3=)SX~ zCwy7-H^M)ke7Mx=KUMS-zTmgU%AIQMM`0oHSMM2=c@6T6KQc3rKN0&Zyw_tD7EEzx ze?KR!<#7rS`(E6>+s0Y=-?#cFiG8tfl=|mbm8laql!5QzM;|hi;Wrd%YyGE=G?0g1 zl7~W{`!{#o%Y*a#x8u*b@Pqul9=%^B4$b)e$OM(yPnwModq*~S9BOq)m1xEDgK0V1mt(w>>~PE8C;YyC_-gwNXfwW%o;KcpJR! zW0LxL1Gb_gn8nB3NEeuIu~v?L!|z|WwU?7qBfTl>9aAom*}I%Bn|&iICsQtIm^$T> zmARJA<+;X&j`M`Fu#$a!R*%nf6<6gdxZt6@Dz_lK^&_5tg?@-Ux@Blj^BA};bT?^| zeB1mw>-CgNtlzK8UXm>dq|(-G*rVN2cw5JPwurCPW$u``hY<^|A2PkY3j4wfALv(&r#1g@;~(_cVC=O+w%w9%Y7I(<8~!| zf})N1p!6w6`IBMC)bplKri0aAx6F+upQhWkdO~-0b)Y|Yh4m^}ab!-jU_SR=<*Mc^ zEL+6XDP_&jEKB5C8gxxz{jvO-%G_0RmdK4li|1d@yvY3(=HXEY4pT$b5H(7TR%6r& zY7ohFBA0gzEB1=KL0-{d$p`6+f?r{L3fmV>^jP}^j z2A23Gy6liSC4J7EBwMbhT!NF_vgX?5o!N7;jI8-YuR1qx!JNxEmS|yhY-~8VXmIi1 zAw@%rhYlG^6pOtfg9mwo_!SK*9yElzW3U(V;6Z=>^I!h**T3$3FZZp`&-K!mOLw=C z1maPhPP*L3^M0|XpS&NYbeDnsSnR(K?Cxzf^n2|G+-j zn|?(eUERqAK(Nk+97D*5dG{`_a9UI$;I{CX(=!{39%Ukn}K zco4*2c=G!IW9lW~eT-jrgG(7ly_GS}=${v5PR4$+r5VQ0Ww;ZWanO3kWFN!bK;3c8E7_8fT0@PCo9nS@{B@5=v(M5}}+;rg-j{1fMSuk-v< z=lLm~+pX-+oacSc^Urziv2LDro`1n}pXEQ}JpUKZ5*P{3FP-O|JWDv`_ig9-3FrAc z&hy7m5V+q3U&1NB?>f)lYKKuMhDR9=! zFbZ!EMpVG#?|9nwF|_W|!vFvLr@seg2V{La7m;;Lm5+aTFo_b`aW$c_({~h#ZDe=B zw5i6<-jGMV=KRZc&dYaoIlNGZ!;8z_RL=o2k+gOf@T_!>xGzHN&_;hFk>!{X*}G&H9_(E!&Q`v3dv`r7 z;e!6%46&l6)`Sade?%S5yeT<+P)8K}-&hyIu_Iy7d85xf3WrR=xUhUq)q?AC)m3xm zaX%6RpDW%;YPi)+c1Xg%iLZ|+rfSa+#9Z1`oLr5^B&K4(a# z5rhGC9!^!?T_Q$lo2~%WA1YSWx0v2Eu#q^$yt`Oc++VC-_;j)Q+9}MX=UZ2|IPC`==tMV_IsViauWP2 z;D2sBd*oRNydIsE==mz))0oz;`R-=IgU904E{re z}WUeFLcjM-tU^MQ2 z1P&68OR$@Pn=;&g1ONVj?#FTaTl8<{c_w~7f!$YecNx!TA^$h@{*iF5L;iQ@$s_kC z;?|AKTy%Bf|2uHIk>`cTehqy$V^@KWo1ovt?zg1JBKX6hFQfAxB8T3&m`{Q~3b{$- z&Bx*8@#hZYK98UGK;K5%4MNv{d88xgGul+@EkZWenLD!BX58AvY4e|3>FU z@ZJplHDP=kbSUXRAAB1BuSMtO=s64j-$1;cmJ8mDuT#W1(p10!fPeqROS&QEB zk`{#Fhdj@MzY8}vqwDq9HxZss@H`3nE5g?d?!$ctasDRH?*=d7_vi8R2K25VOg{d6 z3H~|AkB9#$__yHx5d0PJuH*U3=zA@8H{<7S!uA!y`6Kj>!Oib+|8De@fC0srDa}RV4{6)Aq8@I0`E(hTM4L1|fwI09D#myt|r@&i=pI^qE zf?tl@LlQ>(KY(AS;?gLgb(UqHCJ(Ba}1Yr~_-jM(}y?9q=2VK3}ZHf@xqLr~_{U z9|E5PKLo!3&x2vxiq%=*jo@m~0@i_#fycle@ErITIPD9?>O626xDMP5?gXC!yTI?k zkS`Xiv%x%22W|rog71UBf|I_44zLI`fK^~4cnmxV{s0DTM+cY>y1+WH8SDbjfPa7y zUoKW9U=dgbZU+y59pIRKFEVxz=y!6z&F5?;CI0LDsI6=;2O{k-VYuI zKLCFOLw6LbGr$|b0?+{70qzD{!7gwByaZ1E8s!ko2RDKbfCs@2@DuP`@Ha5*>%0k?zuz-PhZU@!O`_%rx7@V`mez!jhoyaQ|mp9Wt5d%$zxzroPQi`7VQ9+(4a zKpVIf+yx#5Pk^6+=fR+FQK!IUFb`Z0ZUnc0jo?x6ZSZUGFEC;!Z2_nRH-c4Q9e4zM z5qt;y7x)_({_SEl4$J^ofqL*R@DcC`_%?V3`~kcKhCV?Z02hO6K?~>s8^LDq4e%8B zJ@^MG{tk5kOagBNi@`F`1=fT6!56^y!7spb;4sMSqMn2Ez$`Ei+yI)uDzE`;1owl_ zfG>l`!BgNj;CXP;cZ=0IU?x}u@?aIX4fKLX!4B|!@C$GV6nziBK^DvaSAts51MUEu z!S}(Rz`wwd?~@*22Dk#$f)(H%@EP!3@H_A~Fnl*<47?tcgQcJuya(J5c7UhBpFq(M z2m_c7t_1bqt)K^d7(4>L1a^YogBQR_PtvY~$)F4@1s&l1U^CbOehLnQ6MsnC2&RMi zpb9JnZw2oF8^FiGXTZ0>kHK@`WpLsi>LR!Zlz}Cn5imO8ebr!9q(~Qa9D6{HSHsxJ zGn{QwC#jR!kZ}t8qfX{(5KJU)1R14HqYN1-h9)mZjDz#Wu^CiwTe3i3AU8k;BH}Kx<&FU>Gr)pHKs#Eps z_06kgYPo7uP3lH(qPI?dpAMy?Vd8Lw!JPP#;uxst>8V)Q8na)JN4u^)Yp~`ncMp z?os!u`&6&GUwuM7pdM78RG(6xR-4sB>S6VW+M+(A9#x-JTh-^(W9sv2oBD$KqWY5B zuD-0kqQ0tjsIRH7t8cK!;hXAl^)0nieOo=DzN2=j@2c;q@2lPF2kJ@nL$yc!Nc~v- zMD0~SRZpp(v8Vdy>S^^0^^E#2^-J|DwO{>O{YL#(9ZJ_rzV;|gLvsKJH&Kv3-?+x=# z@P>OQdM9}&dl~N(?^N$J&-X@nBfU}HXm5;nx;NGv=Z*I!cxQN7?@aG3?`&_P_ZsgU z@3r0}?{(g}-s`=|-W2aV?|iSso9a#Trh7BI3%m=xi@cfM#ojFM4c=_;jou~RrCzBw z$Ggm%>y>%s-aPMeufm(}UEy8nE%2`L7J7@kO7BfxmABZd_OAA>@viljc-MK?dpCGX zy*GPr@p4{`SL@Yz^ZJO1CjZ-M(!6B<-!ln!P6fE z1}6vF)1zfqtv^IyIQ?8;F=dOkR zRI(p#(!IVQueP~9H%HDUt!@jI@&2k26ZFg5= zu9eJk+zG#~sjD-|GsjJ)xi%+eq}dc|zG+pOJAHUwA`Es%wi}EluKgfM4eJQkmTOI7 zPh3jO^#U%7q8;9{Vhfgyt(B4D8xx4aCoVXrfs5h$)xkCC`p$E?W8LhJwaTo8+3b_x zb>#DLj$Hj|!eGVlb*dbSC}-a$Ez-Qfy{_5?ZgpkltmV)`E_HVeISwya5$A9^bay_d zkH63^xwAdEqj6anbcZR`z-WM3+u&S?oW?a*0Lqr*n60gL{o3mDwnB;E@Gj1d=xC0( zjrn>xOH$w7D2MMxHadUWbUm@zPgvyy2kr<9BFX(x6uRI>zliJjAa};m93?UvRocRc zhWa#5Uo0r4D9)A))7z;-wh@*K`vRYrHFtM52CZxq>R2A=LSG;4pbv$OMVDMU&9Sr{ zw!jfmZQ-;dAJ1wDwQVPQtx~f=Aa7I^maxZ%k=A>V`0{LB~dZQH@bE~!(#ID$ZiT7ABlFLA+#-Q zd|YRGd}xQHXPNr^3IgN6{8QZ%)rMH?A z&Hh?VvFoSR)K+|=SkMBBg>wx=dZCXTFi>nD>RnA-36YE>$5v3a`S4TD;tLv{bRUxq zxP(H^N3}DE)KH3jFmeel0d&)=y}N@858{QspH4x%3)_%X&qCXHr(gv2_{hB%+zkd> zhe;S2>cz^HW}6z?E}d&y48)Bt;cXpu;7B{Jy~KhEk-omYKx=T^K))9KdlnXAW;*@2 zq6fs4{@l%tWwHyDQ1S(>e7Qz=*gxIX9t#hbVsT|vjHhhM1EwRBF( z?N7eIQ>j5*z}?!#L9IDCydoAMQ@8Z}J+8)x9i@()UFX8#all|CK)0>CHLW|wZ{z}n zaKaa}k%Q^X@x6soa)fCi*B%Qd0d+KmlgD79>Dsw%u*q2TGflIZ9pmJdnMxXGn%*Vm z4Yhk}GD$5jHRGf;NK0y(t-mQ0lG^iXZe+&K;Jv%q#7LjIs+WnRwU#rcq%dY$?U&Sz~M#$b*sDbI;?ilC>%Nl{Yf-Qm&QV75{yT5FwEuWy4i5d$qBsUzF-<} zJ7>2$aAx(vvZh4YT$&y&S!!Ovj6YmYNS)~?XZhMJ1t^-zYZkput*nITNOA6Y`2Ce( zbekg1MdUemJZ(m4PIF}jaW1=`btuP4u&&~;%;~bR+V9wQa1U^sSyObliSeJYY3f`t zO~)XXJ>{zWJY@~H;Yn$6!8B@p&-keS)a+)nk88_)Q z%rJ(PkD`-dI*voA~w2dAY zaEiJ)Cq4)-9~_#Z<}iX=31Z75=+Mi+tRezi1Lzm{1;)XQW ziFusXpm~nQ!a1FGW+!dwuATCt9d~yy1|)P*2ODEYB{mAQ6`|bNLkn!e7fz`{nP7&b zhoUmdk59J5%fN}-ZVTU(UH#HQ&Q;-V_P{%Hs%mI**0;2rG3Sa|pSEl{(ZaatJ1^ue1rPnqNhyMuQdp|qY6*UFV_5z9%@u*wDfNa!lG zi6%m#JZM4mNMDvv!ojAomD5IYiQ;QUl5Sl`jW`rmJc|+)TE70}*0X}jY}p(V!@=B9 zS&JhL5TFrQi&MG=$fs+h3Db@x=#s;N6AW6ZFlH1c5AS?%&we7{h+1y)4al-OtZ~v?SzNC=g}9S>I1Li(|-|a$jimHQre73U&E7l0g-AG z?~+_6X={ICpGexEKM|{NO*F_YJ0%o5nMgz@GHo{HmR5Uxe<|fReSSS-`Zigi1 z{uamrJ5%Kf6WLuD6Spb-g|HJ{gl5@hL!QGj8tWorHc=O0*wK4L$DCX@bFJ`$V<3Zd zMc2kon}ZQ|x>ZcjeG#Oc(}dd;idP(I+g*!XyLmyZh2o95u+mn!G(Tm9OY_6kEisu! zJ}mJCZGPlNFQwY{UARFL9_!o+!Y2qqVZuF0SZ}CWghliQ67)JDOKVFLKR36go87oD<(GBOLppQ66n^j5zGU;k}k= zcoW=&F-T8;xF|oLR4bz%p8*Q4VncX~gg^B%#$9~6B;8+SAOMzo4 za4ZFmrNFTiIF)>1w%Q*!pXFy$O`u{&N43${P)7Fqm_$x1kqvV4wRAUhe^^Bvhz z+@#6!3AdK*feOUm*~m^qR@@6pElv766TXDG2PzQRYGkKdSuvLa(UFu*^S2q<8CJFk zky4N*o91s1vKJsLehPZ}kq!LSj&LY$Hz147FuwiC2L8ITn~}ZP$_~`uK4fP(@g0c2 zdy##E6W=WHkU}SAN+4xQkXAMhAUoTUE$v4(NUI*~1roo*$iC5$6@Hq(fvlTWMSm{J zlp-s6D&RR)Hc00l>;>X)7Flj1)3RbN1xNC?2YZ3IosH~`j=#cBlMVcJ!@LC9n;d`p zlTC|n7qZP(wg^8qN`9WkiAuD0xr6}_WD?5mA^cP>r-(-AeAp3wT z+mF8@n~ZNYvY)cDB;$bmZAbRguIvE(U61UhJ|}-m)AMK&K}yDV6SDWXvOPzZb?d?w zWbZ{*(pcy30Q}vF?0v560Q`Lh*R{FbwM)|3?+yQe;2r%Jv*t){Sp9vY$d$cmwsf8QD*}vIFpU zEwY>4Fb^P|HzNB`O!ny0c?+@+yI~%HzdMnABqn?G{yu~37G$N((BsI`Bj*uG8MezyVeK>M@(k=z61-UTFSA!*WM zA#F@EvV&aNtch=$taL|ieAgp8*p(%lm;bnZiTj3e9gDza{v_ab|?m6f_u3Z$JrnsMD>WG6bZJ;-JIkxhaXmX-9UlD~qT7$tL~13)%CXFb~Av z?Z}q6vIFq<840tB`h7&zAaFEw{~)qc#3dOdd6NZ4E35veD03dNrN|&YAXy*T^-h>Y zN1DHB^>;F|?{{Q-UPV?1jsQv+%aGmR#JBWSWP7j|h-?kAA9Q4ef21(G{;omxE@VrQ z5nV!$B-?|%K-_Lb_QQ^>@Q)`MpnWy zP=ALXW{l*@4#3~Z$ZkQll&DJD4J5t`ko}A+n?3sYHY58evOzkR8n2byM=0qffsu8U zwDPnt&Xh7NqQ$`)B2+}??Gfg@5uHbn*~XKMK&4V;eRX2Y;$BqF3sPx_)bLj3kg|~Px>pe$@tDj z_KV1tihCe5&EK^6E=BfBj%*LIS&;NMExv1z-R{VWT$;aW@x2S#FDGQv{7sAR7Gy8z zQ-gb~f2GhPwK?KWAZfE3*$W+6;U7s>3n3`72a&zVku8On7T>gV&itMASVy)8*(^Ak zbe@6i#g44VrG+^yofjZGDYkb~Ca8TW0R1I5`^GMr0qdvZ8w+vg?t31X+=j zvN#ag&B$&+wg;(!%I-$?GssFB3{>_YvX3HLioa4O2NLGtFBE0ILb8gSmgSH5pG;@T z-{hEoBC=n@sgy%q76%|(hV0j^>_Gi(K=vC}R?0_^W=9j|9%TEF6+gAV1pG+x)sAo| zZZ{(PEjPXckll{#PB*>-kllyux83*-K=v@QYZLKB91j1T@s;GSv^j2khyJrD^B(K3 zmf_FQ%1%Ufos|vJ`DkTJk$ta~)%iOBf0rOT2U+n``^%pr`P+j#fw*l(w#<$10A$x8 zTkghp0J0AvJI{^p0AzO{+tKH&Z6bT5@+@%`;7lDrw$qg*p|bGP>QTXX^2MUe3M(tR zMB&l;TY~ILS9SpYRwH{CvSIsd{Y{Qlg7Vx$&;%03c4R;7%36QZWRvk-kL*W~4dNNl zG}&a|y#?8iy0QcCcQ>*dku9}x7>K_Ik^Pt}I{<%&|Enl-H?lqWEBQJQe@l@4xGOsV zf2)zbMXAB!XIA_zlHLsOgZ4^z{De11Zc^vJKu9~X?{Z|b@DMMM6}N*3Q}7e>dSu`I zit)EsTOcWVQ~Vt=L@aP*$rfbaJjUNtcYk?sQkpd3)$lcvsI_lS_chTxffm> zy~6x=B9F;(wGY{kII@x`fvnrMr^y~b_G8G3do42n*%y$#+saC~2jcJWmna)nmJ~i} zS#c`Aamc@dyfF>zZyB;2;QSxS4$P-xu8*a_u@pF#0>@I|SPC3V0Z9R_CVb_PD$ZO> z?;Ak)!L!i7Y@Sm7){ONxzP6a5Vb8bu! zp{1w#dxY*e#Xlr;|4IJvDZ(G^PZD})sJ}qyp3#1d(30c*HQN4of1}XKk`7a3V$@-&9puLnE zp?gmBtA%EV`3*u#NBCVrONRODh4!4{Zx-5qioaXvhSUASLTgU){i(t~$)6##beLZ) zv~rkVBXqy-uM=7`%-<-q=Olldro;R`Z9m%IFSPPB{{^8NhWY+9X!{6%qR>5*KcU%E z{iQXrFh4UL{+?m}459mn`AdWz8s>KiRVVlxH9f`O zAvAM>zh7wf1Yga7mYm>E5~@b{l|nNk{ASG`<8KhUb+q3rw0*R{O=#%}{!XDiWBh$W zvt#_B7eFgd@GFIGpnM6~U=%G{n4MN*b^LGl}pYexY3{_+OnL>NB z{!*cbPW0Ca&7A3P7MdOF?-9B+>mL?cn)N5nf-2vy6q@ndHt7*m`K3mMA{h315aKB4vX1KpeXm+^2TWHB}|De#` z6a8^-gw~MnLQ8QcRGsAS6uRLw|FF=?(f-6sgbw$sg_fS|_X@2U?jI1^KHMLDDYR#} zzeMN;^a$-8?(Y)1b-14?g=S9iD}?q9_csXLGu-bJx_`K@=0MdLze4Dt;r<$JKGEMH zbbr=AsQFoc(q))4WBnSTeOZ5aMOy%&1O_uGYLvi=sK*^&Np+MfKLhq-i= z-!62|>HapM`zQDZg>v&>$>q?kw4Xvt$M{=?R*vxx2(208XDXoWWBdg|H&FhC_Kxv) z2`!!A7tI&@34WQ-o(cXcp&KUnJB4P)`$MmQmW=evgtnjQuM?U*)8DE2_q&AljQ1ZDT1o#Pbk7-n(N)k5=n>jG-rpc} z>v(^+(7y40W+8OXcz>zT{p0;!p@+u%&j?i${7H+T8QNQ+*$Mu3p*17@7ldvl9V?-S z#`--%+XOV0F*s-b(b{%oO@`+DjPfglZW!gS z(&lk~pEi&44{P%o{>*Ez?;Yo_5xRAp|BTQ+{J$2uXPm!8=zjDI-H`R45qfBZpIrhi z8SPgK&5ZNc3OzK=-zjthH%DFvRpb51LNnw28lg33`WrO=On;ZqJ!Adh*9-p)zf`Ci z=dTjFf2_YnOih(~9SOb3zY|@n^pUs!sRU2<;o?Zx^~}ls_~F-B0=n?HlXgr78Xj z-Fk+ft$`jo!*3AUJJ#PObk9h?s1{n2^(%z#AL*|XdT5ltN7IqMUx!(Z@*9O_M)?m4 zEjitPPH5@r{^WXS<>`Kd&>G5%&|b>3(Cj#WXaltG48KBC+G(No*C3yN%_z=fJmrtR zpg8jZ%#F}{pS3ze$w?UtTe*nt9BY!ge344hAMksrF{4G%S ztN8n&?BnpWbBg6%qrVi|2i*wW1>FVxE_CQ+#hLFx%b?$fwnIM%?Sm?J@li{ zozUIT4E@MPXf>2|R(~V(0q9=nhee)#=GD(1t``!P?ZKlvoI9r||oTcDdUABH{z zok@SfzBa!H+78_TU52|N`Vsc5`PI;iFmHl>5%V+9tc41?CL>$qvlxq3_1L6UuvMzleV18_?O%#qfKeWzZea zZ^AzWy&Ll+`jb`AM(A?rc4!{^=b$T~S^ANE&_?Kou>B7XG2FoS3y4t-2rWcsy7#Bp26KrXcOkO&>NwB(3_yc-$MHct%hC-y$f0j z-4C4%os^>-6%jw^OM}r19fA1;s1Kc8Q=AzIT@M`seFmC=POL4?jDj{mPl0ZQK9BrC z=xLZ|*HK>x*IMY?p*x`mpsKz&^E+q-^jYXSXcyt=gT4dvA?P~jO0%#BPJm`bamyzEE9gX=Q^fKts<;9unp_8E3K`WuxLVKV~pqruBKzBl02y1iBX51N|8MP0$B1Z->spya)PM%r8KnhfZuN&ioH_0rW9w7xXZ6 zBlK_3txzAiUC_T{-Us~$^bqs~Xy(S^%s-)%p||3$4EjFIOQ7wTo1rga?t%Ub+6#RN zx*f`EFn>4n73cwI748p1J!tl(;>;VM6;NIa`i)Rts`+c7^P#=aw?cP7KZX20=z7ct zq3?vM=Hg5-bR6_%=uGHPXa)3mXalqZ+5;U1-2^=Wx(zxUx(9k9^cko+_B)mW$5P<` z^(pYcnJSZpWW)kDNq(A{wrg-2|EPHX3*TM8^72bB9NOR4^NKh4xRcMg^qu1WbGOj9 z-Ws)EpBwXyvW3rwi4?C-G@_+OF&U&#+q-vdvB=fR+5L(~K? z3oHT6paA!hN#oQByb_P0$c-@ zft$g4unBAd+rb|28}K5?T!|c*1}*`WpaI+rZU=XRZD1GJ2mT0N1Sc&Rq9%fwU;$_V zJ>X98FxUZ}0)GTAfuUCsH*hYP0ZKs?XaHScE!YSi244qzz#l=;Lh1^b1{Q#2pbOjv zHi9kSaj+LW3tj}7MbsNG8!QDKU<23!c7X#xRSr?(z$|bLXa{$JFM_AQv*2Yg{7r-# zOa`;TLQn@*fIGov@D;Ed{1O}jFN2e+2sbzv%mP*5Mz9v#3mygA!4u$V@OMzO7{9S zfGW@q)`4EI9qa;6gM;8@aOyRr1E>HsV1?jvbVIj;C&7O3cQE8y@&RN)38(Z&!9nl>82)DJCYTIL!4hyIxD9Lsn?WCV3Ooy52IJmBJqA~RI`9r~H+U561be}= zV0aGQ;2ba$%mYh77q}g40*`^6U=Mf}90r4GhzmF!OawE*W#Agn2v&f#;7-sB9s}P4 zzX8vKA+^YYnc#Y`2HXWUgU7*B;92l87*|L7f(t<@r~+>RUEo%*5o`f{U>`ULUIN4G zkp+{%EKmWeKn+*}HiA!q9pJ~{S@0ql(m)=8ncxbr6s!PufX!e#cpU5o&w@ep$D_e{ zU^b`%HJ}x&0e6B%%J>p656l2(f#KlAd6XmYG}sNk0v-l;gFC<)&>- z#)HSkuE)l%j7^V?U5|}jk34etKiBr1gXdOVS6RI%cQbdmw$-aE0<*sG_LJUa^A~ZY zQE*@IWNp^h8`~R%S80y9%*fn6xmt7N9>Od2lUAf2(9fbt?lo2FP1-D1EE@BtLVJBd zqN)zfTvNo9;rAqX(zAjn4-aHfKI&P~r*FAqw^V+*R z*`{)Ze&#mD1{0^-v{`N?RO-|ESz=<$OSD;H!mVo^tK|l`&NjAQZ4TYV`5!fWx$?V} z`-9aSZC;kE>t42uOWM`>+N>{s*4H3vY4vb%c~w=ey_+leIy%}q)Hdykd#r=3Q6JJA zxqpuRp!#`ESy>fs5 z#*_mSo-YnvR9U`I-$8hjsK~W;H#e)tT&`BNHO3)<)mL1OPW~H$GT36uWN+xAp((E( z(P8gw)z`5vQ)-0{i`+-9Lt@KQ`H=E!Dsxwrg&Z}%-;?m+=OM`m4SZwFcudFDq zvISXv&E<(ZdqMCMNq*CcTyws4c^Bp6&0$FME%hzz6B;~s(N&dXZA&{Bi+1Mfs8Toa zU9INo+k+b{?`N)7?aYMqzg)iK(^p--gwB!qo3S(Z8LPA0xa!=W=yC{Go>F{<%hNeC z-sR}x$0cj(1kEjLT24v3x}CbpW}+buZ(dVtZL{1js>UVd)$xwI#oXPi-KxH1OmvkT zF|2CN!m^ycnq8@XIx(8x+9dZ*suvwz5R!j5yeK5|f{@7V?`o(Mia=Mf!!x1!=CH*T zbEf9RfqL9LS99}jCzsT*E%6EAOq({t*ndx(F1XN`z8{zz_dgWg^qJQEPsDV=)M>{3 z-oWIz-+bIvWfvH0^^ks!EawDe%r?6n`MkO(tP#R&?aZrJ2I(>;B}3==OOaXU?#E57 z;eNap^-DJg$L1|Tnh+f>rB`bLb7xnFn17(dU3q2s zb#z|!-E#jrH?($jD)ppm!)35#6-s?O;_0;ed1SU7$@?OX_CFVy!`Rmp@VKN?T^;9Y z>8dzSm;c)$UIW)AugIH=g4KHp_>v8B9kx>MPTHyaBM$k>jjUEnZ<4RxQ&c`TcX`#K zt1IQ|`W$J5m-=GnFN%$%9Q=|T?LF!FuHpJl@r84)DmNLR9yn2RbbPK?a~3b0np-rt zy1bfu$E)TqygWxWQcoE-JoX;9V3A>-chdF2qk6lOYps%PYM;@>wT~^f z$LD;PqqSY*a%_DVPSu>NB$~9CZ%?<$)pm1Tt+_T> zb)~pzX`^mSlcDSP@h9n;8>BVKY6niVom|VRZZWaabzLgu_l-tL%g*k)8yT{ic4COp zV@t#bj4PdJIm^4-@?>E24o9nulx}y-+?mc;YG^^YxSizqN=BsSGU}$boCI8bGYSvm z@qDY?D;wm<17?&gSDrW5GBh@0(=UW&UwRrD4}aF>=$7Z}E~m4NvbHp+k@PWUhH&t> zMVDQXYi(+n*2(yOuo=}!y6ADnpvbJ#xyYDrZf>emWxC(Xx7M3su`1VQ5jBI%y46}l z%?tSrdc+m*Tch^7wzG9A*ZMLuA-|M*Yr;ksYq?xo6&05+ynOyb8f+>Y3H;r`Wfi7T zJ*4B&**cA=DD{H0_qP3S>g>|YZw7sUG*ES`1MAur%ICJgPS@^BO>USvuP>#iZPfRa z)7i#zudG5>jZQV5lvy}WDhihpH{+*zo6a|BYU5?`KF!x^P3c7G-%lb}bwup-%bhf# zGA|2rP#TzAeaGtdt~T}Ykjv0@mGnw`b?kNVmL^#()M?J>gpNVRCH30OGvhs_8bZ?r z7b=wxOpNW6S{9fX+wp=&n;P<+T%cXAE(%TghWvERQrBu;NBsMt?QayW-0&c#Nv(warj zG={X|*Wfq@spDfD(erGi$M|kyqLa{zxkjU7_xpb3@Ldh+S5j<8Xxn;9VRLg+Z5VBJ zcAOtXL!EE3&UP+e!!*Oinvz> zT&a~Idv(B#^^;2it~5ZQ-nM{CbE}tv)W4%Sgt)XfR=-7$N2qe9QB-$mvkagX=qDWj zG$?hi9l3NeT9OpID@-vNyL7iONX)lTqkE%P+cenfm%5JDb>?e3>Kk)PJ)WFd=(guP zx9yQJLUUW&P4rkdn!aVhqD5CSyp`VN|7!2s!>TINw_kLds8ncVm}I2XFon4e?>e7Q zp)^rZNUbPDHww801T->g$f&T$P#JTKii{d7rmwrkPgb2|8#`&v^4y$kD7)g{*q)!e z9LRagZ*29a=fI#SIQdpSH6t6JU38MI7{=bMMJL(Hu8V!tBS1?|vWHuLj&hBxlkb56 zWmosY8SFQmCtf)TYJ-q@-b}>LONNg$b>?7pldnpR zpEEI`@5=5z*%tTe)}Cw&rU$&05oNOOH@9czt8dZO5#0S%aJ8t4>^hB%|H!FZV?Xb3>Nr zr7gxa)8LttlM+*B$0sFDjq`4dtn}8w*T~6+u3{3IPhF6fmx(H}tZy3(z~!JM`Tf>l zPmYiTZ%q;uazZ>ivUh}|@p)*ld(KG{lcr8~H@i2cd!J$}X3j`DqQKX=nQ`G z@C=t)v5|)H!G@WP^w`$YZ2$5=x~oD%y)~J=t9qw}xh3Xf8~RBcJ!hK)?Ogx@-II z7v}lSt`f*Urptl*gtbb@B?BhSNX^VkU74PXSenh27-D}Sdc}!-S>D4 zM`0M-%gxu_R=0za?)}Pw%&84%o+{8@=@*C#?5e@%P>Jo{!4TiuG4AIM9EHqQ2^`*X5gE%&FsJ#b7u^~60^ z_w9j?GOg!Xoh2u%$9I-*yqn41REH;)i52O)%0KO^9t8CX;A?0qgxGgJkyB9gVl*XU# z-XwYJ=ACd z?xKaFB*={4Elp1qIYl7npM0CjYXUjos)s3!d?;NJ` z99l}e%#pW`tPwb>rZVH=G-);(m#6`VZ`T{lOwUc7G=q>Yy)7=mUXsP?&*B-q zCMWsI-NvTq2%%bxPwaEoPEHFf#9X4Ukn0Y|Cw*%t5%Rga+P~Spw_GOuYbaypLWc&5|+|q$l^AdBj7oyjjoqHL^ z4zrZVx?ZSqs|H<}1wG&or2FFw7DDiVjNwQiErd*F=l{*kL)cj+djg^N=p=1Wa(eDk zG+Xm=0{4W3jQ7m~lfN-BJ(tB*8oC9O8SlgihMstYseW=szqQF3tlVQI*~8ZM-R{J^ zqqlojP+VqS+5+6XyK_S3g50#+8!_gAJTh${OPWlu`IYHO3Gncyum=woV?5&07c5`A zI6e2sIP7qb&qUDjoT)G-=aR*2&2*QKPH_ilE+Nz6XU~XF5CwO7$Ylhk>p}!5nZn)y z5%5d~fd#lQ1EY62TgOao66fy6)?G+aAt=1ZHGpD^vJsKkKO4Eg?YXMwV6FG=dctnd zjZ~7BlR18A-uN3bv&Q2HW_JH0{O^4_>(rH<8i7+IaB2ijjlloL5kNx_T*Uji0xuMQL-2QK?_a!}`uQ&& z0d))s{V%?~Q@8eiH3C6yFob)*N~hl^gWT_(f%#w5ZzbLaks&^&Z}5A7*5dzV|Ifc= z=h(yk7cUhLWC%NlB#~778&78A-BdD@%)s(g{CgSRv!Ct0ukqDuY~0y5{`9>%?pE)2 zEDh*=f8?bdD}r#me3DBtNfud*qh*o+Nym}1$RYy4N9x^uIN&@7{l;Dw;9o*klJWTL zWbCt))ico&JQ%fV|F&XPnDu$+iMw zf_g{QPnNr*`k%~0GDayI$5?`MLq0>NvwQbu=g4u6AAytIehzOKla4$M91GCWDc9H)Pw?NmS24r+D!YBS#| zunMgrtJo^BO06=h+}dbWSd~_lwZ*Eowpuk-tyO2$TXFUjJHbx0lkItSx$`6|V6k2v zFW|o67Vtmux#AK!PMR*=FMT9!Fy1y4Gv3TLL#zqbWNWUq#QKA^-ukn(&3emfv%0Kc zJHj??KpTn1p$>nWy-C}TIFHoY2_v5ZDpVGjS{2|S1(X` zb)q^;O;eYtx2kK^ht;Rmm(;h_ed;%AkTzVqK;yNE+AJ+iTc+Krt<@gZg7tH8C-Kf> z?0$3HVJ2IJVDTpLW$~ZlBlHpJH0^9{j+U-Hru|JT(Hry$#x(OLv&j6_B1P^Hk>Pw3 ze*oiiu`o$U7H$^S3(wIfBtx!~ign1zP1CZpKWa7F zZtZma_xiQ^3jHq_(O>klj6(Ze`x@s_hivtZe+jpQ-^Py>#?iZ^U!-{XfV@O`McJf2 zrIz5+T?VNq#KiHR#ruN$qQ`OB<$# z>JOVq_Ukrj!q;HovqQPd`G9!4_>nk(j;55x)92_mx?7ql$0+wHf5G`aQM#22Ra<3o zuu5I8R;hneUqhsxsZG#QwI#OC8N%kE&6|Tz?gB1_OXL17M2R2Lz49z&jxtRDgZ{Ry zIkt13Q{}wr>|y(NdNDeL8_DUM!;`VWexR3dN@`D9SNpTiB4bCp7(P?s;offCn zX>;1015St2>2x{WP7gZ;xWrs+t}}O7?^&7 zsY&Vs>LJzAuG6x$+q9)Rv3+*19b$*tVRksOCDM+vqwN@*v#G5jcVg}SIhkV5xBYg8 z9k6rke7nFdw2SOwyTmTF%j|M{qg`Q>$RJXI>kxUJ@8OBy6M}^hAyfzx!i5OoZJ|Z@ zLKr2ch)-aS?x6QeKS`ryL(Y@W>xUX$YPZ^ROrC~o5n7}crA2Eo8mCcB)l4l`i_@lP z30k6-tj*I>wE3D}JJXzCUT&tEH=7Td&zWzVNkE+EtR5@O{)~+=7v#p+NWM`xTfCB< zBXvmM$MVPK|+w2 zfM~czEmn78G!5;q+6P*w9%_s;es8Flo0-P_MuGW+`K@)0{f&Ld4tCCRu5f0uYrvO# zvsk5EBKIk`hu6g!bQS%Yj+AytpGw`*4CP{VlKP-ptB%wz(HgWf^(*yf^>AajnPJ^* ztpm0lv`)ty++tVTd+aZ5GCv5<*`d$D&F4PjJ`ytNW7L)=OPi(7r03;-$ZyI&$b*#- z7(>W{dfAMx}+!SbM-~~ zQvD9SO5dVa>s$32y;iT&>w#ap^hUkG*kv>tO-8fPVze4eX;zuF zW}R7YHkiB2Ml;>M+y2=8#Xj3HoOI`I=P%A{&Ib;`7gA@iA?22F8@U?pb?zWHisyKn zf1BUKxA7MUmk85@*}@XxPN7ox5?TCv(H0ZL$HXRauXs@WS-gNwpeyK0$gURYMO`u{ zn{&)od!K#S9_?g052FJ8#OAEX%gw>uDCG9z+-sP*)A+Y(qBK`pE&mM|`<*-*G5Ld* z=HBs_dY67!Kg~Gbm}H#GK3^8ZV46I{y~@4MjpoPl7JoOtncvNi5aNW}g~8GU$&#i? z3#4qRNLnpDBK=j`Exm;b_my;58YmB!$H?PkMUIs(mn-Eb9xm1Z)HUQTS zD`%@IYPNcdx>VbweQJDfbeY78vl6XtYbdL0l|f*{gd7$!fsX6MDshh(L@%J*rMYsJ zoG-7(F~3)asG;g)twbBESLnPk%{ap>um;#?*<{Q4L7HTNSok)Mfq*w257Iyz9eNSGxo6)VJN=_j;C z+9vsx3?-oCDEUf(Qm7Ou#Y%}%s+1|^%0{I^sZ^?zElRbrRjE;Gl{%$fX;5}4jY^Z! zth6YtN;x9$Bkfmhm42T-+PK8XG;T508_yaez#VddLqFSRIWwFjpmYl`78h0@IUGr{<~mX*;wwZHMuNF~VGCwwmucAF|Ih1(6iIH1jQdE8?jg z6}E%#Ti_^5b5ypCQVZIr5voyH!+u~Myk;Lm;5^H!s^&pKoc!&qJl)O>`^ zNm~$!z{?WzN9!Ux)&9HvsXfHeoLTI=ok6b7X0@b%{~I49Y!pIq>@m`<(x>vJx~R8e zjz^mRv}*19+5TjJi)$VHUxg}q4X)q~={~t$Zk3->!qm~~UbPQV*8)>U=vV1$_5J#L z#`&ll1Kik%1mn4#tKxQYjodq2H#dkM!7t$p`RDkTc^MhBUZ@f77XKl(i4l~e)9G@$ zp6;eUqAE4X!;~4y&*}x*B5i}#sHK^AnD3cGEz7#g8f=eZ*B3d!tIzy=`U{N)cl$;9 zqkKQ&c$@qZxa1r1yK* zy~c|`^=?zK9=BSpRMb1-R66gWHVlAvBt+n5a=&or@t5*f@b~hM^P`1m;cnq6;ao9Q z+#o(KHi!b9N$1mLK>Ww(%XAO@oc7SeQUGk|cgjP`J4y;FimKHDNwW3LdW^Bac*9s~ zJ_N2d%6i_eXK|D0jpZd=Dp$h&nLor&5dGpqA}`5OnzTq-kJ*1&+9ieHIDYMR{Zaiz z{T=-?)F#cCVJtN6Fm~JR_W9s1NluCLwL|6)aCzNKu0{Ap7%h%cvcZ#nQO;1$M;%(C zU8oN;74uPZV=rHS&3?uChRs3F08$KpXfC&k`z!YW7sOu%G<#a86}Ag63$F=p3GWGe zg?++j!a?CX;YZ9u~w`T>oJnM#73Zav)CfGA|~6BdmUn@_zhU=FLa9p;c;=+NA^F3Z2jZ-BOQ4WS<-?hsdFFm>e!g$dPiC9F1t=WGbuj zByhADN-j|C7HESV%FD`Y%3I2N%3j3OXUaj;;2)J=l|kw-XoYjs^H7O@k4h}522{i4 z>U1!)tJG9AU0nkGaD#fYdYfC1%hio)g<1*5x&>8vt6BqwP^Z?b4eBnn@g&NtFXNAB z9gjmj45WKmdrf;wdr#Yoy8Rgx+IQNIK+-|_Fnzdwj((m#4qSc$D!8Ff)Gybk>q)?i zR6Si^qA$~L&~Mg@^%A{QFVoBQji?oszfs?t^k%(9Z`IrMcKv|fp?9JxcI!RRTRtP$ z2!ZMfGs=x;jDtqEF~AHr4RbD3$p-TUpvO1nVKdB9tr=F1wHEp?%GT_w?VIeiz|L3g zHv3=pS1cEbyx0v#^?wSL^=s}Neggj?p95}r6MX@!`4Q_?_41g@j8sQQ$M02 z2gjU@k+0IOgxVQrMp|Q?cxWB(dK@mApU&&TZp8lY=v3%c71wc-GDdY&8N6tQ@qqcX z*=9aveQf=M-ADZZ7w=oRbNRV^CI5i9RIZQ>HBlX)ZPtF)?$;L>L(NX}HY?JOfOa5F z1Ki&?{}z|W|GtAWZW~X=t`OLVYxthR{$NM#E_YeFH4sFcOV%W(sC=G%&NxYPSwp9abl_ zdAD^tbc5-{I&sbvC&5W{lAU=@iZkCi3FVF?dm_R)!ebi1Dk`sO%Z+j{VsWIJpnjna*G7X!zp8(wkAb#W0)6ti5rkQrYbHVwR3j>O z*~6Xl9o?<916>`N#;pKTeVeNWTX|CWP?#vKkg}8qlx@m~s-hF~LNmc!4UObjnebpf zM>QMl2ySg1Nao>kRW5;B$!+1@lo!;W)K9dF^w;&l<^$FX)&j(13slrx@HreLaUfhDa z!)-wId58O!yOO_52*aJ^*b=vwRQp<|E&XEuK$r3 zLcc^cyb;``SiM_~I!2SXYhP-f(mPot*kC+hJZd}*^%rc81;d*I^tlVFZ-?0eH}4`V z)|zLfSo1Bvm0<-?1y1H5F0eDf^egQudkfU?R=dWowXcIdB=rMbFC>MZ&-?idKEUVj z`FsJ`Y`l;l%!B(dADk&e42U`KmI@Guzo!MXkQQOAOK2%AqvdoXjR9|1BQ2GWM~T(Y zD98H_8CpQg(ekwdpv6N#&~EDuHcm|gU2dhpTRR;b`WIom7%$!owlW-CcWAAJ#~dra;st_%q96*r8J@`i8={F`vFw^`x?;@#47 z(s(GhKY}lRj~Y8eJxBW&SnEt9!zjhs1WlrUz^H5Td}x5NN{0HmS`Wl4!EwsK5;htYMkV5Li&1TCHEJ+kbw<6> za1sZh!#Ea`hgs3~baqdXK6hO5p-NNWl3puRfSU$M=St6l+np`zaw?R-Td2~HLoXGB zA8pr7<4R+Wb*<}I@33FC;mx7bg#Y=*jTWvKMoM!KA3LGYUzbONn^mhM*5~qyk-}}_ z^Wsvv0f-a>R{4Vzg6w)1u6UQ~L!|6yIiBcq@sLGj5ns%g@TGi;oG#ym*}XzZS5_#u zD`%-$V1R#sr@m2tMjr}gy36#z=U!p$wSw&L?K; zFNp7p*C49nIH z;5dVobCk>B@ZX`VQ(jaKDI3*qfy-xT=fJmqP}`=pXfvRUTJ(F&?dCyX;s`d*MLrh? zr*R9pa_%*88hw@CBqhp4+8@Dr-obv@rwr#q|9={o+S_6~og=5fr_6A@h?R1Yd8sh&*2RCXXnDlya+C)0KdqFgLwt~%Q8Ko+ zSqau`)Q{^>J+4RXSb^TtDs-OKpzpK^U8l!TWuHOEX@}Kd?Y5e%Jz%E$!ArjaEB(nL z_G$3LN5Bmq126nyIN>sU@JZ-Q&49ObH5~9o@V|3W4R3+>eHWbX4X8q!QG=dB1$q%G z{S~{>eg}NzV<_z}>`wT#6tk}04=?&z^&cv@t2R{|s4v$)(huoF zjDHy|P!`Kvm+cYjS0e8PW@ZrUQDOxQ0R5GG@!lE8pVfa@=bABz*|Wzmk65Fg+Zo5vfN3H)3=S$f4>cup>^N0`y1( za%AWMU`M`Q0Q4yOk2HVlzt#HTMuZUwM2R+HfGHGx64QtUqRcZ=fGK`(hJcY{Pm=z8biUb0wmI(}sv!(!r60PL_fX7z% z>wq^{yWkc#SVLBjO4@v+9P#esg1HbNSr``%EQ{o#fMziq2M<8yOk`>tHwDTxkxS<0p*K4p-OdbT zZxL6F3@!y*Er%CW!Bs+IZsDrAt?+khxjL?%Yv6W)Z#HqwTnpFAwH@Ohgz%y0w}$f( zV7XCzG#>-xq`bQVDNl3t!D|HJgP%%sl7bC<- zV1Be1BXS}YRdm7Wh766I9^G_ApN2z4h>zU@HN4%!J!?S^+wB%c%vTn&}NfUGe$z6I!$eE_MvYrV1)Q0@q#+7dk|qA{WDx>OmhrA04p{bgcdGf?L&a^uEiW z`-6eoMd+<|>l7GTjZSJ5Fs=fa6$T6{#Z~xl#zN@hE}KK1Zb2Qy{e=#4pXZ50CT&D! zgd);Q5V-`ASb)gt6k?!~TfmIE@gz++5Jv?Inuq>>4%kl-ysa|yKq|p}YJnmxK#p#B zG~qxB6^`CKAVL9)J?;Y5vn{78f(7nhsp}bIdTD1R`ChWMm4lnt?PX@qN~>|x1fXACby$I)d5xB zEfd9uCkaB8FeMy{D^iJq=891`MTO>y>wOlCf>7t=I(zEdUnWP9uRY8^LNr zp|eZi8xzGu@25uTRATT6+CCF(P2b`hg4$T!+{=U zK#E|XLXlmEJff(j)p$k--#$&E!SADxB^9V$VW>r=h+iLSMIo@iOW?rWx4=`10;;wl z?_VRd9;54n^GacYEJy231z_SP|3iC&S zXmMaK$%sBb+_!vSS}{X8#*oKV5ChBx2fO5w*J&b-M#|*@O5BL9LEJosL0`HpMtp>10%BKV~@}kyng-C`V7U z3jNR;^g_Vv>pA=F7#l0=)Z)a_Y#HY7AY!k9I9?IDy|>VnvWbRhQC=31y=>N zQiBTH0AINoN~IlDwF?#1hiV!oML?s(pq84bqY0>?DX55wYu!x}sl(tsyIn&IBG zqb7DKJ@D#7)G##yzDOv!jQ#t+9PAF8QXEmg~1#Z(Qfs6+R(5znl)!l&tg zH`fDqE(9J;1fDdD!Bb`?{Fww)*c5cq1Mp@F(FZC;CRYGos`1og9iF9VgeTLgwZoC= zg1+)WTZKVaML| -#include -#else #include #include -#endif // return data from the server #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) diff --git a/iguana.vcxproj b/iguana.vcxproj index e7a0d7a57..16d1eced8 100644 --- a/iguana.vcxproj +++ b/iguana.vcxproj @@ -73,12 +73,16 @@ true + $(ProjectDir)\includes;$(IncludePath) + $(ProjectDir)\OSlibs\win;$(LibraryPath) true false + C:\Users\faded_000\Desktop\needupdate\includes;$(IncludePath) + C:\Users\faded_000\Desktop\needupdate\OSlibs\win;$(LibraryPath) false @@ -97,7 +101,7 @@ Console true - Ws2_32.lib;pthreadVC2.lib;nanomsg.lib;%(AdditionalDependencies) + Ws2_32.lib;pthreadVC2.lib;nanomsg.lib;libcurl.lib;%(AdditionalDependencies) .\iguana;.\OSlibs\win;%(AdditionalLibraryDirectories) @@ -133,7 +137,7 @@ true true true - Ws2_32.lib;pthreadVC2.lib;nanomsg.lib;%(AdditionalDependencies) + Ws2_32.lib;pthreadVC2.lib;nanomsg.lib;libcurl.lib;%(AdditionalDependencies) .\OSlibs\win\release;%(AdditionalLibraryDirectories) diff --git a/includes/curl/.gitignore b/includes/curl/.gitignore new file mode 100644 index 000000000..228a961fb --- /dev/null +++ b/includes/curl/.gitignore @@ -0,0 +1,4 @@ +curlbuild.h +curlver.h.dist +stamp-h2 +stamp-h3 diff --git a/includes/curl/Makefile.am b/includes/curl/Makefile.am new file mode 100644 index 000000000..7c924fcb5 --- /dev/null +++ b/includes/curl/Makefile.am @@ -0,0 +1,53 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### +pkginclude_HEADERS = \ + curl.h curlver.h easy.h mprintf.h stdcheaders.h multi.h \ + typecheck-gcc.h curlbuild.h curlrules.h + +pkgincludedir= $(includedir)/curl + +# curlbuild.h does not exist in the git tree. When the original libcurl +# source code distribution archive file is created, curlbuild.h.dist is +# renamed to curlbuild.h and included in the tarball so that it can be +# used directly on non-configure systems. +# +# The distributed curlbuild.h will be overwritten on configure systems +# when the configure script runs, with one that is suitable and specific +# to the library being configured and built. +# +# curlbuild.h.in is the distributed template file from which the configure +# script creates curlbuild.h at library configuration time, overwiting the +# one included in the distribution archive. +# +# curlbuild.h.dist is not included in the source code distribution archive. + +EXTRA_DIST = curlbuild.h.in + +DISTCLEANFILES = curlbuild.h + +checksrc: + @@PERL@ $(top_srcdir)/lib/checksrc.pl -Wcurlbuild.h -D$(top_srcdir)/include/curl $(pkginclude_HEADERS) $(EXTRA_DIST) + +if CURLDEBUG +# for debug builds, we scan the sources on all regular make invokes +all-local: checksrc +endif diff --git a/includes/curl/curl.h b/includes/curl/curl.h new file mode 100644 index 000000000..7c7d28d6a --- /dev/null +++ b/includes/curl/curl.h @@ -0,0 +1,2551 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + +#include "curlver.h" /* libcurl version defines */ +#include "curlbuild.h" /* libcurl build definitions */ +#include "curlrules.h" /* libcurl rules enforcement */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else +typedef void CURL; +typedef void CURLSH; +#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist *contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_READ_SIZE + /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ +#define CURL_MAX_READ_SIZE 524288 +#endif + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char *b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of miliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAINFO, STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAPATH, STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CINIT(PROXY_SSLVERSION, LONG, 250), + + /* Set a username for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + + /* CRL file for proxy */ + CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CINIT(PROXY_SSL_OPTIONS, LONG, 261), + + /* Name of pre proxy to use. */ + CINIT(PRE_PROXY, STRINGPOINT, 262), + + /* The public key in DER form used to validate the proxy public key + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), + + /* Path to an abstract Unix domain socket */ + CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), + + /* Suppress proxy CONNECT response headers from user callbacks */ + CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + CURL_SSLVERSION_TLSv1_3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum { + CURL_SSLVERSION_MAX_NONE = 0, + CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), + CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), + CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), + CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), + CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), + + /* never use, keep last */ + CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details + + !checksrc! disable SPACEBEFOREPAREN 2 +*/ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_CYASSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL 1 +#define CURLSSLBACKEND_BORINGSSL 1 +#define CURLSSLBACKEND_WOLFSSL 6 + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_SLIST + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_SLIST + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, + CURLINFO_PROTOCOL = CURLINFO_LONG + 48, + CURLINFO_SCHEME = CURLINFO_STRING + 49, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 49 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FOURTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is suported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ +#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/includes/curl/curlbuild.h.cmake b/includes/curl/curlbuild.h.cmake new file mode 100644 index 000000000..bbb31a940 --- /dev/null +++ b/includes/curl/curlbuild.h.cmake @@ -0,0 +1,197 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +#cmakedefine CURL_PULL_WS2TCPIP_H +#ifdef CURL_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_TYPES_H +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +#cmakedefine CURL_PULL_STDINT_H +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +#cmakedefine CURL_PULL_INTTYPES_H +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_SOCKET_H +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +#cmakedefine CURL_PULL_SYS_POLL_H +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CURL_SIZEOF_LONG ${CURL_SIZEOF_LONG} + +/* Integral data type used for curl_socklen_t. */ +#define CURL_TYPEOF_CURL_SOCKLEN_T ${CURL_TYPEOF_CURL_SOCKLEN_T} + +/* The size of `curl_socklen_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_SOCKLEN_T ${CURL_SIZEOF_CURL_SOCKLEN_T} + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +/* Signed integral data type used for curl_off_t. */ +#define CURL_TYPEOF_CURL_OFF_T ${CURL_TYPEOF_CURL_OFF_T} + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +/* curl_off_t formatting string directive without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_T "${CURL_FORMAT_CURL_OFF_T}" + +/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_TU "${CURL_FORMAT_CURL_OFF_TU}" + +/* curl_off_t formatting string directive with "%" conversion specifier. */ +#define CURL_FORMAT_OFF_T "${CURL_FORMAT_OFF_T}" + +/* The size of `curl_off_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_OFF_T ${CURL_SIZEOF_CURL_OFF_T} + +/* curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_T ${CURL_SUFFIX_CURL_OFF_T} + +/* unsigned curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_TU ${CURL_SUFFIX_CURL_OFF_TU} + +#endif /* __CURL_CURLBUILD_H */ diff --git a/includes/curl/curlbuild.h.dist b/includes/curl/curlbuild.h.dist new file mode 100644 index 000000000..ae95095fa --- /dev/null +++ b/includes/curl/curlbuild.h.dist @@ -0,0 +1,586 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * See file include/curl/curlbuild.h.in, run configure, and forget + * that this file exists it is only used for non-configure systems. + * But you can keep reading if you want ;-) + * + */ + +/* ================================================================ */ +/* NOTES FOR NON-CONFIGURE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * Try to keep one section per platform, compiler and architecture, + * otherwise, if an existing section is reused for a different one and + * later on the original is adjusted, probably the piggybacking one can + * be adversely changed. + * + * In order to differentiate between platforms/compilers/architectures + * use only compiler built in predefined preprocessor symbols. + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a + * 64-bit wide signed integral data type. The width of this data type + * must remain constant and independent of any possible large file + * support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a + * 32-bit wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This + * rule shall only be violated if off_t is the only 64-bit data type + * available and the size of off_t is independent of large file support + * settings. Keep your build on the safe side avoiding an off_t gating. + * If you have a 64-bit off_t then take for sure that another 64-bit + * data type exists, dig deeper and you will find it. + * + * NOTE 3: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.dist or + * at file include/curl/curlbuild.h, this is due to the following reason: + * file include/curl/curlbuild.h.dist is renamed to include/curl/curlbuild.h + * when the libcurl source code distribution archive file is created. + * + * File include/curl/curlbuild.h.dist is not included in the distribution + * archive. File include/curl/curlbuild.h is not present in the git tree. + * + * The distributed include/curl/curlbuild.h file is only intended to be used + * on systems which can not run the also distributed configure script. + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + * If you check out from git on a non-configure platform, you must run the + * appropriate buildconf* script to set up curlbuild.h and other local files. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR NON-CONFIGURE SYSTEMS ONLY */ +/* ================================================================ */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__SALFORDC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__TURBOC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__WATCOMC__) +# if defined(__386__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__LCC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__SYMBIAN32__) +# if defined(__EABI__) /* Treat all ARM compilers equally */ +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__CW32__) +# pragma longlong on +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__VC32__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__MWERKS__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(_WIN32_WCE) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__MINGW32__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__OS400__) +# if defined(__ILEC400__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__MVS__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# define CURL_SIZEOF_LONG 4 +# elif defined(_LP64) +# define CURL_SIZEOF_LONG 8 +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# define CURL_SIZEOF_LONG 4 +# elif defined(_LP64) +# define CURL_SIZEOF_LONG 8 +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_SIZEOF_LONG 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) +# if !defined(__LP64__) && (defined(__ILP32__) || \ + defined(__i386__) || defined(__ppc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__)) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) +# define CURL_SIZEOF_LONG 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +# error "Unknown non-configure build target!" + Error Compilation_aborted_Unknown_non_configure_build_target +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +#endif /* __CURL_CURLBUILD_H */ diff --git a/includes/curl/curlbuild.h.in b/includes/curl/curlbuild.h.in new file mode 100644 index 000000000..ffab35670 --- /dev/null +++ b/includes/curl/curlbuild.h.in @@ -0,0 +1,197 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +#undef CURL_PULL_WS2TCPIP_H +#ifdef CURL_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#undef CURL_PULL_SYS_TYPES_H +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +#undef CURL_PULL_STDINT_H +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +#undef CURL_PULL_INTTYPES_H +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +#undef CURL_PULL_SYS_SOCKET_H +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +#undef CURL_PULL_SYS_POLL_H +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#undef CURL_SIZEOF_LONG + +/* Integral data type used for curl_socklen_t. */ +#undef CURL_TYPEOF_CURL_SOCKLEN_T + +/* The size of `curl_socklen_t', as computed by sizeof. */ +#undef CURL_SIZEOF_CURL_SOCKLEN_T + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +/* Signed integral data type used for curl_off_t. */ +#undef CURL_TYPEOF_CURL_OFF_T + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +/* curl_off_t formatting string directive without "%" conversion specifier. */ +#undef CURL_FORMAT_CURL_OFF_T + +/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +#undef CURL_FORMAT_CURL_OFF_TU + +/* curl_off_t formatting string directive with "%" conversion specifier. */ +#undef CURL_FORMAT_OFF_T + +/* The size of `curl_off_t', as computed by sizeof. */ +#undef CURL_SIZEOF_CURL_OFF_T + +/* curl_off_t constant suffix. */ +#undef CURL_SUFFIX_CURL_OFF_T + +/* unsigned curl_off_t constant suffix. */ +#undef CURL_SUFFIX_CURL_OFF_TU + +#endif /* __CURL_CURLBUILD_H */ diff --git a/includes/curl/curlrules.h b/includes/curl/curlrules.h new file mode 100644 index 000000000..55d21f68f --- /dev/null +++ b/includes/curl/curlrules.h @@ -0,0 +1,262 @@ +#ifndef __CURL_CURLRULES_H +#define __CURL_CURLRULES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* COMPILE TIME SANITY CHECKS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * All checks done in this file are intentionally placed in a public + * header file which is pulled by curl/curl.h when an application is + * being built using an already built libcurl library. Additionally + * this file is also included and used when building the library. + * + * If compilation fails on this file it is certainly sure that the + * problem is elsewhere. It could be a problem in the curlbuild.h + * header file, or simply that you are using different compilation + * settings than those used to build the library. + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * Do not deactivate any check, these are done to make sure that the + * library is properly built and used. + * + * You can find further help on the libcurl development mailing list: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * NOTE 2 + * ------ + * + * Some of the following compile time checks are based on the fact + * that the dimension of a constant array can not be a negative one. + * In this way if the compile time verification fails, the compilation + * will fail issuing an error. The error description wording is compiler + * dependent but it will be quite similar to one of the following: + * + * "negative subscript or subscript is too large" + * "array must have at least one element" + * "-1 is an illegal array size" + * "size of array is negative" + * + * If you are building an application which tries to use an already + * built libcurl library and you are getting this kind of errors on + * this file, it is a clear indication that there is a mismatch between + * how the library was built and how you are trying to use it for your + * application. Your already compiled or binary library provider is the + * only one who can give you the details you need to properly use it. + */ + +/* + * Verify that some macros are actually defined. + */ + +#ifndef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing +#endif + +#ifndef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing +#endif + +/* + * Macros private to this header file. + */ + +#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 + +#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 + +/* + * Verify that the size previously defined and expected for long + * is the same as the one reported by sizeof() at compile time. + */ + +typedef char + __curl_rule_01__ + [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; + +/* + * Verify that the size previously defined and expected for + * curl_off_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_02__ + [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; + +/* + * Verify at compile time that the size of curl_off_t as reported + * by sizeof() is greater or equal than the one reported for long + * for the current compilation. + */ + +typedef char + __curl_rule_03__ + [CurlchkszGE(curl_off_t, long)]; + +/* + * Verify that the size previously defined and expected for + * curl_socklen_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_04__ + [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; + +/* + * Verify at compile time that the size of curl_socklen_t as reported + * by sizeof() is greater or equal than the one reported for int for + * the current compilation. + */ + +typedef char + __curl_rule_05__ + [CurlchkszGE(curl_socklen_t, int)]; + +/* ================================================================ */ +/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ +/* ================================================================ */ + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +/* + * Get rid of macros private to this header file. + */ + +#undef CurlchkszEQ +#undef CurlchkszGE + +/* + * Get rid of macros not intended to exist beyond this point. + */ + +#undef CURL_PULL_WS2TCPIP_H +#undef CURL_PULL_SYS_TYPES_H +#undef CURL_PULL_SYS_SOCKET_H +#undef CURL_PULL_SYS_POLL_H +#undef CURL_PULL_STDINT_H +#undef CURL_PULL_INTTYPES_H + +#undef CURL_TYPEOF_CURL_SOCKLEN_T +#undef CURL_TYPEOF_CURL_OFF_T + +#ifdef CURL_NO_OLDIES +#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */ +#endif + +#endif /* __CURL_CURLRULES_H */ diff --git a/includes/curl/curlver.h b/includes/curl/curlver.h new file mode 100644 index 000000000..7beda3fa7 --- /dev/null +++ b/includes/curl/curlver.h @@ -0,0 +1,77 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2017 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.54.0-DEV" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 54 +#define LIBCURL_VERSION_PATCH 0 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x073600 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date should follow this template: + * + * "Mon Feb 12 11:35:33 UTC 2007" + */ +#define LIBCURL_TIMESTAMP "DEV" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --git a/includes/curl/easy.h b/includes/curl/easy.h new file mode 100644 index 000000000..752c5049f --- /dev/null +++ b/includes/curl/easy.h @@ -0,0 +1,102 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/includes/curl/mprintf.h b/includes/curl/mprintf.h new file mode 100644 index 000000000..e20f546e1 --- /dev/null +++ b/includes/curl/mprintf.h @@ -0,0 +1,50 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ +#include "curl.h" /* for CURL_EXTERN */ + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/includes/curl/multi.h b/includes/curl/multi.h new file mode 100644 index 000000000..d1e00cc5d --- /dev/null +++ b/includes/curl/multi.h @@ -0,0 +1,439 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else +typedef void CURLM; +#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic informations. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/includes/curl/stdcheaders.h b/includes/curl/stdcheaders.h new file mode 100644 index 000000000..027b6f421 --- /dev/null +++ b/includes/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread(void *, size_t, size_t, FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/includes/curl/typecheck-gcc.h b/includes/curl/typecheck-gcc.h new file mode 100644 index 000000000..3d683152b --- /dev/null +++ b/includes/curl/typecheck-gcc.h @@ -0,0 +1,624 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__(option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__(info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string ('char *' or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a 'FILE *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a 'struct curl_httppost *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to 'char *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (CURLINFO_SLIST < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true iff expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void *)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *)) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func), type*)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (_curl_write_callback2)(const char *, size_t, size_t, + const void *); +typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (_curl_write_callback5)(const void *, size_t, size_t, + const void *); +typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ From 630415d0a01877efc6a26d309b190a875f56ad43 Mon Sep 17 00:00:00 2001 From: fadedreamz Date: Wed, 15 Mar 2017 04:53:18 -0500 Subject: [PATCH 0005/2705] fixed an issue with fixed path location for include and library path in makefile Signed-off-by: fadedreamz --- iguana.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana.vcxproj b/iguana.vcxproj index 16d1eced8..32dc556d7 100644 --- a/iguana.vcxproj +++ b/iguana.vcxproj @@ -81,8 +81,8 @@ false - C:\Users\faded_000\Desktop\needupdate\includes;$(IncludePath) - C:\Users\faded_000\Desktop\needupdate\OSlibs\win;$(LibraryPath) + $(ProjectDir)\includes;$(IncludePath) + $(ProjectDir)\OSlibs\win;$(LibraryPath) false From 0c479bce28499d7f89bef9a50957c061d1153033 Mon Sep 17 00:00:00 2001 From: fadedreamz Date: Wed, 15 Mar 2017 05:10:40 -0500 Subject: [PATCH 0006/2705] added libcurl, openssl dll for x86, updated makefile and headerfiles Signed-off-by: fadedreamz --- iguana.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana.vcxproj b/iguana.vcxproj index 32dc556d7..ab0c9975d 100644 --- a/iguana.vcxproj +++ b/iguana.vcxproj @@ -73,16 +73,16 @@ true - $(ProjectDir)\includes;$(IncludePath) - $(ProjectDir)\OSlibs\win;$(LibraryPath) + .\includes;$(IncludePath) + .\OSlibs\win;$(LibraryPath) true false - $(ProjectDir)\includes;$(IncludePath) - $(ProjectDir)\OSlibs\win;$(LibraryPath) + .\includes;$(IncludePath) + .\OSlibs\win;$(LibraryPath) false From 667ea67a506667d759a0be758c3ea02b7e753263 Mon Sep 17 00:00:00 2001 From: fadedreamz Date: Wed, 15 Mar 2017 05:15:03 -0500 Subject: [PATCH 0007/2705] updated makefile for msvs Signed-off-by: fadedreamz --- iguana.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana.vcxproj b/iguana.vcxproj index ab0c9975d..5a0050e59 100644 --- a/iguana.vcxproj +++ b/iguana.vcxproj @@ -73,16 +73,16 @@ true - .\includes;$(IncludePath) - .\OSlibs\win;$(LibraryPath) + $(ProjectDir)\includes;$(ProjectDir)\includes\curl;$(IncludePath) + $(ProjectDir)\OSlibs\win;$(LibraryPath) true false - .\includes;$(IncludePath) - .\OSlibs\win;$(LibraryPath) + $(ProjectDir)\includes;$(ProjectDir)\includes\curl;$(IncludePath) + $(ProjectDir)\OSlibs\win;$(LibraryPath) false From 5d0170cfd4cd9b56e428d3ff64e4821ba7728a14 Mon Sep 17 00:00:00 2001 From: fadedreamz Date: Wed, 15 Mar 2017 05:18:28 -0500 Subject: [PATCH 0008/2705] added missing header file due to gitignore Signed-off-by: fadedreamz --- includes/curl/curlbuild.h | 586 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 586 insertions(+) create mode 100644 includes/curl/curlbuild.h diff --git a/includes/curl/curlbuild.h b/includes/curl/curlbuild.h new file mode 100644 index 000000000..ae95095fa --- /dev/null +++ b/includes/curl/curlbuild.h @@ -0,0 +1,586 @@ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * See file include/curl/curlbuild.h.in, run configure, and forget + * that this file exists it is only used for non-configure systems. + * But you can keep reading if you want ;-) + * + */ + +/* ================================================================ */ +/* NOTES FOR NON-CONFIGURE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * Try to keep one section per platform, compiler and architecture, + * otherwise, if an existing section is reused for a different one and + * later on the original is adjusted, probably the piggybacking one can + * be adversely changed. + * + * In order to differentiate between platforms/compilers/architectures + * use only compiler built in predefined preprocessor symbols. + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a + * 64-bit wide signed integral data type. The width of this data type + * must remain constant and independent of any possible large file + * support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a + * 32-bit wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This + * rule shall only be violated if off_t is the only 64-bit data type + * available and the size of off_t is independent of large file support + * settings. Keep your build on the safe side avoiding an off_t gating. + * If you have a 64-bit off_t then take for sure that another 64-bit + * data type exists, dig deeper and you will find it. + * + * NOTE 3: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.dist or + * at file include/curl/curlbuild.h, this is due to the following reason: + * file include/curl/curlbuild.h.dist is renamed to include/curl/curlbuild.h + * when the libcurl source code distribution archive file is created. + * + * File include/curl/curlbuild.h.dist is not included in the distribution + * archive. File include/curl/curlbuild.h is not present in the git tree. + * + * The distributed include/curl/curlbuild.h file is only intended to be used + * on systems which can not run the also distributed configure script. + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + * If you check out from git on a non-configure platform, you must run the + * appropriate buildconf* script to set up curlbuild.h and other local files. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR NON-CONFIGURE SYSTEMS ONLY */ +/* ================================================================ */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__SALFORDC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__TURBOC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__WATCOMC__) +# if defined(__386__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__LCC__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__SYMBIAN32__) +# if defined(__EABI__) /* Treat all ARM compilers equally */ +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__CW32__) +# pragma longlong on +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__VC32__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__MWERKS__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(_WIN32_WCE) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__MINGW32__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +#elif defined(__OS400__) +# if defined(__ILEC400__) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__MVS__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# define CURL_SIZEOF_LONG 4 +# elif defined(_LP64) +# define CURL_SIZEOF_LONG 8 +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# define CURL_SIZEOF_LONG 4 +# elif defined(_LP64) +# define CURL_SIZEOF_LONG 8 +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_SIZEOF_LONG 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_FORMAT_OFF_T "%I64d" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 4 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) +# if !defined(__LP64__) && (defined(__ILP32__) || \ + defined(__i386__) || defined(__ppc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__)) +# define CURL_SIZEOF_LONG 4 +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_FORMAT_OFF_T "%lld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) +# define CURL_SIZEOF_LONG 8 +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_FORMAT_OFF_T "%ld" +# define CURL_SIZEOF_CURL_OFF_T 8 +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_SIZEOF_CURL_SOCKLEN_T 4 +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +# error "Unknown non-configure build target!" + Error Compilation_aborted_Unknown_non_configure_build_target +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +#endif /* __CURL_CURLBUILD_H */ From dddccd26fd6dcef53b5cb344e30b1e9f70a11be9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 15 Mar 2017 14:50:51 +0200 Subject: [PATCH 0009/2705] Support null username in path creation --- basilisk/basilisk_MSG.c | 2 +- iguana/iguana_chains.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_MSG.c b/basilisk/basilisk_MSG.c index 6619c4db0..0fba54c91 100755 --- a/basilisk/basilisk_MSG.c +++ b/basilisk/basilisk_MSG.c @@ -98,7 +98,7 @@ char *basilisk_iterate_MSG(struct supernet_info *myinfo,uint32_t channel,uint32_ // char str[65],str2[65]; printf("MSGiterate (%s) -> (%s)\n",bits256_str(str,srchash),bits256_str(str2,desthash)); array = cJSON_CreateArray(); portable_mutex_lock(&myinfo->messagemutex); - printf("iterate_MSG width.%d channel.%d msgid.%d src.%llx -> %llx\n",origwidth,channel,msgid,(long long)srchash.txid,(long long)desthash.txid); + //printf("iterate_MSG width.%d channel.%d msgid.%d src.%llx -> %llx\n",origwidth,channel,msgid,(long long)srchash.txid,(long long)desthash.txid); for (i=0; i Date: Wed, 15 Mar 2017 17:29:54 +0200 Subject: [PATCH 0010/2705] Make windows specific path --- iguana/iguana_chains.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/iguana_chains.c b/iguana/iguana_chains.c index 7b610fbea..4fc5a0b76 100755 --- a/iguana/iguana_chains.c +++ b/iguana/iguana_chains.c @@ -232,9 +232,12 @@ void set_coinconfname(char *fname,char *coinstr,char *userhome,char *coindir,cha sprintf(confname,"%s.conf",buf); } printf("userhome.(%s) coindir.(%s) confname.(%s)\n",userhome,coindir,confname); - if ( userhome != 0 && userhome[0] != 0 ) +#ifdef WIN32 + if ( userhome == 0 || userhome[0] == 0 ) + sprintf(fname,"%s/%s",coindir,confname); + else +#endif sprintf(fname,"%s/%s/%s",userhome,coindir,confname); - else sprintf(fname,"%s/%s",coindir,confname); } uint16_t extract_userpass(char *serverport,char *userpass,char *coinstr,char *userhome,char *coindir,char *confname) From 4fbdb279cb7c9488d722b9247a167a95a7714f6f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 15 Mar 2017 19:05:14 +0200 Subject: [PATCH 0011/2705] Test --- .gitignore | 2 ++ iguana/tests/crash | 6 ++++++ iguana/tests/test | 3 --- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100755 iguana/tests/crash delete mode 100755 iguana/tests/test diff --git a/.gitignore b/.gitignore index 593be70c7..f3176906f 100755 --- a/.gitignore +++ b/.gitignore @@ -208,3 +208,5 @@ iguana/DB/SWAPS/467927158-3437055573 iguana/DB/SWAPS/270159951-1269722638 iguana/DB/SWAPS/244991424-1008712592 + +iguana/confs/1cc0270abba7f4463a3dcb9908b9d875691a6773fe3cc1b4302233ed76665300 diff --git a/iguana/tests/crash b/iguana/tests/crash new file mode 100755 index 000000000..82a39bd5d --- /dev/null +++ b/iguana/tests/crash @@ -0,0 +1,6 @@ +coins/basilisk/kmd + +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"bitcoinrpc\",\"method\":\"walletpassphrase\",\"password\":\"amount common obey erupt ensure salon shrug digital phone vacant provide word nurse legend shaft ritual strike black fiscal circle dove tone inmate plunge\",\"timeout\":864445678904}" + +curl --url "http://127.0.0.1:7778" --data "{\"symbol\":\"KMD\",\"agent\":\"basilisk\",\"method\":\"utxorawtx\",\"vals\":{\"timelock\":0,\"changeaddr\":\"RD5Sj6igy53nscMiFS4ECXByfqVeyV9NdG\",\"destaddr\":\"RD5Sj6igy53nscMiFS4ECXByfqVeyV9NdG\",\"txfee\":0,\"amount\":0.0001,\"sendflag\":0},\"utxos\":[{\"bestblock\":\"0000119186ecfaa8d72a7d3c62e78135043db220a6d29a9605f1fbe383bcedfb\",\"confirmations\":65549,\"value\":0.04900000,\"scriptPubKey\":{\"asm\":\"OP_DUP OP_HASH160 29a7bd36e6913b674bb2b5c65e61a6544426ddd7 OP_EQUALVERIFY OP_CHECKSIG\",\"hex\":\"76a91429a7bd36e6913b674bb2b5c65e61a6544426ddd788ac\",\"reqSigs\":1,\"type\":\"pubkeyhash\",\"addresses\":[\"RD5Sj6igy53nscMiFS4ECXByfqVeyV9NdG\"]},\"version\":1,\"coinbase\":false,\"randipbits\":579036043,\"coin\":\"KMD\",\"txid\":\"b32af9977bc8ed0e54631d27f490c79841a03bccce4d6b8181456657b06194ef\",\"vout\":0,\"amount\":0.04900000}, {\"bestblock\":\"0000119186ecfaa8d72a7d3c62e78135043db220a6d29a9605f1fbe383bcedfb\",\"confirmations\":65553,\"value\":1,\"scriptPubKey\":{\"asm\":\"OP_DUP OP_HASH160 29a7bd36e6913b674bb2b5c65e61a6544426ddd7 OP_EQUALVERIFY OP_CHECKSIG\",\"hex\":\"76a91429a7bd36e6913b674bb2b5c65e61a6544426ddd788ac\",\"reqSigs\":1,\"type\":\"pubkeyhash\",\"addresses\":[\"RD5Sj6igy53nscMiFS4ECXByfqVeyV9NdG\"]},\"version\":1,\"coinbase\":false,\"randipbits\":3795805790,\"coin\":\"KMD\",\"txid\":\"84ca2ba7f621c820ab642e358813fcc33171c9999a47bb99dcf3a309dc847419\",\"vout\":1,\"amount\":1}]}" + diff --git a/iguana/tests/test b/iguana/tests/test deleted file mode 100755 index 495928084..000000000 --- a/iguana/tests/test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -echo "{\"field\":\"requiredvalue\"}" > /tmp/foo -./jsoncmp /tmp/foo {\"fields\":[{\"field\":\"requiredvalue\"}]} From 7c7da1cf897c4084021ff18f76dd70e41c39bc8b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 15 Mar 2017 19:06:10 +0200 Subject: [PATCH 0012/2705] test --- iguana/tests/crash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/tests/crash b/iguana/tests/crash index 82a39bd5d..33cf53106 100755 --- a/iguana/tests/crash +++ b/iguana/tests/crash @@ -1,4 +1,4 @@ -coins/basilisk/kmd +../coins/basilisk/kmd curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"bitcoinrpc\",\"method\":\"walletpassphrase\",\"password\":\"amount common obey erupt ensure salon shrug digital phone vacant provide word nurse legend shaft ritual strike black fiscal circle dove tone inmate plunge\",\"timeout\":864445678904}" From 779732a8bae55cfe066c1e72ad4e84c98dfb2e16 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 15 Mar 2017 20:46:02 +0200 Subject: [PATCH 0013/2705] support wifstr that encode to less than 38 bytes --- iguana/exchanges/bitcoin.c | 18 +++++++++++++++--- iguana/iguana_sign.c | 2 +- iguana/mini-gmp.c | 2 +- iguana/tests/KMD.batch13 | 1 + iguana/tests/crash | 1 + 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index bf37462f0..a40524d11 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -107,18 +107,30 @@ int32_t base58encode_checkbuf(uint8_t addrtype,uint8_t *data,int32_t data_len) int32_t bitcoin_wif2priv(uint8_t *addrtypep,bits256 *privkeyp,char *wifstr) { - int32_t len = -1; bits256 hash; uint8_t buf[64]; + int32_t len = -1; bits256 hash; uint8_t buf[256]; + memset(buf,0,sizeof(buf)); if ( (len= bitcoin_base58decode(buf,wifstr)) >= 4 ) { // validate with trailing hash, then remove hash + if ( len < 38 ) + len = 38; hash = bits256_doublesha256(0,buf,len - 4); *addrtypep = *buf; memcpy(privkeyp,buf+1,32); - if ( (buf[len - 4]&0xff) == hash.bytes[31] && (buf[len - 3]&0xff) == hash.bytes[30] &&(buf[len - 2]&0xff) == hash.bytes[29] &&(buf[len - 1]&0xff) == hash.bytes[28] ) + if ( (buf[len - 4]&0xff) == hash.bytes[31] && (buf[len - 3]&0xff) == hash.bytes[30] &&(buf[len - 2]&0xff) == hash.bytes[29] && (buf[len - 1]&0xff) == hash.bytes[28] ) { - //printf("coinaddr.(%s) valid checksum\n",coinaddr); + //int32_t i; for (i=0; isuppress_pubkeys)) != 0 ) { //printf("back from bitcoin_hex2json (%s)\n",jprint(vins,0)); diff --git a/iguana/mini-gmp.c b/iguana/mini-gmp.c index ef9e235df..c2c975f12 100644 --- a/iguana/mini-gmp.c +++ b/iguana/mini-gmp.c @@ -4394,7 +4394,7 @@ int32_t bitcoin_base58decode(uint8_t *data,char *coinaddr) //memset(data,0,be_sz); //for (i=0; i Date: Thu, 16 Mar 2017 20:06:18 +0200 Subject: [PATCH 0014/2705] 300000 planned upgrade Fix interest granularity for long term utxo. 1/10 of a year to 1/9 has same interest result. Change to new calculation of minutes / 3652460 directly instead of via intermediate denominator to eliminate integer clipping Will activate at 300000 planned upgrade, so not urgent to update --- iguana/iguana_payments.c | 10 ++++++++-- iguana/tests/dexgetT | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index 0517b94a3..cdb27e36c 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -346,18 +346,24 @@ uint64_t _iguana_interest(uint32_t now,int32_t chainheight,uint32_t txlocktime,u int32_t minutes; uint64_t numerator=0,denominator=0,interest = 0; if ( (minutes= ((uint32_t)time(NULL) - 60 - txlocktime) / 60) >= 60 ) { + if ( minutes > 365 * 24 * 60 ) + minutes = 365 * 24 * 60; denominator = (((uint64_t)365 * 24 * 60) / minutes); if ( denominator == 0 ) denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually! if ( value > 25000LL*SATOSHIDEN && chainheight > 155949 ) { numerator = (value / 20); // assumes 5%! - interest = (numerator / denominator); + if ( chainheight < 300000 ) + interest = (numerator / denominator); + else interest = (numerator * minutes) / ((uint64_t)365 * 24 * 60); } else if ( value >= 10*SATOSHIDEN ) { numerator = (value * KOMODO_INTEREST); - interest = (numerator / denominator) / SATOSHIDEN; + if ( chainheight < 300000 || numerator * minutes < 365 * 24 * 60 ) + interest = (numerator / denominator) / SATOSHIDEN; + else interest = ((numerator * minutes) / ((uint64_t)365 * 24 * 60)) / SATOSHIDEN; } //fprintf(stderr,"komodo_interest.%d %lld %.8f nLockTime.%u tiptime.%u minutes.%d interest %lld %.8f (%llu / %llu)\n",chainheight,(long long)value,(double)value/SATOSHIDEN,txlocktime,now,minutes,(long long)interest,(double)interest/SATOSHIDEN,(long long)numerator,(long long)denominator); } diff --git a/iguana/tests/dexgetT b/iguana/tests/dexgetT index 7483dbd01..18241a84d 100755 --- a/iguana/tests/dexgetT +++ b/iguana/tests/dexgetT @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"gettransaction\",\"txid\":\"3c00ee16d12c6aae81863d1da485cdd6cd2b73847f8ab93de3663adf6c285e3b\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"gettransaction\",\"txid\":\"88794bbb699f130951c40dc99a27d2c7c7016e12824fd1040cbedf86980de04d\",\"symbol\":\"REVS\"}" From 1003e5b0d53627a875c1b14ab20c99a66e023e53 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 17 Mar 2017 02:53:55 +0200 Subject: [PATCH 0015/2705] Print coin name in vin error --- iguana/kmd_lookup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index f3abf52d2..0d6e2f2f9 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -117,7 +117,7 @@ int32_t kmd_transactionvin(struct iguana_info *coin,bits256 spendtxid,int32_t vi } return(0); } - char str[65]; printf("vin error %s vout.%d of %d vs ptr %p [%d] spent.%p\n",bits256_str(str,txid),vout,ptr!=0?ptr->numvouts:-1,ptr,ptr!=0?ptr->numvouts:-1,spendptr); + char str[65]; printf("%s.vin error %s vout.%d of %d vs ptr %p [%d] spent.%p\n",coin->symbol,bits256_str(str,txid),vout,ptr!=0?ptr->numvouts:-1,ptr,ptr!=0?ptr->numvouts:-1,spendptr); return(-1); } From fe11ff854ff1a7f410035e433f675a9d94b2ac2d Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 17 Mar 2017 06:20:17 +0200 Subject: [PATCH 0016/2705] Prevent 'A' qpreturn --- iguana/dpow/dpow_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/dpow/dpow_tx.c b/iguana/dpow/dpow_tx.c index 194285053..fac9033af 100755 --- a/iguana/dpow/dpow_tx.c +++ b/iguana/dpow/dpow_tx.c @@ -224,7 +224,7 @@ int32_t dpow_voutstandard(struct dpow_block *bp,uint8_t *serialized,int32_t m,in } printf("numvouts.%d len.%d RATIFY vouts\n",numvouts,len); } - if ( (src_or_dest == 0 || strcmp(bp->destcoin->symbol,"BTC") != 0) && (n= dpow_paxpending(extras,&paxwdcrc)) > 0 ) + if ( 0 && (src_or_dest == 0 || strcmp(bp->destcoin->symbol,"BTC") != 0) && (n= dpow_paxpending(extras,&paxwdcrc)) > 0 ) { for (i=0; i Date: Fri, 17 Mar 2017 10:51:17 +0200 Subject: [PATCH 0017/2705] Test --- iguana/dpow/dpow_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index cadc11faa..91a0d96a9 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -2138,11 +2138,11 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo) if ( (flags & 4) == 0 && (size= nn_recv(myinfo->repsock,&dexp,NN_MSG,0)) > 0 ) { num2++; - //printf("REP got %d crc.%08x\n",size,calc_crc32(0,(void *)dexp,size)); + printf("REP got %d crc.%08x\n",size,calc_crc32(0,(void *)dexp,size)); if ( (retstr= dex_response(&broadcastflag,myinfo,dexp)) != 0 ) { signed_nn_send(myinfo,myinfo->ctx,myinfo->persistent_priv,myinfo->repsock,retstr,(int32_t)strlen(retstr)+1); - //printf("send back[%ld]\n",strlen(retstr)+1); + printf("send back[%ld]\n",strlen(retstr)+1); free(retstr); if ( broadcastflag != 0 ) { From 42c4174d9e137231b808f73b29ebe5630eeb8a96 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 17 Mar 2017 15:48:37 +0200 Subject: [PATCH 0018/2705] Test --- crypto777/OS_portable.h | 2 +- iguana/dpow/dpow_network.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index 040436d1a..d687df9e0 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -18,7 +18,7 @@ // iguana_OS has functions that invoke system calls. Whenever possible stdio and similar functions are use and most functions are fully portable and in this file. For things that require OS specific, the call is routed to iguana_OS_portable_* Usually, all but one OS can be handled with the same code, so iguana_OS_portable.c has most of this shared logic and an #ifdef iguana_OS_nonportable.c #ifdef __APPLE__ -#define LIQUIDITY_PROVIDER 1 +//#define LIQUIDITY_PROVIDER 1 #endif #ifdef NATIVE_WINDOWS diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 91a0d96a9..cadc11faa 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -2138,11 +2138,11 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo) if ( (flags & 4) == 0 && (size= nn_recv(myinfo->repsock,&dexp,NN_MSG,0)) > 0 ) { num2++; - printf("REP got %d crc.%08x\n",size,calc_crc32(0,(void *)dexp,size)); + //printf("REP got %d crc.%08x\n",size,calc_crc32(0,(void *)dexp,size)); if ( (retstr= dex_response(&broadcastflag,myinfo,dexp)) != 0 ) { signed_nn_send(myinfo,myinfo->ctx,myinfo->persistent_priv,myinfo->repsock,retstr,(int32_t)strlen(retstr)+1); - printf("send back[%ld]\n",strlen(retstr)+1); + //printf("send back[%ld]\n",strlen(retstr)+1); free(retstr); if ( broadcastflag != 0 ) { From 2c551f0deac6fb419dee9a1057a9eb505e603828 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 18 Mar 2017 13:52:52 +0200 Subject: [PATCH 0019/2705] Test --- iguana/kmd_lookup.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index 0d6e2f2f9..a07b5db29 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -694,9 +694,11 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) { bitcoin_addr2rmd160(&type_rmd160[0],&type_rmd160[1],jstri(addresses,0)); kmd_transactionvout(coin,ptr,j,jdouble(vout,"value")*SATOSHIDEN,type_rmd160,zero,-1); + fprintf(stderr,"%.8f ",jdouble(vout,"value")); } // else printf("missing sobj.%p or addresses.%p (%s)\n",sobj,addresses,jprint(vout,0)); //likely OP_RETURN sobj = addresses = 0; } + fprintf(stderr,"numvouts.%d ht.%d %s\n",numvouts,height,coin->symbol); if ( coin->kmd_txidfp != 0 ) { ptr->fpos = ftell(coin->kmd_txidfp); From b3da8ebbf7be8392411cf3aeeefe03870b71c14e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 18 Mar 2017 16:44:24 +0200 Subject: [PATCH 0020/2705] Test --- iguana/kmd_lookup.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index a07b5db29..f44779156 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -694,11 +694,11 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) { bitcoin_addr2rmd160(&type_rmd160[0],&type_rmd160[1],jstri(addresses,0)); kmd_transactionvout(coin,ptr,j,jdouble(vout,"value")*SATOSHIDEN,type_rmd160,zero,-1); - fprintf(stderr,"%.8f ",jdouble(vout,"value")); + //fprintf(stderr,"%.8f ",jdouble(vout,"value")); } // else printf("missing sobj.%p or addresses.%p (%s)\n",sobj,addresses,jprint(vout,0)); //likely OP_RETURN sobj = addresses = 0; } - fprintf(stderr,"numvouts.%d ht.%d %s\n",numvouts,height,coin->symbol); + //fprintf(stderr,"numvouts.%d ht.%d %s\n",numvouts,height,coin->symbol); if ( coin->kmd_txidfp != 0 ) { ptr->fpos = ftell(coin->kmd_txidfp); From 502492912b704745ebdaf819ead9fb2dd0b1c558 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 21 Mar 2017 21:58:12 +0200 Subject: [PATCH 0021/2705] Height 250000 update --- .gitignore | 6 ++++++ iguana/iguana_payments.c | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f3176906f..1d70ba0e5 100755 --- a/.gitignore +++ b/.gitignore @@ -210,3 +210,9 @@ iguana/DB/SWAPS/270159951-1269722638 iguana/DB/SWAPS/244991424-1008712592 iguana/confs/1cc0270abba7f4463a3dcb9908b9d875691a6773fe3cc1b4302233ed76665300 + +iguana/autoAPI.md + +iguana/confs/5228bcea7ae2515a29c3844673de6ee2acba53bf45724744a00ff4306f192912 + +iguana/confs/630929d976025fafde221c7358eb5805f4359bad3c6b8bd50ad3f6e0a9b5ce78 diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index cdb27e36c..842dd261c 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -348,20 +348,22 @@ uint64_t _iguana_interest(uint32_t now,int32_t chainheight,uint32_t txlocktime,u { if ( minutes > 365 * 24 * 60 ) minutes = 365 * 24 * 60; + if ( chainheight >= 250000 ) + minutes -= 59; denominator = (((uint64_t)365 * 24 * 60) / minutes); if ( denominator == 0 ) denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually! if ( value > 25000LL*SATOSHIDEN && chainheight > 155949 ) { numerator = (value / 20); // assumes 5%! - if ( chainheight < 300000 ) + if ( chainheight < 250000 ) interest = (numerator / denominator); else interest = (numerator * minutes) / ((uint64_t)365 * 24 * 60); } else if ( value >= 10*SATOSHIDEN ) { numerator = (value * KOMODO_INTEREST); - if ( chainheight < 300000 || numerator * minutes < 365 * 24 * 60 ) + if ( chainheight < 250000 || numerator * minutes < 365 * 24 * 60 ) interest = (numerator / denominator) / SATOSHIDEN; else interest = ((numerator * minutes) / ((uint64_t)365 * 24 * 60)) / SATOSHIDEN; } From 72a288eb8396902aa77e18a3011bb33c4244296d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 25 Mar 2017 12:55:40 +0200 Subject: [PATCH 0022/2705] batch14 --- iguana/main.c | 4 +- iguana/tests/KMD.batch14 | 145 +++++++++++++++++++++++++++ iguana/tests/KMD.batch14.listunspent | 117 +++++++++++++++++++++ iguana/tests/dexlistunspent | 2 +- iguana/tests/sendtoaddress | 2 +- 5 files changed, 266 insertions(+), 4 deletions(-) create mode 100755 iguana/tests/KMD.batch14 create mode 100755 iguana/tests/KMD.batch14.listunspent diff --git a/iguana/main.c b/iguana/main.c index 984f2c27a..b737885c5 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -2055,7 +2055,7 @@ void komodo_ICO_batch(cJSON *array,int32_t batchid) if ( (n= cJSON_GetArraySize(array)) > 0 ) { totalKMD = totalREVS = 0; - for (iter=0; iter<1; iter++) + for (iter=3; iter<4; iter++) for (i=0; i Date: Sat, 25 Mar 2017 12:57:11 +0200 Subject: [PATCH 0023/2705] test --- iguana/tests/KMD.batch14 | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/tests/KMD.batch14 b/iguana/tests/KMD.batch14 index df9901513..5b3f4d6fa 100755 --- a/iguana/tests/KMD.batch14 +++ b/iguana/tests/KMD.batch14 @@ -1,3 +1,4 @@ +sleep 999999 # RN1t6SGGsWGrgcfE8fJPJWwHmKH4zE93Vj KMD 283716.36806687 ./komodo-cli sendtoaddress RN1t6SGGsWGrgcfE8fJPJWwHmKH4zE93Vj 283716.36806687 sleep 3 From ebbe381996b977e005e0bf43ea62b27935e642ff Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 26 Mar 2017 22:45:57 +0300 Subject: [PATCH 0024/2705] April 5th --- iguana/iguana_payments.c | 32 +++++++++++++++++++++++--------- iguana/kmd_lookup.h | 1 + 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index 842dd261c..43760ebd7 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -341,33 +341,47 @@ bits256 iguana_sendrawtransaction(struct supernet_info *myinfo,struct iguana_inf return(txid); } -uint64_t _iguana_interest(uint32_t now,int32_t chainheight,uint32_t txlocktime,uint64_t value) +uint64_t _iguana_interest(uint32_t now,int32_t txheight,uint32_t txlocktime,uint64_t value) { - int32_t minutes; uint64_t numerator=0,denominator=0,interest = 0; + int32_t minutes; uint64_t numerator=0,denominator=0,interest=0; uint32_t activation = 1491350400; + if ( (minutes= ((uint32_t)time(NULL) - 60 - txlocktime) / 60) >= 60 ) { if ( minutes > 365 * 24 * 60 ) minutes = 365 * 24 * 60; - if ( chainheight >= 250000 ) + if ( txheight >= 250000 ) minutes -= 59; denominator = (((uint64_t)365 * 24 * 60) / minutes); if ( denominator == 0 ) denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually! - if ( value > 25000LL*SATOSHIDEN && chainheight > 155949 ) + if ( value > 25000LL*SATOSHIDEN && txheight > 155949 ) { numerator = (value / 20); // assumes 5%! - if ( chainheight < 250000 ) + if ( txheight < 250000 ) interest = (numerator / denominator); else interest = (numerator * minutes) / ((uint64_t)365 * 24 * 60); } else if ( value >= 10*SATOSHIDEN ) { - numerator = (value * KOMODO_INTEREST); - if ( chainheight < 250000 || numerator * minutes < 365 * 24 * 60 ) + /*numerator = (value * KOMODO_INTEREST); + if ( txheight < 250000 || numerator * minutes < 365 * 24 * 60 ) interest = (numerator / denominator) / SATOSHIDEN; - else interest = ((numerator * minutes) / ((uint64_t)365 * 24 * 60)) / SATOSHIDEN; + else interest = ((numerator * minutes) / ((uint64_t)365 * 24 * 60)) / SATOSHIDEN;*/ + numerator = (value * KOMODO_INTEREST); + if ( txheight < 250000 || now < activation ) + { + if ( txheight < 250000 || numerator * minutes < 365 * 24 * 60 ) + interest = (numerator / denominator) / SATOSHIDEN; + else interest = ((numerator * minutes) / ((uint64_t)365 * 24 * 60)) / SATOSHIDEN; + } + else + { + numerator = (value / 20); // assumes 5%! + interest = ((numerator * minutes) / ((uint64_t)365 * 24 * 60)); + //fprintf(stderr,"interest %llu %.8f <- numerator.%llu minutes.%d\n",(long long)interest,(double)interest/COIN,(long long)numerator,(int32_t)minutes); + } } - //fprintf(stderr,"komodo_interest.%d %lld %.8f nLockTime.%u tiptime.%u minutes.%d interest %lld %.8f (%llu / %llu)\n",chainheight,(long long)value,(double)value/SATOSHIDEN,txlocktime,now,minutes,(long long)interest,(double)interest/SATOSHIDEN,(long long)numerator,(long long)denominator); + //fprintf(stderr,"komodo_interest.%d %lld %.8f nLockTime.%u tiptime.%u minutes.%d interest %lld %.8f (%llu / %llu)\n",txheight,(long long)value,(double)value/SATOSHIDEN,txlocktime,now,minutes,(long long)interest,(double)interest/SATOSHIDEN,(long long)numerator,(long long)denominator); } return(interest); } diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index f44779156..a09c83ee2 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -309,6 +309,7 @@ cJSON *kmd_unspentjson(struct supernet_info *myinfo,struct iguana_info *coin,int { char *script; cJSON *sobj,*txout,*item = cJSON_CreateObject(); jaddstr(item,"type","received"); + jaddnum(item,"confirmations",height - tx->height); jaddnum(item,"height",tx->height); jaddnum(item,"timestamp",tx->timestamp); jaddbits256(item,"txid",tx->txid); From f3dbb8e68b2305145586c3246ef301ac323f31cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 26 Mar 2017 22:53:01 +0300 Subject: [PATCH 0025/2705] port= arg --- iguana/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/main.c b/iguana/main.c index b737885c5..8f778dd4c 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -2192,6 +2192,11 @@ void iguana_main(void *arg) myinfo->IAMNOTARY = 1; myinfo->DEXEXPLORER = 1; } + else if ( strncmp((char *)arg,"port=",5) == 0 ) + { + myinfo->rpcport = atoi(&((char *)arg)[5]); + printf("OVERRIDE IGUANA port <- %u\n",myinfo->rpcport); + } } #ifdef IGUANA_OSTESTS do_OStests = 1; From cb2cb6310db8fdef78a140d715f00619209b56f7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 26 Mar 2017 22:55:35 +0300 Subject: [PATCH 0026/2705] -port= --- iguana/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/main.c b/iguana/main.c index 8f778dd4c..8896ceae5 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -2192,9 +2192,9 @@ void iguana_main(void *arg) myinfo->IAMNOTARY = 1; myinfo->DEXEXPLORER = 1; } - else if ( strncmp((char *)arg,"port=",5) == 0 ) + else if ( strncmp((char *)arg,"-port=",6) == 0 ) { - myinfo->rpcport = atoi(&((char *)arg)[5]); + myinfo->rpcport = atoi(&((char *)arg)[6]); printf("OVERRIDE IGUANA port <- %u\n",myinfo->rpcport); } } From ae071443d90109bdadb484c396d180eb0631bea5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 27 Mar 2017 10:11:30 +0300 Subject: [PATCH 0027/2705] WLC --- iguana/iguana_notary.c | 2 +- iguana/m_notary | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index dc4d436d8..55e55b25d 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -437,7 +437,7 @@ STRING_ARG(iguana,addnotary,ipaddr) char NOTARY_CURRENCIES[][16] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", - "REVS", "SUPERNET", "DEX", "PANGEA", "JUMBLR", "BET", "CRYPTO", "HODL", "SHARK", "BOTS", "MGW", "MVP", "WIRELESS", "KV", "CEAL", "MESH" }; + "REVS", "SUPERNET", "DEX", "PANGEA", "JUMBLR", "BET", "CRYPTO", "HODL", "SHARK", "BOTS", "MGW", "MVP", "WLC", "KV", "CEAL", "MESH" }; ZERO_ARGS(dpow,notarychains) { diff --git a/iguana/m_notary b/iguana/m_notary index a1df17e7e..f6fe26d75 100755 --- a/iguana/m_notary +++ b/iguana/m_notary @@ -35,7 +35,8 @@ coins/crypto_7776 coins/pangea_7776 coins/mgw_7776 coins/mvp_7776 -coins/wireless_7776 +coins/wlc_7776 +#coins/wireless_7776 coins/kv_7776 coins/ceal_7776 coins/mesh_7776 From 46a54ffddac0e256822be96aa0a76e74e197781b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 27 Mar 2017 10:15:59 +0300 Subject: [PATCH 0028/2705] WLC --- iguana/coins/basilisk/wireless | 1 - iguana/coins/basilisk/wlc | 1 + iguana/coins/wireless_7776 | 1 - iguana/coins/wlc_7776 | 1 + iguana/iguana777.h | 1 + 5 files changed, 3 insertions(+), 2 deletions(-) delete mode 100755 iguana/coins/basilisk/wireless create mode 100755 iguana/coins/basilisk/wlc delete mode 100755 iguana/coins/wireless_7776 create mode 100755 iguana/coins/wlc_7776 diff --git a/iguana/coins/basilisk/wireless b/iguana/coins/basilisk/wireless deleted file mode 100755 index f1a56bef5..000000000 --- a/iguana/coins/basilisk/wireless +++ /dev/null @@ -1 +0,0 @@ -curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"WIRELESS.conf\",\"path\":\"${HOME#"/"}/.komodo/WIRELESS\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"WIRELESS\",\"name\":\"WIRELESS\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"62071ed3\",\"p2p\":11666,\"rpc\":11667,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/basilisk/wlc b/iguana/coins/basilisk/wlc new file mode 100755 index 000000000..bf98898b1 --- /dev/null +++ b/iguana/coins/basilisk/wlc @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"WLC.conf\",\"path\":\"${HOME#"/"}/.komodo/WLC\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"WLC\",\"name\":\"WLC\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7ec1c253\",\"p2p\":15431,\"rpc\":15432,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/wireless_7776 b/iguana/coins/wireless_7776 deleted file mode 100755 index 420a3508c..000000000 --- a/iguana/coins/wireless_7776 +++ /dev/null @@ -1 +0,0 @@ -curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"WIRELESS.conf\",\"path\":\"${HOME#"/"}/.komodo/WIRELESS\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"WIRELESS\",\"name\":\"WIRELESS\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"62071ed3\",\"p2p\":11666,\"rpc\":11667,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/wlc_7776 b/iguana/coins/wlc_7776 new file mode 100755 index 000000000..086c678cd --- /dev/null +++ b/iguana/coins/wlc_7776 @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"WLC.conf\",\"path\":\"${HOME#"/"}/.komodo/WLC\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"WLC\",\"name\":\"WLC\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7ec1c253\",\"p2p\":15431,\"rpc\":15432,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 682d3da13..774ebb515 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -15,6 +15,7 @@ /* adding assetchain coin: copy genCOIN to SuperNET/iguana/coins, make a _7776 variant with RELAY=-1 and VALIDATE=0 + copy that into basilisk as coin, changing RELAY -> 0 */ #ifndef iguana777_net_h From a3ca15bcda04d279f2c6687dce73cffef010d8b4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 27 Mar 2017 15:02:30 +0300 Subject: [PATCH 0029/2705] Remove 7778 and IGUANA_PORT hardcodes --- iguana/iguana_accept.c | 2 +- iguana/iguana_json.c | 10 +++++----- iguana/iguana_rpc.c | 2 +- iguana/main.c | 14 +++++++------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/iguana/iguana_accept.c b/iguana/iguana_accept.c index e86c74bcf..2463a09a8 100755 --- a/iguana/iguana_accept.c +++ b/iguana/iguana_accept.c @@ -115,7 +115,7 @@ void iguana_acceptloop(void *args) printf("another daemon running, no need to have iguana accept connections\n"); return; } - //if ( port != IGUANA_RPCPORT ) + //if ( port != myinfo->rpcport ) // return; sleep(5); } diff --git a/iguana/iguana_json.c b/iguana/iguana_json.c index 7e38b1ad7..99d851641 100755 --- a/iguana/iguana_json.c +++ b/iguana/iguana_json.c @@ -18,7 +18,7 @@ cJSON *helpjson(cJSON *json,cJSON *array,cJSON *agents,char *agentstr,char *method,cJSON *methodargs) { - cJSON *methodobj,*item; int32_t i,n; char url[2048],curl[2048]; + cJSON *methodobj,*item; int32_t i,n; char url[2048],curl[2048]; struct supernet_info *myinfo = SuperNET_MYINFO(0); /*if ( *agentstrp == 0 || strcmp(*agentstrp,agentstr) != 0 ) { if ( array != 0 ) @@ -43,8 +43,8 @@ cJSON *helpjson(cJSON *json,cJSON *array,cJSON *agents,char *agentstr,char *meth methodobj = cJSON_CreateObject(); jaddstr(methodobj,"agent",agentstr); jaddstr(methodobj,"method",method); - sprintf(url,"http://127.0.0.1:7778/api/%s/%s",agentstr,method); - sprintf(curl,"curl --url \"http://127.0.0.1:7778\" --data \"{\\\"agent\\\":\\\"%s\\\",\\\"method\\\":\\\"%s\\\"",agentstr,method); + sprintf(url,"http://127.0.0.1:%u/api/%s/%s",myinfo->rpcport,agentstr,method); + sprintf(curl,"curl --url \"http://127.0.0.1:%u\" --data \"{\\\"agent\\\":\\\"%s\\\",\\\"method\\\":\\\"%s\\\"",myinfo->rpcport,agentstr,method); if ( methodargs != 0 && (n= cJSON_GetArraySize(methodargs)) > 0 ) { //printf("method.%s n.%d %s\n",method,n,jprint(methodargs,0)); @@ -203,7 +203,7 @@ cJSON *SuperNET_helpjson() int32_t agentform(FILE *fp,char *form,int32_t max,char *agent,cJSON *methoditem) { - cJSON *item,*fieldsarray; int32_t j,m,width=1,size = 0; + cJSON *item,*fieldsarray; int32_t j,m,width=1,size = 0; struct supernet_info *myinfo = SuperNET_MYINFO(0); char *methodstr,*typestr,outstr[2048],outstr2[2048],fields[8192],str[2],agent_method[256],*fieldname; form[0] = 0; if ( (methodstr= jstr(methoditem,"method")) == 0 ) @@ -252,7 +252,7 @@ int32_t agentform(FILE *fp,char *form,int32_t max,char *agent,cJSON *methoditem) //printf("fields[%d] (%s)\n",j,fields); } } else sprintf(fields+strlen(fields),"%s ",agent_method); - sprintf(&form[size],"

%s",agent,methodstr,outstr,fields,outstr2,methodstr); + sprintf(&form[size],"
%s
",myinfo->rpcport,agent,methodstr,outstr,fields,outstr2,methodstr); if ( fp != 0 ) fprintf(fp,"%s\n",&form[size]); //printf("%s\n",&form[size]); diff --git a/iguana/iguana_rpc.c b/iguana/iguana_rpc.c index 19d546676..20ad9aa78 100755 --- a/iguana/iguana_rpc.c +++ b/iguana/iguana_rpc.c @@ -759,7 +759,7 @@ char *iguana_bitcoinRPC(struct supernet_info *myinfo,char *method,cJSON *json,ch //printf("add params[%d] of %d <- (%s) %p.(%p %p)\n",i,n,jprint(params[i],0),params[i],params[i]->next,params[i]->prev); } } - retstr = iguana_bitcoinrpc(myinfo,IGUANA_RPCPORT,coin,method,params,n,json,remoteaddr,array); + retstr = iguana_bitcoinrpc(myinfo,myinfo->rpcport,coin,method,params,n,json,remoteaddr,array); if ( n > 0 ) for (i=0; irpcport) ) { if ( coin != 0 ) { @@ -2051,7 +2051,7 @@ FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase) void komodo_ICO_batch(cJSON *array,int32_t batchid) { - int32_t i,n,iter; cJSON *item; uint64_t kmdamount,revsamount; char *coinaddr,cmd[512]; double totalKMD,totalREVS; + int32_t i,n,iter; cJSON *item; uint64_t kmdamount,revsamount; char *coinaddr,cmd[512]; double totalKMD,totalREVS; struct supernet_info *myinfo = SuperNET_MYINFO(0); if ( (n= cJSON_GetArraySize(array)) > 0 ) { totalKMD = totalREVS = 0; @@ -2070,7 +2070,7 @@ void komodo_ICO_batch(cJSON *array,int32_t batchid) { if ( dstr(revsamount) >= 1. && (iter & 1) == 0 ) { - printf("curl --url \"http://127.0.0.1:7778\" --data \"{\\\"agent\\\":\\\"dex\\\",\\\"method\\\":\\\"importaddress\\\",\\\"address\\\":\\\"%s\\\",\\\"symbol\\\":\\\"REVS\\\"}\" # %.8f\n",coinaddr,dstr(revsamount)); + printf("curl --url \"http://127.0.0.1:%u\" --data \"{\\\"agent\\\":\\\"dex\\\",\\\"method\\\":\\\"importaddress\\\",\\\"address\\\":\\\"%s\\\",\\\"symbol\\\":\\\"REVS\\\"}\" # %.8f\n",myinfo->rpcport,coinaddr,dstr(revsamount)); printf("sleep 3\n"); } else printf("sleep 1\n"); if ( (iter & 1) != 0 ) @@ -2093,9 +2093,9 @@ void komodo_ICO_batch(cJSON *array,int32_t batchid) { if ( (0) ) { - printf("curl --url \"http://127.0.0.1:7778\" --data \"{\\\"agent\\\":\\\"dex\\\",\\\"method\\\":\\\"importaddress\\\",\\\"address\\\":\\\"%s\\\",\\\"symbol\\\":\\\"KMD\\\"}\" # %.8f\n",coinaddr,dstr(kmdamount)); + printf("curl --url \"http://127.0.0.1:%u\" --data \"{\\\"agent\\\":\\\"dex\\\",\\\"method\\\":\\\"importaddress\\\",\\\"address\\\":\\\"%s\\\",\\\"symbol\\\":\\\"KMD\\\"}\" # %.8f\n",myinfo->rpcport,coinaddr,dstr(kmdamount)); printf("sleep 3\n"); - } else printf("curl --url \"http://127.0.0.1:7778\" --data \"{\\\"agent\\\":\\\"dex\\\",\\\"method\\\":\\\"listunspent\\\",\\\"address\\\":\\\"%s\\\",\\\"symbol\\\":\\\"KMD\\\"}\"\n",coinaddr); + } else printf("curl --url \"http://127.0.0.1:%u\" --data \"{\\\"agent\\\":\\\"dex\\\",\\\"method\\\":\\\"listunspent\\\",\\\"address\\\":\\\"%s\\\",\\\"symbol\\\":\\\"KMD\\\"}\"\n",myinfo->rpcport,coinaddr); } else { @@ -2114,7 +2114,7 @@ void komodo_ICO_batch(cJSON *array,int32_t batchid) void komodo_REVS_merge(char *str,char *str2) { - char line[1024],line2[1024],*coinaddr; int32_t i,n=0,m=0,k=0; + char line[1024],line2[1024],*coinaddr; int32_t i,n=0,m=0,k=0; struct supernet_info *myinfo = SuperNET_MYINFO(0); while ( 1 ) { if ( str[n] == 0 || str2[m] == 0 ) @@ -2136,7 +2136,7 @@ void komodo_REVS_merge(char *str,char *str2) coinaddr[i] = 0; if ( atof(&coinaddr[i+1]) > 1 ) { - printf("curl --url \"http://127.0.0.1:7778\" --data \"{\\\"agent\\\":\\\"dex\\\",\\\"method\\\":\\\"importaddress\\\",\\\"address\\\":\\\"%s\\\",\\\"symbol\\\":\\\"REVS\\\"}\" # %.8f\n",coinaddr,atof(coinaddr+i+1)); + printf("curl --url \"http://127.0.0.1:%u\" --data \"{\\\"agent\\\":\\\"dex\\\",\\\"method\\\":\\\"importaddress\\\",\\\"address\\\":\\\"%s\\\",\\\"symbol\\\":\\\"REVS\\\"}\" # %.8f\n",myinfo->rpcport,coinaddr,atof(coinaddr+i+1)); printf("sleep 3\n"); } k++; From 1144093e810a7ebb45e2cc6adf1d0dc4cf9d28aa Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 29 Mar 2017 18:37:57 +0300 Subject: [PATCH 0030/2705] Remove test_schnorr_threshold --- .gitignore | 2 + basilisk/basilisk.c | 10 +-- basilisk/jumblr.c | 126 ++++++++++++++++++++++++++++++------ iguana/iguana_secp.c | 89 ------------------------- iguana/main.c | 15 ++--- iguana/tests/dexlistunspent | 2 +- includes/iguana_funcs.h | 4 +- includes/iguana_structs.h | 11 ++++ 8 files changed, 135 insertions(+), 124 deletions(-) diff --git a/.gitignore b/.gitignore index 1d70ba0e5..e689f7231 100755 --- a/.gitignore +++ b/.gitignore @@ -216,3 +216,5 @@ iguana/autoAPI.md iguana/confs/5228bcea7ae2515a29c3844673de6ee2acba53bf45724744a00ff4306f192912 iguana/confs/630929d976025fafde221c7358eb5805f4359bad3c6b8bd50ad3f6e0a9b5ce78 + +iguana/confs/5f3283a017c31e52443d61cb43944e2157f7c03eb12d701ebf4a35a695688e1f diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index ba880e2e6..eb2d7237c 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1301,7 +1301,7 @@ STRING_ARG(jumblr,setpassphrase,passphrase) safecopy(myinfo->jumblr_passphrase,passphrase,sizeof(myinfo->jumblr_passphrase)); retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); - privkey = jumblr_privkey(myinfo,BTCaddr,KMDaddr,JUMBLR_DEPOSITPREFIX); + privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); smartaddress_add(myinfo,privkey,BTCaddr,KMDaddr); myinfo->jumblr_depositkey = curve25519(privkey,curve25519_basepoint9()); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); @@ -1316,7 +1316,7 @@ STRING_ARG(jumblr,setpassphrase,passphrase) jumblr_importprivkey(myinfo,coinbtc,wifstr); jaddnum(retjson,"BTCdeposits",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); } - privkey = jumblr_privkey(myinfo,BTCaddr,KMDaddr,""); + privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); smartaddress_add(myinfo,privkey,BTCaddr,KMDaddr); myinfo->jumblr_pubkey = curve25519(privkey,curve25519_basepoint9()); jaddstr(retjson,"KMDjumblr",KMDaddr); @@ -1335,14 +1335,14 @@ ZERO_ARGS(jumblr,status) jumblr_opidsupdate(myinfo,coin); retjson = cJSON_CreateObject(); step_t2z = step_z2z = step_z2t = deposited = finished = pending = 0; - jumblr_privkey(myinfo,BTCaddr,KMDaddr,JUMBLR_DEPOSITPREFIX); + jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); jaddstr(retjson,"KMDdeposit",KMDaddr); jaddstr(retjson,"BTCdeposit",BTCaddr); if ( (coinbtc= iguana_coinfind("BTC")) != 0 ) jaddnum(retjson,"BTCdeposits",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); received = jumblr_receivedby(myinfo,coin,KMDaddr); deposited = jumblr_balance(myinfo,coin,KMDaddr); - jumblr_privkey(myinfo,BTCaddr,KMDaddr,""); + jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); jaddstr(retjson,"KMDjumblr",KMDaddr); jaddstr(retjson,"BTCjumblr",BTCaddr); if ( coinbtc != 0 ) @@ -1706,7 +1706,7 @@ HASH_ARRAY_STRING(InstantDEX,request,hash,vals,hexstr) jadd64bits(vals,"destsatoshis",jdouble(vals,"destamount") * SATOSHIDEN); jaddnum(vals,"timestamp",time(NULL)); if ( (jumblr= jint(vals,"usejumblr")) != 0 ) - privkey = jumblr_privkey(myinfo,BTCaddr,KMDaddr,jumblr == 1 ? JUMBLR_DEPOSITPREFIX : ""); + privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,jumblr == 1 ? JUMBLR_DEPOSITPREFIX : ""); else privkey = myinfo->persistent_priv; hash = curve25519(privkey,curve25519_basepoint9()); if ( jobj(vals,"srchash") == 0 ) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 0710007c6..5dea0d784 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -289,8 +289,8 @@ void jumblr_opidupdate(struct supernet_info *myinfo,struct iguana_info *coin,str if ( strcmp(status,"success") == 0 ) { ptr->status = jumblr_itemset(ptr,item,status); - jumblr_privkey(myinfo,BTCaddr,KMDdeposit,JUMBLR_DEPOSITPREFIX); - jumblr_privkey(myinfo,BTCaddr,KMDjumblr,""); + jumblr_privkey(myinfo,BTCaddr,0,KMDdeposit,JUMBLR_DEPOSITPREFIX); + jumblr_privkey(myinfo,BTCaddr,0,KMDjumblr,""); if ( (jumblr_addresstype(myinfo,coin,ptr->src) == 't' && jumblr_addresstype(myinfo,coin,ptr->src) == 'z' && strcmp(ptr->src,KMDdeposit) != 0) || (jumblr_addresstype(myinfo,coin,ptr->src) == 'z' && jumblr_addresstype(myinfo,coin,ptr->src) == 't' && strcmp(ptr->dest,KMDjumblr) != 0) ) { printf("a non-jumblr t->z pruned\n"); @@ -364,37 +364,125 @@ void jumblr_opidsupdate(struct supernet_info *myinfo,struct iguana_info *coin) } } -bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,char *KMDaddr,char *prefix) +bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,uint8_t pubtype,char *KMDaddr,char *prefix) { bits256 privkey,pubkey; uint8_t pubkey33[33]; char passphrase[sizeof(myinfo->jumblr_passphrase) + 64]; sprintf(passphrase,"%s%s",prefix,myinfo->jumblr_passphrase); conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); - bitcoin_address(BTCaddr,0,pubkey33,33); + bitcoin_address(BTCaddr,pubtype,pubkey33,33); bitcoin_address(KMDaddr,60,pubkey33,33); return(privkey); } -void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coinkmd,char *BTCaddr,char *KMDaddr,bits256 privkey) +/*struct DEXcoin_info { - static double kmdprice,pending; static uint32_t lasttime; - double btcavail=0,minbtc,avebid,aveask,highbid,lowask,CMC_average,USD_average,changes[3]; struct iguana_info *coinbtc; cJSON *vals; bits256 hash; char *retstr; - coinbtc = iguana_coinfind("BTC"); - if ( kmdprice == 0. || time(NULL) > lasttime+60 ) + bits256 deposit_privkey,jumblr_privkey; + struct iguana_info *coin; + cJSON *utxos,*spentutxos,*bigutxos,*normalutxos,*smallutxos,*feeutxos,*otherutxos; + double btcprice,USD_average,DEXpending,maxbid,minask,avail,KMDavail; + uint32_t lasttime; + char CMCname[32],symbol[16],depositaddr[64],KMDdepositaddr[64],KMDjumblraddr[64],jumblraddr[64]; +};*/ + +int32_t jumblr_DEXsplit(struct supernet_info *myinfo,bits256 *splittxidp,bits256 txid,int32_t vout,uint64_t value,double bigprice,double middleprice,double smallprice,double feeprice) +{ + +} + +int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,bits256 *splittxidp,bits256 txid,int32_t vout,uint64_t value,int32_t isbob) +{ + double targetpriceB,targetpriceM,targetpriceS,fee,depositfactor,dexfeeratio,margin = 1.1; + depositfactor = (isbob == 0) ? 1. : 1.2; + dexfeeratio = 500.; + memset(splittxidp,0,sizeof(*splittxidp)); + fee = JUMBLR_INCR * JUMBLR_FEE; + targetpriceB = depositfactor * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE); + targetpriceM = depositfactor * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE); + targetpriceS = depositfactor * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); + if ( value >= targetpriceB ) + { + if ( value > margin * (targetpriceB + targetpriceS) ) + jumblr_DEXsplit(myinfo,splittxidp,txid,vout,value,margin * targetpriceB,margin * targetpriceM,margin * targetpriceS,margin * targetpriceB/dexfeeratio); + return(0); + } + else + { + if ( value >= targetpriceM ) + { + if ( value > margin * (targetpriceM + targetpriceS) ) + return(jumblr_DEXsplit(myinfo,splittxidp,txid,vout,value,0.,margin * targetpriceM,margin * targetpriceS,margin * targetpriceM/dexfeeratio)); + else return(0); + } + else + { + if ( value >= targetpriceS ) + { + if ( value > margin * targetpriceS ) + return(jumblr_DEXsplit(myinfo,splittxidp,txid,vout,value,0.,0.,margin * targetpriceS,margin * targetpriceS/dexfeeratio)); + else return(0); + } + else if ( value > targetpriceS/dexfeeratio ) + return(jumblr_DEXsplit(myinfo,splittxidp,txid,vout,value,0.,0.,0.,margin * targetpriceS/dexfeeratio)); + else return(0); + } + } +} + +void jumblr_DEXupdate(struct supernet_info *myinfo,struct DEXcoin_info *ptr,char *symbol,char *CMCname,double BTC2KMD,double KMDavail) +{ + double avebid,aveask,highbid,lowask,CMC_average,changes[3]; struct iguana_info *kmdcoin = iguana_coinfind("KMD"); + if ( kmdcoin != 0 && time(NULL) > ptr->lasttime+60 ) { - kmdprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,"komodo","KMD","BTC",&USD_average); - lasttime = (uint32_t)time(NULL); - printf("KMD %.8f\n",kmdprice); + if ( strcmp(symbol,ptr->symbol) != 0 || ptr->coin == 0 ) + { + safecopy(ptr->symbol,symbol,sizeof(ptr->symbol)); + safecopy(ptr->CMCname,CMCname,sizeof(ptr->CMCname)); + if ( ptr->coin == 0 ) + ptr->coin = iguana_coinfind(symbol); + } + if ( ptr->coin != 0 ) + { + if ( ptr->depositaddr[0] == 0 ) + ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,ptr->coin->chain->pubtype,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); + if ( ptr->jumblraddr[0] == 0 ) + ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,ptr->coin->chain->pubtype,ptr->KMDjumblraddr,""); + ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); + } + ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); + if ( strcmp("KMD",symbol) == 0 ) + { + ptr->BTC2KMD = ptr->btcprice; + ptr->kmdprice = 1.; + ptr->KMDavail = ptr->avail; + } + else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) + { + ptr->kmdprice = ptr->btcprice / BTC2KMD; + ptr->KMDavail = KMDavail; + } + ptr->lasttime = (uint32_t)time(NULL); } - if ( kmdprice > SMALLVAL ) +} + +void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) +{ + struct iguana_info *kmdcoin; + if ( (kmdcoin= iguana_coinfind("KMD")) == 0 ) + return; + jumblr_DEXupdate(myinfo,&kmdcoin->DEXinfo,"KMD","komodo",0.,0.); + if ( strcmp(coin->symbol,"KMD") != 0 && kmdcoin->DEXinfo.btcprice > 0. ) + jumblr_DEXupdate(myinfo,&coin->DEXinfo,"KMD","komodo",kmdcoin->DEXinfo.btcprice,kmdcoin->DEXinfo.avail); + /*if ( kmdprice > SMALLVAL ) { - minbtc = (kmdprice * 1.1) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); - if ( coinbtc != 0 && (btcavail= dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))) > minbtc+pending ) + minbtc = (kmdprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); + btcavail = dstr(jumblr_balance(myinfo,coinbtc,BTCaddr)); + if ( coinbtc != 0 && btcavail > minbtc+pending ) { printf("BTC deposits %.8f, min %.8f\n",btcavail,minbtc); + vals = cJSON_CreateObject(); jaddstr(vals,"source","BTC"); - //hash = curve25519(privkey,curve25519_basepoint9()); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",btcavail*.3); jaddnum(vals,"minprice",kmdprice*.95); @@ -408,7 +496,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coinkmd,ch } // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - } else printf("null kmdprice %.8f\n",kmdprice); + } else printf("null kmdprice %.8f\n",kmdprice);*/ } void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval) @@ -424,7 +512,7 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 switch ( selector ) { case 0: // public -> z, need to importprivkey - jumblr_privkey(myinfo,BTCaddr,KMDaddr,JUMBLR_DEPOSITPREFIX); + jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); if ( (total= jumblr_balance(myinfo,coin,KMDaddr)) >= (JUMBLR_INCR + 3*(fee+JUMBLR_TXFEE))*SATOSHIDEN ) { if ( (r & 1) == 0 ) @@ -477,7 +565,7 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 { if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN ) { - privkey = jumblr_privkey(myinfo,BTCaddr,KMDaddr,""); + privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); if ( (retstr= jumblr_sendz_to_t(myinfo,coin,ptr->dest,KMDaddr,dstr(total))) != 0 ) { printf("sendz_to_t.(%s)\n",retstr); diff --git a/iguana/iguana_secp.c b/iguana/iguana_secp.c index 614f970e4..c53170908 100755 --- a/iguana/iguana_secp.c +++ b/iguana/iguana_secp.c @@ -451,95 +451,6 @@ int32_t bitcoin_rangeproof(void *ctx,uint8_t *proof,uint8_t *commit,bits256 blin return(retval); } -/* - * The intended procedure for creating a multiparty signature is: - * - Each signer S[i] with private key x[i] and public key Q[i] runs - * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of private/public nonces. - * - All signers communicate their public nonces to each other (revealing your - * private nonce can lead to discovery of your private key, so it should be considered secret). - * - All signers combine all the public nonces they received (excluding their - * own) using secp256k1_ec_pubkey_combine to obtain an Rall[i] = sum(R[0..i-1,i+1..n]). - * - All signers produce a partial signature using - * secp256k1_schnorr_partial_sign, passing in their own private key x[i], - * their own private nonce k[i], and the sum of the others' public nonces Rall[i]. - * - All signers communicate their partial signatures to each other. - * - Someone combines all partial signatures using secp256k1_schnorr_partial_combine, to obtain a full signature. - * - The resulting signature is validatable using secp256k1_schnorr_verify, with - * public key equal to the result of secp256k1_ec_pubkey_combine of the signers' public keys (sum(Q[0..n])). - * - * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine - * function take their arguments in any order, and it is possible to - * pre-combine several inputs already with one call, and add more inputs later - * by calling the function again (they are commutative and associative). - */ - -#ifdef test_schnorr -#include "secp256k1/src/util.h" -#include "secp256k1/src/hash_impl.h" -#include "secp256k1/src/testrand_impl.h" - -void test_schnorr_threshold(void *ctx) { - unsigned char msg[32]; - unsigned char sec[5][32]; - secp256k1_pubkey pub[5]; - unsigned char nonce[5][32]; - secp256k1_pubkey pubnonce[5]; - unsigned char sig[5][64]; - const unsigned char* sigs[5]; - unsigned char allsig[64]; - const secp256k1_pubkey* pubs[5]; - secp256k1_pubkey allpub; - int n, i; - int damage; - int ret = 0; - - damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0; - secp256k1_rand256_test(msg); - n = 2 + secp256k1_rand_int(4); - for (i = 0; i < n; i++) { - do { - secp256k1_rand256_test(sec[i]); - } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); - CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); - pubs[i] = &pub[i]; - } - if (damage == 1) { - nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } else if (damage == 2) { - sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - for (i = 0; i < n; i++) { - secp256k1_pubkey allpubnonce; - const secp256k1_pubkey *pubnonces[4]; - int j; - for (j = 0; j < i; j++) { - pubnonces[j] = &pubnonce[j]; - } - for (j = i + 1; j < n; j++) { - pubnonces[j - 1] = &pubnonce[j]; - } - CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); - ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; - sigs[i] = sig[i]; - } - if (damage == 3) { - sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255); - } - ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; - if ((ret & 1) == 0) { - ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; - } - if (damage == 4) { - allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - if ((ret & 7) == 0) { - ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; - } - CHECK((ret == 0) == (damage == 0)); -} -#endif - int32_t iguana_pederson_test(void *ctx) { uint8_t commits[100][33],*commitptrs[100],proofs[100][5138]; uint16_t vouts[100]; int64_t min_value,values[100],totalpos,totalneg; bits256 txids[100],nonces[100],blinds[100],*blindptrs[100],blindsum; int32_t prooflens[100],i,r,pos,neg,numpos,exponent,min_bits,n,N = 100; diff --git a/iguana/main.c b/iguana/main.c index 8acec8c89..7b38676f9 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -749,19 +749,18 @@ void iguana_urlinit(struct supernet_info *myinfo,int32_t ismainnet,int32_t usess void jumblr_loop(void *ptr) { - struct iguana_info *coin; char BTCaddr[64],KMDaddr[64]; bits256 privkey; uint32_t t; struct supernet_info *myinfo = ptr; int32_t mult = 10; + struct iguana_info *coin; uint32_t t; struct supernet_info *myinfo = ptr; int32_t mult = 10; printf("JUMBLR loop\n"); while ( 1 ) { - if ( (coin= iguana_coinfind("KMD")) != 0 && coin->FULLNODE < 0 ) + if ( myinfo->jumblr_passphrase[0] != 0 && (coin= iguana_coinfind("KMD")) != 0 && coin->FULLNODE < 0 ) { - privkey = jumblr_privkey(myinfo,BTCaddr,KMDaddr,JUMBLR_DEPOSITPREFIX); - // if BTC has arrived in deposit address, invoke DEX -> KMD // if BTC has arrived in destination address, invoke DEX -> BTC - jumblr_DEXcheck(myinfo,coin,BTCaddr,KMDaddr,privkey); + jumblr_DEXcheck(myinfo,coin); t = (uint32_t)time(NULL); - if ( myinfo->jumblr_passphrase[0] != 0 && (t % (120 * mult)) < 60 ) + if ( (t % (120 * mult)) < 60 ) { + // if BTC has arrived in deposit address, invoke DEX -> KMD jumblr_iteration(myinfo,coin,(t % (360 * mult)) / (120 * mult),t % (120 * mult)); } //printf("t.%u %p.%d %s\n",t,coin,coin!=0?coin->FULLNODE:0,myinfo->jumblr_passphrase); @@ -1909,10 +1908,10 @@ ZERO_ARGS(SuperNET,activehandle) } else jaddstr(retjson,"status","locked"); if ( myinfo->jumblr_passphrase[0] != 0 ) { - jumblr_privkey(myinfo,BTCaddr,KMDaddr,JUMBLR_DEPOSITPREFIX); + jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); jaddstr(retjson,"BTCdeposit","notyet"); jaddstr(retjson,"KMDdeposit",KMDaddr); - jumblr_privkey(myinfo,BTCaddr,KMDaddr,""); + jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); jaddstr(retjson,"BTCjumblr","notyet"); jaddstr(retjson,"KMDjumblr",KMDaddr); } diff --git a/iguana/tests/dexlistunspent b/iguana/tests/dexlistunspent index 3c4870cc8..98f1490fa 100755 --- a/iguana/tests/dexlistunspent +++ b/iguana/tests/dexlistunspent @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"\",\"symbol\":\"BTC\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REMYL4s4zSiKeLEit5FawHFuGKZ4apm297\",\"symbol\":\"KMD\"}" diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index ac4487c49..464fd2eab 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -629,8 +629,8 @@ int32_t iguana_staker_sort(struct iguana_info *coin,bits256 *hash2p,uint8_t *ref bits256 mpz_div64(bits256 hash,uint64_t divval); void iguana_walletinitcheck(struct supernet_info *myinfo,struct iguana_info *coin); void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval); -void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coinkmd,char *BTCaddr,char *KMDaddr,bits256 privkey); -bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,char *KMDaddr,char *prefix); +void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin); +bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,uint8_t pubtype,char *KMDaddr,char *prefix); char *jumblr_importprivkey(struct supernet_info *myinfo,struct iguana_info *coin,char *wifstr); int64_t iguana_esttxfee(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx,char *signedtx,int32_t numvins); diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index 813bd77a7..642748fa9 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -466,6 +466,16 @@ struct iguana_RTtxid struct hashstr_item { UT_hash_handle hh; char address[40]; }; +struct DEXcoin_info +{ + bits256 deposit_privkey,jumblr_privkey; + struct iguana_info *coin; + cJSON *utxos,*spentutxos,*bigutxos,*normalutxos,*smallutxos,*feeutxos,*otherutxos; + double btcprice,BTC2KMD,kmdprice,USD_average,DEXpending,maxbid,minask,avail,KMDavail; + uint32_t lasttime; + char CMCname[32],symbol[16],depositaddr[64],KMDdepositaddr[64],KMDjumblraddr[64],jumblraddr[64]; +}; + struct iguana_info { UT_hash_handle hh; @@ -534,6 +544,7 @@ struct iguana_info uint64_t estimatedfee; char seedipaddr[64]; uint32_t lastbesthashtime; bits256 lastbesthash; int32_t lastbestheight; + struct DEXcoin_info DEXinfo; struct iguana_block *RTblocks[65536]; uint8_t *RTrawdata[65536]; int32_t RTrecvlens[65536],RTnumtx[65536]; struct iguana_RTtxid *RTdataset; struct iguana_RTaddr *RTaddrs; struct hashstr_item *alladdresses; From e3c0c07effdabd0fd9e7c401d49f25ddd85054d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 29 Mar 2017 18:47:48 +0300 Subject: [PATCH 0031/2705] Remove single disabled function --- .gitignore | 2 + iguana/iguana_secp.c | 89 -------------------------------------------- 2 files changed, 2 insertions(+), 89 deletions(-) diff --git a/.gitignore b/.gitignore index 1d70ba0e5..e689f7231 100755 --- a/.gitignore +++ b/.gitignore @@ -216,3 +216,5 @@ iguana/autoAPI.md iguana/confs/5228bcea7ae2515a29c3844673de6ee2acba53bf45724744a00ff4306f192912 iguana/confs/630929d976025fafde221c7358eb5805f4359bad3c6b8bd50ad3f6e0a9b5ce78 + +iguana/confs/5f3283a017c31e52443d61cb43944e2157f7c03eb12d701ebf4a35a695688e1f diff --git a/iguana/iguana_secp.c b/iguana/iguana_secp.c index 614f970e4..c53170908 100755 --- a/iguana/iguana_secp.c +++ b/iguana/iguana_secp.c @@ -451,95 +451,6 @@ int32_t bitcoin_rangeproof(void *ctx,uint8_t *proof,uint8_t *commit,bits256 blin return(retval); } -/* - * The intended procedure for creating a multiparty signature is: - * - Each signer S[i] with private key x[i] and public key Q[i] runs - * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of private/public nonces. - * - All signers communicate their public nonces to each other (revealing your - * private nonce can lead to discovery of your private key, so it should be considered secret). - * - All signers combine all the public nonces they received (excluding their - * own) using secp256k1_ec_pubkey_combine to obtain an Rall[i] = sum(R[0..i-1,i+1..n]). - * - All signers produce a partial signature using - * secp256k1_schnorr_partial_sign, passing in their own private key x[i], - * their own private nonce k[i], and the sum of the others' public nonces Rall[i]. - * - All signers communicate their partial signatures to each other. - * - Someone combines all partial signatures using secp256k1_schnorr_partial_combine, to obtain a full signature. - * - The resulting signature is validatable using secp256k1_schnorr_verify, with - * public key equal to the result of secp256k1_ec_pubkey_combine of the signers' public keys (sum(Q[0..n])). - * - * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine - * function take their arguments in any order, and it is possible to - * pre-combine several inputs already with one call, and add more inputs later - * by calling the function again (they are commutative and associative). - */ - -#ifdef test_schnorr -#include "secp256k1/src/util.h" -#include "secp256k1/src/hash_impl.h" -#include "secp256k1/src/testrand_impl.h" - -void test_schnorr_threshold(void *ctx) { - unsigned char msg[32]; - unsigned char sec[5][32]; - secp256k1_pubkey pub[5]; - unsigned char nonce[5][32]; - secp256k1_pubkey pubnonce[5]; - unsigned char sig[5][64]; - const unsigned char* sigs[5]; - unsigned char allsig[64]; - const secp256k1_pubkey* pubs[5]; - secp256k1_pubkey allpub; - int n, i; - int damage; - int ret = 0; - - damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0; - secp256k1_rand256_test(msg); - n = 2 + secp256k1_rand_int(4); - for (i = 0; i < n; i++) { - do { - secp256k1_rand256_test(sec[i]); - } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); - CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); - pubs[i] = &pub[i]; - } - if (damage == 1) { - nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } else if (damage == 2) { - sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - for (i = 0; i < n; i++) { - secp256k1_pubkey allpubnonce; - const secp256k1_pubkey *pubnonces[4]; - int j; - for (j = 0; j < i; j++) { - pubnonces[j] = &pubnonce[j]; - } - for (j = i + 1; j < n; j++) { - pubnonces[j - 1] = &pubnonce[j]; - } - CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); - ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; - sigs[i] = sig[i]; - } - if (damage == 3) { - sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255); - } - ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; - if ((ret & 1) == 0) { - ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; - } - if (damage == 4) { - allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - if ((ret & 7) == 0) { - ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; - } - CHECK((ret == 0) == (damage == 0)); -} -#endif - int32_t iguana_pederson_test(void *ctx) { uint8_t commits[100][33],*commitptrs[100],proofs[100][5138]; uint16_t vouts[100]; int64_t min_value,values[100],totalpos,totalneg; bits256 txids[100],nonces[100],blinds[100],*blindptrs[100],blindsum; int32_t prooflens[100],i,r,pos,neg,numpos,exponent,min_bits,n,N = 100; From f3f20f107a9ef18d7a8b1dcf1950cdda951bbb7a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 29 Mar 2017 18:48:50 +0300 Subject: [PATCH 0032/2705] Remove single unused/skipped function --- .gitignore | 2 + iguana/iguana_secp.c | 89 -------------------------------------------- 2 files changed, 2 insertions(+), 89 deletions(-) diff --git a/.gitignore b/.gitignore index 1d70ba0e5..e689f7231 100755 --- a/.gitignore +++ b/.gitignore @@ -216,3 +216,5 @@ iguana/autoAPI.md iguana/confs/5228bcea7ae2515a29c3844673de6ee2acba53bf45724744a00ff4306f192912 iguana/confs/630929d976025fafde221c7358eb5805f4359bad3c6b8bd50ad3f6e0a9b5ce78 + +iguana/confs/5f3283a017c31e52443d61cb43944e2157f7c03eb12d701ebf4a35a695688e1f diff --git a/iguana/iguana_secp.c b/iguana/iguana_secp.c index 614f970e4..c53170908 100755 --- a/iguana/iguana_secp.c +++ b/iguana/iguana_secp.c @@ -451,95 +451,6 @@ int32_t bitcoin_rangeproof(void *ctx,uint8_t *proof,uint8_t *commit,bits256 blin return(retval); } -/* - * The intended procedure for creating a multiparty signature is: - * - Each signer S[i] with private key x[i] and public key Q[i] runs - * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of private/public nonces. - * - All signers communicate their public nonces to each other (revealing your - * private nonce can lead to discovery of your private key, so it should be considered secret). - * - All signers combine all the public nonces they received (excluding their - * own) using secp256k1_ec_pubkey_combine to obtain an Rall[i] = sum(R[0..i-1,i+1..n]). - * - All signers produce a partial signature using - * secp256k1_schnorr_partial_sign, passing in their own private key x[i], - * their own private nonce k[i], and the sum of the others' public nonces Rall[i]. - * - All signers communicate their partial signatures to each other. - * - Someone combines all partial signatures using secp256k1_schnorr_partial_combine, to obtain a full signature. - * - The resulting signature is validatable using secp256k1_schnorr_verify, with - * public key equal to the result of secp256k1_ec_pubkey_combine of the signers' public keys (sum(Q[0..n])). - * - * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine - * function take their arguments in any order, and it is possible to - * pre-combine several inputs already with one call, and add more inputs later - * by calling the function again (they are commutative and associative). - */ - -#ifdef test_schnorr -#include "secp256k1/src/util.h" -#include "secp256k1/src/hash_impl.h" -#include "secp256k1/src/testrand_impl.h" - -void test_schnorr_threshold(void *ctx) { - unsigned char msg[32]; - unsigned char sec[5][32]; - secp256k1_pubkey pub[5]; - unsigned char nonce[5][32]; - secp256k1_pubkey pubnonce[5]; - unsigned char sig[5][64]; - const unsigned char* sigs[5]; - unsigned char allsig[64]; - const secp256k1_pubkey* pubs[5]; - secp256k1_pubkey allpub; - int n, i; - int damage; - int ret = 0; - - damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0; - secp256k1_rand256_test(msg); - n = 2 + secp256k1_rand_int(4); - for (i = 0; i < n; i++) { - do { - secp256k1_rand256_test(sec[i]); - } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); - CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); - pubs[i] = &pub[i]; - } - if (damage == 1) { - nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } else if (damage == 2) { - sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - for (i = 0; i < n; i++) { - secp256k1_pubkey allpubnonce; - const secp256k1_pubkey *pubnonces[4]; - int j; - for (j = 0; j < i; j++) { - pubnonces[j] = &pubnonce[j]; - } - for (j = i + 1; j < n; j++) { - pubnonces[j - 1] = &pubnonce[j]; - } - CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); - ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; - sigs[i] = sig[i]; - } - if (damage == 3) { - sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255); - } - ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; - if ((ret & 1) == 0) { - ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; - } - if (damage == 4) { - allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - if ((ret & 7) == 0) { - ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; - } - CHECK((ret == 0) == (damage == 0)); -} -#endif - int32_t iguana_pederson_test(void *ctx) { uint8_t commits[100][33],*commitptrs[100],proofs[100][5138]; uint16_t vouts[100]; int64_t min_value,values[100],totalpos,totalneg; bits256 txids[100],nonces[100],blinds[100],*blindptrs[100],blindsum; int32_t prooflens[100],i,r,pos,neg,numpos,exponent,min_bits,n,N = 100; From 304f05a02ad39b9374cc39227f39510746099117 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 29 Mar 2017 18:56:18 +0300 Subject: [PATCH 0033/2705] Remove single unused function out of 24 --- .gitignore | 10 +++++ .vscode/launch.json | 22 +++++++++++ README.md | 49 +++++------------------- iguana/iguana_secp.c | 89 -------------------------------------------- 4 files changed, 42 insertions(+), 128 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.gitignore b/.gitignore index d7f6bfab7..1ae724886 100755 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,13 @@ iguana/confs/BTC_hdrs.txt deprecated/.DS_Store .DS_Store + +iguana/help/.tmpmarker + +iguana/genesis/.tmpmarker + +iguana/help.json + +iguana/autoAPI.md + +iguana/basilisk.o-2ad8cb38 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..20c9e805a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C++ Launch (Windows)", + "type": "cppvsdbg", + "request": "launch", + "program": "enter program name, for example ${workspaceRoot}/a.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceRoot}", + "environment": [], + "externalConsole": false + }, + { + "name": "C++ Attach (Windows)", + "type": "cppvsdbg", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 3aa7e99dd..2d49a0b55 100755 --- a/README.md +++ b/README.md @@ -23,11 +23,11 @@ iguana: most efficient bitcoin core implementation that can simultaneously be fu komodo: this is the top secret project I cant talk about publicly yet > #TL;DR# -> -> ```sudo apt-get update; sudo apt-get install git libcurl4-openssl-dev build-essential; git clone https://github.com/jl777/SuperNET; cd SuperNET; ./m_onetime m_unix;``` -> -> The above one line gets SuperNET installed, built and launched for unix. -> +> +> ```sudo apt-get update; sudo apt-get install git libcurl4-openssl-dev build-essential libnanomsg-dev; git clone https://github.com/jl777/SuperNET; cd SuperNET; ./m_onetime m_unix;``` +> +> The above one line gets SuperNET installed, built and launched for unix. +> > After that ```./m_unix``` updates to latest. > *Continue below at "Running".* @@ -44,6 +44,8 @@ The above two definitions need to be changed to match the mingw install on your You need to make sure the nacl sdk is properly installed and you are able to build the examples. Now you will need to get the external libs, which can be built from scratch using naclports or there use the reference builds of libcurl.a and libz.a in the SuperNET/crypto777/pnacl_libs. You can just copy those over into $(NACL_SDK_ROOT)//lib/pnacl. +##For android## +You have to build a native libnanomsg for android. This section is work in progress. Contact ca333@protonmail.ch for assistance on building latest iguana for android. #ONETIME# Now you are ready to build. @@ -103,14 +105,14 @@ Internally, all paths convert the request into a standard SuperNET JSON request. Another approach is to use the bitcoin RPC syntax via: curl --url "http://127.0.0.1:7778" --data "{\"coin\":\"BTCD\",\"method\":\"getinfo\",\"params\":[]}" the params:[] array is where the standard bitcoin parameters go, the only change that is needed is to specify the coin -alternatively {"agent":"SuperNET","method":"bitcoinrpc","coin":"BTCD"} will set the coin +alternatively {"agent":"SuperNET","method":"bitcoinrpc","coin":"BTCD"} will set the coin to use for bitcoin RPC calls. this will suffice in single coin environments curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"iguana",\"method\":\"test\"}" curl --url "http://127.0.0.1:7778/iguana/test" -> html page with results curl --url "http://127.0.0.1:7778/api/iguana/test" -> just json text http://127.0.0.1:7778 -> superugly GUI -http://127.0.0.1:7778/iguana/test +http://127.0.0.1:7778/iguana/test http://127.0.0.1:7778/api/iguana/test postCall('{"agent":"iguana","method":"test"}'} iguana_JSON("{\"agent\":\"iguana",\"method\":\"test\"}"); -> direct C function call @@ -124,7 +126,7 @@ iguana can be invoked with a command line argument. if it is a name of a file, i "exchanges" -> { "name":"", ... } "apikey", "apisecret", "userid", "tradepassword" these are as expected "pollgap" -> gap between each access to exchange for getting prices - + on OSX mksquashfs is not native, you will need to install fuse: https://osxfuse.github.io/ and a squashfs for mac: https://github.com/vasi/squashfuse ********** @@ -221,34 +223,3 @@ sudo service ntp start Now things should be ready. To update and run notary node: pkill iguana; ./m_LP; tests/notaryinit - - -##Build for OSX distribution## -Get OSX SDK 10.6 from https://github.com/ca333/MacOSX-SDKs/releases/tag/10.6 - -Unpack & move the .sdk folder to Xcodes SDK folder: - -```cd DownloadDirectory``` - -```mv MacOSX10.6.sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/.``` - -If you are using Xcode > 7.3 add the new SDK to XCode by changing MinimumSDKVersion in your Info.plist: - -```vi /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Info.plist``` - -Change the value to: - -``` -MinimumSDKVersion -10.6 -``` -Build crypto777 library and agents with OSX release makefile: - -```./m_onetime m_osx_release``` - -Execute the OSX deploy script: - -``` -./osx_deploy.sh -``` -The iguana binary and its linked libraries are in ```$HOME/tmp/iguana```. diff --git a/iguana/iguana_secp.c b/iguana/iguana_secp.c index f7a51164a..acc345d17 100755 --- a/iguana/iguana_secp.c +++ b/iguana/iguana_secp.c @@ -451,95 +451,6 @@ int32_t bitcoin_rangeproof(void *ctx,uint8_t *proof,uint8_t *commit,bits256 blin return(retval); } -/* - * The intended procedure for creating a multiparty signature is: - * - Each signer S[i] with private key x[i] and public key Q[i] runs - * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of private/public nonces. - * - All signers communicate their public nonces to each other (revealing your - * private nonce can lead to discovery of your private key, so it should be considered secret). - * - All signers combine all the public nonces they received (excluding their - * own) using secp256k1_ec_pubkey_combine to obtain an Rall[i] = sum(R[0..i-1,i+1..n]). - * - All signers produce a partial signature using - * secp256k1_schnorr_partial_sign, passing in their own private key x[i], - * their own private nonce k[i], and the sum of the others' public nonces Rall[i]. - * - All signers communicate their partial signatures to each other. - * - Someone combines all partial signatures using secp256k1_schnorr_partial_combine, to obtain a full signature. - * - The resulting signature is validatable using secp256k1_schnorr_verify, with - * public key equal to the result of secp256k1_ec_pubkey_combine of the signers' public keys (sum(Q[0..n])). - * - * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine - * function take their arguments in any order, and it is possible to - * pre-combine several inputs already with one call, and add more inputs later - * by calling the function again (they are commutative and associative). - */ - -#ifdef test_schnorr -#include "secp256k1/src/util.h" -#include "secp256k1/src/hash_impl.h" -#include "secp256k1/src/testrand_impl.h" - -void test_schnorr_threshold(void *ctx) { - unsigned char msg[32]; - unsigned char sec[5][32]; - secp256k1_pubkey pub[5]; - unsigned char nonce[5][32]; - secp256k1_pubkey pubnonce[5]; - unsigned char sig[5][64]; - const unsigned char* sigs[5]; - unsigned char allsig[64]; - const secp256k1_pubkey* pubs[5]; - secp256k1_pubkey allpub; - int n, i; - int damage; - int ret = 0; - - damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0; - secp256k1_rand256_test(msg); - n = 2 + secp256k1_rand_int(4); - for (i = 0; i < n; i++) { - do { - secp256k1_rand256_test(sec[i]); - } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); - CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); - pubs[i] = &pub[i]; - } - if (damage == 1) { - nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } else if (damage == 2) { - sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - for (i = 0; i < n; i++) { - secp256k1_pubkey allpubnonce; - const secp256k1_pubkey *pubnonces[4]; - int j; - for (j = 0; j < i; j++) { - pubnonces[j] = &pubnonce[j]; - } - for (j = i + 1; j < n; j++) { - pubnonces[j - 1] = &pubnonce[j]; - } - CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); - ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; - sigs[i] = sig[i]; - } - if (damage == 3) { - sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255); - } - ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; - if ((ret & 1) == 0) { - ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; - } - if (damage == 4) { - allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - if ((ret & 7) == 0) { - ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; - } - CHECK((ret == 0) == (damage == 0)); -} -#endif - int32_t iguana_pederson_test(void *ctx) { uint8_t commits[100][33],*commitptrs[100],proofs[100][5138]; uint16_t vouts[100]; int64_t min_value,values[100],totalpos,totalneg; bits256 txids[100],nonces[100],blinds[100],*blindptrs[100],blindsum; int32_t prooflens[100],i,r,pos,neg,numpos,exponent,min_bits,n,N = 100; From a393381bf43f120476cd43e7079b5cadf591ce22 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 02:19:02 +0300 Subject: [PATCH 0034/2705] Test --- basilisk/basilisk.c | 4 +- basilisk/basilisk_bitcoin.c | 10 +- basilisk/jumblr.c | 270 +++++++++++++++++++++++++++++------- crypto777/iguana_utils.c | 2 +- iguana/coins/genbtc | 2 +- iguana/iguana_payments.c | 6 +- iguana/tests/dexgetO | 2 +- includes/iguana_funcs.h | 2 +- includes/iguana_globals.h | 2 +- includes/iguana_structs.h | 8 +- 10 files changed, 245 insertions(+), 63 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index eb2d7237c..ddb1634a4 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1603,7 +1603,7 @@ TWO_STRINGS(basilisk,refresh,symbol,address) STRING_ARRAY_OBJ_STRING(basilisk,utxorawtx,symbol,utxos,vals,ignore) { - char *destaddr,*changeaddr; uint64_t satoshis,txfee; int32_t completed,sendflag,timelock; + char *destaddr,*changeaddr; int64_t satoshis,txfee; int32_t completed,sendflag,timelock; timelock = jint(vals,"timelock"); sendflag = jint(vals,"sendflag"); satoshis = jdouble(vals,"amount") * SATOSHIDEN; @@ -1612,7 +1612,7 @@ STRING_ARRAY_OBJ_STRING(basilisk,utxorawtx,symbol,utxos,vals,ignore) if ( destaddr != 0 && changeaddr != 0 && symbol != 0 && (coin= iguana_coinfind(symbol)) != 0 ) { txfee = jdouble(vals,"txfee") * SATOSHIDEN; - return(iguana_utxorawtx(myinfo,coin,timelock,destaddr,changeaddr,satoshis,txfee,&completed,sendflag,utxos)); + return(iguana_utxorawtx(myinfo,coin,timelock,destaddr,changeaddr,&satoshis,1,txfee,&completed,sendflag,utxos)); } return(clonestr("{\"error\":\"invalid coin or address specified\"}")); } diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index 8dec9ae69..3e29d422f 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -658,9 +658,9 @@ int64_t iguana_verifytimelock(struct supernet_info *myinfo,struct iguana_info *c } return(-2); } -char *iguana_utxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,int32_t timelock,char *destaddr,char *changeaddr,uint64_t satoshis,uint64_t txfee,int32_t *completedp,int32_t sendflag,cJSON *utxos) +char *iguana_utxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,int32_t timelock,char *destaddr,char *changeaddr,int64_t *satoshis,int32_t numoutputs,uint64_t txfee,int32_t *completedp,int32_t sendflag,cJSON *utxos) { - uint8_t script[35],p2shscript[128],rmd160[20],addrtype; bits256 txid; int32_t p2shlen,iter,spendlen; cJSON *retjson,*txcopy,*txobj=0,*vins=0; char *rawtx=0,*signedtx=0; uint32_t timelocked = 0; + uint8_t script[35],p2shscript[128],rmd160[20],addrtype; bits256 txid; int32_t i,p2shlen,iter,spendlen; cJSON *retjson,*txcopy,*txobj=0,*vins=0; char *rawtx=0,*signedtx=0; uint32_t timelocked = 0; *completedp = 0; if ( iguana_addressvalidate(coin,&addrtype,destaddr) < 0 || iguana_addressvalidate(coin,&addrtype,changeaddr) < 0 ) return(clonestr("{\"error\":\"invalid coin address\"}")); @@ -687,11 +687,13 @@ char *iguana_utxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,int spendlen = bitcoin_p2shspend(script,0,rmd160); printf("timelock.%d spend timelocked %u\n",timelock,timelocked); } - bitcoin_txoutput(txobj,script,spendlen,satoshis); + for (i=0; i 0 ) + bitcoin_txoutput(txobj,script,spendlen,satoshis[i]); for (iter=0; iter<2; iter++) { txcopy = jduplicate(txobj); - if ( (rawtx= iguana_calcutxorawtx(myinfo,coin,&vins,txobj,satoshis,changeaddr,txfee,utxos,"",0,0)) != 0 ) + if ( (rawtx= iguana_calcutxorawtx(myinfo,coin,&vins,txobj,satoshis,numoutputs,changeaddr,txfee,utxos,"",0,0)) != 0 ) { if ( iter == 1 || txfee != 0 ) jaddstr(retjson,"rawtx",rawtx); diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 5dea0d784..3a15322ac 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -375,104 +375,280 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,uint8_t pubtyp return(privkey); } -/*struct DEXcoin_info +int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4]) { - bits256 deposit_privkey,jumblr_privkey; - struct iguana_info *coin; - cJSON *utxos,*spentutxos,*bigutxos,*normalutxos,*smallutxos,*feeutxos,*otherutxos; - double btcprice,USD_average,DEXpending,maxbid,minask,avail,KMDavail; - uint32_t lasttime; - char CMCname[32],symbol[16],depositaddr[64],KMDdepositaddr[64],KMDjumblraddr[64],jumblraddr[64]; -};*/ + int64_t values[4],outputs[64],value,total,estfee = 50000; int32_t i,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; + total = 0; + memset(values,0,sizeof(values)); + memset(outputs,0,sizeof(outputs)); + if ( bigprice > SMALLVAL ) + values[0] = SATOSHIDEN * bigprice; + if ( middleprice > SMALLVAL ) + values[1] = SATOSHIDEN * middleprice; + if ( smallprice > SMALLVAL ) + values[2] = SATOSHIDEN * smallprice; + for (i=0; i<4; i++) + { + if ( fees[i] > SMALLVAL ) + values[3+i] = SATOSHIDEN * fees[i]; + } + for (i=0; i<7; i++) + { + if ( (value= values[i]) != 0 ) + { + while ( remaining > value+estfee && numoutputs < sizeof(outputs)/sizeof(*outputs) ) + { + outputs[numoutputs++] = value; + remaining -= value; + total += value; + printf("%.8f ",dstr(value)); + } + } + } + char str[65]; printf("numoutputs.%d total %.8f %s/v%d\n",numoutputs,dstr(total),bits256_str(str,txid),vout); + if ( numoutputs > 0 ) + { + if ( (retstr= _dex_gettxout(myinfo,coin->symbol,txid,vout)) != 0 ) + { + item = cJSON_Parse(retstr); + free(retstr); + if ( item != 0 ) + { + utxo = cJSON_CreateArray(); + jaddi(utxo,item); + sendflag = 0; + if ( (retstr= iguana_utxorawtx(myinfo,coin,0,coinaddr,coinaddr,outputs,numoutputs,0,&completed,sendflag,utxo)) != 0 ) + { + if ( completed != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( jobj(retjson,"error") == 0 && jobj(retjson,"sent") != 0 ) + { + *splittxidp = jbits256(retjson,"sent"); + success = 1; + printf("DEXsplit success %.8f\n",dstr(total)); + } + free_json(retjson); + } + } + free(retstr); + } + free_json(utxo); + } + } + } + return(success * total); +} -int32_t jumblr_DEXsplit(struct supernet_info *myinfo,bits256 *splittxidp,bits256 txid,int32_t vout,uint64_t value,double bigprice,double middleprice,double smallprice,double feeprice) +double jumblr_DEXutxosize(double *targetpriceBp,double *targetpriceMp,double *targetpriceSp,int32_t isbob) { - + double fee,depositfactor = (isbob == 0) ? 1. : 1.2; + fee = JUMBLR_INCR * JUMBLR_FEE; + *targetpriceBp = depositfactor * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE); + *targetpriceMp = depositfactor * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE); + *targetpriceSp = depositfactor * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); + return(depositfactor); } -int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,bits256 *splittxidp,bits256 txid,int32_t vout,uint64_t value,int32_t isbob) +int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetpriceB,double targetpriceM,double targetpriceS,double amount,double margin,double dexfeeratio,double esttxfee) { - double targetpriceB,targetpriceM,targetpriceS,fee,depositfactor,dexfeeratio,margin = 1.1; - depositfactor = (isbob == 0) ? 1. : 1.2; - dexfeeratio = 500.; - memset(splittxidp,0,sizeof(*splittxidp)); - fee = JUMBLR_INCR * JUMBLR_FEE; - targetpriceB = depositfactor * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE); - targetpriceM = depositfactor * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE); - targetpriceS = depositfactor * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); - if ( value >= targetpriceB ) + *shouldsplitp = 0; + if ( amount >= targetpriceB ) { - if ( value > margin * (targetpriceB + targetpriceS) ) - jumblr_DEXsplit(myinfo,splittxidp,txid,vout,value,margin * targetpriceB,margin * targetpriceM,margin * targetpriceS,margin * targetpriceB/dexfeeratio); + if ( amount > margin * (targetpriceB + targetpriceS) ) + *shouldsplitp = 1; return(0); } else { - if ( value >= targetpriceM ) + if ( amount >= targetpriceM ) { - if ( value > margin * (targetpriceM + targetpriceS) ) - return(jumblr_DEXsplit(myinfo,splittxidp,txid,vout,value,0.,margin * targetpriceM,margin * targetpriceS,margin * targetpriceM/dexfeeratio)); - else return(0); + if ( amount > margin * (targetpriceM + targetpriceS) ) + *shouldsplitp = 1; + return(1); } else { - if ( value >= targetpriceS ) + if ( amount >= targetpriceS ) + { + if ( amount > margin * targetpriceS ) + *shouldsplitp = 1; + return(2); + } + else if ( amount >= targetpriceB/dexfeeratio ) + { + if ( amount > margin * targetpriceB/dexfeeratio ) + *shouldsplitp = 1; + return(3); + } + else if ( amount >= targetpriceM/dexfeeratio ) + { + if ( amount > margin * targetpriceM/dexfeeratio ) + *shouldsplitp = 1; + return(4); + } + else if ( amount >= targetpriceS/dexfeeratio ) { - if ( value > margin * targetpriceS ) - return(jumblr_DEXsplit(myinfo,splittxidp,txid,vout,value,0.,0.,margin * targetpriceS,margin * targetpriceS/dexfeeratio)); - else return(0); + if ( amount > margin * targetpriceS/dexfeeratio ) + *shouldsplitp = 1; + return(5); } - else if ( value > targetpriceS/dexfeeratio ) - return(jumblr_DEXsplit(myinfo,splittxidp,txid,vout,value,0.,0.,0.,margin * targetpriceS/dexfeeratio)); - else return(0); + else if ( amount >= esttxfee ) + { + if ( amount > esttxfee*4 ) + *shouldsplitp = 1; + return(6); + } + else return(-1); } } } -void jumblr_DEXupdate(struct supernet_info *myinfo,struct DEXcoin_info *ptr,char *symbol,char *CMCname,double BTC2KMD,double KMDavail) +int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t isbob) { - double avebid,aveask,highbid,lowask,CMC_average,changes[3]; struct iguana_info *kmdcoin = iguana_coinfind("KMD"); - if ( kmdcoin != 0 && time(NULL) > ptr->lasttime+60 ) + double fees[4],targetpriceB,amount,targetpriceM,targetpriceS,depositfactor,dexfeeratio,margin; int32_t ind,shouldsplit; + margin = 1.1; + depositfactor = (isbob == 0) ? 1. : 1.2; + dexfeeratio = 500.; + amount = dstr(value); + memset(splittxidp,0,sizeof(*splittxidp)); + depositfactor = jumblr_DEXutxosize(&targetpriceB,&targetpriceM,&targetpriceS,isbob); + fees[0] = (margin * targetpriceB) / dexfeeratio; + fees[1] = (margin * targetpriceM) / dexfeeratio; + fees[2] = (margin * targetpriceS) / dexfeeratio; + fees[3] = (strcmp("BTC",coin->symbol) == 0) ? 50000 : 10000; + if ( (ind= jumblr_DEXutxoind(&shouldsplit,targetpriceB,targetpriceM,targetpriceS,amount,margin,dexfeeratio,fees[3])) >= 0 ) { - if ( strcmp(symbol,ptr->symbol) != 0 || ptr->coin == 0 ) + if ( shouldsplit != 0 ) + return(jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetpriceB,margin * targetpriceM,margin * targetpriceS,fees)); + } + return(0); +} + +/*struct DEXcoin_info + { + bits256 deposit_privkey,jumblr_privkey; + struct iguana_info *coin; + cJSON *utxos,*spentutxos,*bigutxos,*normalutxos,*smallutxos,*feeutxos,*otherutxos; + double btcprice,USD_average,DEXpending,maxbid,minask,avail,KMDavail; + uint32_t lasttime; + char CMCname[32],symbol[16],depositaddr[64],KMDdepositaddr[64],KMDjumblraddr[64],jumblraddr[64]; + };*/ + +int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp,struct iguana_info *coin,bits256 txid,int32_t vout) +{ + int32_t i; + memset(splittxidp,0,sizeof(*splittxidp)); + for (i=0; iDEXinfo.numpending; i++) + { + if ( coin->DEXinfo.pending[i].vout == vout && bits256_cmp(coin->DEXinfo.pending[i].txid,txid) == 0 ) + { + *splittxidp = coin->DEXinfo.pending[i].splittxid; + return(i); + } + } + return(-1); +} + +void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout,bits256 splittxid) +{ + struct jumblr_pending pend; + memset(&pend,0,sizeof(pend)); + pend.splittxid = splittxid; + pend.txid = txid; + pend.vout = vout; + coin->DEXinfo.pending = realloc(coin->DEXinfo.pending,sizeof(*coin->DEXinfo.pending) * (1 + coin->DEXinfo.numpending)); + coin->DEXinfo.pending[coin->DEXinfo.numpending++] = pend; +} + +void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,double price,char *coinaddr) +{ + char *retstr; cJSON *array,*item; int32_t i,n,vout; bits256 txid,splittxid; uint64_t value; + if ( (retstr= _dex_listunspent(myinfo,coin->symbol,coinaddr)) != 0 ) + { + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; iIAMLP); + jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid); + } + } + } + free_json(array); + } + free(retstr); + } +} + +void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char *symbol,char *CMCname,double BTC2KMD,double KMDavail) +{ + double avebid,aveask,highbid,lowask,CMC_average,changes[3]; struct iguana_info *btccoin,*kmdcoin; struct DEXcoin_info *ptr = &coin->DEXinfo; + if ( coin != 0 && (kmdcoin= iguana_coinfind("KMD")) != 0 && time(NULL) > ptr->lasttime+60 ) + { + ptr->coin = coin; + if ( strcmp(symbol,ptr->symbol) != 0 ) { safecopy(ptr->symbol,symbol,sizeof(ptr->symbol)); safecopy(ptr->CMCname,CMCname,sizeof(ptr->CMCname)); - if ( ptr->coin == 0 ) - ptr->coin = iguana_coinfind(symbol); } - if ( ptr->coin != 0 ) + if ( ptr->depositaddr[0] == 0 ) { - if ( ptr->depositaddr[0] == 0 ) - ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,ptr->coin->chain->pubtype,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); - if ( ptr->jumblraddr[0] == 0 ) - ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,ptr->coin->chain->pubtype,ptr->KMDjumblraddr,""); - ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); + if ( strcmp("KMD",symbol) == 0 ) + ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,0,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); + else ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,ptr->coin->chain->pubtype,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); } + if ( ptr->jumblraddr[0] == 0 ) + ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,ptr->coin->chain->pubtype,ptr->KMDjumblraddr,""); + ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); if ( strcmp("KMD",symbol) == 0 ) { ptr->BTC2KMD = ptr->btcprice; ptr->kmdprice = 1.; ptr->KMDavail = ptr->avail; + if ( (btccoin= iguana_coinfind("BTC")) != 0 ) + jumblr_utxoupdate(myinfo,btccoin,ptr->btcprice,ptr->depositaddr); + jumblr_utxoupdate(myinfo,kmdcoin,1.,ptr->KMDdepositaddr); } else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) { ptr->kmdprice = ptr->btcprice / BTC2KMD; ptr->KMDavail = KMDavail; + jumblr_utxoupdate(myinfo,ptr->coin,ptr->kmdprice,ptr->depositaddr); } ptr->lasttime = (uint32_t)time(NULL); } } +void jumblr_CMCname(char *CMCname,char *symbol) +{ + if ( strcmp(symbol,"KMD") == 0 ) + strcpy(CMCname,"komodo"); +} + void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) { struct iguana_info *kmdcoin; if ( (kmdcoin= iguana_coinfind("KMD")) == 0 ) return; - jumblr_DEXupdate(myinfo,&kmdcoin->DEXinfo,"KMD","komodo",0.,0.); + jumblr_DEXupdate(myinfo,kmdcoin,"KMD","komodo",0.,0.); if ( strcmp(coin->symbol,"KMD") != 0 && kmdcoin->DEXinfo.btcprice > 0. ) - jumblr_DEXupdate(myinfo,&coin->DEXinfo,"KMD","komodo",kmdcoin->DEXinfo.btcprice,kmdcoin->DEXinfo.avail); + { + if ( coin->CMCname[0] == 0 ) + jumblr_CMCname(coin->CMCname,coin->symbol); + if ( coin->CMCname[0] != 0 ) + jumblr_DEXupdate(myinfo,coin,coin->symbol,coin->CMCname,kmdcoin->DEXinfo.btcprice,kmdcoin->DEXinfo.avail); + } /*if ( kmdprice > SMALLVAL ) { minbtc = (kmdprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); diff --git a/crypto777/iguana_utils.c b/crypto777/iguana_utils.c index 80988fa5f..115e90a98 100755 --- a/crypto777/iguana_utils.c +++ b/crypto777/iguana_utils.c @@ -1279,7 +1279,7 @@ double get_theoretical(double *avebidp,double *aveaskp,double *highbidp,double * weighted = weighted_orderbook(avebidp,aveaskp,highbidp,lowaskp,bittrex_orderbook(base,rel,25),1./(*CMC_averagep)); if ( *CMC_averagep > SMALLVAL && weighted > SMALLVAL ) theoretical = calc_theoretical(weighted,*CMC_averagep,changes); - if ( counter++ == 0 ) + if ( counter++ < 100 ) printf("HBLA.[%.8f %.8f] AVE.[%.8f %.8f] (%s) CMC %f %f %f %f\n",*highbidp,*lowaskp,*avebidp,*aveaskp,jprint(item,0),*CMC_averagep,changes[0],changes[1],changes[2]); free_json(cmcjson); } diff --git a/iguana/coins/genbtc b/iguana/coins/genbtc index 839825619..407783045 100755 --- a/iguana/coins/genbtc +++ b/iguana/coins/genbtc @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"prefetchlag\":-1,\"poll\":1,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"newcoin\":\"BTC\",\"startpend\":64,\"endpend\":64,\"services\":129,\"maxpeers\":512,\"RELAY\":1,\"VALIDATE\":1,\"portp2p\":8333,\"minconfirms\":1}" +curl --url "http://127.0.0.1:7778" --data "{\"prefetchlag\":-1,\"poll\":1,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"newcoin\":\"BTC\",\"startpend\":16,\"endpend\":4,\"services\":129,\"maxpeers\":512,\"RELAY\":1,\"VALIDATE\":1,\"portp2p\":8333,\"minconfirms\":1}" diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index 43760ebd7..cfe164a8a 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -545,12 +545,14 @@ char *iguana_calcrawtx(struct supernet_info *myinfo,struct iguana_info *coin,cJS return(rawtx); } -char *iguana_calcutxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,cJSON **vinsp,cJSON *txobj,int64_t satoshis,char *changeaddr,int64_t txfee,cJSON *utxos,char *remoteaddr,struct vin_info *V,int32_t maxmode) +char *iguana_calcutxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,cJSON **vinsp,cJSON *txobj,int64_t *outputs,int32_t numoutputs,char *changeaddr,int64_t txfee,cJSON *utxos,char *remoteaddr,struct vin_info *V,int32_t maxmode) { - uint8_t addrtype,rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE]; int32_t allocflag=0,max,i,n,num,spendlen; char *spendscriptstr,*rawtx=0; bits256 txid; cJSON *sobj,*vins=0,*item; uint64_t value,avail=0,total,change,interests; struct iguana_outpoint *unspents = 0; + uint8_t addrtype,rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE]; int32_t allocflag=0,max,i,n,num,spendlen; char *spendscriptstr,*rawtx=0; uint64_t satoshis = 0; bits256 txid; cJSON *sobj,*vins=0,*item; uint64_t value,avail=0,total,change,interests; struct iguana_outpoint *unspents = 0; *vinsp = 0; max = 0; interests = 0; + for (i=0; i Date: Thu, 30 Mar 2017 02:22:25 +0300 Subject: [PATCH 0035/2705] Test --- basilisk/jumblr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 3a15322ac..0ba6e311b 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -639,8 +639,9 @@ void jumblr_CMCname(char *CMCname,char *symbol) void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) { struct iguana_info *kmdcoin; - if ( (kmdcoin= iguana_coinfind("KMD")) == 0 ) + if ( (kmdcoin= iguana_coinfind("KMD")) == 0 || iguana_coinfind("BTC") == 0 ) return; + printf("jumblr_DEXcheck\n"); jumblr_DEXupdate(myinfo,kmdcoin,"KMD","komodo",0.,0.); if ( strcmp(coin->symbol,"KMD") != 0 && kmdcoin->DEXinfo.btcprice > 0. ) { From 625cdd982aba865a493127c24f9fd9b430a25167 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 02:36:52 +0300 Subject: [PATCH 0036/2705] Test --- iguana/iguana_tx.c | 2 +- iguana/m_LP | 6 +++--- iguana/m_osx | 2 +- iguana/m_test | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/iguana_tx.c b/iguana/iguana_tx.c index e096ab1bb..2385fa6e8 100755 --- a/iguana/iguana_tx.c +++ b/iguana/iguana_tx.c @@ -307,7 +307,7 @@ int32_t iguana_peerblockrequest(struct supernet_info *myinfo,struct iguana_info char str[65],str2[65]; if ( counter++ < 100 ) { - for (i=0; ihdrsi,bundlei,bits256_str(str,checktxid),bits256_str(str2,T.txid)); } diff --git a/iguana/m_LP b/iguana/m_LP index d09ee9373..999ba620c 100755 --- a/iguana/m_LP +++ b/iguana/m_LP @@ -4,6 +4,6 @@ rm -f ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. cd ../crypto777; ./m_LP; cd ../iguana -clang -g -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -clang -g -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c -clang -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm +gcc -g -fno-aggressive-loop-optimizations -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c +gcc -g -fno-aggressive-loop-optimizations -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c +gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm diff --git a/iguana/m_osx b/iguana/m_osx index 500053d38..e752b11cc 100755 --- a/iguana/m_osx +++ b/iguana/m_osx @@ -4,5 +4,5 @@ rm ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. gcc -g -Wno-address-of-packed-member -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -gcc -g -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c +gcc -g -Wno-address-of-packed-member -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a -lnanomsg -lcurl -lssl -lcrypto -lpthread -lz -lm diff --git a/iguana/m_test b/iguana/m_test index 702cbb33e..27c8be43a 100755 --- a/iguana/m_test +++ b/iguana/m_test @@ -5,7 +5,7 @@ git pull cd secp256k1; ./m_unix; cd .. cd ../crypto777; ./m_LP; cd ../iguana gcc -g -fno-aggressive-loop-optimizations -Wno-deprecated -c -O2 -DISNOTARYNODE=1 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -gcc -g -fno-aggressive-loop-optimizations -Wno-deprecated -c -DISNOTARYNODE=1 -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c +gcc -g -fno-aggressive-loop-optimizations -Wno-deprecated -c -DISNOTARYNODE=1 -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a -lnanomsg -lcurl -lssl -lcrypto -lpthread -lz -lm ../agents/iguana notary & #> iguana.log 2> error.log & From cab64f08e4e90baef733046924303ed5fc3cda65 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 02:47:55 +0300 Subject: [PATCH 0037/2705] Test --- iguana/m_LP | 6 +++--- iguana/m_osx_release | 6 +++--- iguana/pangea777.h | 2 +- includes/iguana_structs.h | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iguana/m_LP b/iguana/m_LP index 999ba620c..ff173b759 100755 --- a/iguana/m_LP +++ b/iguana/m_LP @@ -4,6 +4,6 @@ rm -f ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. cd ../crypto777; ./m_LP; cd ../iguana -gcc -g -fno-aggressive-loop-optimizations -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -gcc -g -fno-aggressive-loop-optimizations -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c -gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm +clang -g -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c +clang -g -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c +clang -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm diff --git a/iguana/m_osx_release b/iguana/m_osx_release index 19c94d74b..5f74885e7 100755 --- a/iguana/m_osx_release +++ b/iguana/m_osx_release @@ -3,6 +3,6 @@ rm ../agents/iguana *.o git pull cd secp256k1; ./m_osx_release; cd .. -gcc -g -mmacosx-version-min=10.6 -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -gcc -g -mmacosx-version-min=10.6 -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c -gcc -g -mmacosx-version-min=10.6 /usr/local/lib/libnanomsg.5.0.0.dylib -o ../agents/iguana *.o ../agents/libcrypto777.a -lcurl -lssl -lcrypto -lpthread -lz -lm +clang -g -mmacosx-version-min=10.6 -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c +clang -g -mmacosx-version-min=10.6 -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c +clang -g -mmacosx-version-min=10.6 /usr/local/lib/libnanomsg.5.0.0.dylib -o ../agents/iguana *.o ../agents/libcrypto777.a -lcurl -lssl -lcrypto -lpthread -lz -lm diff --git a/iguana/pangea777.h b/iguana/pangea777.h index 731531f84..1ff471e3a 100755 --- a/iguana/pangea777.h +++ b/iguana/pangea777.h @@ -128,7 +128,7 @@ struct pangea_msghdr char cmd[8]; int8_t turni,cardi,destplayer,myind; // ALL DATA MUST BE SERIALIZED!!! uint8_t serialized[]; -} PACKED; +};// PACKED; #define PANGEA_ARGS struct supernet_info *myinfo,struct table_info *tp,cJSON *json #define PANGEA_CALLARGS myinfo,tp,json diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index e52b6c037..27ea9af8f 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -141,7 +141,7 @@ struct iguana_msgmerkle uint32_t branch_length; bits256 branch_hash[4096]; uint32_t branch_side_mask; -}PACKEDSTRUCT; +}; //PACKEDSTRUCT; struct iguana_msgblock { @@ -155,9 +155,9 @@ struct iguana_msgzblock uint32_t txn_count; } PACKEDSTRUCT; -struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }PACKEDSTRUCT; +struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }; //PACKEDSTRUCT; -struct iguana_msgvout { uint64_t value; uint32_t pk_scriptlen; uint8_t *pk_script; }PACKEDSTRUCT; +struct iguana_msgvout { uint64_t value; uint32_t pk_scriptlen; uint8_t *pk_script; }; //PACKEDSTRUCT; struct iguana_msgtx { @@ -168,7 +168,7 @@ struct iguana_msgtx int32_t allocsize,timestamp,numinputs,numoutputs; int64_t inputsum,outputsum,txfee; uint8_t *serialized; -} PACKEDSTRUCT; +};// PACKEDSTRUCT; struct iguana_msgjoinsplit { From fc53dc61a93d8b1f3e885db55aeebf2cdfe2f445 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 02:55:50 +0300 Subject: [PATCH 0038/2705] Test --- iguana/iguana_ramchain.c | 1 + iguana/m_LP | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/iguana_ramchain.c b/iguana/iguana_ramchain.c index a2cb07fdc..fab094e61 100755 --- a/iguana/iguana_ramchain.c +++ b/iguana/iguana_ramchain.c @@ -2176,6 +2176,7 @@ int32_t iguana_bundlefiles(struct iguana_info *coin,uint32_t *ipbits,void **ptrs void iguana_bundlemapfree(struct iguana_info *coin,struct OS_memspace *mem,struct OS_memspace *hashmem,uint32_t *ipbits,void **ptrs,long *filesizes,int32_t num,struct iguana_ramchain *R,int32_t starti,int32_t endi) { int32_t j,n = (endi - starti + 1); + sleep(3); for (j=0; j Date: Thu, 30 Mar 2017 03:06:43 +0300 Subject: [PATCH 0039/2705] Test --- iguana/iguana_ramchain.c | 1 - iguana/iguana_tx.c | 7 +++++-- iguana/m_LP | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/iguana_ramchain.c b/iguana/iguana_ramchain.c index fab094e61..a2cb07fdc 100755 --- a/iguana/iguana_ramchain.c +++ b/iguana/iguana_ramchain.c @@ -2176,7 +2176,6 @@ int32_t iguana_bundlefiles(struct iguana_info *coin,uint32_t *ipbits,void **ptrs void iguana_bundlemapfree(struct iguana_info *coin,struct OS_memspace *mem,struct OS_memspace *hashmem,uint32_t *ipbits,void **ptrs,long *filesizes,int32_t num,struct iguana_ramchain *R,int32_t starti,int32_t endi) { int32_t j,n = (endi - starti + 1); - sleep(3); for (j=0; j Date: Thu, 30 Mar 2017 03:12:46 +0300 Subject: [PATCH 0040/2705] Test --- iguana/iguana_ramchain.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/iguana/iguana_ramchain.c b/iguana/iguana_ramchain.c index a2cb07fdc..2926906b9 100755 --- a/iguana/iguana_ramchain.c +++ b/iguana/iguana_ramchain.c @@ -258,7 +258,9 @@ uint32_t iguana_ramchain_addpkhash(struct iguana_info *coin,RAMCHAIN_FUNC,uint8_ P[pkind].firstunspentind = unspentind; printf("%p P[%d] <- firstunspent.%d\n",&P[pkind],pkind,unspentind); }*/ - memcpy(P[pkind].rmd160,rmd160,sizeof(P[pkind].rmd160)); + //memcpy(P[pkind].rmd160,rmd160,sizeof(P[pkind].rmd160)); + for (i=0; i<20; i++) + P[pkind].rmd160[i] = rmd160[i]; //for (i=0; i<20; i++) // printf("%02x",rmd160[i]); //printf(" -> rmd160 pkind.%d \n",pkind); @@ -276,7 +278,7 @@ uint32_t iguana_ramchain_addpkhash(struct iguana_info *coin,RAMCHAIN_FUNC,uint8_ uint32_t iguana_ramchain_addunspent20(struct iguana_info *coin,struct iguana_peer *addr,RAMCHAIN_FUNC,uint64_t value,uint8_t *script,int32_t scriptlen,bits256 txid,int32_t vout,int8_t type,struct iguana_bundle *bp,uint8_t rmd160[20]) { - uint32_t unspentind; struct iguana_unspent20 *u; long scriptpos; struct vin_info V; char asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; + uint32_t unspentind,i; struct iguana_unspent20 *u; long scriptpos; struct vin_info V; char asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; unspentind = ramchain->H.unspentind++; u = &U[unspentind]; if ( scriptlen > 0 ) @@ -287,14 +289,16 @@ uint32_t iguana_ramchain_addunspent20(struct iguana_info *coin,struct iguana_pee type = iguana_calcrmd160(coin,asmstr,&V,script,scriptlen,txid,vout,0xffffffff); if ( (type == 12 && scriptlen == 0) || (type == 1 && bitcoin_pubkeylen(script+1) <= 0) ) { - int32_t i; for (i=0; iH.ROflag != 0 ) @@ -309,7 +313,9 @@ uint32_t iguana_ramchain_addunspent20(struct iguana_info *coin,struct iguana_pee { u->value = value; u->type = type; - memcpy(u->rmd160,rmd160,sizeof(u->rmd160)); + //memcpy(u->rmd160,rmd160,sizeof(u->rmd160)); + for (i=0; i<20; i++) + u->rmd160[i] = rmd160[i]; if ( type == IGUANA_SCRIPT_76AC ) { static uint64_t totalsize; @@ -693,7 +699,7 @@ void *iguana_ramchain_offset(char *fname,void *dest,uint8_t *lhash,FILE *fp,uint int32_t iguana_ramchain_prefetch(struct iguana_info *coin,struct iguana_ramchain *ramchain,int32_t flag) { RAMCHAIN_DECLARE; RAMCHAIN_ZEROES; - struct iguana_pkhash p; struct iguana_unspent u; struct iguana_txid txid; uint32_t i,numpkinds,numtxids,numunspents,numexternal,tlen,plen,nonz=0; uint8_t *ptr; struct iguana_ramchaindata *rdata; + struct iguana_pkhash p; struct iguana_unspent u; struct iguana_txid txid; uint32_t i,j,numpkinds,numtxids,numunspents,numexternal,tlen,plen,nonz=0; uint8_t *ptr; struct iguana_ramchaindata *rdata; //return(0); if ( (rdata= ramchain->H.data) != 0 ) { @@ -716,7 +722,9 @@ int32_t iguana_ramchain_prefetch(struct iguana_info *coin,struct iguana_ramchain tlen = (rdata->numtxsparse * rdata->txsparsebits) >> 3; for (i=0; i Date: Thu, 30 Mar 2017 03:17:56 +0300 Subject: [PATCH 0041/2705] Test --- crypto777/iguana_OS.c | 1 + iguana/iguana_ramchain.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto777/iguana_OS.c b/crypto777/iguana_OS.c index 8bd55e0d1..504905ee1 100755 --- a/crypto777/iguana_OS.c +++ b/crypto777/iguana_OS.c @@ -422,6 +422,7 @@ void *iguana_meminit(struct OS_memspace *mem,char *name,void *ptr,int64_t totals mem->totalsize = totalsize; } mem->threadsafe = threadsafe; + mem->alignflag = 4; iguana_memreset(mem); if ( mem->totalsize == 0 ) printf("meminit.%s ILLEGAL STATE null size\n",mem->name), getchar(); diff --git a/iguana/iguana_ramchain.c b/iguana/iguana_ramchain.c index 2926906b9..91b388a46 100755 --- a/iguana/iguana_ramchain.c +++ b/iguana/iguana_ramchain.c @@ -71,7 +71,7 @@ struct iguana_kvitem *iguana_hashsetPT(struct iguana_ramchain *ramchain,int32_t printf("negative itemind\n"); iguana_exit(0,0); } - if ( (0) ) + if ( (1) ) { if ( selector == 'T' ) HASH_FIND(hh,ramchain->txids,key,keylen,tmp); From 36b602a3ab7dd2742acd14eba2f007a7f467dce2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 03:20:06 +0300 Subject: [PATCH 0042/2705] Test --- iguana/m_LP | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/m_LP b/iguana/m_LP index 229b1936d..c93d5cf6b 100755 --- a/iguana/m_LP +++ b/iguana/m_LP @@ -4,6 +4,6 @@ rm -f ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. cd ../crypto777; ./m_LP; cd ../iguana -gcc -g -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -#gcc -g -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c +gcc -g -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c +gcc -g -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm From edc1adf132ff9a4cdc7b241bc392cfa70c93d928 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 03:26:38 +0300 Subject: [PATCH 0043/2705] Test --- includes/iguana_globals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/iguana_globals.h b/includes/iguana_globals.h index 07170e132..f4fda978c 100755 --- a/includes/iguana_globals.h +++ b/includes/iguana_globals.h @@ -42,7 +42,7 @@ char GLOBAL_GENESISDIR[512] = "genesis"; char GLOBAL_VALIDATEDIR[512] = "DB/purgeable"; char GLOBAL_CONFSDIR[512] = "confs"; #ifdef __linux -int32_t IGUANA_NUMHELPERS = 4; +int32_t IGUANA_NUMHELPERS = 1; #else int32_t IGUANA_NUMHELPERS = 1; #endif From 32d19a6d2685463267e9a8946a88a94e13656a54 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 03:48:17 +0300 Subject: [PATCH 0044/2705] Test --- iguana/iguana_ramchain.c | 2 ++ includes/iguana_globals.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/iguana_ramchain.c b/iguana/iguana_ramchain.c index 91b388a46..64ca06287 100755 --- a/iguana/iguana_ramchain.c +++ b/iguana/iguana_ramchain.c @@ -2197,6 +2197,8 @@ void iguana_bundlemapfree(struct iguana_info *coin,struct OS_memspace *mem,struc { for (j=starti; j<=endi; j++) { + R[j].fileptr = 0; + R[j].filesize = 0; iguana_ramchain_free(coin,&R[j],1); } myfree(R,n * sizeof(*R)); diff --git a/includes/iguana_globals.h b/includes/iguana_globals.h index f4fda978c..31a91a073 100755 --- a/includes/iguana_globals.h +++ b/includes/iguana_globals.h @@ -42,7 +42,7 @@ char GLOBAL_GENESISDIR[512] = "genesis"; char GLOBAL_VALIDATEDIR[512] = "DB/purgeable"; char GLOBAL_CONFSDIR[512] = "confs"; #ifdef __linux -int32_t IGUANA_NUMHELPERS = 1; +int32_t IGUANA_NUMHELPERS = 8; #else int32_t IGUANA_NUMHELPERS = 1; #endif From b5286807344c62de67e1868e1ba6943b9601af49 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 03:52:36 +0300 Subject: [PATCH 0045/2705] Test --- iguana/m_LP | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/m_LP b/iguana/m_LP index c93d5cf6b..8a00d3caa 100755 --- a/iguana/m_LP +++ b/iguana/m_LP @@ -4,6 +4,6 @@ rm -f ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. cd ../crypto777; ./m_LP; cd ../iguana -gcc -g -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -gcc -g -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c +gcc -g -Waggressive-loop-optimizations -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c +gcc -g -Waggressive-loop-optimizations -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm From 61432a9a91e870b3c9476397228381ed239a2330 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 03:54:16 +0300 Subject: [PATCH 0046/2705] Test --- iguana/m_LP | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/m_LP b/iguana/m_LP index 8a00d3caa..0e1135b48 100755 --- a/iguana/m_LP +++ b/iguana/m_LP @@ -4,6 +4,6 @@ rm -f ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. cd ../crypto777; ./m_LP; cd ../iguana -gcc -g -Waggressive-loop-optimizations -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -gcc -g -Waggressive-loop-optimizations -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c +gcc -g -Wno-aggressive-loop-optimizations -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c +gcc -g -Wno-aggressive-loop-optimizations -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm From adcd5f956b3e002f7aa41e83eed85788f6509c95 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 03:59:16 +0300 Subject: [PATCH 0047/2705] Test --- basilisk/basilisk_swap.c | 36 +++++++++++++++++++++--------------- iguana/iguana_unspents.c | 5 ++++- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 9b3abc4d5..c810ea103 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1120,20 +1120,22 @@ void basilisk_swaps_init(struct supernet_info *myinfo) if ( M.datalen < 100000 ) { M.data = malloc(M.datalen); - fread(M.data,1,M.datalen,fp); - if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) + if ( fread(M.data,1,M.datalen,fp) == M.datalen ) { - if ( iter == 1 ) + if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) { - if ( swap == 0 ) + if ( iter == 1 ) { - swap = basilisk_thread_start(myinfo,privkey,&R,statebits,optionduration,1); - swap->I.choosei = swap->I.otherchoosei = -1; + if ( swap == 0 ) + { + swap = basilisk_thread_start(myinfo,privkey,&R,statebits,optionduration,1); + swap->I.choosei = swap->I.otherchoosei = -1; + } + if ( swap != 0 ) + basilisk_swapgotdata(myinfo,swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); } - if ( swap != 0 ) - basilisk_swapgotdata(myinfo,swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); - } - } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); + } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); + } else printf("error reading M.datalen %d\n",M.datalen); free(M.data), M.data = 0; } } @@ -1456,14 +1458,15 @@ int32_t basilisk_swap_loadtx(struct basilisk_rawtx *rawtx,FILE *fp,char *bobcoin struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 privkey,uint8_t *pubkey33,bits256 pubkey25519,struct basilisk_swap *swap,int32_t optionduration,uint32_t statebits,int32_t reinit) { - FILE *fp; char fname[512]; uint8_t *alicepub33=0,*bobpub33=0; int32_t jumblrflag,x = -1; + FILE *fp; char fname[512]; uint8_t *alicepub33=0,*bobpub33=0; int32_t errs=0,jumblrflag,x = -1; if ( reinit != 0 ) { sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); printf("reinit.(%s)\n",fname); if ( (fp= fopen(fname,"rb")) != 0 ) { - fread(&swap->I,1,sizeof(swap->I),fp); + if ( fread(&swap->I,1,sizeof(swap->I),fp) != sizeof(swap->I) ) + errs++; if ( swap->bobcoin == 0 ) swap->bobcoin = iguana_coinfind(swap->I.req.dest); if ( swap->alicecoin == 0 ) @@ -1482,9 +1485,12 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv basilisk_swap_loadtx(&swap->bobrefund,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); basilisk_swap_loadtx(&swap->alicereclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol);*/ } else printf("missing coins (%p %p)\n",swap->bobcoin,swap->alicecoin); - fread(swap->privkeys,1,sizeof(swap->privkeys),fp); - fread(swap->otherdeck,1,sizeof(swap->otherdeck),fp); - fread(swap->deck,1,sizeof(swap->deck),fp); + if ( fread(swap->privkeys,1,sizeof(swap->privkeys),fp) != sizeof(swap->privkeys) ) + errs++; + if ( fread(swap->otherdeck,1,sizeof(swap->otherdeck),fp) != sizeof(swap->otherdeck) ) + errs++; + if ( fread(swap->deck,1,sizeof(swap->deck),fp) != sizeof(swap->deck) ) + errs++; fclose(fp); } else printf("cant find.(%s)\n",fname); } diff --git a/iguana/iguana_unspents.c b/iguana/iguana_unspents.c index 6534c2431..2974c300f 100755 --- a/iguana/iguana_unspents.c +++ b/iguana/iguana_unspents.c @@ -1896,7 +1896,10 @@ INT_ARRAY_STRING(iguana,dividends,height,vals,symbol) { sprintf(buf,"%s %s %.8f %s",prefix,field,dstr(val),suffix); if ( execflag != 0 ) - system(buf); + { + if ( system(buf) != 0 ) + printf("error system.(%s)\n",buf); + } else printf("%s\n",buf); emit += val; } else dustsum += val; From ed2048ebc8009423f350e3139adbd1471c93fc92 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 04:03:51 +0300 Subject: [PATCH 0048/2705] Test --- iguana/coins/genbtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/coins/genbtc b/iguana/coins/genbtc index 407783045..839825619 100755 --- a/iguana/coins/genbtc +++ b/iguana/coins/genbtc @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"prefetchlag\":-1,\"poll\":1,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"newcoin\":\"BTC\",\"startpend\":16,\"endpend\":4,\"services\":129,\"maxpeers\":512,\"RELAY\":1,\"VALIDATE\":1,\"portp2p\":8333,\"minconfirms\":1}" +curl --url "http://127.0.0.1:7778" --data "{\"prefetchlag\":-1,\"poll\":1,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"newcoin\":\"BTC\",\"startpend\":64,\"endpend\":64,\"services\":129,\"maxpeers\":512,\"RELAY\":1,\"VALIDATE\":1,\"portp2p\":8333,\"minconfirms\":1}" From 85c471e732ce4c90f0019c3f652c13948cc8a48e Mon Sep 17 00:00:00 2001 From: Mihail Fedorov Date: Thu, 30 Mar 2017 17:12:28 +0300 Subject: [PATCH 0049/2705] Fixed WLC ports and added splitfund --- iguana/coins/basilisk/wlc | 2 +- iguana/coins/wlc_7776 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/coins/basilisk/wlc b/iguana/coins/basilisk/wlc index bf98898b1..8c10b2475 100755 --- a/iguana/coins/basilisk/wlc +++ b/iguana/coins/basilisk/wlc @@ -1 +1 @@ -curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"WLC.conf\",\"path\":\"${HOME#"/"}/.komodo/WLC\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"WLC\",\"name\":\"WLC\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7ec1c253\",\"p2p\":15431,\"rpc\":15432,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"WLC.conf\",\"path\":\"${HOME#"/"}/.komodo/WLC\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"WLC\",\"name\":\"WLC\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7ec1c253\",\"p2p\":12166,\"rpc\":12167,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/wlc_7776 b/iguana/coins/wlc_7776 index 086c678cd..b43b7f793 100755 --- a/iguana/coins/wlc_7776 +++ b/iguana/coins/wlc_7776 @@ -1 +1 @@ -curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"WLC.conf\",\"path\":\"${HOME#"/"}/.komodo/WLC\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"WLC\",\"name\":\"WLC\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7ec1c253\",\"p2p\":15431,\"rpc\":15432,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"WLC.conf\",\"path\":\"${HOME#"/"}/.komodo/WLC\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"WLC\",\"name\":\"WLC\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7ec1c253\",\"p2p\":12166,\"rpc\":12167,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" From d9a0d8efb944bc542a3b4c25fcf6e1e857fc2cc4 Mon Sep 17 00:00:00 2001 From: Mihail Fedorov Date: Thu, 30 Mar 2017 17:13:11 +0300 Subject: [PATCH 0050/2705] Fixed WLC ports and added splitfund --- iguana/m_splifund | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100755 iguana/m_splifund diff --git a/iguana/m_splifund b/iguana/m_splifund new file mode 100755 index 000000000..36da01d22 --- /dev/null +++ b/iguana/m_splifund @@ -0,0 +1,57 @@ +#!/bin/bash + +set -x + +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"BTC\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"KMD\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" + +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"REVS\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"SUPERNET\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"DEX\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"PANGEA\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"JUMBLR\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"BET\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"CRYPTO\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"HODL\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"SHARK\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"BOTS\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"MGW\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"MVP\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"WLC\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"KV\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"CEAL\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"MESH\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" + +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"USD\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"EUR\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" + +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"JPY\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"GBP\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"AUD\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"CAD\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"CHF\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"NZD\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"CNY\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"RUB\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"MXN\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"BRL\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"INR\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"HKD\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"TRY\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"ZAR\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"PLN\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"NOK\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"SEK\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"DKK\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"CZK\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"HUF\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"ILS\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"KRW\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"MYR\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"PHP\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"RON\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"SGD\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"THB\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"BGN\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"IDR\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7776" --data "{\"coin\":\"HRK\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" From 2293781887c6857ead019b131fbb7741aa29190b Mon Sep 17 00:00:00 2001 From: Mihail Fedorov Date: Thu, 30 Mar 2017 17:13:52 +0300 Subject: [PATCH 0051/2705] Fixed WLC ports and added splitfund --- iguana/{m_splifund => m_splitfund} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename iguana/{m_splifund => m_splitfund} (100%) diff --git a/iguana/m_splifund b/iguana/m_splitfund similarity index 100% rename from iguana/m_splifund rename to iguana/m_splitfund From 3efa457f7d0ff6f63e71d650a49d6d2fd691ecc4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 18:25:37 +0300 Subject: [PATCH 0052/2705] Test --- basilisk/basilisk.c | 2 +- basilisk/basilisk_bitcoin.c | 2 +- basilisk/jumblr.c | 21 +++++++++++++++------ iguana/exchanges/bittrex.c | 2 +- iguana/main.c | 15 +++++++++------ iguana/wp | 4 ++++ 6 files changed, 31 insertions(+), 15 deletions(-) create mode 100755 iguana/wp diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index ddb1634a4..59e4480b3 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1294,7 +1294,7 @@ HASH_ARRAY_STRING(basilisk,rawtx,hash,vals,hexstr) STRING_ARG(jumblr,setpassphrase,passphrase) { cJSON *retjson; char KMDaddr[64],BTCaddr[64],wifstr[64]; bits256 privkey; struct iguana_info *coinbtc; - if ( passphrase == 0 || passphrase[0] == 0 || (coin= iguana_coinfind("KMD")) == 0 || coin->FULLNODE >= 0 ) + if ( passphrase == 0 || passphrase[0] == 0 || (coin= iguana_coinfind("KMD")) == 0 )//|| coin->FULLNODE >= 0 ) return(clonestr("{\"error\":\"no passphrase or no native komodod\"}")); else { diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index 3e29d422f..cbe759041 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -594,7 +594,7 @@ char *iguana_utxoduplicates(struct supernet_info *myinfo,struct iguana_info *coi for (i=0; i duplicates/4 ) + if ( cJSON_GetArraySize(vins) > duplicates/2 ) { free(rawtx); rawtx = 0; diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 0ba6e311b..fcae77073 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -364,14 +364,17 @@ void jumblr_opidsupdate(struct supernet_info *myinfo,struct iguana_info *coin) } } -bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,uint8_t pubtype,char *KMDaddr,char *prefix) +bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubtype,char *KMDaddr,char *prefix) { bits256 privkey,pubkey; uint8_t pubkey33[33]; char passphrase[sizeof(myinfo->jumblr_passphrase) + 64]; sprintf(passphrase,"%s%s",prefix,myinfo->jumblr_passphrase); + if ( myinfo->jumblr_passphrase[0] == 0 ) + strcpy(myinfo->jumblr_passphrase,"password"); conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); - bitcoin_address(BTCaddr,pubtype,pubkey33,33); + bitcoin_address(coinaddr,pubtype,pubkey33,33); bitcoin_address(KMDaddr,60,pubkey33,33); + printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); return(privkey); } @@ -567,6 +570,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou char *retstr; cJSON *array,*item; int32_t i,n,vout; bits256 txid,splittxid; uint64_t value; if ( (retstr= _dex_listunspent(myinfo,coin->symbol,coinaddr)) != 0 ) { + printf("%s.(%s)\n",coin->symbol,retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -601,16 +605,21 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char safecopy(ptr->symbol,symbol,sizeof(ptr->symbol)); safecopy(ptr->CMCname,CMCname,sizeof(ptr->CMCname)); } - if ( ptr->depositaddr[0] == 0 ) + //if ( ptr->depositaddr[0] == 0 ) { if ( strcmp("KMD",symbol) == 0 ) ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,0,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); else ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,ptr->coin->chain->pubtype,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); } - if ( ptr->jumblraddr[0] == 0 ) - ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,ptr->coin->chain->pubtype,ptr->KMDjumblraddr,""); + //if ( ptr->jumblraddr[0] == 0 ) + { + if ( strcmp("KMD",symbol) == 0 ) + ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,0,ptr->KMDjumblraddr,""); + else ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,ptr->coin->chain->pubtype,ptr->KMDjumblraddr,""); + } ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); + printf("%s avail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); if ( strcmp("KMD",symbol) == 0 ) { ptr->BTC2KMD = ptr->btcprice; @@ -627,7 +636,7 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char jumblr_utxoupdate(myinfo,ptr->coin,ptr->kmdprice,ptr->depositaddr); } ptr->lasttime = (uint32_t)time(NULL); - } + } else printf("skip\n"); } void jumblr_CMCname(char *CMCname,char *symbol) diff --git a/iguana/exchanges/bittrex.c b/iguana/exchanges/bittrex.c index 227cab9b1..dd7d4be26 100755 --- a/iguana/exchanges/bittrex.c +++ b/iguana/exchanges/bittrex.c @@ -169,7 +169,7 @@ uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,cha if ( //CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,payload,payload)) != 0 ) { - if ( *retstrp != 0 ) + if ( 0 && *retstrp != 0 ) printf("SIGNPOST returned.(%s) %s\n",*retstrp,jprint(json,0)); if ( is_cJSON_True(cJSON_GetObjectItem(json,"success")) != 0 && (resultobj= cJSON_GetObjectItem(json,"result")) != 0 ) { diff --git a/iguana/main.c b/iguana/main.c index 7b38676f9..71aad6eea 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -753,17 +753,20 @@ void jumblr_loop(void *ptr) printf("JUMBLR loop\n"); while ( 1 ) { - if ( myinfo->jumblr_passphrase[0] != 0 && (coin= iguana_coinfind("KMD")) != 0 && coin->FULLNODE < 0 ) + if ( (coin= iguana_coinfind("KMD")) != 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC jumblr_DEXcheck(myinfo,coin); - t = (uint32_t)time(NULL); - if ( (t % (120 * mult)) < 60 ) + if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { - // if BTC has arrived in deposit address, invoke DEX -> KMD - jumblr_iteration(myinfo,coin,(t % (360 * mult)) / (120 * mult),t % (120 * mult)); + t = (uint32_t)time(NULL); + if ( (t % (120 * mult)) < 60 ) + { + // if BTC has arrived in deposit address, invoke DEX -> KMD + jumblr_iteration(myinfo,coin,(t % (360 * mult)) / (120 * mult),t % (120 * mult)); + } + //printf("t.%u %p.%d %s\n",t,coin,coin!=0?coin->FULLNODE:0,myinfo->jumblr_passphrase); } - //printf("t.%u %p.%d %s\n",t,coin,coin!=0?coin->FULLNODE:0,myinfo->jumblr_passphrase); } sleep(55); } diff --git a/iguana/wp b/iguana/wp new file mode 100755 index 000000000..089af663c --- /dev/null +++ b/iguana/wp @@ -0,0 +1,4 @@ +#!/bin/bash +#curl --url "http://127.0.0.1:7778" --data "{\"method\":\"walletpassphrase\",\"params\":[\"test\", 600]}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"bitcoinrpc\",\"method\":\"walletpassphrase\",\"password\":\"3809853923098test\",\"timeout\":86444}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"jumblr\",\"method\":\"setpassphrase\",\"passphrase\":\"jumblr 3809853923098test\"}" From 7ba62c4a5bfb2393642878fd6ac64fb7ba4d5dd1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 18:26:06 +0300 Subject: [PATCH 0053/2705] Test --- iguana/wp | 4 ---- 1 file changed, 4 deletions(-) delete mode 100755 iguana/wp diff --git a/iguana/wp b/iguana/wp deleted file mode 100755 index 089af663c..000000000 --- a/iguana/wp +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -#curl --url "http://127.0.0.1:7778" --data "{\"method\":\"walletpassphrase\",\"params\":[\"test\", 600]}" -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"bitcoinrpc\",\"method\":\"walletpassphrase\",\"password\":\"3809853923098test\",\"timeout\":86444}" -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"jumblr\",\"method\":\"setpassphrase\",\"passphrase\":\"jumblr 3809853923098test\"}" From 479fac14527476206caf2c2948b56c6451224ffa Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 18:46:20 +0300 Subject: [PATCH 0054/2705] Test --- iguana/dpow/dpow_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index cadc11faa..9a12103f9 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1154,7 +1154,7 @@ char *_dex_listunspentarg(struct supernet_info *myinfo,char *symbol,char *addres dexreq.func = arg; if ( (retstr= _dex_sendrequeststr(myinfo,&dexreq,address,0,1,"")) != 0 ) { - //printf("UNSPENTS.(%s)\n",retstr); + printf("UNSPENTS.(%s)\n",retstr); } return(_dex_arrayreturn(retstr)); } From cacf188f6366c073182bc694293785f038c06236 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 18:50:31 +0300 Subject: [PATCH 0055/2705] Test --- basilisk/jumblr.c | 4 +++- iguana/dpow/dpow_network.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index fcae77073..d20d58a99 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -173,6 +173,8 @@ char *jumblr_zgetbalance(struct supernet_info *myinfo,struct iguana_info *coin,c char *jumblr_listunspent(struct supernet_info *myinfo,struct iguana_info *coin,char *addr) { char params[1024]; + if ( coin->FULLNODE == 0 ) + return(_dex_listunspent(myinfo,coin->symbol,addr)); sprintf(params,"[1, 99999999, [\"%s\"]]",addr); return(bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listunspent",params)); } @@ -568,7 +570,7 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info * void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,double price,char *coinaddr) { char *retstr; cJSON *array,*item; int32_t i,n,vout; bits256 txid,splittxid; uint64_t value; - if ( (retstr= _dex_listunspent(myinfo,coin->symbol,coinaddr)) != 0 ) + if ( (retstr= jumblr_listunspent(myinfo,coin,coinaddr)) != 0 ) { printf("%s.(%s)\n",coin->symbol,retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 9a12103f9..94b80c90d 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1154,7 +1154,7 @@ char *_dex_listunspentarg(struct supernet_info *myinfo,char *symbol,char *addres dexreq.func = arg; if ( (retstr= _dex_sendrequeststr(myinfo,&dexreq,address,0,1,"")) != 0 ) { - printf("UNSPENTS.(%s)\n",retstr); + printf("%s UNSPENTS.(%s)\n",symbol,retstr); } return(_dex_arrayreturn(retstr)); } From 113e95e98dc86eda1d66722aa4d9a6c4bf759c09 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 19:04:47 +0300 Subject: [PATCH 0056/2705] Test --- basilisk/jumblr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index d20d58a99..b987b7126 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -170,12 +170,12 @@ char *jumblr_zgetbalance(struct supernet_info *myinfo,struct iguana_info *coin,c return(bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"z_getbalance",params)); } -char *jumblr_listunspent(struct supernet_info *myinfo,struct iguana_info *coin,char *addr) +char *jumblr_listunspent(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr) { char params[1024]; if ( coin->FULLNODE == 0 ) - return(_dex_listunspent(myinfo,coin->symbol,addr)); - sprintf(params,"[1, 99999999, [\"%s\"]]",addr); + return(dex_listunspent(myinfo,coin,0,0,coin->symbol,coinaddr)); + sprintf(params,"[1, 99999999, [\"%s\"]]",coinaddr); return(bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listunspent",params)); } From 6b7d6af3eaabc12c6198207f4e6dc803a6cfc07c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 19:11:11 +0300 Subject: [PATCH 0057/2705] Test --- basilisk/jumblr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index b987b7126..1eb937a08 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -583,6 +583,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou txid = jbits256(item,"txid"); vout = jint(item,"vout"); value = SATOSHIDEN * jdouble(item,"amount"); + printf("%llx/v%d %.8f %d of %d\n",(long long)txid.txid,vout,dstr(value),i,n); if ( jumblr_utxotxidpending(myinfo,&splittxid,coin,txid,vout) < 0 ) { jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,txid,vout,value,myinfo->IAMLP); From 8790db453d6bc391637e158988b5ee8ffe36e596 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 30 Mar 2017 19:26:39 +0300 Subject: [PATCH 0058/2705] Test --- basilisk/jumblr.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 1eb937a08..606e1c5dd 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -525,9 +525,10 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co fees[3] = (strcmp("BTC",coin->symbol) == 0) ? 50000 : 10000; if ( (ind= jumblr_DEXutxoind(&shouldsplit,targetpriceB,targetpriceM,targetpriceS,amount,margin,dexfeeratio,fees[3])) >= 0 ) { + printf("shouldsplit.%d ind.%d\n",shouldsplit,ind); if ( shouldsplit != 0 ) return(jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetpriceB,margin * targetpriceM,margin * targetpriceS,fees)); - } + } else printf("negative ind\n"); return(0); } @@ -544,21 +545,25 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp,struct iguana_info *coin,bits256 txid,int32_t vout) { int32_t i; + printf("jumblr_utxotxidpending\n"); memset(splittxidp,0,sizeof(*splittxidp)); for (i=0; iDEXinfo.numpending; i++) { if ( coin->DEXinfo.pending[i].vout == vout && bits256_cmp(coin->DEXinfo.pending[i].txid,txid) == 0 ) { *splittxidp = coin->DEXinfo.pending[i].splittxid; + printf("jumblr_utxotxidpending found txid in slot.%d\n",i); return(i); } } + printf("jumblr_utxotxidpending cant find txid\n"); return(-1); } void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout,bits256 splittxid) { struct jumblr_pending pend; + printf("add txid to pending\n"); memset(&pend,0,sizeof(pend)); pend.splittxid = splittxid; pend.txid = txid; @@ -586,9 +591,10 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou printf("%llx/v%d %.8f %d of %d\n",(long long)txid.txid,vout,dstr(value),i,n); if ( jumblr_utxotxidpending(myinfo,&splittxid,coin,txid,vout) < 0 ) { + printf("call utxoupdate\n"); jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,txid,vout,value,myinfo->IAMLP); jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid); - } + } else printf("already have txid\n"); } } free_json(array); From 9be6578f324210ed8a91b5472e0642b3975139d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 09:58:35 +0300 Subject: [PATCH 0059/2705] File:// --- iguana/iguana_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/iguana_rpc.c b/iguana/iguana_rpc.c index 20ad9aa78..26fc9ac0b 100755 --- a/iguana/iguana_rpc.c +++ b/iguana/iguana_rpc.c @@ -874,7 +874,7 @@ char *SuperNET_rpcparse(struct supernet_info *myinfo,char *retbuf,int32_t bufsiz originstr = &urlstr[i + strlen(fieldstr)]; if ( strncmp(originstr,"http://127.0.0.",strlen("http://127.0.0.")) == 0 ) originstr = "http://127.0.0.1:"; - else if ( strncmp(originstr,"file://127.0.0.",strlen("file://127.0.0.")) == 0 ) + else if ( strncmp(originstr,"file://",strlen("file://")) == 0 ) //127.0.0. originstr = "http://127.0.0.1:"; else if ( strncmp(originstr,"chrome-extension://",strlen("chrome-extension://")) == 0 ) originstr = "http://127.0.0.1:"; From 0fee3ebfd9bdd188051874c4cb38f98b9dec6d75 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 10:24:47 +0300 Subject: [PATCH 0060/2705] Agama:// --- iguana/iguana_rpc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/iguana_rpc.c b/iguana/iguana_rpc.c index 26fc9ac0b..554624dc2 100755 --- a/iguana/iguana_rpc.c +++ b/iguana/iguana_rpc.c @@ -874,7 +874,9 @@ char *SuperNET_rpcparse(struct supernet_info *myinfo,char *retbuf,int32_t bufsiz originstr = &urlstr[i + strlen(fieldstr)]; if ( strncmp(originstr,"http://127.0.0.",strlen("http://127.0.0.")) == 0 ) originstr = "http://127.0.0.1:"; - else if ( strncmp(originstr,"file://",strlen("file://")) == 0 ) //127.0.0. + else if ( strncmp(originstr,"agama://",strlen("agama://")) == 0 ) + originstr = "http://127.0.0.1:"; + else if ( strncmp(originstr,"file://127.0.0.",strlen("file://127.0.0.")) == 0 ) originstr = "http://127.0.0.1:"; else if ( strncmp(originstr,"chrome-extension://",strlen("chrome-extension://")) == 0 ) originstr = "http://127.0.0.1:"; From 03fb2302866337945cdf7a07d7d60bf05dda58f0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 17:54:46 +0300 Subject: [PATCH 0061/2705] Test --- basilisk/jumblr.c | 49 ++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 606e1c5dd..9c71c209e 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -446,56 +446,56 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi return(success * total); } -double jumblr_DEXutxosize(double *targetpriceBp,double *targetpriceMp,double *targetpriceSp,int32_t isbob) +double jumblr_DEXutxosize(double *targetvolBp,double *targetvolMp,double *targetvolSp,int32_t isbob) { double fee,depositfactor = (isbob == 0) ? 1. : 1.2; fee = JUMBLR_INCR * JUMBLR_FEE; - *targetpriceBp = depositfactor * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE); - *targetpriceMp = depositfactor * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE); - *targetpriceSp = depositfactor * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); + *targetvolBp = depositfactor * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE); + *targetvolMp = depositfactor * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE); + *targetvolSp = depositfactor * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); return(depositfactor); } -int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetpriceB,double targetpriceM,double targetpriceS,double amount,double margin,double dexfeeratio,double esttxfee) +int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetvolB,double targetvolM,double targetvolS,double amount,double margin,double dexfeeratio,double esttxfee) { *shouldsplitp = 0; - if ( amount >= targetpriceB ) + if ( amount >= targetvolB ) { - if ( amount > margin * (targetpriceB + targetpriceS) ) + if ( amount > margin * (targetvolB + targetvolS) ) *shouldsplitp = 1; return(0); } else { - if ( amount >= targetpriceM ) + if ( amount >= targetvolM ) { - if ( amount > margin * (targetpriceM + targetpriceS) ) + if ( amount > margin * (targetvolM + targetvolS) ) *shouldsplitp = 1; return(1); } else { - if ( amount >= targetpriceS ) + if ( amount >= targetvolS ) { - if ( amount > margin * targetpriceS ) + if ( amount > margin * targetvolS ) *shouldsplitp = 1; return(2); } - else if ( amount >= targetpriceB/dexfeeratio ) + else if ( amount >= targetvolB/dexfeeratio ) { - if ( amount > margin * targetpriceB/dexfeeratio ) + if ( amount > margin * targetvolB/dexfeeratio ) *shouldsplitp = 1; return(3); } - else if ( amount >= targetpriceM/dexfeeratio ) + else if ( amount >= targetvolM/dexfeeratio ) { - if ( amount > margin * targetpriceM/dexfeeratio ) + if ( amount > margin * targetvolM/dexfeeratio ) *shouldsplitp = 1; return(4); } - else if ( amount >= targetpriceS/dexfeeratio ) + else if ( amount >= targetvolS/dexfeeratio ) { - if ( amount > margin * targetpriceS/dexfeeratio ) + if ( amount > margin * targetvolS/dexfeeratio ) *shouldsplitp = 1; return(5); } @@ -512,22 +512,23 @@ int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetpriceB,double targe int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t isbob) { - double fees[4],targetpriceB,amount,targetpriceM,targetpriceS,depositfactor,dexfeeratio,margin; int32_t ind,shouldsplit; + double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,shouldsplit; margin = 1.1; depositfactor = (isbob == 0) ? 1. : 1.2; dexfeeratio = 500.; amount = dstr(value); memset(splittxidp,0,sizeof(*splittxidp)); - depositfactor = jumblr_DEXutxosize(&targetpriceB,&targetpriceM,&targetpriceS,isbob); - fees[0] = (margin * targetpriceB) / dexfeeratio; - fees[1] = (margin * targetpriceM) / dexfeeratio; - fees[2] = (margin * targetpriceS) / dexfeeratio; + depositfactor = jumblr_DEXutxosize(&targetvolB,&targetvolM,&targetvolS,isbob); + printf("depositfactor %.8f targetvols %.8f %.8f %.8f\n",depositfactor,targetvolB,targetvolM,targetvolS); + fees[0] = (margin * targetvolB) / dexfeeratio; + fees[1] = (margin * targetvolM) / dexfeeratio; + fees[2] = (margin * targetvolS) / dexfeeratio; fees[3] = (strcmp("BTC",coin->symbol) == 0) ? 50000 : 10000; - if ( (ind= jumblr_DEXutxoind(&shouldsplit,targetpriceB,targetpriceM,targetpriceS,amount,margin,dexfeeratio,fees[3])) >= 0 ) + if ( (ind= jumblr_DEXutxoind(&shouldsplit,targetvolB,targetvolM,targetvolS,amount,margin,dexfeeratio,fees[3])) >= 0 ) { printf("shouldsplit.%d ind.%d\n",shouldsplit,ind); if ( shouldsplit != 0 ) - return(jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetpriceB,margin * targetpriceM,margin * targetpriceS,fees)); + return(jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees)); } else printf("negative ind\n"); return(0); } From bd790211469f3534f7686f72316aecf345771c97 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 18:17:36 +0300 Subject: [PATCH 0062/2705] Test --- basilisk/jumblr.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 9c71c209e..f515e6f35 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -446,13 +446,13 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi return(success * total); } -double jumblr_DEXutxosize(double *targetvolBp,double *targetvolMp,double *targetvolSp,int32_t isbob) +double jumblr_DEXutxosize(double *targetvolBp,double *targetvolMp,double *targetvolSp,int32_t isbob,double kmdprice) { double fee,depositfactor = (isbob == 0) ? 1. : 1.2; fee = JUMBLR_INCR * JUMBLR_FEE; - *targetvolBp = depositfactor * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE); - *targetvolMp = depositfactor * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE); - *targetvolSp = depositfactor * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); + *targetvolBp = depositfactor * kmdprice * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE); + *targetvolMp = depositfactor * kmdprice * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE); + *targetvolSp = depositfactor * kmdprice * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); return(depositfactor); } @@ -510,7 +510,7 @@ int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetvolB,double targetv } } -int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t isbob) +int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice) { double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,shouldsplit; margin = 1.1; @@ -518,7 +518,7 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co dexfeeratio = 500.; amount = dstr(value); memset(splittxidp,0,sizeof(*splittxidp)); - depositfactor = jumblr_DEXutxosize(&targetvolB,&targetvolM,&targetvolS,isbob); + depositfactor = jumblr_DEXutxosize(&targetvolB,&targetvolM,&targetvolS,isbob,kmdprice); printf("depositfactor %.8f targetvols %.8f %.8f %.8f\n",depositfactor,targetvolB,targetvolM,targetvolS); fees[0] = (margin * targetvolB) / dexfeeratio; fees[1] = (margin * targetvolM) / dexfeeratio; @@ -589,11 +589,11 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou txid = jbits256(item,"txid"); vout = jint(item,"vout"); value = SATOSHIDEN * jdouble(item,"amount"); - printf("%llx/v%d %.8f %d of %d\n",(long long)txid.txid,vout,dstr(value),i,n); + printf("price %.8f %llx/v%d %.8f %d of %d\n",price,(long long)txid.txid,vout,dstr(value),i,n); if ( jumblr_utxotxidpending(myinfo,&splittxid,coin,txid,vout) < 0 ) { printf("call utxoupdate\n"); - jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,txid,vout,value,myinfo->IAMLP); + jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,txid,vout,value,myinfo->IAMLP,price); jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid); } else printf("already have txid\n"); } From 8e95b8ef075f58a9cfb8a48a7ad4d686234c2bf6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 18:46:40 +0300 Subject: [PATCH 0063/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index f515e6f35..88bc0f8b6 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -382,7 +382,7 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4]) { - int64_t values[4],outputs[64],value,total,estfee = 50000; int32_t i,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; + int64_t values[4],outputs[64],value,total,estfee = 250000; int32_t i,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; total = 0; memset(values,0,sizeof(values)); memset(outputs,0,sizeof(outputs)); From 08f95e75babaf5de50d46d558a986ae1f90ef998 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 18:50:29 +0300 Subject: [PATCH 0064/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 88bc0f8b6..96f854c8a 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -382,7 +382,7 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4]) { - int64_t values[4],outputs[64],value,total,estfee = 250000; int32_t i,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; + int64_t values[4],outputs[64],value,total,estfee = 100000; int32_t i,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; total = 0; memset(values,0,sizeof(values)); memset(outputs,0,sizeof(outputs)); From 624552e76846efcece145c867c487672f16ad637 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 19:44:24 +0300 Subject: [PATCH 0065/2705] Test --- basilisk/jumblr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 96f854c8a..2141ec676 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -382,7 +382,7 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4]) { - int64_t values[4],outputs[64],value,total,estfee = 100000; int32_t i,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; + int64_t values[4],outputs[64],value,total,estfee = 100000; int32_t i,n,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; total = 0; memset(values,0,sizeof(values)); memset(outputs,0,sizeof(outputs)); @@ -401,12 +401,14 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi { if ( (value= values[i]) != 0 ) { - while ( remaining > value+estfee && numoutputs < sizeof(outputs)/sizeof(*outputs) ) + n = 0; + while ( n < 10 && remaining > value+estfee && numoutputs < sizeof(outputs)/sizeof(*outputs) ) { outputs[numoutputs++] = value; remaining -= value; total += value; printf("%.8f ",dstr(value)); + n++; } } } From 117fa0b44d195a71d643ffd4a3f7b18baa8b4f17 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 20:27:14 +0300 Subject: [PATCH 0066/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 2141ec676..0933bf094 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -382,7 +382,7 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4]) { - int64_t values[4],outputs[64],value,total,estfee = 100000; int32_t i,n,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; + int64_t values[4],outputs[64],value,total,estfee = 150000; int32_t i,n,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; total = 0; memset(values,0,sizeof(values)); memset(outputs,0,sizeof(outputs)); From 6143b50101122b02e74b7f95695d1b189d1b7ebf Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 21:34:55 +0300 Subject: [PATCH 0067/2705] Test --- basilisk/basilisk.c | 2 +- basilisk/basilisk_bitcoin.c | 4 ++-- basilisk/jumblr.c | 28 +++++++++++++++++----------- includes/iguana_funcs.h | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 59e4480b3..fb65f069a 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1612,7 +1612,7 @@ STRING_ARRAY_OBJ_STRING(basilisk,utxorawtx,symbol,utxos,vals,ignore) if ( destaddr != 0 && changeaddr != 0 && symbol != 0 && (coin= iguana_coinfind(symbol)) != 0 ) { txfee = jdouble(vals,"txfee") * SATOSHIDEN; - return(iguana_utxorawtx(myinfo,coin,timelock,destaddr,changeaddr,&satoshis,1,txfee,&completed,sendflag,utxos)); + return(iguana_utxorawtx(myinfo,coin,timelock,destaddr,changeaddr,&satoshis,1,txfee,&completed,sendflag,utxos,0)); } return(clonestr("{\"error\":\"invalid coin or address specified\"}")); } diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index cbe759041..48fb97254 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -658,7 +658,7 @@ int64_t iguana_verifytimelock(struct supernet_info *myinfo,struct iguana_info *c } return(-2); } -char *iguana_utxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,int32_t timelock,char *destaddr,char *changeaddr,int64_t *satoshis,int32_t numoutputs,uint64_t txfee,int32_t *completedp,int32_t sendflag,cJSON *utxos) +char *iguana_utxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,int32_t timelock,char *destaddr,char *changeaddr,int64_t *satoshis,int32_t numoutputs,uint64_t txfee,int32_t *completedp,int32_t sendflag,cJSON *utxos,cJSON *privkeys) { uint8_t script[35],p2shscript[128],rmd160[20],addrtype; bits256 txid; int32_t i,p2shlen,iter,spendlen; cJSON *retjson,*txcopy,*txobj=0,*vins=0; char *rawtx=0,*signedtx=0; uint32_t timelocked = 0; *completedp = 0; @@ -697,7 +697,7 @@ char *iguana_utxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,int { if ( iter == 1 || txfee != 0 ) jaddstr(retjson,"rawtx",rawtx); - if ( (signedtx= iguana_signrawtx(myinfo,coin,0,&txid,completedp,vins,rawtx,0,0)) != 0 ) + if ( (signedtx= iguana_signrawtx(myinfo,coin,0,&txid,completedp,vins,rawtx,privkeys,0)) != 0 ) { if ( (iter == 1 || txfee != 0) && *completedp != 0 ) { diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 0933bf094..130ddad8d 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -380,7 +380,7 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty return(privkey); } -int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4]) +int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4],cJSON *privkeys) { int64_t values[4],outputs[64],value,total,estfee = 150000; int32_t i,n,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; total = 0; @@ -424,7 +424,7 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi utxo = cJSON_CreateArray(); jaddi(utxo,item); sendflag = 0; - if ( (retstr= iguana_utxorawtx(myinfo,coin,0,coinaddr,coinaddr,outputs,numoutputs,0,&completed,sendflag,utxo)) != 0 ) + if ( (retstr= iguana_utxorawtx(myinfo,coin,0,coinaddr,coinaddr,outputs,numoutputs,0,&completed,sendflag,utxo,privkeys)) != 0 ) { if ( completed != 0 ) { @@ -512,9 +512,9 @@ int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetvolB,double targetv } } -int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice) +int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 privkey,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice) { - double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,shouldsplit; + double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,shouldsplit; cJSON *privkeys; char wifstr[128]; int64_t retval = 0; margin = 1.1; depositfactor = (isbob == 0) ? 1. : 1.2; dexfeeratio = 500.; @@ -530,9 +530,15 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co { printf("shouldsplit.%d ind.%d\n",shouldsplit,ind); if ( shouldsplit != 0 ) - return(jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees)); + { + privkeys = cJSON_CreateArray(); + bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); + jaddistr(privkeys,wifstr); + retval = jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees,privkeys); + free_json(privkeys); + } } else printf("negative ind\n"); - return(0); + return(retval); } /*struct DEXcoin_info @@ -575,7 +581,7 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info * coin->DEXinfo.pending[coin->DEXinfo.numpending++] = pend; } -void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,double price,char *coinaddr) +void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,double price,char *coinaddr,bits256 privkey) { char *retstr; cJSON *array,*item; int32_t i,n,vout; bits256 txid,splittxid; uint64_t value; if ( (retstr= jumblr_listunspent(myinfo,coin,coinaddr)) != 0 ) @@ -595,7 +601,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou if ( jumblr_utxotxidpending(myinfo,&splittxid,coin,txid,vout) < 0 ) { printf("call utxoupdate\n"); - jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,txid,vout,value,myinfo->IAMLP,price); + jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price); jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid); } else printf("already have txid\n"); } @@ -638,14 +644,14 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char ptr->kmdprice = 1.; ptr->KMDavail = ptr->avail; if ( (btccoin= iguana_coinfind("BTC")) != 0 ) - jumblr_utxoupdate(myinfo,btccoin,ptr->btcprice,ptr->depositaddr); - jumblr_utxoupdate(myinfo,kmdcoin,1.,ptr->KMDdepositaddr); + jumblr_utxoupdate(myinfo,btccoin,ptr->btcprice,ptr->depositaddr,ptr->deposit_privkey); + jumblr_utxoupdate(myinfo,kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey); } else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) { ptr->kmdprice = ptr->btcprice / BTC2KMD; ptr->KMDavail = KMDavail; - jumblr_utxoupdate(myinfo,ptr->coin,ptr->kmdprice,ptr->depositaddr); + jumblr_utxoupdate(myinfo,ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey); } ptr->lasttime = (uint32_t)time(NULL); } else printf("skip\n"); diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index 215596380..6be0f931a 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -528,7 +528,7 @@ char *basilisk_bitcoinrawtx(struct supernet_info *myinfo,struct iguana_info *coi int32_t iguana_markedunspents_find(struct iguana_info *coin,int32_t *firstslotp,bits256 txid,int32_t vout); void jumblr_opidsupdate(struct supernet_info *myinfo,struct iguana_info *coin); -char *iguana_signrawtx(struct supernet_info *myinfo,struct iguana_info *coin,int32_t height,bits256 *signedtxidp,int32_t *completedp,cJSON *vins,char *rawtx,cJSON *privkey,struct vin_info *V); +char *iguana_signrawtx(struct supernet_info *myinfo,struct iguana_info *coin,int32_t height,bits256 *signedtxidp,int32_t *completedp,cJSON *vins,char *rawtx,cJSON *privkeys,struct vin_info *V); bits256 scrypt_blockhash(const void *input); bits256 iguana_calcblockhash(char *symbol,int32_t (*hashalgo)(uint8_t *blockhashp,uint8_t *serialized,int32_t len),uint8_t *serialized,int32_t len); struct bitcoin_eventitem *instantdex_event(char *cmdstr,cJSON *argjson,cJSON *newjson,uint8_t *serdata,int32_t serdatalen); From de8c25200d911b2c3344231dc399dd43c99f6379 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 21:38:41 +0300 Subject: [PATCH 0068/2705] Test --- basilisk/basilisk_bitcoin.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index 48fb97254..f91ca9ac3 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -705,10 +705,9 @@ char *iguana_utxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,int jaddstr(retjson,"signedtx",signedtx); if ( sendflag != 0 ) { - //printf("send signedtx.(%s)\n",signedtx); txid = iguana_sendrawtransaction(myinfo,coin,signedtx); jaddbits256(retjson,"sent",txid); - } + } else printf("dont send signedtx.(%s)\n",signedtx); } } else printf("error signing raw utxorawtx tx\n"); } else printf("null rawtx from calcutxorawtx\n"); From 6891e63d0cacbc98752fe680925b0f537bf64d49 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 21:42:58 +0300 Subject: [PATCH 0069/2705] Test --- basilisk/jumblr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 130ddad8d..c6ff49b75 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -514,7 +514,7 @@ int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetvolB,double targetv int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 privkey,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice) { - double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,shouldsplit; cJSON *privkeys; char wifstr[128]; int64_t retval = 0; + double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,i,shouldsplit; cJSON *privkeys; char wifstr[128]; int64_t retval = 0; margin = 1.1; depositfactor = (isbob == 0) ? 1. : 1.2; dexfeeratio = 500.; @@ -526,6 +526,9 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co fees[1] = (margin * targetvolM) / dexfeeratio; fees[2] = (margin * targetvolS) / dexfeeratio; fees[3] = (strcmp("BTC",coin->symbol) == 0) ? 50000 : 10000; + for (i=0; i<4; i++) + if ( fees[i] < 10000 ) + fees[i] = 10000; if ( (ind= jumblr_DEXutxoind(&shouldsplit,targetvolB,targetvolM,targetvolS,amount,margin,dexfeeratio,fees[3])) >= 0 ) { printf("shouldsplit.%d ind.%d\n",shouldsplit,ind); From 1841276084eca8b8905bd5ba11b7ad67b4a4e1da Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 22:55:07 +0300 Subject: [PATCH 0070/2705] Test --- basilisk/jumblr.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index c6ff49b75..f9091a904 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -424,6 +424,7 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi utxo = cJSON_CreateArray(); jaddi(utxo,item); sendflag = 0; + printf("jitem.(%s)\n",jprint(utxo,0)); if ( (retstr= iguana_utxorawtx(myinfo,coin,0,coinaddr,coinaddr,outputs,numoutputs,0,&completed,sendflag,utxo,privkeys)) != 0 ) { if ( completed != 0 ) @@ -531,7 +532,7 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co fees[i] = 10000; if ( (ind= jumblr_DEXutxoind(&shouldsplit,targetvolB,targetvolM,targetvolS,amount,margin,dexfeeratio,fees[3])) >= 0 ) { - printf("shouldsplit.%d ind.%d\n",shouldsplit,ind); + //printf("shouldsplit.%d ind.%d\n",shouldsplit,ind); if ( shouldsplit != 0 ) { privkeys = cJSON_CreateArray(); @@ -540,7 +541,7 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co retval = jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees,privkeys); free_json(privkeys); } - } else printf("negative ind\n"); + } // else printf("negative ind\n"); return(retval); } @@ -557,25 +558,23 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp,struct iguana_info *coin,bits256 txid,int32_t vout) { int32_t i; - printf("jumblr_utxotxidpending\n"); memset(splittxidp,0,sizeof(*splittxidp)); for (i=0; iDEXinfo.numpending; i++) { if ( coin->DEXinfo.pending[i].vout == vout && bits256_cmp(coin->DEXinfo.pending[i].txid,txid) == 0 ) { *splittxidp = coin->DEXinfo.pending[i].splittxid; - printf("jumblr_utxotxidpending found txid in slot.%d\n",i); + // printf("jumblr_utxotxidpending found txid in slot.%d\n",i); return(i); } } - printf("jumblr_utxotxidpending cant find txid\n"); + // printf("jumblr_utxotxidpending cant find txid\n"); return(-1); } void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout,bits256 splittxid) { struct jumblr_pending pend; - printf("add txid to pending\n"); memset(&pend,0,sizeof(pend)); pend.splittxid = splittxid; pend.txid = txid; @@ -603,10 +602,9 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou printf("price %.8f %llx/v%d %.8f %d of %d\n",price,(long long)txid.txid,vout,dstr(value),i,n); if ( jumblr_utxotxidpending(myinfo,&splittxid,coin,txid,vout) < 0 ) { - printf("call utxoupdate\n"); jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price); jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid); - } else printf("already have txid\n"); + } //else printf("already have txid\n"); } } free_json(array); @@ -657,7 +655,7 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char jumblr_utxoupdate(myinfo,ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey); } ptr->lasttime = (uint32_t)time(NULL); - } else printf("skip\n"); + } // else printf("skip\n"); } void jumblr_CMCname(char *CMCname,char *symbol) From 1c5a55acff2ec4ee481eb5f8e149e1a9871c96c7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 31 Mar 2017 23:01:58 +0300 Subject: [PATCH 0071/2705] Test --- basilisk/jumblr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index f9091a904..be33f8905 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -418,13 +418,15 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi if ( (retstr= _dex_gettxout(myinfo,coin->symbol,txid,vout)) != 0 ) { item = cJSON_Parse(retstr); + jaddbits256(item,"txid",txid); + jaddnum(item,"vout",vout); free(retstr); if ( item != 0 ) { utxo = cJSON_CreateArray(); jaddi(utxo,item); sendflag = 0; - printf("jitem.(%s)\n",jprint(utxo,0)); + ///printf("jitem.(%s)\n",jprint(utxo,0)); if ( (retstr= iguana_utxorawtx(myinfo,coin,0,coinaddr,coinaddr,outputs,numoutputs,0,&completed,sendflag,utxo,privkeys)) != 0 ) { if ( completed != 0 ) From 56a59515091eb968e9485a44383e827a96f01d18 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 13:11:30 +0300 Subject: [PATCH 0072/2705] Test --- basilisk/jumblr.c | 27 ++++++++++++++++----------- iguana/tests/splitfunds | 2 +- includes/iguana_structs.h | 4 ++-- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index be33f8905..4390f970a 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -515,9 +515,9 @@ int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetvolB,double targetv } } -int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 privkey,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice) +int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 privkey,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice) { - double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,i,shouldsplit; cJSON *privkeys; char wifstr[128]; int64_t retval = 0; + double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,i,shouldsplit; cJSON *privkeys; char wifstr[128]; margin = 1.1; depositfactor = (isbob == 0) ? 1. : 1.2; dexfeeratio = 500.; @@ -540,11 +540,12 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeys,wifstr); - retval = jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees,privkeys); + jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees,privkeys); free_json(privkeys); + ind = -1; } } // else printf("negative ind\n"); - return(retval); + return(ind); } /*struct DEXcoin_info @@ -557,7 +558,7 @@ int64_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co char CMCname[32],symbol[16],depositaddr[64],KMDdepositaddr[64],KMDjumblraddr[64],jumblraddr[64]; };*/ -int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp,struct iguana_info *coin,bits256 txid,int32_t vout) +int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp,int32_t *indp,struct iguana_info *coin,bits256 txid,int32_t vout) { int32_t i; memset(splittxidp,0,sizeof(*splittxidp)); @@ -565,6 +566,7 @@ int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp, { if ( coin->DEXinfo.pending[i].vout == vout && bits256_cmp(coin->DEXinfo.pending[i].txid,txid) == 0 ) { + *indp = coin->DEXinfo.pending[i].ind; *splittxidp = coin->DEXinfo.pending[i].splittxid; // printf("jumblr_utxotxidpending found txid in slot.%d\n",i); return(i); @@ -574,20 +576,21 @@ int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp, return(-1); } -void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout,bits256 splittxid) +void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout,bits256 splittxid,int32_t ind) { struct jumblr_pending pend; memset(&pend,0,sizeof(pend)); pend.splittxid = splittxid; pend.txid = txid; pend.vout = vout; + pend.ind = ind; coin->DEXinfo.pending = realloc(coin->DEXinfo.pending,sizeof(*coin->DEXinfo.pending) * (1 + coin->DEXinfo.numpending)); coin->DEXinfo.pending[coin->DEXinfo.numpending++] = pend; } void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,double price,char *coinaddr,bits256 privkey) { - char *retstr; cJSON *array,*item; int32_t i,n,vout; bits256 txid,splittxid; uint64_t value; + char *retstr; cJSON *array,*item; int32_t i,n,vout,ind; bits256 txid,splittxid; uint64_t value; if ( (retstr= jumblr_listunspent(myinfo,coin,coinaddr)) != 0 ) { printf("%s.(%s)\n",coin->symbol,retstr); @@ -602,10 +605,10 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou vout = jint(item,"vout"); value = SATOSHIDEN * jdouble(item,"amount"); printf("price %.8f %llx/v%d %.8f %d of %d\n",price,(long long)txid.txid,vout,dstr(value),i,n); - if ( jumblr_utxotxidpending(myinfo,&splittxid,coin,txid,vout) < 0 ) + if ( jumblr_utxotxidpending(myinfo,&splittxid,&ind,coin,txid,vout) < 0 ) { - jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price); - jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid); + ind = jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price); + jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid,ind); } //else printf("already have txid\n"); } } @@ -618,6 +621,8 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char *symbol,char *CMCname,double BTC2KMD,double KMDavail) { double avebid,aveask,highbid,lowask,CMC_average,changes[3]; struct iguana_info *btccoin,*kmdcoin; struct DEXcoin_info *ptr = &coin->DEXinfo; + // wait for one confirmation to clear most in mempool (ha, ha) + // deal with changing addresses, ie all pendings? if ( coin != 0 && (kmdcoin= iguana_coinfind("KMD")) != 0 && time(NULL) > ptr->lasttime+60 ) { ptr->coin = coin; @@ -671,7 +676,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) struct iguana_info *kmdcoin; if ( (kmdcoin= iguana_coinfind("KMD")) == 0 || iguana_coinfind("BTC") == 0 ) return; - printf("jumblr_DEXcheck\n"); + //printf("jumblr_DEXcheck\n"); jumblr_DEXupdate(myinfo,kmdcoin,"KMD","komodo",0.,0.); if ( strcmp(coin->symbol,"KMD") != 0 && kmdcoin->DEXinfo.btcprice > 0. ) { diff --git a/iguana/tests/splitfunds b/iguana/tests/splitfunds index da05ff6e5..75f93431e 100755 --- a/iguana/tests/splitfunds +++ b/iguana/tests/splitfunds @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"coin\":\"BTC\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"1000\",\"sendflag\":1,\"duplicates\":10}" +curl --url "http://127.0.0.1:7778" --data "{\"coin\":\"BTC\",\"agent\":\"iguana\",\"method\":\"splitfunds\",\"satoshis\":\"50000\",\"sendflag\":1,\"duplicates\":10}" diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index 27ea9af8f..efcc33b01 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -466,14 +466,14 @@ struct iguana_RTtxid struct hashstr_item { UT_hash_handle hh; char address[40]; }; -struct jumblr_pending { bits256 splittxid,txid; int32_t vout; }; +struct jumblr_pending { bits256 splittxid,txid; int32_t vout,ind; }; struct DEXcoin_info { bits256 deposit_privkey,jumblr_privkey; struct iguana_info *coin; double btcprice,BTC2KMD,kmdprice,USD_average,DEXpending,maxbid,minask,avail,KMDavail; - uint32_t lasttime,numpending; + uint32_t lasttime; int32_t numpending; char CMCname[32],symbol[16],depositaddr[64],KMDdepositaddr[64],KMDjumblraddr[64],jumblraddr[64]; struct jumblr_pending *pending; }; From 96fa4031592c08c85cb4fe608feccbaaa0f26e3a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 15:11:10 +0300 Subject: [PATCH 0073/2705] Utxocombine --- basilisk/basilisk.c | 59 +++++++++++++++++++++++++++++++++++ basilisk/jumblr.c | 29 +++++++++-------- iguana/tests/utxocombine | 2 ++ iguana/tests/utxorawtx | 3 +- includes/iguana_apideclares.h | 1 + 5 files changed, 79 insertions(+), 15 deletions(-) create mode 100755 iguana/tests/utxocombine diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index fb65f069a..d781a657e 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -33,6 +33,44 @@ int32_t basilisk_notarycmd(char *cmd) else return(0); }*/ +cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *satoshis,uint64_t limit,char *coinaddr) +{ + int32_t i,n; char *retstr; uint64_t value,biggest = 0; struct iguana_info *coin=0; cJSON *item,*biggestitem=0,*array,*utxos = 0; + coin = iguana_coinfind(symbol); + if ( (retstr= dex_listunspent(myinfo,coin,0,0,symbol,coinaddr)) != 0 ) + { + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + n = cJSON_GetArraySize(array); + for (i=0; i biggest ) + { + if ( biggestitem != 0 ) + free_json(biggestitem); + biggestitem = jduplicate(item); + *satoshis = biggest = value; + } + } + } + free_json(array); + if ( biggestitem != 0 ) + jaddi(utxos,biggestitem); + } + free(retstr); + } + return(utxos); +} + uint32_t basilisk_calcnonce(struct supernet_info *myinfo,uint8_t *data,int32_t datalen,uint32_t nBits) { int32_t i,numiters = 0; bits256 hash,hash2,threshold; uint32_t basilisktag; @@ -1071,6 +1109,7 @@ ARRAY_OBJ_INT(tradebot,goals,currencies,vals,targettime) return(clonestr("{\"result\":\"success\"}")); } else return(clonestr("{\"error\":\"no currencies or vals\"}")); } + HASH_ARRAY_STRING(basilisk,getmessage,hash,vals,hexstr) { uint32_t msgid,width,channel; char *retstr; @@ -1617,6 +1656,26 @@ STRING_ARRAY_OBJ_STRING(basilisk,utxorawtx,symbol,utxos,vals,ignore) return(clonestr("{\"error\":\"invalid coin or address specified\"}")); } +HASH_ARRAY_STRING(basilisk,utxocombine,ignore,vals,symbol) +{ + char *coinaddr,*retstr=0; cJSON *utxos; int64_t satoshis,limit,txfee; int32_t completed,sendflag,timelock; + timelock = 0; + sendflag = jint(vals,"sendflag"); + coinaddr = jstr(vals,"coinaddr"); + limit = jdouble(vals,"maxamount") * SATOSHIDEN; + if ( limit > 0 && symbol != 0 && symbol[0] != 0 && (utxos= basilisk_utxosweep(myinfo,symbol,&satoshis,limit,coinaddr)) != 0 && cJSON_GetArraySize(utxos) > 0 ) + { + if ( coinaddr != 0 && symbol != 0 && (coin= iguana_coinfind(symbol)) != 0 ) + { + txfee = jdouble(vals,"txfee") * SATOSHIDEN; + retstr = iguana_utxorawtx(myinfo,coin,timelock,coinaddr,coinaddr,&satoshis,1,txfee,&completed,sendflag,utxos,0); + } + free_json(utxos); + } + if ( retstr == 0 ) + return(clonestr("{\"error\":\"invalid coin or address specified or no available utxos\"}")); + return(retstr); +} //int64_t iguana_verifytimelock(struct supernet_info *myinfo,struct iguana_info *coin,uint32_t timelocked,char *destaddr,bits256 txid,int32_t vout) THREE_STRINGS_AND_DOUBLE(tradebot,aveprice,comment,base,rel,basevolume) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 4390f970a..091d08de8 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -380,10 +380,11 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty return(privkey); } -int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4],cJSON *privkeys) +int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4],cJSON *privkeys,double esttxfee) { - int64_t values[4],outputs[64],value,total,estfee = 150000; int32_t i,n,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; + int64_t values[4],outputs[64],value,total,estfee; int32_t i,n,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; total = 0; + estfee = SATOSHIDEN * esttxfee; memset(values,0,sizeof(values)); memset(outputs,0,sizeof(outputs)); if ( bigprice > SMALLVAL ) @@ -515,7 +516,7 @@ int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetvolB,double targetv } } -int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 privkey,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice) +int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 privkey,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice,double estfee) { double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,i,shouldsplit; cJSON *privkeys; char wifstr[128]; margin = 1.1; @@ -525,9 +526,9 @@ int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co memset(splittxidp,0,sizeof(*splittxidp)); depositfactor = jumblr_DEXutxosize(&targetvolB,&targetvolM,&targetvolS,isbob,kmdprice); printf("depositfactor %.8f targetvols %.8f %.8f %.8f\n",depositfactor,targetvolB,targetvolM,targetvolS); - fees[0] = (margin * targetvolB) / dexfeeratio; - fees[1] = (margin * targetvolM) / dexfeeratio; - fees[2] = (margin * targetvolS) / dexfeeratio; + fees[0] = estfee + (margin * targetvolB) / dexfeeratio; + fees[1] = estfee + (margin * targetvolM) / dexfeeratio; + fees[2] = estfee + (margin * targetvolS) / dexfeeratio; fees[3] = (strcmp("BTC",coin->symbol) == 0) ? 50000 : 10000; for (i=0; i<4; i++) if ( fees[i] < 10000 ) @@ -540,7 +541,7 @@ int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeys,wifstr); - jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees,privkeys); + jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees,privkeys,estfee); free_json(privkeys); ind = -1; } @@ -588,7 +589,7 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info * coin->DEXinfo.pending[coin->DEXinfo.numpending++] = pend; } -void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,double price,char *coinaddr,bits256 privkey) +void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,double price,char *coinaddr,bits256 privkey,double estfee) { char *retstr; cJSON *array,*item; int32_t i,n,vout,ind; bits256 txid,splittxid; uint64_t value; if ( (retstr= jumblr_listunspent(myinfo,coin,coinaddr)) != 0 ) @@ -607,7 +608,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou printf("price %.8f %llx/v%d %.8f %d of %d\n",price,(long long)txid.txid,vout,dstr(value),i,n); if ( jumblr_utxotxidpending(myinfo,&splittxid,&ind,coin,txid,vout) < 0 ) { - ind = jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price); + ind = jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price,estfee); jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid,ind); } //else printf("already have txid\n"); } @@ -620,9 +621,11 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char *symbol,char *CMCname,double BTC2KMD,double KMDavail) { - double avebid,aveask,highbid,lowask,CMC_average,changes[3]; struct iguana_info *btccoin,*kmdcoin; struct DEXcoin_info *ptr = &coin->DEXinfo; + double avebid,aveask,highbid,lowask,CMC_average,changes[3],estfee,estbtcfee; struct iguana_info *btccoin,*kmdcoin; struct DEXcoin_info *ptr = &coin->DEXinfo; // wait for one confirmation to clear most in mempool (ha, ha) // deal with changing addresses, ie all pendings? + estfee = 0.0001; + estbtcfee = 0.0015; if ( coin != 0 && (kmdcoin= iguana_coinfind("KMD")) != 0 && time(NULL) > ptr->lasttime+60 ) { ptr->coin = coin; @@ -652,14 +655,14 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char ptr->kmdprice = 1.; ptr->KMDavail = ptr->avail; if ( (btccoin= iguana_coinfind("BTC")) != 0 ) - jumblr_utxoupdate(myinfo,btccoin,ptr->btcprice,ptr->depositaddr,ptr->deposit_privkey); - jumblr_utxoupdate(myinfo,kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey); + jumblr_utxoupdate(myinfo,btccoin,ptr->btcprice,ptr->depositaddr,ptr->deposit_privkey,estbtcfee); + jumblr_utxoupdate(myinfo,kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey,estfee); } else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) { ptr->kmdprice = ptr->btcprice / BTC2KMD; ptr->KMDavail = KMDavail; - jumblr_utxoupdate(myinfo,ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey); + jumblr_utxoupdate(myinfo,ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey,estfee); } ptr->lasttime = (uint32_t)time(NULL); } // else printf("skip\n"); diff --git a/iguana/tests/utxocombine b/iguana/tests/utxocombine new file mode 100755 index 000000000..8f7ab3ff9 --- /dev/null +++ b/iguana/tests/utxocombine @@ -0,0 +1,2 @@ +#!/bin/bash +curl --url "http://127.0.0.1:7778" --data "{\"symbol\":\"BTC\",\"agent\":\"basilisk\",\"method\":\"utxocombine\",\"vals\":{\"coinaddr\":\"1E2ac2gxeFR2ir1H3vqETTperWkiXkwy99\",\"maxamount\":0.0001,\"sendflag\":0}}" diff --git a/iguana/tests/utxorawtx b/iguana/tests/utxorawtx index 57d252129..7fc804c2f 100755 --- a/iguana/tests/utxorawtx +++ b/iguana/tests/utxorawtx @@ -1,2 +1 @@ -#!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"symbol\":\"BTC\",\"agent\":\"basilisk\",\"method\":\"utxorawtx\",\"vals\":{\"timelock\":0,\"changeaddr\":\"1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg\",\"destaddr\":\"1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg\",\"txfee\":0,\"amount\":0.0001,\"sendflag\":0},\"utxos\":[{\"value\":0.00100000,\"address\":\"1Hgzt5xsnbfc8UTWqWKSTLRm5bEYHYBoCE\",\"scriptPubKey\":\"76a914b7128d2ee837cf03e30a2c0e3e0181f7b9669bb688ac\",\"confirmations\":23351,\"spendable\":true}]}" +#!/bin/bashcurl --url "http://127.0.0.1:7778" --data "{\"symbol\":\"BTC\",\"agent\":\"basilisk\",\"method\":\"utxorawtx\",\"vals\":{\"timelock\":0,\"changeaddr\":\"1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg\",\"destaddr\":\"1P3rU1Nk1pmc2BiWC8dEy9bZa1ZbMp5jfg\",\"txfee\":0,\"amount\":0.0001,\"sendflag\":0},\"utxos\":[{\"value\":0.00100000,\"address\":\"1Hgzt5xsnbfc8UTWqWKSTLRm5bEYHYBoCE\",\"scriptPubKey\":\"76a914b7128d2ee837cf03e30a2c0e3e0181f7b9669bb688ac\",\"confirmations\":23351,\"spendable\":true}]}" diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 861e71444..77e23adf8 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -67,6 +67,7 @@ HASH_ARRAY_STRING(basilisk,rawtx,hash,vals,hexstr); TWO_STRINGS(basilisk,refresh,symbol,address); ZERO_ARGS(basilisk,cancelrefresh); STRING_ARRAY_OBJ_STRING(basilisk,utxorawtx,symbol,utxos,vals,ignore); +HASH_ARRAY_STRING(basilisk,utxocombine,ignore,vals,symbol); HASH_ARRAY_STRING(basilisk,getmessage,hash,vals,hexstr); HASH_ARRAY_STRING(basilisk,sendmessage,hash,vals,hexstr); From 1e90915092050a4966ddbcb8d4482633d91ef62a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 15:16:08 +0300 Subject: [PATCH 0074/2705] Test --- iguana/iguana_notary.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 55e55b25d..1b75c02ba 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -665,6 +665,8 @@ TWO_STRINGS(dex,listunspent,symbol,address) return(retstr); } } + else if ( coin != 0 && coin->FULLNODE < 0 ) + return(jprint(dpow_listunspent(myinfo,coin,address),1)); return(_dex_listunspent(myinfo,symbol,address)); } From ded21306f910c44d5225d3c7ace7adb1f444fb9b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 15:19:24 +0300 Subject: [PATCH 0075/2705] Test --- basilisk/basilisk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index d781a657e..1a5eb6a14 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -39,6 +39,7 @@ cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *sat coin = iguana_coinfind(symbol); if ( (retstr= dex_listunspent(myinfo,coin,0,0,symbol,coinaddr)) != 0 ) { + printf("(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { n = cJSON_GetArraySize(array); @@ -47,6 +48,7 @@ cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *sat item = jitem(array,i); if ( (value= SATOSHIDEN*jdouble(item,"amount")) != 0 || (value= SATOSHIDEN*jdouble(item,"value")) != 0 ) { + fprintf(stderr,"%.8f ",dstr(value)); if ( value <= limit ) { if ( utxos == 0 ) From b60446894a5be649be9567356fd59df721aacaef Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 15:23:14 +0300 Subject: [PATCH 0076/2705] Test --- basilisk/basilisk.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 1a5eb6a14..2f0829dd1 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -39,7 +39,7 @@ cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *sat coin = iguana_coinfind(symbol); if ( (retstr= dex_listunspent(myinfo,coin,0,0,symbol,coinaddr)) != 0 ) { - printf("(%s)\n",retstr); + //printf("(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { n = cJSON_GetArraySize(array); @@ -51,22 +51,27 @@ cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *sat fprintf(stderr,"%.8f ",dstr(value)); if ( value <= limit ) { + fprintf(stderr,"< "); if ( utxos == 0 ) utxos = cJSON_CreateArray(); jaddi(utxos,jduplicate(item)); } else if ( value > biggest ) { + fprintf(stderr,"biggest! "); if ( biggestitem != 0 ) free_json(biggestitem); biggestitem = jduplicate(item); *satoshis = biggest = value; - } + } else fprintf(stderr,"> "); } } free_json(array); - if ( biggestitem != 0 ) + if ( utxos == 0 && biggestitem != 0 ) + { + printf("add biggest.(%s)\n",jprint(biggestitem,0)); jaddi(utxos,biggestitem); + } } free(retstr); } From 72a9613a4d8f0538c15b6df20ce1943f01a024b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 15:28:16 +0300 Subject: [PATCH 0077/2705] Test --- basilisk/basilisk.c | 10 +++++----- iguana/iguana_payments.c | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 2f0829dd1..b10ffc52c 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -48,28 +48,28 @@ cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *sat item = jitem(array,i); if ( (value= SATOSHIDEN*jdouble(item,"amount")) != 0 || (value= SATOSHIDEN*jdouble(item,"value")) != 0 ) { - fprintf(stderr,"%.8f ",dstr(value)); + //fprintf(stderr,"%.8f ",dstr(value)); if ( value <= limit ) { - fprintf(stderr,"< "); + //fprintf(stderr,"< "); if ( utxos == 0 ) utxos = cJSON_CreateArray(); jaddi(utxos,jduplicate(item)); } else if ( value > biggest ) { - fprintf(stderr,"biggest! "); + //fprintf(stderr,"biggest! "); if ( biggestitem != 0 ) free_json(biggestitem); biggestitem = jduplicate(item); *satoshis = biggest = value; - } else fprintf(stderr,"> "); + } //else fprintf(stderr,"> "); } } free_json(array); if ( utxos == 0 && biggestitem != 0 ) { - printf("add biggest.(%s)\n",jprint(biggestitem,0)); + fprintf(stderr,"add biggest.(%s)\n",jprint(biggestitem,0)); jaddi(utxos,biggestitem); } } diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index cfe164a8a..f1a5a6948 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -554,7 +554,10 @@ char *iguana_calcutxorawtx(struct supernet_info *myinfo,struct iguana_info *coin for (i=0; i Date: Sat, 1 Apr 2017 15:30:28 +0300 Subject: [PATCH 0078/2705] Test --- iguana/iguana_payments.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index f1a5a6948..a6cc3b028 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -571,9 +571,10 @@ char *iguana_calcutxorawtx(struct supernet_info *myinfo,struct iguana_info *coin continue; } unspents = realloc(unspents,(1 + max) * sizeof(*unspents)); - value = jdouble(item,"value") * SATOSHIDEN; + if ( (value= jdouble(item,"value") * SATOSHIDEN) == 0 ) + value = jdouble(item,"amount") * SATOSHIDEN; interests += SATOSHIDEN * jdouble(item,"interest"); - printf("(%s) ",jprint(item,0)); + //printf("(%s) ",jprint(item,0)); iguana_outptset(myinfo,coin,&unspents[max++],jbits256(item,"txid"),jint(item,"vout"),value,spendscriptstr); avail += value; } From 56b6a4037ab6c8907a9f71737e35131fb9552969 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 15:33:39 +0300 Subject: [PATCH 0079/2705] Test --- iguana/iguana_sign.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index 20ce30e9d..a26f1d3e5 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -568,14 +568,15 @@ void iguana_vinobjset(struct iguana_msgvin *vin,cJSON *item,uint8_t *spendscript } } -int32_t iguana_vinarray_check(cJSON *vinarray,bits256 txid) +int32_t iguana_vinarray_check(cJSON *vinarray,bits256 txid,int32_t vout) { - bits256 array_txid; cJSON *item; int32_t i,n = cJSON_GetArraySize(vinarray); + bits256 array_txid; cJSON *item; int32_t array_vout,i,n = cJSON_GetArraySize(vinarray); for (i=0; ivins[i],jitem(vins,i),spendscript,sizeof(spendscript)); sigtxid = bitcoin_sigtxid(coin,height,sigser,maxsize*2,msg,i,msg->vins[i].spendscript,msg->vins[i].spendlen,SIGHASH_ALL,vpnstr,suppress_pubkeys); //printf("after vini.%d vinscript.%p spendscript.%p spendlen.%d (%s)\n",i,msg->vins[i].vinscript,msg->vins[i].spendscript,msg->vins[i].spendlen,jprint(jitem(vins,i),0)); - if ( iguana_vinarray_check(vinarray,msg->vins[i].prev_hash) < 0 ) + if ( iguana_vinarray_check(vinarray,msg->vins[i].prev_hash,msg->vins[i].prev_vout) < 0 ) jaddi(vinarray,iguana_vinjson(coin,&msg->vins[i],sigtxid)); if ( msg->vins[i].spendscript == spendscript ) msg->vins[i].spendscript = 0; - } else if ( iguana_vinarray_check(vinarray,msg->vins[i].prev_hash) < 0 ) + } else if ( iguana_vinarray_check(vinarray,msg->vins[i].prev_hash,msg->vins[i].prev_vout) < 0 ) jaddi(vinarray,iguana_vinjson(coin,&msg->vins[i],sigtxid)); } free(sigser); From f70efd1285cc79bc68328d06334fee8f09681b61 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 15:41:41 +0300 Subject: [PATCH 0080/2705] Test --- basilisk/basilisk.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index b10ffc52c..37238ca84 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -33,9 +33,9 @@ int32_t basilisk_notarycmd(char *cmd) else return(0); }*/ -cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *satoshis,uint64_t limit,char *coinaddr) +cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *satoshis,uint64_t limit,int32_t maxvins,char *coinaddr) { - int32_t i,n; char *retstr; uint64_t value,biggest = 0; struct iguana_info *coin=0; cJSON *item,*biggestitem=0,*array,*utxos = 0; + int32_t i,n,numvins = 0; char *retstr; uint64_t value,biggest = 0; struct iguana_info *coin=0; cJSON *item,*biggestitem=0,*array,*utxos = 0; coin = iguana_coinfind(symbol); if ( (retstr= dex_listunspent(myinfo,coin,0,0,symbol,coinaddr)) != 0 ) { @@ -54,7 +54,11 @@ cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *sat //fprintf(stderr,"< "); if ( utxos == 0 ) utxos = cJSON_CreateArray(); - jaddi(utxos,jduplicate(item)); + if ( numvins < maxvins ) + { + jaddi(utxos,jduplicate(item)); + numvins++; + } } else if ( value > biggest ) { @@ -1665,12 +1669,14 @@ STRING_ARRAY_OBJ_STRING(basilisk,utxorawtx,symbol,utxos,vals,ignore) HASH_ARRAY_STRING(basilisk,utxocombine,ignore,vals,symbol) { - char *coinaddr,*retstr=0; cJSON *utxos; int64_t satoshis,limit,txfee; int32_t completed,sendflag,timelock; + char *coinaddr,*retstr=0; cJSON *utxos; int64_t satoshis,limit,txfee; int32_t maxvins,completed,sendflag,timelock; timelock = 0; + if ( (maxvins= jint(vals,"maxvins")) == 0 ) + maxvins = 20; sendflag = jint(vals,"sendflag"); coinaddr = jstr(vals,"coinaddr"); limit = jdouble(vals,"maxamount") * SATOSHIDEN; - if ( limit > 0 && symbol != 0 && symbol[0] != 0 && (utxos= basilisk_utxosweep(myinfo,symbol,&satoshis,limit,coinaddr)) != 0 && cJSON_GetArraySize(utxos) > 0 ) + if ( limit > 0 && symbol != 0 && symbol[0] != 0 && (utxos= basilisk_utxosweep(myinfo,symbol,&satoshis,limit,maxvins,coinaddr)) != 0 && cJSON_GetArraySize(utxos) > 0 ) { if ( coinaddr != 0 && symbol != 0 && (coin= iguana_coinfind(symbol)) != 0 ) { From 52a6b42fd331d33f2af887f61812494273b56b95 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 21:16:17 +0300 Subject: [PATCH 0081/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 091d08de8..2d8e71769 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -376,7 +376,7 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); bitcoin_address(coinaddr,pubtype,pubkey33,33); bitcoin_address(KMDaddr,60,pubkey33,33); - printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); + //printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); return(privkey); } From e51145a9a17b90b7e4d195b93a9d9122310aa296 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Apr 2017 21:18:38 +0300 Subject: [PATCH 0082/2705] Test --- basilisk/jumblr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 2d8e71769..c1d0d2dcc 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -408,12 +408,12 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi outputs[numoutputs++] = value; remaining -= value; total += value; - printf("%.8f ",dstr(value)); + //printf("%.8f ",dstr(value)); n++; } } } - char str[65]; printf("numoutputs.%d total %.8f %s/v%d\n",numoutputs,dstr(total),bits256_str(str,txid),vout); + //char str[65]; printf("numoutputs.%d total %.8f %s/v%d\n",numoutputs,dstr(total),bits256_str(str,txid),vout); if ( numoutputs > 0 ) { if ( (retstr= _dex_gettxout(myinfo,coin->symbol,txid,vout)) != 0 ) @@ -525,7 +525,7 @@ int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co amount = dstr(value); memset(splittxidp,0,sizeof(*splittxidp)); depositfactor = jumblr_DEXutxosize(&targetvolB,&targetvolM,&targetvolS,isbob,kmdprice); - printf("depositfactor %.8f targetvols %.8f %.8f %.8f\n",depositfactor,targetvolB,targetvolM,targetvolS); + //printf("depositfactor %.8f targetvols %.8f %.8f %.8f\n",depositfactor,targetvolB,targetvolM,targetvolS); fees[0] = estfee + (margin * targetvolB) / dexfeeratio; fees[1] = estfee + (margin * targetvolM) / dexfeeratio; fees[2] = estfee + (margin * targetvolS) / dexfeeratio; @@ -594,7 +594,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou char *retstr; cJSON *array,*item; int32_t i,n,vout,ind; bits256 txid,splittxid; uint64_t value; if ( (retstr= jumblr_listunspent(myinfo,coin,coinaddr)) != 0 ) { - printf("%s.(%s)\n",coin->symbol,retstr); + //printf("%s.(%s)\n",coin->symbol,retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -605,7 +605,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou txid = jbits256(item,"txid"); vout = jint(item,"vout"); value = SATOSHIDEN * jdouble(item,"amount"); - printf("price %.8f %llx/v%d %.8f %d of %d\n",price,(long long)txid.txid,vout,dstr(value),i,n); + //printf("price %.8f %llx/v%d %.8f %d of %d\n",price,(long long)txid.txid,vout,dstr(value),i,n); if ( jumblr_utxotxidpending(myinfo,&splittxid,&ind,coin,txid,vout) < 0 ) { ind = jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price,estfee); @@ -648,7 +648,7 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char } ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); - printf("%s avail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); + //printf("%s avail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); if ( strcmp("KMD",symbol) == 0 ) { ptr->BTC2KMD = ptr->btcprice; From 57d6528c206e4b498ef0637cb5f986cfac35b864 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 11:14:15 +0300 Subject: [PATCH 0083/2705] Test --- basilisk/basilisk_swap.c | 6 +++--- basilisk/jumblr.c | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index c810ea103..b3733495b 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -550,7 +550,7 @@ int32_t _basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swap free(retarray); } else printf("error parsing.(%s)\n",retstr); free(retstr); - } else printf("error creating %s feetx\n",iambob != 0 ? "BOB" : "ALICE"); + } else printf("error creating %s %s\n",iambob != 0 ? "BOB" : "ALICE",rawtx->name); free_json(valsobj); free(V); return(retval); @@ -790,7 +790,7 @@ int32_t basilisk_alicepayment_spend(struct supernet_info *myinfo,struct basilisk return(-1); } -int32_t basilisk_bobpayment_spendclone(struct supernet_info *myinfo,struct iguana_info *bobcoin,struct basilisk_rawtx *dest,struct basilisk_rawtx *src,uint32_t swapstarted,uint8_t *changepubkey33,uint32_t quoteid,uint64_t amount,bits256 privAm,bits256 myprivs0,uint8_t *data,int32_t datalen,int32_t jumblrflag) +/*int32_t basilisk_bobpayment_spendclone(struct supernet_info *myinfo,struct iguana_info *bobcoin,struct basilisk_rawtx *dest,struct basilisk_rawtx *src,uint32_t swapstarted,uint8_t *changepubkey33,uint32_t quoteid,uint64_t amount,bits256 privAm,bits256 myprivs0,uint8_t *data,int32_t datalen,int32_t jumblrflag) { bits256 revAm; uint8_t userdata[512]; int32_t i,len,numconfirms = 0,retval = -1; uint32_t sequenceid = 0xffffffff; basilisk_rawtx_setparms("bobpayment",quoteid,src,bobcoin,numconfirms,0,amount,3,0,jumblrflag); @@ -878,7 +878,7 @@ int32_t basilisk_alicepayment_spendclone(struct supernet_info *myinfo,struct igu } return(retval); -} +}*/ int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) { diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index c1d0d2dcc..a0f2f14b4 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -577,9 +577,9 @@ int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp, return(-1); } -void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout,bits256 splittxid,int32_t ind) +void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct iguana_info *coin,bits256 txid,int32_t vout,uint64_t value,bits256 splittxid,int32_t ind,double price,double estfee) { - struct jumblr_pending pend; + struct jumblr_pending pend; cJSON *vals,*retjson; bits256 hash; char *retstr; memset(&pend,0,sizeof(pend)); pend.splittxid = splittxid; pend.txid = txid; @@ -587,9 +587,32 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,struct iguana_info * pend.ind = ind; coin->DEXinfo.pending = realloc(coin->DEXinfo.pending,sizeof(*coin->DEXinfo.pending) * (1 + coin->DEXinfo.numpending)); coin->DEXinfo.pending[coin->DEXinfo.numpending++] = pend; + if ( ind < 3 ) + { + if ( price > SMALLVAL ) + { + vals = cJSON_CreateObject(); + jaddstr(vals,"source",coin->symbol); + jaddstr(vals,"dest",dest); + jaddnum(vals,"amount",dstr(value)); + jaddnum(vals,"minprice",price); + jaddnum(vals,"usejumblr",1); + memset(hash.bytes,0,sizeof(hash)); + if ( (retstr= InstantDEX_request(myinfo,coin,0,0,hash,vals,"")) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); + free_json(retjson); + } + free(retstr); + } + free_json(vals); + } + } } -void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,double price,char *coinaddr,bits256 privkey,double estfee) +void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_info *coin,double price,char *coinaddr,bits256 privkey,double estfee) { char *retstr; cJSON *array,*item; int32_t i,n,vout,ind; bits256 txid,splittxid; uint64_t value; if ( (retstr= jumblr_listunspent(myinfo,coin,coinaddr)) != 0 ) @@ -609,7 +632,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,dou if ( jumblr_utxotxidpending(myinfo,&splittxid,&ind,coin,txid,vout) < 0 ) { ind = jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price,estfee); - jumblr_utxotxidpendingadd(myinfo,coin,txid,vout,splittxid,ind); + jumblr_utxotxidpendingadd(myinfo,dest,coin,txid,vout,value,splittxid,ind,price,estfee); } //else printf("already have txid\n"); } } @@ -655,14 +678,14 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char ptr->kmdprice = 1.; ptr->KMDavail = ptr->avail; if ( (btccoin= iguana_coinfind("BTC")) != 0 ) - jumblr_utxoupdate(myinfo,btccoin,ptr->btcprice,ptr->depositaddr,ptr->deposit_privkey,estbtcfee); - jumblr_utxoupdate(myinfo,kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey,estfee); + jumblr_utxoupdate(myinfo,"KMD",btccoin,ptr->btcprice,ptr->depositaddr,ptr->deposit_privkey,estbtcfee); + jumblr_utxoupdate(myinfo,"BTC",kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey,estfee); } else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) { ptr->kmdprice = ptr->btcprice / BTC2KMD; ptr->KMDavail = KMDavail; - jumblr_utxoupdate(myinfo,ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey,estfee); + jumblr_utxoupdate(myinfo,"KMD",ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey,estfee); } ptr->lasttime = (uint32_t)time(NULL); } // else printf("skip\n"); From a398d7d35887d6504b6b883b1e9331a9044e07d2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 11:32:12 +0300 Subject: [PATCH 0084/2705] Test --- basilisk/jumblr.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index a0f2f14b4..735ac0451 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -408,12 +408,12 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi outputs[numoutputs++] = value; remaining -= value; total += value; - //printf("%.8f ",dstr(value)); + printf("%.8f ",dstr(value)); n++; } } } - //char str[65]; printf("numoutputs.%d total %.8f %s/v%d\n",numoutputs,dstr(total),bits256_str(str,txid),vout); + char str[65]; printf("numoutputs.%d total %.8f %s/v%d\n",numoutputs,dstr(total),bits256_str(str,txid),vout); if ( numoutputs > 0 ) { if ( (retstr= _dex_gettxout(myinfo,coin->symbol,txid,vout)) != 0 ) @@ -516,9 +516,10 @@ int32_t jumblr_DEXutxoind(int32_t *shouldsplitp,double targetvolB,double targetv } } -int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 privkey,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice,double estfee) +int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *coin,int32_t *shouldsplitp,bits256 *splittxidp,char *coinaddr,bits256 privkey,bits256 txid,int32_t vout,uint64_t value,int32_t isbob,double kmdprice,double estfee) { - double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind,i,shouldsplit; cJSON *privkeys; char wifstr[128]; + double fees[4],targetvolB,amount,targetvolM,targetvolS,depositfactor,dexfeeratio,margin; int32_t ind = -1,i; cJSON *privkeys; char wifstr[128]; + *shouldsplitp = 0; margin = 1.1; depositfactor = (isbob == 0) ? 1. : 1.2; dexfeeratio = 500.; @@ -533,10 +534,10 @@ int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co for (i=0; i<4; i++) if ( fees[i] < 10000 ) fees[i] = 10000; - if ( (ind= jumblr_DEXutxoind(&shouldsplit,targetvolB,targetvolM,targetvolS,amount,margin,dexfeeratio,fees[3])) >= 0 ) + if ( (ind= jumblr_DEXutxoind(shouldsplitp,targetvolB,targetvolM,targetvolS,amount,margin,dexfeeratio,fees[3])) >= 0 ) { //printf("shouldsplit.%d ind.%d\n",shouldsplit,ind); - if ( shouldsplit != 0 ) + if ( *shouldsplitp != 0 ) { privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); @@ -577,7 +578,7 @@ int32_t jumblr_utxotxidpending(struct supernet_info *myinfo,bits256 *splittxidp, return(-1); } -void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct iguana_info *coin,bits256 txid,int32_t vout,uint64_t value,bits256 splittxid,int32_t ind,double price,double estfee) +void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct iguana_info *coin,bits256 txid,int32_t vout,uint64_t value,bits256 splittxid,int32_t ind,double price,double estfee,int32_t shouldsplit) { struct jumblr_pending pend; cJSON *vals,*retjson; bits256 hash; char *retstr; memset(&pend,0,sizeof(pend)); @@ -587,7 +588,7 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct ig pend.ind = ind; coin->DEXinfo.pending = realloc(coin->DEXinfo.pending,sizeof(*coin->DEXinfo.pending) * (1 + coin->DEXinfo.numpending)); coin->DEXinfo.pending[coin->DEXinfo.numpending++] = pend; - if ( ind < 3 ) + if ( shouldsplit == 0 && ind < 3 ) { if ( price > SMALLVAL ) { @@ -614,7 +615,7 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct ig void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_info *coin,double price,char *coinaddr,bits256 privkey,double estfee) { - char *retstr; cJSON *array,*item; int32_t i,n,vout,ind; bits256 txid,splittxid; uint64_t value; + char *retstr; cJSON *array,*item; int32_t shouldsplit,i,n,vout,ind; bits256 txid,splittxid; uint64_t value; if ( (retstr= jumblr_listunspent(myinfo,coin,coinaddr)) != 0 ) { //printf("%s.(%s)\n",coin->symbol,retstr); @@ -631,8 +632,8 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_inf //printf("price %.8f %llx/v%d %.8f %d of %d\n",price,(long long)txid.txid,vout,dstr(value),i,n); if ( jumblr_utxotxidpending(myinfo,&splittxid,&ind,coin,txid,vout) < 0 ) { - ind = jumblr_DEXutxoupdate(myinfo,coin,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price,estfee); - jumblr_utxotxidpendingadd(myinfo,dest,coin,txid,vout,value,splittxid,ind,price,estfee); + ind = jumblr_DEXutxoupdate(myinfo,coin,&shouldsplit,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price,estfee); + jumblr_utxotxidpendingadd(myinfo,dest,coin,txid,vout,value,splittxid,ind,price,estfee,shouldsplit); } //else printf("already have txid\n"); } } From 25fc4ae79a01e531751f4a7f9c8d9f92e1ace317 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 11:41:24 +0300 Subject: [PATCH 0085/2705] Test --- basilisk/jumblr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 735ac0451..d029c1f14 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -526,10 +526,10 @@ int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co amount = dstr(value); memset(splittxidp,0,sizeof(*splittxidp)); depositfactor = jumblr_DEXutxosize(&targetvolB,&targetvolM,&targetvolS,isbob,kmdprice); - //printf("depositfactor %.8f targetvols %.8f %.8f %.8f\n",depositfactor,targetvolB,targetvolM,targetvolS); - fees[0] = estfee + (margin * targetvolB) / dexfeeratio; - fees[1] = estfee + (margin * targetvolM) / dexfeeratio; - fees[2] = estfee + (margin * targetvolS) / dexfeeratio; + printf("depositfactor %.8f targetvols %.8f %.8f %.8f\n",depositfactor,targetvolB,targetvolM,targetvolS); + fees[0] = (margin * targetvolB) / dexfeeratio; + fees[1] = (margin * targetvolM) / dexfeeratio; + fees[2] = (margin * targetvolS) / dexfeeratio; fees[3] = (strcmp("BTC",coin->symbol) == 0) ? 50000 : 10000; for (i=0; i<4; i++) if ( fees[i] < 10000 ) From 340da0043e05901b86dcb2432133a454f20f4ff0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 11:48:43 +0300 Subject: [PATCH 0086/2705] Test --- basilisk/jumblr.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index d029c1f14..33589b868 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -536,7 +536,7 @@ int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co fees[i] = 10000; if ( (ind= jumblr_DEXutxoind(shouldsplitp,targetvolB,targetvolM,targetvolS,amount,margin,dexfeeratio,fees[3])) >= 0 ) { - //printf("shouldsplit.%d ind.%d\n",shouldsplit,ind); + printf("shouldsplit.%d ind.%d\n",*shouldsplitp,ind); if ( *shouldsplitp != 0 ) { privkeys = cJSON_CreateArray(); @@ -586,8 +586,6 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct ig pend.txid = txid; pend.vout = vout; pend.ind = ind; - coin->DEXinfo.pending = realloc(coin->DEXinfo.pending,sizeof(*coin->DEXinfo.pending) * (1 + coin->DEXinfo.numpending)); - coin->DEXinfo.pending[coin->DEXinfo.numpending++] = pend; if ( shouldsplit == 0 && ind < 3 ) { if ( price > SMALLVAL ) @@ -595,7 +593,7 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct ig vals = cJSON_CreateObject(); jaddstr(vals,"source",coin->symbol); jaddstr(vals,"dest",dest); - jaddnum(vals,"amount",dstr(value)); + jaddnum(vals,"amount",dstr(value) - estfee); jaddnum(vals,"minprice",price); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); @@ -611,6 +609,8 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct ig free_json(vals); } } + coin->DEXinfo.pending = realloc(coin->DEXinfo.pending,sizeof(*coin->DEXinfo.pending) * (1 + coin->DEXinfo.numpending)); + coin->DEXinfo.pending[coin->DEXinfo.numpending++] = pend; } void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_info *coin,double price,char *coinaddr,bits256 privkey,double estfee) @@ -634,7 +634,11 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_inf { ind = jumblr_DEXutxoupdate(myinfo,coin,&shouldsplit,&splittxid,coinaddr,privkey,txid,vout,value,myinfo->IAMLP,price,estfee); jumblr_utxotxidpendingadd(myinfo,dest,coin,txid,vout,value,splittxid,ind,price,estfee,shouldsplit); - } //else printf("already have txid\n"); + } + else + { + // update status of utxo + } } } free_json(array); From bb6fae3138868f5af42985d7846bed4875032f63 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 11:52:00 +0300 Subject: [PATCH 0087/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 33589b868..b8257f147 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -403,7 +403,7 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi if ( (value= values[i]) != 0 ) { n = 0; - while ( n < 10 && remaining > value+estfee && numoutputs < sizeof(outputs)/sizeof(*outputs) ) + while ( n < 10 && remaining > value && numoutputs < sizeof(outputs)/sizeof(*outputs) ) { outputs[numoutputs++] = value; remaining -= value; From 1fffe0ea549753e3dc35ef96abd8127639d613b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 11:56:32 +0300 Subject: [PATCH 0088/2705] Test --- basilisk/jumblr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index b8257f147..6e2563552 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -414,7 +414,7 @@ int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bi } } char str[65]; printf("numoutputs.%d total %.8f %s/v%d\n",numoutputs,dstr(total),bits256_str(str,txid),vout); - if ( numoutputs > 0 ) + if ( numoutputs > 1 ) // no point to make just one { if ( (retstr= _dex_gettxout(myinfo,coin->symbol,txid,vout)) != 0 ) { @@ -542,9 +542,10 @@ int32_t jumblr_DEXutxoupdate(struct supernet_info *myinfo,struct iguana_info *co privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeys,wifstr); - jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees,privkeys,estfee); + if ( jumblr_DEXsplit(myinfo,coin,splittxidp,coinaddr,txid,vout,value,margin * targetvolB,margin * targetvolM,margin * targetvolS,fees,privkeys,estfee) > 0 ) + ind = -1; + else *shouldsplitp = 0; free_json(privkeys); - ind = -1; } } // else printf("negative ind\n"); return(ind); From 69fd47873dac732b2772cea9428b50e603ad20a6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 12:29:22 +0300 Subject: [PATCH 0089/2705] bypass jumble for notaries --- basilisk/jumblr.c | 6 +++++- iguana/dpow/dpow_network.c | 2 +- iguana/iguana_notary.c | 4 ++-- iguana/main.c | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 6e2563552..730c976c0 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -587,7 +587,7 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct ig pend.txid = txid; pend.vout = vout; pend.ind = ind; - if ( shouldsplit == 0 && ind < 3 ) + if ( myinfo->IAMLP == 0 && shouldsplit == 0 && ind < 3 ) { if ( price > SMALLVAL ) { @@ -706,6 +706,8 @@ void jumblr_CMCname(char *CMCname,char *symbol) void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) { struct iguana_info *kmdcoin; + if ( myinfo->IAMNOTARY != 0 ) + return; if ( (kmdcoin= iguana_coinfind("KMD")) == 0 || iguana_coinfind("BTC") == 0 ) return; //printf("jumblr_DEXcheck\n"); @@ -747,6 +749,8 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 { //static uint32_t lasttime; char BTCaddr[64],KMDaddr[64],*zaddr,*retstr; bits256 privkey; uint64_t amount=0,total=0; double fee; struct jumblr_item *ptr,*tmp; uint8_t r; + if ( myinfo->IAMNOTARY != 0 ) + return; fee = JUMBLR_INCR * JUMBLR_FEE; OS_randombytes(&r,sizeof(r)); //r = 0; diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 94b80c90d..6d2211c03 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1154,7 +1154,7 @@ char *_dex_listunspentarg(struct supernet_info *myinfo,char *symbol,char *addres dexreq.func = arg; if ( (retstr= _dex_sendrequeststr(myinfo,&dexreq,address,0,1,"")) != 0 ) { - printf("%s UNSPENTS.(%s)\n",symbol,retstr); + //printf("_dex_listunspentarg: %s UNSPENTS.(%s)\n",symbol,retstr); } return(_dex_arrayreturn(retstr)); } diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 1b75c02ba..842828271 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -665,8 +665,8 @@ TWO_STRINGS(dex,listunspent,symbol,address) return(retstr); } } - else if ( coin != 0 && coin->FULLNODE < 0 ) - return(jprint(dpow_listunspent(myinfo,coin,address),1)); + //else if ( coin != 0 && coin->FULLNODE < 0 ) + // return(jprint(dpow_listunspent(myinfo,coin,address),1)); return(_dex_listunspent(myinfo,symbol,address)); } diff --git a/iguana/main.c b/iguana/main.c index 71aad6eea..d9932835e 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -755,10 +755,10 @@ void jumblr_loop(void *ptr) { if ( (coin= iguana_coinfind("KMD")) != 0 ) { - // if BTC has arrived in destination address, invoke DEX -> BTC - jumblr_DEXcheck(myinfo,coin); if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { + // if BTC has arrived in destination address, invoke DEX -> BTC + jumblr_DEXcheck(myinfo,coin); t = (uint32_t)time(NULL); if ( (t % (120 * mult)) < 60 ) { From 3a1b651b53aee2194f67a7976cea81676765e74d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 12:40:42 +0300 Subject: [PATCH 0090/2705] Remove print --- iguana/dpow/dpow_network.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 6d2211c03..e5283d42a 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -798,7 +798,13 @@ char *dex_response(int32_t *broadcastflagp,struct supernet_info *myinfo,struct d } //printf("DEX NOTARIES -> (%s)\n",retstr); } - } else printf("(%s) not active\n",dexreq.name); + } + else + { + static uint32_t counter; + if ( counter++ < 10 ) + printf("request came in from GUI for (%s) that is not active\n",dexreq.name); + } if ( retstr == 0 ) return(clonestr("{\"error\":\"null return\"}")); } From 54eeff2f97dd2569e372caca02e56faee72f16da Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Apr 2017 12:46:34 +0300 Subject: [PATCH 0091/2705] Test --- iguana/iguana_notary.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 842828271..1b75c02ba 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -665,8 +665,8 @@ TWO_STRINGS(dex,listunspent,symbol,address) return(retstr); } } - //else if ( coin != 0 && coin->FULLNODE < 0 ) - // return(jprint(dpow_listunspent(myinfo,coin,address),1)); + else if ( coin != 0 && coin->FULLNODE < 0 ) + return(jprint(dpow_listunspent(myinfo,coin,address),1)); return(_dex_listunspent(myinfo,symbol,address)); } From 54af944673c62372830b52fd3bc6b539411d4f47 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 3 Apr 2017 19:14:02 +0300 Subject: [PATCH 0092/2705] Test --- .gitignore | 4 ++++ basilisk/jumblr.c | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e689f7231..d97f08f97 100755 --- a/.gitignore +++ b/.gitignore @@ -218,3 +218,7 @@ iguana/confs/5228bcea7ae2515a29c3844673de6ee2acba53bf45724744a00ff4306f192912 iguana/confs/630929d976025fafde221c7358eb5805f4359bad3c6b8bd50ad3f6e0a9b5ce78 iguana/confs/5f3283a017c31e52443d61cb43944e2157f7c03eb12d701ebf4a35a695688e1f + +iguana/DB/SWAPS/1313603851-3952777544 + +iguana/DB/SWAPS/1923456555-3815385469 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 730c976c0..88ca376ab 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -589,12 +589,14 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct ig pend.ind = ind; if ( myinfo->IAMLP == 0 && shouldsplit == 0 && ind < 3 ) { - if ( price > SMALLVAL ) + static uint32_t num; + if ( num == 0 && price > SMALLVAL ) { + num++; vals = cJSON_CreateObject(); jaddstr(vals,"source",coin->symbol); jaddstr(vals,"dest",dest); - jaddnum(vals,"amount",dstr(value) - estfee); + jaddnum(vals,"amount",price * 100);//dstr(value) - estfee); jaddnum(vals,"minprice",price); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); From 54457c309830b2ad61977655ab4295b2f04d749f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 3 Apr 2017 19:21:02 +0300 Subject: [PATCH 0093/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d97f08f97..629e273c2 100755 --- a/.gitignore +++ b/.gitignore @@ -222,3 +222,5 @@ iguana/confs/5f3283a017c31e52443d61cb43944e2157f7c03eb12d701ebf4a35a695688e1f iguana/DB/SWAPS/1313603851-3952777544 iguana/DB/SWAPS/1923456555-3815385469 + +iguana/DB/SWAPS/897416195-4050269921 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b3733495b..9788c7268 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2418,7 +2418,7 @@ void basilisk_swaploop(void *_swap) printf("ALICE's error %d %d %d\n",swap->myfee.I.datalen,swap->alicepayment.I.datalen,swap->alicepayment.I.datalen); retval = -7; } - else if ( swap->I.iambob != 0 && (swap->myfee.I.datalen == 0 || swap->bobpayment.I.datalen == 0 || swap->bobdeposit.I.datalen == 0) ) + else if ( swap->I.iambob != 0 && (swap->myfee.I.datalen == 0 || swap->bobdeposit.I.datalen == 0) ) //swap->bobpayment.I.datalen == 0 { printf("BOB's error %d %d %d\n",swap->myfee.I.datalen,swap->bobpayment.I.datalen,swap->bobdeposit.I.datalen); retval = -7; From dd6dc105d220a834b5c1edeac8bb604808f99690 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 09:17:06 +0300 Subject: [PATCH 0094/2705] Test --- .gitignore | 2 ++ basilisk/jumblr.c | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 629e273c2..d6e2c7039 100755 --- a/.gitignore +++ b/.gitignore @@ -224,3 +224,5 @@ iguana/DB/SWAPS/1313603851-3952777544 iguana/DB/SWAPS/1923456555-3815385469 iguana/DB/SWAPS/897416195-4050269921 + +iguana/DB/SWAPS/2465996447-4202128826 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 88ca376ab..d7f6b491e 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -587,7 +587,7 @@ void jumblr_utxotxidpendingadd(struct supernet_info *myinfo,char *dest,struct ig pend.txid = txid; pend.vout = vout; pend.ind = ind; - if ( myinfo->IAMLP == 0 && shouldsplit == 0 && ind < 3 ) + if ( 0 && myinfo->IAMLP == 0 && shouldsplit == 0 && ind < 3 ) { static uint32_t num; if ( num == 0 && price > SMALLVAL ) @@ -707,10 +707,10 @@ void jumblr_CMCname(char *CMCname,char *symbol) void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) { - struct iguana_info *kmdcoin; + struct iguana_info *kmdcoin,*coinbtc = 0; if ( myinfo->IAMNOTARY != 0 ) return; - if ( (kmdcoin= iguana_coinfind("KMD")) == 0 || iguana_coinfind("BTC") == 0 ) + if ( (kmdcoin= iguana_coinfind("KMD")) == 0 || (coinbtc= iguana_coinfind("BTC")) == 0 ) return; //printf("jumblr_DEXcheck\n"); jumblr_DEXupdate(myinfo,kmdcoin,"KMD","komodo",0.,0.); @@ -721,11 +721,12 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) if ( coin->CMCname[0] != 0 ) jumblr_DEXupdate(myinfo,coin,coin->symbol,coin->CMCname,kmdcoin->DEXinfo.btcprice,kmdcoin->DEXinfo.avail); } - /*if ( kmdprice > SMALLVAL ) + if ( myinfo->IAMLP == 0 && kmdcoin->DEXinfo.btcprice > SMALLVAL ) { - minbtc = (kmdprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); - btcavail = dstr(jumblr_balance(myinfo,coinbtc,BTCaddr)); - if ( coinbtc != 0 && btcavail > minbtc+pending ) + double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; + minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); + btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); + if ( coinbtc != 0 && btcavail > minbtc+kmdcoin->DEXinfo.DEXpending ) { printf("BTC deposits %.8f, min %.8f\n",btcavail,minbtc); @@ -733,18 +734,19 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",btcavail*.3); - jaddnum(vals,"minprice",kmdprice*.95); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice*1.01); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); - pending = btcavail; + kmdcoin->DEXinfo.DEXpending += btcavail; if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) { printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); free(retstr); } + free_json(vals); // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - } else printf("null kmdprice %.8f\n",kmdprice);*/ + } else printf("null kmdprice %.8f\n",kmdcoin->DEXinfo.btcprice); } void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval) From aaef528ff4c1d388384e2afac5aaae9cbab3092d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 09:23:11 +0300 Subject: [PATCH 0095/2705] Test --- .gitignore | 2 ++ basilisk/jumblr.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d6e2c7039..b5ff1b12d 100755 --- a/.gitignore +++ b/.gitignore @@ -226,3 +226,5 @@ iguana/DB/SWAPS/1923456555-3815385469 iguana/DB/SWAPS/897416195-4050269921 iguana/DB/SWAPS/2465996447-4202128826 + +iguana/DB/SWAPS/3078036996-3700749298 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index d7f6b491e..ddacf2adf 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -733,7 +733,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) vals = cJSON_CreateObject(); jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); - jaddnum(vals,"amount",btcavail*.3); + jaddnum(vals,"amount",btcavail*.9); jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice*1.01); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); From 21ed6aaa62073ab7dd75131fe90e4cd582a51481 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 09:26:05 +0300 Subject: [PATCH 0096/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index ddacf2adf..f185f290e 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -733,7 +733,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) vals = cJSON_CreateObject(); jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); - jaddnum(vals,"amount",btcavail*.9); + jaddnum(vals,"amount",btcavail*.75); jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice*1.01); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); From 24a4902dd72712d4e240825a5f37d4a6a519166f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 16:31:57 +0300 Subject: [PATCH 0097/2705] Test --- .gitignore | 2 ++ basilisk/jumblr.c | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index b5ff1b12d..3c28444d0 100755 --- a/.gitignore +++ b/.gitignore @@ -228,3 +228,5 @@ iguana/DB/SWAPS/897416195-4050269921 iguana/DB/SWAPS/2465996447-4202128826 iguana/DB/SWAPS/3078036996-3700749298 + +iguana/DB/SWAPS/1061498231-3266306388 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index f185f290e..15bab9163 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -679,21 +679,21 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char } ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); - //printf("%s avail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); + printf("%s avail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); if ( strcmp("KMD",symbol) == 0 ) { ptr->BTC2KMD = ptr->btcprice; ptr->kmdprice = 1.; ptr->KMDavail = ptr->avail; - if ( (btccoin= iguana_coinfind("BTC")) != 0 ) + /*if ( (btccoin= iguana_coinfind("BTC")) != 0 ) jumblr_utxoupdate(myinfo,"KMD",btccoin,ptr->btcprice,ptr->depositaddr,ptr->deposit_privkey,estbtcfee); - jumblr_utxoupdate(myinfo,"BTC",kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey,estfee); + jumblr_utxoupdate(myinfo,"BTC",kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey,estfee);*/ } else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) { ptr->kmdprice = ptr->btcprice / BTC2KMD; ptr->KMDavail = KMDavail; - jumblr_utxoupdate(myinfo,"KMD",ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey,estfee); + //jumblr_utxoupdate(myinfo,"KMD",ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey,estfee); } ptr->lasttime = (uint32_t)time(NULL); } // else printf("skip\n"); @@ -746,7 +746,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) free_json(vals); // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - } else printf("null kmdprice %.8f\n",kmdcoin->DEXinfo.btcprice); + } //else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); } void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval) From 8fec666c36af20a502dc5f43360484d4420417d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 16:37:27 +0300 Subject: [PATCH 0098/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 15bab9163..f5a30de20 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -733,7 +733,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) vals = cJSON_CreateObject(); jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); - jaddnum(vals,"amount",btcavail*.75); + jaddnum(vals,"amount",btcavail*.9); jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice*1.01); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); From 79507f59b7bc48002c72aa9432659f8c0600c8b6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 16:41:28 +0300 Subject: [PATCH 0099/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index f5a30de20..40acf7401 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -733,7 +733,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) vals = cJSON_CreateObject(); jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); - jaddnum(vals,"amount",btcavail*.9); + jaddnum(vals,"amount",minbtc); jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice*1.01); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); From e04ebf4868e1baf4042a157e836b869b36c4fe66 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 16:52:13 +0300 Subject: [PATCH 0100/2705] Test --- .gitignore | 2 ++ basilisk/jumblr.c | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3c28444d0..188d00a61 100755 --- a/.gitignore +++ b/.gitignore @@ -230,3 +230,5 @@ iguana/DB/SWAPS/2465996447-4202128826 iguana/DB/SWAPS/3078036996-3700749298 iguana/DB/SWAPS/1061498231-3266306388 + +iguana/DB/SWAPS/1060082251-3390546616 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 40acf7401..9d104061b 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -726,7 +726,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( coinbtc != 0 && btcavail > minbtc+kmdcoin->DEXinfo.DEXpending ) + if ( 0 && coinbtc != 0 && btcavail > minbtc+kmdcoin->DEXinfo.DEXpending ) { printf("BTC deposits %.8f, min %.8f\n",btcavail,minbtc); @@ -746,6 +746,25 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) free_json(vals); // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); + if ( coinbtc != 0 && kmdcoin->DEXinfo.avail > JUMBLR_INCR+kmdcoin->DEXinfo.DEXpending ) + { + printf("KMD deposits %.8f, min %.8f\n",kmdcoin->DEXinfo.avail,JUMBLR_INCR); + vals = cJSON_CreateObject(); + jaddstr(vals,"source","KMD"); + jaddstr(vals,"dest","BTC"); + jaddnum(vals,"amount",JUMBLR_INCR); + jaddnum(vals,"minprice",1./kmdcoin->DEXinfo.btcprice*1.01); + jaddnum(vals,"usejumblr",1); + memset(hash.bytes,0,sizeof(hash)); + kmdcoin->DEXinfo.DEXpending += btcavail; + if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) + { + printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); + free(retstr); + } + free_json(vals); + // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" + } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); } //else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); } From 492271c900dfca7f41d66c183f8bccc88204b530 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 16:56:41 +0300 Subject: [PATCH 0101/2705] Test --- basilisk/jumblr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 9d104061b..812023f30 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -746,9 +746,9 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) free_json(vals); // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - if ( coinbtc != 0 && kmdcoin->DEXinfo.avail > JUMBLR_INCR+kmdcoin->DEXinfo.DEXpending ) + if ( coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > JUMBLR_INCR+kmdcoin->DEXinfo.DEXpending ) { - printf("KMD deposits %.8f, min %.8f\n",kmdcoin->DEXinfo.avail,JUMBLR_INCR); + printf("KMD deposits %.8f, min %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR); vals = cJSON_CreateObject(); jaddstr(vals,"source","KMD"); jaddstr(vals,"dest","BTC"); From 2cc359c16b63fd4457e2543cd5a7fced311a7d1b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 17:02:37 +0300 Subject: [PATCH 0102/2705] Test --- basilisk/jumblr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 812023f30..469150761 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -679,12 +679,13 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char } ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); + KMDavail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->KMDjumblraddr)); printf("%s avail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); if ( strcmp("KMD",symbol) == 0 ) { ptr->BTC2KMD = ptr->btcprice; ptr->kmdprice = 1.; - ptr->KMDavail = ptr->avail; + ptr->KMDavail = KMDavail; /*if ( (btccoin= iguana_coinfind("BTC")) != 0 ) jumblr_utxoupdate(myinfo,"KMD",btccoin,ptr->btcprice,ptr->depositaddr,ptr->deposit_privkey,estbtcfee); jumblr_utxoupdate(myinfo,"BTC",kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey,estfee);*/ From bc94f63192a07ff4b2026ad67d62dd849541d62c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 17:06:30 +0300 Subject: [PATCH 0103/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 469150761..20a39d1a1 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -680,7 +680,7 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); KMDavail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->KMDjumblraddr)); - printf("%s avail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); + printf("%s avail %.8f KMDavail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,KMDavail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); if ( strcmp("KMD",symbol) == 0 ) { ptr->BTC2KMD = ptr->btcprice; From a91e728ac1cdb93e8e06742ccc4642d8f98a4827 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 17:17:13 +0300 Subject: [PATCH 0104/2705] Test --- .gitignore | 2 ++ basilisk/jumblr.c | 3 +-- basilisk/tradebots_liquidity.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 188d00a61..50040a9de 100755 --- a/.gitignore +++ b/.gitignore @@ -232,3 +232,5 @@ iguana/DB/SWAPS/3078036996-3700749298 iguana/DB/SWAPS/1061498231-3266306388 iguana/DB/SWAPS/1060082251-3390546616 + +iguana/SVM/rawfeatures/BTCD_BTC diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 20a39d1a1..a46e9a99d 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -754,7 +754,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddstr(vals,"source","KMD"); jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",JUMBLR_INCR); - jaddnum(vals,"minprice",1./kmdcoin->DEXinfo.btcprice*1.01); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.DEXpending += btcavail; @@ -764,7 +764,6 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) free(retstr); } free_json(vals); - // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); } //else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); } diff --git a/basilisk/tradebots_liquidity.c b/basilisk/tradebots_liquidity.c index 7e21127aa..85a28bcea 100755 --- a/basilisk/tradebots_liquidity.c +++ b/basilisk/tradebots_liquidity.c @@ -932,7 +932,7 @@ void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 li.ask = jdouble(vals,"ask"); if ( (li.minvol= jdouble(vals,"minvol")) <= 0. ) li.minvol = (strcmp("BTC",base) == 0) ? 0.0001 : 0.001; - if ( strcmp(li.base,"KMD") == 0 && strcmp(li.rel,"BTC") == 0 && li.minvol > 100. ) + if ( strcmp(li.base,"KMD") == 0 && strcmp(li.rel,"BTC") == 0 && li.minvol >= 100. ) li.minvol = 100.; if ( (li.maxvol= jdouble(vals,"maxvol")) < li.minvol ) li.maxvol = li.minvol; From 26ead7ab7b6f6eff7f29fa2f52cd8092e2a52594 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 17:21:44 +0300 Subject: [PATCH 0105/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index a46e9a99d..1952a15c3 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -753,7 +753,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) vals = cJSON_CreateObject(); jaddstr(vals,"source","KMD"); jaddstr(vals,"dest","BTC"); - jaddnum(vals,"amount",JUMBLR_INCR); + jaddnum(vals,"amount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); From f98c7566dab3bef49c2d66317661c52558ead5ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 20:51:10 +0300 Subject: [PATCH 0106/2705] Test --- basilisk/jumblr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 1952a15c3..f61457206 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -753,7 +753,8 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) vals = cJSON_CreateObject(); jaddstr(vals,"source","KMD"); jaddstr(vals,"dest","BTC"); - jaddnum(vals,"amount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"amount",JUMBLR_INCR); + jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); From 26a710f516335905c9e5f71cdf030f2b42d1de61 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 21:00:12 +0300 Subject: [PATCH 0107/2705] Test --- basilisk/basilisk_DEX.c | 5 ++++- basilisk/basilisk_tradebot.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index 5ec6fcaed..cc44ade73 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -159,7 +159,10 @@ cJSON *basilisk_requestjson(struct basilisk_request *rp) jadd64bits(item,"minamount",rp->minamount); jaddstr(item,"dest",rp->dest); if ( rp->destamount != 0 ) - jadd64bits(item,"destamount",rp->destamount); + { + //jadd64bits(item,"destamount",rp->destamount); + jadd64bits(item,"destsatoshis",rp->destamount); + } jaddnum(item,"quotetime",rp->quotetime); jaddnum(item,"timestamp",rp->timestamp); jaddnum(item,"requestid",rp->requestid); diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 5d16548dc..b84f428b0 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -228,7 +228,8 @@ struct basilisk_request *basilisk_parsejson(struct basilisk_request *rp,cJSON *r rp->desthash = jbits256(reqjson,"desthash"); rp->srcamount = j64bits(reqjson,"srcamount"); rp->minamount = j64bits(reqjson,"minamount"); - rp->destamount = j64bits(reqjson,"destamount"); + //rp->destamount = j64bits(reqjson,"destamount"); + rp->destamount = j64bits(reqjson,"destsatoshis"); requestid = juint(reqjson,"requestid"); quoteid = juint(reqjson,"quoteid"); //if ( jstr(reqjson,"relay") != 0 ) From e94ce01e0eb0c1ee7027ef4cbab9a45ee925d448 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 4 Apr 2017 21:08:58 +0300 Subject: [PATCH 0108/2705] Test --- basilisk/basilisk_tradebot.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index b84f428b0..baf3bdc23 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -306,6 +306,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk if ( list[i].destamount > maxamount ) { maxamount = list[i].destamount; + printf("set maxamount %llu\n",(long long)maxamount); maxi = i; } } @@ -317,12 +318,14 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk // MVP -> USD myrequest.0 pendingid.0 noquoteflag.1 havequoteflag.0 maxi.-1 0.00000000 double retvals[4],refprice=0.,profitmargin,aveprice,destvolume; cJSON *retjson; char *retstr; destvolume = dstr(maxamount); + printf("destvolume <- %.8f\n",dstr(destvolume)); if ( fabs(destvolume) < SMALLVAL ) { if ( (destvolume= dstr(minamount)) == 0 ) { aveprice = instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,1.3 * dstr(list[0].srcamount)); destvolume = aveprice * dstr(list[0].srcamount); + printf("set destvolume %.8f\n",destvolume); } } printf("%s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); From 3d65325f310968253b91495732151fdb09accaa4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 14:53:09 +0300 Subject: [PATCH 0109/2705] Test --- basilisk/basilisk_DEX.c | 1 + basilisk/basilisk_tradebot.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index cc44ade73..035860e89 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -162,6 +162,7 @@ cJSON *basilisk_requestjson(struct basilisk_request *rp) { //jadd64bits(item,"destamount",rp->destamount); jadd64bits(item,"destsatoshis",rp->destamount); + printf("DESTSATOSHIS.%llu\n",(long long)rp->destamount); } jaddnum(item,"quotetime",rp->quotetime); jaddnum(item,"timestamp",rp->timestamp); diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index baf3bdc23..22e815354 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -230,6 +230,7 @@ struct basilisk_request *basilisk_parsejson(struct basilisk_request *rp,cJSON *r rp->minamount = j64bits(reqjson,"minamount"); //rp->destamount = j64bits(reqjson,"destamount"); rp->destamount = j64bits(reqjson,"destsatoshis"); + printf("parse DESTSATOSHIS.%llu\n",(long long)rp->destamount); requestid = juint(reqjson,"requestid"); quoteid = juint(reqjson,"quoteid"); //if ( jstr(reqjson,"relay") != 0 ) @@ -326,7 +327,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk aveprice = instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,1.3 * dstr(list[0].srcamount)); destvolume = aveprice * dstr(list[0].srcamount); printf("set destvolume %.8f\n",destvolume); - } + } else printf("destvolume %.8f <- minamount\n",destvolume); } printf("%s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); if ( myinfo->IAMLP != 0 && myrequest == 0 && pendingid == 0 && noquoteflag != 0 && ((profitmargin= tradebot_liquidity_active(myinfo,&refprice,"DEX",list[0].src,list[0].dest,destvolume)) > 0. || refprice != 0.) ) From 1a54a7cc90e5f92c6f62372888216193c77e379a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 15:04:02 +0300 Subject: [PATCH 0110/2705] Test --- basilisk/basilisk.c | 2 +- basilisk/basilisk_tradebot.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 37238ca84..b2d1865b6 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1771,7 +1771,7 @@ HASH_ARRAY_STRING(InstantDEX,request,hash,vals,hexstr) { uint8_t serialized[512]; bits256 privkey; char buf[512],BTCaddr[64],KMDaddr[64]; struct basilisk_request R; int32_t jumblr,iambob,optionhours; cJSON *reqjson; uint32_t datalen=0,DEX_channel; struct iguana_info *bobcoin,*alicecoin; myinfo->DEXactive = (uint32_t)time(NULL) + 3*BASILISK_TIMEOUT + 60; - jadd64bits(vals,"minamount",jdouble(vals,"minprice") * jdouble(vals,"amount") * SATOSHIDEN * SATOSHIDEN); + jadd64bits(vals,"minamount",jdouble(vals,"minprice") * jdouble(vals,"amount") * SATOSHIDEN); if ( jobj(vals,"desthash") == 0 ) jaddbits256(vals,"desthash",hash); jadd64bits(vals,"satoshis",jdouble(vals,"amount") * SATOSHIDEN); diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 22e815354..16a7cd2eb 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -230,7 +230,7 @@ struct basilisk_request *basilisk_parsejson(struct basilisk_request *rp,cJSON *r rp->minamount = j64bits(reqjson,"minamount"); //rp->destamount = j64bits(reqjson,"destamount"); rp->destamount = j64bits(reqjson,"destsatoshis"); - printf("parse DESTSATOSHIS.%llu\n",(long long)rp->destamount); + printf("parse DESTSATOSHIS.%llu (%s)\n",(long long)rp->destamount,jprint(reqjson,0)); requestid = juint(reqjson,"requestid"); quoteid = juint(reqjson,"quoteid"); //if ( jstr(reqjson,"relay") != 0 ) From 28e7f8b5c1490e2d084c594bac3c7141c11ea815 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 15:21:57 +0300 Subject: [PATCH 0111/2705] Test --- basilisk/basilisk_DEX.c | 2 +- basilisk/basilisk_tradebot.c | 4 ++-- basilisk/tradebots_liquidity.c | 19 +++++++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index 035860e89..239514d47 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -162,7 +162,7 @@ cJSON *basilisk_requestjson(struct basilisk_request *rp) { //jadd64bits(item,"destamount",rp->destamount); jadd64bits(item,"destsatoshis",rp->destamount); - printf("DESTSATOSHIS.%llu\n",(long long)rp->destamount); + //printf("DESTSATOSHIS.%llu\n",(long long)rp->destamount); } jaddnum(item,"quotetime",rp->quotetime); jaddnum(item,"timestamp",rp->timestamp); diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 16a7cd2eb..e35f0e6c1 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -230,7 +230,7 @@ struct basilisk_request *basilisk_parsejson(struct basilisk_request *rp,cJSON *r rp->minamount = j64bits(reqjson,"minamount"); //rp->destamount = j64bits(reqjson,"destamount"); rp->destamount = j64bits(reqjson,"destsatoshis"); - printf("parse DESTSATOSHIS.%llu (%s)\n",(long long)rp->destamount,jprint(reqjson,0)); + //printf("parse DESTSATOSHIS.%llu (%s)\n",(long long)rp->destamount,jprint(reqjson,0)); requestid = juint(reqjson,"requestid"); quoteid = juint(reqjson,"quoteid"); //if ( jstr(reqjson,"relay") != 0 ) @@ -319,7 +319,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk // MVP -> USD myrequest.0 pendingid.0 noquoteflag.1 havequoteflag.0 maxi.-1 0.00000000 double retvals[4],refprice=0.,profitmargin,aveprice,destvolume; cJSON *retjson; char *retstr; destvolume = dstr(maxamount); - printf("destvolume <- %.8f\n",dstr(destvolume)); + //printf("destvolume <- %.8f\n",dstr(destvolume)); if ( fabs(destvolume) < SMALLVAL ) { if ( (destvolume= dstr(minamount)) == 0 ) diff --git a/basilisk/tradebots_liquidity.c b/basilisk/tradebots_liquidity.c index 85a28bcea..ef762637c 100755 --- a/basilisk/tradebots_liquidity.c +++ b/basilisk/tradebots_liquidity.c @@ -991,10 +991,21 @@ void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 printf("ERROR: too many linfos %d\n",i); } -int32_t _default_volume_ok(struct supernet_info *myinfo,struct liquidity_info *li,int32_t dir,double volume) +int32_t _default_volume_ok(struct supernet_info *myinfo,struct liquidity_info *li,int32_t dir,double volume,double price) { - printf("minvol %f maxvol %f vs volume %f\n",li->minvol,li->maxvol,volume); - if ( (li->minvol == 0 || volume >= li->minvol) && (li->maxvol == 0 || volume <= li->maxvol) ) + double minvol,maxvol; + if ( dir > 0 ) + { + minvol = li->minvol; + maxvol = li->maxvol; + } + else + { + minvol = price * li->minvol; + maxvol = price * li->maxvol; + } + printf("dir.%d minvol %f maxvol %f vs (%f %f) volume %f price %f\n",dir,li->minvol,li->maxvol,minvol,maxvol,volume,price); + if ( (minvol == 0. || volume >= minvol) && (maxvol == 0. || volume <= maxvol) ) return(0); else return(-1); } @@ -1018,7 +1029,7 @@ double _default_liquidity_active(struct supernet_info *myinfo,double *refpricep, printf("continue %s %s/%s [%d] dir.%d vs %s %s/%s\n",exchange,base,rel,i,dir,refli.exchange,refli.base,refli.rel); continue; } - if ( _default_volume_ok(myinfo,&refli,dir,destvolume) == 0 ) + if ( _default_volume_ok(myinfo,&refli,dir,destvolume,dir > 0 ? refli.bid : refli.ask) == 0 ) { if ( refli.profit != 0. ) *refpricep = refli.refprice; From 2cfd5011d1dcdf0b93a4381ef31b76639b09e7d6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 15:25:35 +0300 Subject: [PATCH 0112/2705] Test --- basilisk/tradebots_liquidity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/tradebots_liquidity.c b/basilisk/tradebots_liquidity.c index ef762637c..66fd27944 100755 --- a/basilisk/tradebots_liquidity.c +++ b/basilisk/tradebots_liquidity.c @@ -994,7 +994,7 @@ void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 int32_t _default_volume_ok(struct supernet_info *myinfo,struct liquidity_info *li,int32_t dir,double volume,double price) { double minvol,maxvol; - if ( dir > 0 ) + if ( dir < 0 ) { minvol = li->minvol; maxvol = li->maxvol; @@ -1004,7 +1004,7 @@ int32_t _default_volume_ok(struct supernet_info *myinfo,struct liquidity_info *l minvol = price * li->minvol; maxvol = price * li->maxvol; } - printf("dir.%d minvol %f maxvol %f vs (%f %f) volume %f price %f\n",dir,li->minvol,li->maxvol,minvol,maxvol,volume,price); + printf("dir.%d minvol %f maxvol %f vs (%f %f) volume %f price %.8f\n",dir,li->minvol,li->maxvol,minvol,maxvol,volume,price); if ( (minvol == 0. || volume >= minvol) && (maxvol == 0. || volume <= maxvol) ) return(0); else return(-1); From 02724bdd6f5dca6527175e9e95c28e10ba067846 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 15:36:18 +0300 Subject: [PATCH 0113/2705] Test --- basilisk/jumblr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index f61457206..6bb9f5149 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -727,7 +727,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( 0 && coinbtc != 0 && btcavail > minbtc+kmdcoin->DEXinfo.DEXpending ) + if ( coinbtc != 0 && btcavail > minbtc+kmdcoin->DEXinfo.DEXpending ) { printf("BTC deposits %.8f, min %.8f\n",btcavail,minbtc); @@ -747,15 +747,15 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) free_json(vals); // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - if ( coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > JUMBLR_INCR+kmdcoin->DEXinfo.DEXpending ) + if ( 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > JUMBLR_INCR+kmdcoin->DEXinfo.DEXpending ) { printf("KMD deposits %.8f, min %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR); vals = cJSON_CreateObject(); jaddstr(vals,"source","KMD"); jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",JUMBLR_INCR); - jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice); + //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.01); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.DEXpending += btcavail; From f566c15355ef81ab2c3b3c6767a7de608ace657c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 15:47:12 +0300 Subject: [PATCH 0114/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 6bb9f5149..b374442ea 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -735,7 +735,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",minbtc); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice*1.01); + jaddnum(vals,"minprice",1./(1.01 * kmdcoin->DEXinfo.btcprice)); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.DEXpending += btcavail; From b3131f816d9cc3a154dad6f04c8e464a063af6b7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 16:06:35 +0300 Subject: [PATCH 0115/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 46 +++++++++++++++++++++------------------- basilisk/jumblr.c | 2 +- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 50040a9de..39c712977 100755 --- a/.gitignore +++ b/.gitignore @@ -234,3 +234,5 @@ iguana/DB/SWAPS/1061498231-3266306388 iguana/DB/SWAPS/1060082251-3390546616 iguana/SVM/rawfeatures/BTCD_BTC + +iguana/DB/SWAPS/1032184933-1028220623 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 9788c7268..43334eb6f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1948,12 +1948,14 @@ void basilisk_sendmostprivs(struct supernet_info *myinfo,struct basilisk_swap *s int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t j,datalen,retval = 0; + if ( swap->I.iambob != 0 ) + swap->I.statebits |= 0x80; while ( ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) { if ( swap->connected == 0 ) basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); - printf("D r%u/q%u swapstate.%x otherstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits); - if ( (swap->I.statebits & 0x80) == 0 ) // wait for fee + printf("D r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); + if ( swap->I.iambob != 0 && (swap->I.statebits & 0x80) == 0 ) // wait for fee { if ( basilisk_swapget(myinfo,swap,0x80,data,maxlen,basilisk_verify_otherfee) == 0 ) { @@ -2384,25 +2386,25 @@ void basilisk_swaploop(void *_swap) break; } } - } - printf("generate fee\n"); - if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) - { - printf("done generate fee\n"); - swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); - iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); - basilisk_txlog(myinfo,swap,&swap->myfee,-1); - for (i=0; imyfee.I.spendlen; i++) - printf("%02x",swap->myfee.txbytes[i]); - printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); - swap->I.statebits |= 0x40; - if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 ) - break; - } - else - { - printf("error creating myfee\n"); - retval = -6; + printf("generate fee\n"); + if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) + { + printf("done generate fee\n"); + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); + iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); + basilisk_txlog(myinfo,swap,&swap->myfee,-1); + for (i=0; imyfee.I.spendlen; i++) + printf("%02x",swap->myfee.txbytes[i]); + printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); + swap->I.statebits |= 0x40; + if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 ) + break; + } + else + { + printf("error creating myfee\n"); + retval = -6; + } } } } @@ -2418,7 +2420,7 @@ void basilisk_swaploop(void *_swap) printf("ALICE's error %d %d %d\n",swap->myfee.I.datalen,swap->alicepayment.I.datalen,swap->alicepayment.I.datalen); retval = -7; } - else if ( swap->I.iambob != 0 && (swap->myfee.I.datalen == 0 || swap->bobdeposit.I.datalen == 0) ) //swap->bobpayment.I.datalen == 0 + else if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) //swap->bobpayment.I.datalen == 0 { printf("BOB's error %d %d %d\n",swap->myfee.I.datalen,swap->bobpayment.I.datalen,swap->bobdeposit.I.datalen); retval = -7; diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index b374442ea..285564543 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -652,7 +652,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_inf void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char *symbol,char *CMCname,double BTC2KMD,double KMDavail) { - double avebid,aveask,highbid,lowask,CMC_average,changes[3],estfee,estbtcfee; struct iguana_info *btccoin,*kmdcoin; struct DEXcoin_info *ptr = &coin->DEXinfo; + double avebid,aveask,highbid,lowask,CMC_average,changes[3],estfee,estbtcfee; struct iguana_info *kmdcoin; struct DEXcoin_info *ptr = &coin->DEXinfo; // wait for one confirmation to clear most in mempool (ha, ha) // deal with changing addresses, ie all pendings? estfee = 0.0001; From f46686667dc7cd3e98feab5b2fd5b538859bccc6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 16:12:47 +0300 Subject: [PATCH 0116/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 39c712977..c567de117 100755 --- a/.gitignore +++ b/.gitignore @@ -236,3 +236,5 @@ iguana/DB/SWAPS/1060082251-3390546616 iguana/SVM/rawfeatures/BTCD_BTC iguana/DB/SWAPS/1032184933-1028220623 + +iguana/DB/SWAPS/771249356-2746947221 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 43334eb6f..eddbce019 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2408,7 +2408,7 @@ void basilisk_swaploop(void *_swap) } } } - if ( (swap->I.statebits & 0x40) == 0 ) + if ( swap->I.iambob == 0 && (swap->I.statebits & 0x40) == 0 ) { printf("couldnt send fee\n"); retval = -8; From d352a4ca54d92af80f20166e62807ecd43b8fd84 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 16:17:35 +0300 Subject: [PATCH 0117/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index c567de117..88f2bc8e0 100755 --- a/.gitignore +++ b/.gitignore @@ -238,3 +238,5 @@ iguana/SVM/rawfeatures/BTCD_BTC iguana/DB/SWAPS/1032184933-1028220623 iguana/DB/SWAPS/771249356-2746947221 + +iguana/DB/SWAPS/2311778512-3235676199 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index eddbce019..37208a705 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1964,6 +1964,8 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap basilisk_sendstate(myinfo,swap,data,maxlen); } } + else if ( swap->I.iambob == 0 ) + swap->I.statebits |= 0x80; basilisk_sendstate(myinfo,swap,data,maxlen); basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); if ( (swap->I.otherstatebits & 0x80) != 0 && (swap->I.statebits & 0x80) != 0 ) From 433608f131073b672ca04f2c3ff0be6dc279af30 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 16:40:09 +0300 Subject: [PATCH 0118/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_tradebot.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 88f2bc8e0..8a19741bc 100755 --- a/.gitignore +++ b/.gitignore @@ -240,3 +240,5 @@ iguana/DB/SWAPS/1032184933-1028220623 iguana/DB/SWAPS/771249356-2746947221 iguana/DB/SWAPS/2311778512-3235676199 + +iguana/DB/SWAPS/3385048746-2109923340 diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index e35f0e6c1..2a583fb48 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -332,13 +332,13 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk printf("%s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); if ( myinfo->IAMLP != 0 && myrequest == 0 && pendingid == 0 && noquoteflag != 0 && ((profitmargin= tradebot_liquidity_active(myinfo,&refprice,"DEX",list[0].src,list[0].dest,destvolume)) > 0. || refprice != 0.) ) { - if ( profitmargin == 0 || (aveprice= instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,1.3 * dstr(list[0].srcamount))) == 0. || refprice > aveprice ) + if ( profitmargin == 0. || (aveprice= instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,1.3 * dstr(list[0].srcamount))) == 0. || refprice > aveprice ) aveprice = refprice; if ( fabs(aveprice) < SMALLVAL ) return(0); //retvals[0] = avebid, retvals[1] = bidvol, retvals[2] = aveask, retvals[3] = askvol; destamount = (1.0 - profitmargin) * aveprice * list[0].srcamount * SATOSHIDEN; - printf("aveprice %f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",aveprice,dstr(destamount),retvals[0],retvals[1],retvals[2],retvals[3]); + printf("%s/%s pm %f aveprice %f src %.8f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",list[0].src,list[0].dest,profitmargin,aveprice,dstr(list[0].srcamount),dstr(destamount),retvals[0],retvals[1],retvals[2],retvals[3]); if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) From 17efeab8e85ffacf6b48f03cb2fdb77e45872100 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 16:47:47 +0300 Subject: [PATCH 0119/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_tradebot.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 8a19741bc..56ecff6e1 100755 --- a/.gitignore +++ b/.gitignore @@ -242,3 +242,5 @@ iguana/DB/SWAPS/771249356-2746947221 iguana/DB/SWAPS/2311778512-3235676199 iguana/DB/SWAPS/3385048746-2109923340 + +iguana/DB/SWAPS/1739581643-2099619754 diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 2a583fb48..504eb9a3b 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -336,6 +336,8 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk aveprice = refprice; if ( fabs(aveprice) < SMALLVAL ) return(0); + if ( strcmp("BTC",list[0].src) == 0 ) + aveprice = (1. / aveprice); //retvals[0] = avebid, retvals[1] = bidvol, retvals[2] = aveask, retvals[3] = askvol; destamount = (1.0 - profitmargin) * aveprice * list[0].srcamount * SATOSHIDEN; printf("%s/%s pm %f aveprice %f src %.8f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",list[0].src,list[0].dest,profitmargin,aveprice,dstr(list[0].srcamount),dstr(destamount),retvals[0],retvals[1],retvals[2],retvals[3]); From 426d6dd447d84404a4b506d4d645ea194cab0468 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 16:54:40 +0300 Subject: [PATCH 0120/2705] Test --- basilisk/basilisk_tradebot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 504eb9a3b..48cd83dff 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -332,14 +332,14 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk printf("%s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); if ( myinfo->IAMLP != 0 && myrequest == 0 && pendingid == 0 && noquoteflag != 0 && ((profitmargin= tradebot_liquidity_active(myinfo,&refprice,"DEX",list[0].src,list[0].dest,destvolume)) > 0. || refprice != 0.) ) { - if ( profitmargin == 0. || (aveprice= instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,1.3 * dstr(list[0].srcamount))) == 0. || refprice > aveprice ) + if ( profitmargin == 0. || (aveprice= instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,.3 * dstr(list[0].srcamount))) == 0. || refprice > aveprice ) aveprice = refprice; if ( fabs(aveprice) < SMALLVAL ) return(0); if ( strcmp("BTC",list[0].src) == 0 ) aveprice = (1. / aveprice); //retvals[0] = avebid, retvals[1] = bidvol, retvals[2] = aveask, retvals[3] = askvol; - destamount = (1.0 - profitmargin) * aveprice * list[0].srcamount * SATOSHIDEN; + destamount = (1.0 - profitmargin) * aveprice * list[0].srcamount; printf("%s/%s pm %f aveprice %f src %.8f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",list[0].src,list[0].dest,profitmargin,aveprice,dstr(list[0].srcamount),dstr(destamount),retvals[0],retvals[1],retvals[2],retvals[3]); if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) { From 1002b9ec20c4547d028bbe338790526b755c04fd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 17:00:14 +0300 Subject: [PATCH 0121/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_tradebot.c | 2 ++ basilisk/jumblr.c | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 56ecff6e1..774e223c8 100755 --- a/.gitignore +++ b/.gitignore @@ -244,3 +244,5 @@ iguana/DB/SWAPS/2311778512-3235676199 iguana/DB/SWAPS/3385048746-2109923340 iguana/DB/SWAPS/1739581643-2099619754 + +iguana/DB/SWAPS/2247429570-1367058185 diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 48cd83dff..44a42f281 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -340,6 +340,8 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk aveprice = (1. / aveprice); //retvals[0] = avebid, retvals[1] = bidvol, retvals[2] = aveask, retvals[3] = askvol; destamount = (1.0 - profitmargin) * aveprice * list[0].srcamount; + if ( destamount > minamount ) + destamount = minamount; printf("%s/%s pm %f aveprice %f src %.8f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",list[0].src,list[0].dest,profitmargin,aveprice,dstr(list[0].srcamount),dstr(destamount),retvals[0],retvals[1],retvals[2],retvals[3]); if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) { diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 285564543..61deafa1c 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -727,7 +727,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( coinbtc != 0 && btcavail > minbtc+kmdcoin->DEXinfo.DEXpending ) + if ( 0 && coinbtc != 0 && btcavail > minbtc+kmdcoin->DEXinfo.DEXpending ) { printf("BTC deposits %.8f, min %.8f\n",btcavail,minbtc); @@ -747,7 +747,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) free_json(vals); // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - if ( 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > JUMBLR_INCR+kmdcoin->DEXinfo.DEXpending ) + if ( coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > JUMBLR_INCR+kmdcoin->DEXinfo.DEXpending ) { printf("KMD deposits %.8f, min %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR); vals = cJSON_CreateObject(); From 429964032280a4de26d96334a8bfa55da7ed8046 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 17:21:35 +0300 Subject: [PATCH 0122/2705] Test --- basilisk/basilisk_tradebot.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 44a42f281..26d06ff01 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -307,7 +307,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk if ( list[i].destamount > maxamount ) { maxamount = list[i].destamount; - printf("set maxamount %llu\n",(long long)maxamount); + //printf("set maxamount %llu\n",(long long)maxamount); maxi = i; } } @@ -341,7 +341,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk //retvals[0] = avebid, retvals[1] = bidvol, retvals[2] = aveask, retvals[3] = askvol; destamount = (1.0 - profitmargin) * aveprice * list[0].srcamount; if ( destamount > minamount ) - destamount = minamount; + destamount = minamount + ((minamount - destamount) * (1 + (rand() % 100))) / 100.; printf("%s/%s pm %f aveprice %f src %.8f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",list[0].src,list[0].dest,profitmargin,aveprice,dstr(list[0].srcamount),dstr(destamount),retvals[0],retvals[1],retvals[2],retvals[3]); if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) { @@ -371,7 +371,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk *issueR = list[maxi]; for (i=0; i %.8f\n",maxi,list[maxi].requestid,list[maxi].quoteid,dstr(maxamount),dstr(minamount)); + printf(" automatch[%d] r.%u quoteid.%u triggered %.8f >= %.8f\n",maxi,list[maxi].requestid,list[maxi].quoteid,dstr(maxamount),dstr(minamount)); if ( minamount > 0 ) metric = (dstr(maxamount) / dstr(minamount)) - 1.; else metric = 1.; From cb438f283b874ca099a8b3577bbbea2fcd0bc42f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 17:34:05 +0300 Subject: [PATCH 0123/2705] Test --- basilisk/jumblr.c | 85 ++++++++++++++++++++++++--------------- includes/iguana_structs.h | 2 +- 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 61deafa1c..762e98fa6 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -708,7 +708,7 @@ void jumblr_CMCname(char *CMCname,char *symbol) void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) { - struct iguana_info *kmdcoin,*coinbtc = 0; + double vol,avail; struct iguana_info *kmdcoin,*coinbtc = 0; if ( myinfo->IAMNOTARY != 0 ) return; if ( (kmdcoin= iguana_coinfind("KMD")) == 0 || (coinbtc= iguana_coinfind("BTC")) == 0 ) @@ -727,44 +727,65 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( 0 && coinbtc != 0 && btcavail > minbtc+kmdcoin->DEXinfo.DEXpending ) + if ( 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { - printf("BTC deposits %.8f, min %.8f\n",btcavail,minbtc); - - vals = cJSON_CreateObject(); - jaddstr(vals,"source","BTC"); - jaddstr(vals,"dest","KMD"); - jaddnum(vals,"amount",minbtc); - jaddnum(vals,"minprice",1./(1.01 * kmdcoin->DEXinfo.btcprice)); - jaddnum(vals,"usejumblr",1); - memset(hash.bytes,0,sizeof(hash)); - kmdcoin->DEXinfo.DEXpending += btcavail; - if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) + avail = (btcavail - kmdcoin->DEXinfo.DEXpending); + printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); + if ( avail >= (100. * minbtc) ) + vol = (100. * minbtc); + else if ( avail >= (10. * minbtc) ) + vol = (10. * minbtc); + else if ( avail >= minbtc ) + vol = minbtc; + else vol = 0.; + if ( vol > 0. ) { - printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); - free(retstr); + vals = cJSON_CreateObject(); + jaddstr(vals,"source","BTC"); + jaddstr(vals,"dest","KMD"); + jaddnum(vals,"amount",vol); + jaddnum(vals,"minprice",1./(1.015 * kmdcoin->DEXinfo.btcprice)); + jaddnum(vals,"usejumblr",1); + memset(hash.bytes,0,sizeof(hash)); + kmdcoin->DEXinfo.DEXpending += vol; + if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) + { + printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); + free(retstr); + } + free_json(vals); + // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } - free_json(vals); - // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - if ( coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > JUMBLR_INCR+kmdcoin->DEXinfo.DEXpending ) + if ( coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (100. + kmdcoin->DEXinfo.KMDpending) ) { - printf("KMD deposits %.8f, min %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR); - vals = cJSON_CreateObject(); - jaddstr(vals,"source","KMD"); - jaddstr(vals,"dest","BTC"); - jaddnum(vals,"amount",JUMBLR_INCR); - //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.01); - jaddnum(vals,"usejumblr",1); - memset(hash.bytes,0,sizeof(hash)); - kmdcoin->DEXinfo.DEXpending += btcavail; - if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) + avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); + printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR,avail); + if ( avail > 10000. ) + vol = 10000.; + else if ( avail > 1000. ) + vol = 1000.; + else if ( avail >= 100. ) + vol = 100.; + else vol = 0.; + if ( vol > 0. ) { - printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); - free(retstr); + vals = cJSON_CreateObject(); + jaddstr(vals,"source","KMD"); + jaddstr(vals,"dest","BTC"); + jaddnum(vals,"amount",vol); + //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.015); + jaddnum(vals,"usejumblr",1); + memset(hash.bytes,0,sizeof(hash)); + kmdcoin->DEXinfo.KMDpending += vol; + if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) + { + printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); + free(retstr); + } + free_json(vals); } - free_json(vals); } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); } //else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); } diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index efcc33b01..76206c409 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -472,7 +472,7 @@ struct DEXcoin_info { bits256 deposit_privkey,jumblr_privkey; struct iguana_info *coin; - double btcprice,BTC2KMD,kmdprice,USD_average,DEXpending,maxbid,minask,avail,KMDavail; + double btcprice,BTC2KMD,kmdprice,USD_average,DEXpending,KMDpending,maxbid,minask,avail,KMDavail; uint32_t lasttime; int32_t numpending; char CMCname[32],symbol[16],depositaddr[64],KMDdepositaddr[64],KMDjumblraddr[64],jumblraddr[64]; struct jumblr_pending *pending; From 65bbdc6c5f1d750dcd6cfffc42893ea09c1af9eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 17:41:30 +0300 Subject: [PATCH 0124/2705] Test --- basilisk/basilisk_tradebot.c | 2 +- basilisk/jumblr.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 26d06ff01..135e5f62f 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -332,7 +332,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk printf("%s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); if ( myinfo->IAMLP != 0 && myrequest == 0 && pendingid == 0 && noquoteflag != 0 && ((profitmargin= tradebot_liquidity_active(myinfo,&refprice,"DEX",list[0].src,list[0].dest,destvolume)) > 0. || refprice != 0.) ) { - if ( profitmargin == 0. || (aveprice= instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,.3 * dstr(list[0].srcamount))) == 0. || refprice > aveprice ) + if ( profitmargin == 0. || (aveprice= instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,.1 * dstr(list[0].srcamount))) == 0. || refprice > aveprice ) aveprice = refprice; if ( fabs(aveprice) < SMALLVAL ) return(0); diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 762e98fa6..299db05a6 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -727,7 +727,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) + if ( coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { avail = (btcavail - kmdcoin->DEXinfo.DEXpending); printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); @@ -757,7 +757,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - if ( coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (100. + kmdcoin->DEXinfo.KMDpending) ) + if ( 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (100. + kmdcoin->DEXinfo.KMDpending) ) { avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR,avail); From 0e914187ae23a87c2ba791c3017eb32811b80596 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 17:48:58 +0300 Subject: [PATCH 0125/2705] Test --- basilisk/basilisk_tradebot.c | 2 +- basilisk/jumblr.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 135e5f62f..706d73709 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -341,7 +341,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk //retvals[0] = avebid, retvals[1] = bidvol, retvals[2] = aveask, retvals[3] = askvol; destamount = (1.0 - profitmargin) * aveprice * list[0].srcamount; if ( destamount > minamount ) - destamount = minamount + ((minamount - destamount) * (1 + (rand() % 100))) / 100.; + destamount = minamount + ((destamount - minamount) * (1 + (rand() % 100))) / 100.; printf("%s/%s pm %f aveprice %f src %.8f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",list[0].src,list[0].dest,profitmargin,aveprice,dstr(list[0].srcamount),dstr(destamount),retvals[0],retvals[1],retvals[2],retvals[3]); if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) { diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 299db05a6..de94d520e 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -744,7 +744,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",1./(1.015 * kmdcoin->DEXinfo.btcprice)); + jaddnum(vals,"minprice",1./(1.01 * kmdcoin->DEXinfo.btcprice)); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.DEXpending += vol; @@ -775,7 +775,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",vol); //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.015); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.01); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.KMDpending += vol; From b43e106a173ba5d024ec7b2e77dea78827530a31 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 17:55:36 +0300 Subject: [PATCH 0126/2705] Test --- .gitignore | 4 ++++ iguana/main.c | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 774e223c8..315e9e178 100755 --- a/.gitignore +++ b/.gitignore @@ -246,3 +246,7 @@ iguana/DB/SWAPS/3385048746-2109923340 iguana/DB/SWAPS/1739581643-2099619754 iguana/DB/SWAPS/2247429570-1367058185 + +iguana/DB/SWAPS/3178831915-912907861 + +iguana/DB/SWAPS/445514331-1083446761 diff --git a/iguana/main.c b/iguana/main.c index d9932835e..454f6eb0a 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -749,7 +749,7 @@ void iguana_urlinit(struct supernet_info *myinfo,int32_t ismainnet,int32_t usess void jumblr_loop(void *ptr) { - struct iguana_info *coin; uint32_t t; struct supernet_info *myinfo = ptr; int32_t mult = 10; + struct iguana_info *coin; uint32_t t,n=0; struct supernet_info *myinfo = ptr; int32_t mult = 10; printf("JUMBLR loop\n"); while ( 1 ) { @@ -758,7 +758,8 @@ void jumblr_loop(void *ptr) if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC - jumblr_DEXcheck(myinfo,coin); + if ( (n++ % 10) == 0 ) + jumblr_DEXcheck(myinfo,coin); t = (uint32_t)time(NULL); if ( (t % (120 * mult)) < 60 ) { From c54930e0e45b77c2478bf1488548ac10b570509d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 18:16:59 +0300 Subject: [PATCH 0127/2705] Test --- basilisk/jumblr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index de94d520e..299db05a6 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -744,7 +744,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",1./(1.01 * kmdcoin->DEXinfo.btcprice)); + jaddnum(vals,"minprice",1./(1.015 * kmdcoin->DEXinfo.btcprice)); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.DEXpending += vol; @@ -775,7 +775,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",vol); //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.01); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.015); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.KMDpending += vol; From 999d6111fddf994b1c26e76f5d59542af34b3269 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 18:21:21 +0300 Subject: [PATCH 0128/2705] Test --- .gitignore | 2 ++ basilisk/jumblr.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 315e9e178..3616893f3 100755 --- a/.gitignore +++ b/.gitignore @@ -250,3 +250,5 @@ iguana/DB/SWAPS/2247429570-1367058185 iguana/DB/SWAPS/3178831915-912907861 iguana/DB/SWAPS/445514331-1083446761 + +iguana/DB/SWAPS/2510768478-2766365035 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 299db05a6..46baf23fe 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -727,7 +727,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) + if ( 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { avail = (btcavail - kmdcoin->DEXinfo.DEXpending); printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); @@ -757,7 +757,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - if ( 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (100. + kmdcoin->DEXinfo.KMDpending) ) + if ( 1 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (100. + kmdcoin->DEXinfo.KMDpending) ) { avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR,avail); From 28219cf3c7e09e156cbd2d396d3772467d212e96 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 5 Apr 2017 19:05:34 +0300 Subject: [PATCH 0129/2705] test --- .gitignore | 6 ++++++ basilisk/jumblr.c | 2 +- iguana/tests/dexlistunspent | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3616893f3..71ff972f2 100755 --- a/.gitignore +++ b/.gitignore @@ -252,3 +252,9 @@ iguana/DB/SWAPS/3178831915-912907861 iguana/DB/SWAPS/445514331-1083446761 iguana/DB/SWAPS/2510768478-2766365035 + +iguana/DB/SWAPS/2072817844-2263105627 + +iguana/DB/SWAPS/230888617-1894645930 + +iguana/DB/SWAPS/3606847984-2574036327 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 46baf23fe..4fc5960f0 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -727,7 +727,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) + if ( coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { avail = (btcavail - kmdcoin->DEXinfo.DEXpending); printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); diff --git a/iguana/tests/dexlistunspent b/iguana/tests/dexlistunspent index 98f1490fa..dfc4bda64 100755 --- a/iguana/tests/dexlistunspent +++ b/iguana/tests/dexlistunspent @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REMYL4s4zSiKeLEit5FawHFuGKZ4apm297\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6\",\"symbol\":\"KMD\"}" From 8dde830186c6a2fc594144b3273ffa24170b562c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 6 Apr 2017 10:39:17 +0300 Subject: [PATCH 0130/2705] Test --- .gitignore | 4 + basilisk/basilisk_swap.c | 232 +++++++++++++++++++++++---------------- iguana/iguana777.h | 2 +- 3 files changed, 145 insertions(+), 93 deletions(-) diff --git a/.gitignore b/.gitignore index 71ff972f2..147479f20 100755 --- a/.gitignore +++ b/.gitignore @@ -258,3 +258,7 @@ iguana/DB/SWAPS/2072817844-2263105627 iguana/DB/SWAPS/230888617-1894645930 iguana/DB/SWAPS/3606847984-2574036327 + +iguana/DB/SWAPS/2384443255-1263480722 + +iguana/DB/SWAPS/845549832-3630913950 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 37208a705..08ae1266d 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -18,7 +18,7 @@ make sure to broadcast deposit before claiming refund, or to just skip it if neither is done */ -#define DEX_SLEEP 1 +#define DEX_SLEEP 5 // Todo: monitor blockchains, ie complete extracting scriptsig // mode to autocreate required outputs @@ -105,6 +105,35 @@ Alice spends bobdeposit in 2*INSTANTDEX_LOCKTIME //Bobdeposit includes a covered put option for alicecoin, duration INSTANTDEX_LOCKTIME //alicepayment includes a covered call option for alicecoin, duration (2*INSTANTDEX_LOCKTIME - elapsed) +int32_t basilisk_istrustedbob(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + // for BTC and if trusted LP + return(0); +} + +int32_t basilisk_priviextract(struct supernet_info *myinfo,struct iguana_info *coin,char *name,bits256 *destp,uint8_t secret160[20],bits256 srctxid,int32_t srcvout) +{ + bits256 txid,privkey; char str[65]; int32_t i,vini,scriptlen; uint8_t rmd160[20],scriptsig[IGUANA_MAXSCRIPTSIZE]; + memset(privkey.bytes,0,sizeof(privkey)); + // use dex_listtransactions! + if ( (vini= iguana_vinifind(myinfo,coin,&txid,srctxid,srcvout)) >= 0 ) + { + if ( (scriptlen= iguana_scriptsigextract(myinfo,coin,scriptsig,sizeof(scriptsig),txid,vini)) > 32 ) + { + for (i=0; i<32; i++) + privkey.bytes[i] = scriptsig[scriptlen - 33 + i]; + revcalc_rmd160_sha256(rmd160,privkey);//.bytes,sizeof(privkey)); + if ( memcmp(secret160,rmd160,sizeof(rmd160)) == sizeof(rmd160) ) + { + *destp = privkey; + printf("basilisk_priviextract found privi %s (%s)\n",name,bits256_str(str,privkey)); + return(0); + } + } + } + return(-1); +} + void revcalc_rmd160_sha256(uint8_t rmd160[20],bits256 revhash) { bits256 hash; int32_t i; @@ -1167,12 +1196,23 @@ int32_t basilisk_swapget(struct supernet_info *myinfo,struct basilisk_swap *swap desthash.bytes[i] = ptr[offset++]; offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),"eid); offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),&_msgbits); - crc32 = calc_crc32(0,&ptr[offset],size-offset); if ( size > offset ) { - //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); - basilisk_swapgotdata(myinfo,swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); + crc32 = calc_crc32(0,&ptr[offset],size-offset); + if ( size > offset ) + { + //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); + basilisk_swapgotdata(myinfo,swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); + } } + else if ( bits256_nonz(srchash) == 0 && bits256_nonz(desthash) == 0 ) + { + if ( swap->aborted == 0 ) + { + swap->aborted = (uint32_t)time(NULL); + printf("got abort signal from other side\n"); + } + } else printf("basilisk_swapget: got strange packet\n"); if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } @@ -1235,26 +1275,23 @@ uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *sw return(nextbits); } -int32_t basilisk_priviextract(struct supernet_info *myinfo,struct iguana_info *coin,char *name,bits256 *destp,uint8_t secret160[20],bits256 srctxid,int32_t srcvout) +void basilisk_swap_sendabort(struct supernet_info *myinfo,struct basilisk_swap *swap) { - bits256 txid,privkey; char str[65]; int32_t i,vini,scriptlen; uint8_t rmd160[20],scriptsig[IGUANA_MAXSCRIPTSIZE]; - memset(privkey.bytes,0,sizeof(privkey)); - if ( (vini= iguana_vinifind(myinfo,coin,&txid,srctxid,srcvout)) >= 0 ) + uint32_t msgbits = 0; uint8_t buf[sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2]; int32_t sentbytes,offset=0; + memset(buf,0,sizeof(buf)); + offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); + offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); + if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) { - if ( (scriptlen= iguana_scriptsigextract(myinfo,coin,scriptsig,sizeof(scriptsig),txid,vini)) > 0 ) + if ( sentbytes < 0 ) { - for (i=0; i<32; i++) - privkey.bytes[i] = scriptsig[scriptlen - 33 + i]; - revcalc_rmd160_sha256(rmd160,privkey);//.bytes,sizeof(privkey)); - if ( memcmp(secret160,rmd160,sizeof(rmd160)) == sizeof(rmd160) ) - { - *destp = privkey; - printf("found privi %s (%s)\n",name,bits256_str(str,privkey)); - return(0); - } + if ( swap->pushsock >= 0 ) + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; } - } - return(-1); + } else printf("basilisk_swap_sendabort\n"); } int32_t basilisk_privBn_extract(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) @@ -1263,13 +1300,13 @@ int32_t basilisk_privBn_extract(struct supernet_info *myinfo,struct basilisk_swa { printf("extracted privBn from blockchain\n"); } - if ( basilisk_swapget(myinfo,swap,0x40000000,data,maxlen,basilisk_verify_privi) == 0 ) + else if ( basilisk_swapget(myinfo,swap,0x40000000,data,maxlen,basilisk_verify_privi) == 0 ) { - if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) - { - char str[65]; printf("have privBn.%s\n",bits256_str(str,swap->I.privBn)); - return(basilisk_alicepayment_spend(myinfo,swap,&swap->alicereclaim)); - } + } + if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) + { + char str[65]; printf("have privBn.%s\n",bits256_str(str,swap->I.privBn)); + return(basilisk_alicepayment_spend(myinfo,swap,&swap->alicereclaim)); } return(-1); } @@ -1278,7 +1315,7 @@ int32_t basilisk_privAm_extract(struct supernet_info *myinfo,struct basilisk_swa { if ( basilisk_priviextract(myinfo,swap->bobcoin,"privAm",&swap->I.privAm,swap->I.secretAm,swap->bobpayment.I.actualtxid,0) == 0 ) { - + printf("extracted privAm from blockchain\n"); } if ( bits256_nonz(swap->I.privAm) != 0 && swap->bobspend.I.datalen == 0 ) { @@ -1950,7 +1987,7 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap int32_t j,datalen,retval = 0; if ( swap->I.iambob != 0 ) swap->I.statebits |= 0x80; - while ( ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) + while ( swap->aborted == 0 && ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) { if ( swap->connected == 0 ) basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); @@ -1977,13 +2014,13 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); } basilisk_swap_saveupdate(myinfo,swap); - while ( retval == 0 && time(NULL) < swap->I.expiration ) // both sides have setup required data and paid txfee + while ( swap->aborted == 0 && retval == 0 && time(NULL) < swap->I.expiration ) // both sides have setup required data and paid txfee { basilisk_swap_saveupdate(myinfo,swap); if ( swap->connected == 0 ) basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); //if ( (rand() % 30) == 0 ) - printf("E r%u/q%u swapstate.%x otherstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits); + printf("E r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); if ( swap->I.iambob != 0 ) { //printf("BOB\n"); @@ -2081,7 +2118,7 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap } else if ( (swap->I.statebits & 0x400) == 0 ) { - if ( basilisk_numconfirms(myinfo,swap,&swap->bobdeposit) >= swap->I.bobconfirms ) + if ( basilisk_istrustedbob(myinfo,swap) != 0 || basilisk_numconfirms(myinfo,swap,&swap->bobdeposit) >= swap->I.bobconfirms ) { printf("bobdeposit confirmed\n"); swap->I.statebits |= 0x400; @@ -2105,7 +2142,7 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap } else if ( (swap->I.statebits & 0x10000) == 0 ) { - if ( basilisk_numconfirms(myinfo,swap,&swap->bobpayment) >= swap->I.bobconfirms ) + if ( basilisk_istrustedbob(myinfo,swap) != 0 || basilisk_numconfirms(myinfo,swap,&swap->bobpayment) >= swap->I.bobconfirms ) { printf("bobpayment confirmed\n"); swap->I.statebits |= 0x10000; @@ -2142,7 +2179,7 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap retval = 1; } } - else if ( basilisk_privBn_extract(myinfo,swap,data,maxlen) == 0 ) + else if ( swap->aborted != 0 || basilisk_privBn_extract(myinfo,swap,data,maxlen) == 0 ) { printf("Alice reclaims her payment\n"); swap->I.statebits |= 0x40000000; @@ -2257,9 +2294,52 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, } } +int32_t basilisk_alicetxs(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,retval = -1; + for (i=0; i<3; i++) + { + basilisk_alicepayment(myinfo,swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) + { + printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); + sleep(20); + } + else + { + retval = 0; + for (i=0; ialicepayment.I.datalen; i++) + printf("%02x",swap->alicepayment.txbytes[i]); + printf(" ALICE PAYMENT created\n"); + iguana_unspents_mark(myinfo,swap->alicecoin,swap->alicepayment.vins); + basilisk_txlog(myinfo,swap,&swap->alicepayment,-1); + break; + } + } + printf("generate fee\n"); + if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) + { + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); + iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); + basilisk_txlog(myinfo,swap,&swap->myfee,-1); + for (i=0; imyfee.I.spendlen; i++) + printf("%02x",swap->myfee.txbytes[i]); + printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); + swap->I.statebits |= 0x40; + if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 ) + return(0); + } + else + { + printf("error creating myfee\n"); + return(-2); + } + return(-1); +} + void basilisk_swaploop(void *_swap) { - uint8_t *data; uint32_t expiration; uint32_t channel; int32_t iters,retval=0,i,j,datalen,maxlen; struct supernet_info *myinfo; struct basilisk_swap *swap = _swap; + uint8_t *data; uint32_t expiration; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct supernet_info *myinfo; struct basilisk_swap *swap = _swap; myinfo = swap->myinfoptr; fprintf(stderr,"start swap\n"); maxlen = 1024*1024 + sizeof(*swap); @@ -2267,7 +2347,7 @@ void basilisk_swaploop(void *_swap) expiration = (uint32_t)time(NULL) + 600; myinfo->DEXactive = expiration; channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); - while ( (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) + while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) { dex_channelsend(myinfo,swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); if ( swap->connected == 0 ) @@ -2290,7 +2370,7 @@ void basilisk_swaploop(void *_swap) printf("couldnt establish connection\n"); retval = -1; } - while ( retval == 0 && (swap->I.statebits & 0x20) == 0 && time(NULL) < expiration ) + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 && time(NULL) < expiration ) { if ( swap->connected == 0 ) basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); @@ -2311,9 +2391,14 @@ void basilisk_swaploop(void *_swap) retval = -1; myinfo->DEXactive = 0; } + if ( swap->aborted != 0 ) + { + printf("swap aborted before tx sent\n"); + retval = -1; + } printf("C r%u/q%u swapstate.%x retval.%d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,retval); iters = 0; - while ( retval == 0 && (swap->I.statebits & 0x40) == 0 && iters++ < 10 ) // send fee + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x40) == 0 && iters++ < 10 ) // send fee { if ( swap->connected == 0 ) basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); @@ -2322,7 +2407,17 @@ void basilisk_swaploop(void *_swap) //printf("swapget\n"); basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); //printf("after swapget\n"); - if ( swap->myfee.I.datalen == 0 ) + if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) + { + printf("bobscripts set\n"); + if ( basilisk_bobscripts_set(myinfo,swap,1,1) < 0 ) + { + sleep(DEX_SLEEP); + printf("bobscripts set error\n"); + continue; + } + } + if ( swap->I.iambob == 0 && swap->myfee.I.datalen == 0 ) { /*for (i=0; i<20; i++) printf("%02x",swap->secretAm[i]); @@ -2354,59 +2449,10 @@ void basilisk_swaploop(void *_swap) for (i=0; i<32; i++) printf("%02x",swap->pubB1.bytes[i]); printf(" <- pubB1\n");*/ - basilisk_txlog(myinfo,swap,0,-1); - if ( swap->I.iambob != 0 ) + if ( (retval= basilisk_alicetxs(myinfo,swap,data,maxlen)) != 0 ) { - printf("bobscripts set\n"); - if ( basilisk_bobscripts_set(myinfo,swap,1,1) < 0 ) - { - sleep(DEX_SLEEP); - printf("bobscripts set error\n"); - continue; - } - } - else - { - for (i=0; i<3; i++) - { - //if ( swap->alicepayment.txbytes != 0 && swap->alicepayment.I.spendlen != 0 ) - // break; - basilisk_alicepayment(myinfo,swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); - if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) - { - printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); - sleep(DEX_SLEEP); - } - else - { - retval = 0; - for (i=0; ialicepayment.I.datalen; i++) - printf("%02x",swap->alicepayment.txbytes[i]); - printf(" ALICE PAYMENT created\n"); - iguana_unspents_mark(myinfo,swap->alicecoin,swap->alicepayment.vins); - basilisk_txlog(myinfo,swap,&swap->alicepayment,-1); - break; - } - } - printf("generate fee\n"); - if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) - { - printf("done generate fee\n"); - swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); - iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); - basilisk_txlog(myinfo,swap,&swap->myfee,-1); - for (i=0; imyfee.I.spendlen; i++) - printf("%02x",swap->myfee.txbytes[i]); - printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); - swap->I.statebits |= 0x40; - if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 ) - break; - } - else - { - printf("error creating myfee\n"); - retval = -6; - } + printf("basilisk_alicetxs error\n"); + break; } } } @@ -2428,7 +2474,7 @@ void basilisk_swaploop(void *_swap) retval = -7; } } - while ( retval == 0 && basilisk_swapiteration(myinfo,swap,data,maxlen) == 0 ) + while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(myinfo,swap,data,maxlen) == 0 ) { sleep(DEX_SLEEP); basilisk_sendstate(myinfo,swap,data,maxlen); @@ -2437,7 +2483,7 @@ void basilisk_swaploop(void *_swap) if ( time(NULL) > swap->I.expiration ) break; } - if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen != 0 ) + if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen != 0 && bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) { printf("BOB waiting for confirm state.%x\n",swap->I.statebits); sleep(60); // wait for confirm/propagation of msig @@ -2456,6 +2502,8 @@ void basilisk_swaploop(void *_swap) } basilisk_swap_saveupdate(myinfo,swap); } + if ( retval != 0 ) + basilisk_swap_sendabort(myinfo,swap); printf("end of atomic swap\n"); if ( swapcompleted(myinfo,swap) > 0 ) // only if swap completed { diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 774ebb515..f80919773 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -182,7 +182,7 @@ struct basilisk_swap { struct supernet_info *myinfoptr; struct iguana_info *bobcoin,*alicecoin; void (*balancingtrade)(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob); - int32_t subsock,pushsock,connected; uint32_t lasttime; + int32_t subsock,pushsock,connected; uint32_t lasttime,aborted; FILE *fp; bits256 persistent_privkey,persistent_pubkey; struct basilisk_swapinfo I; From 636d173454771e120581631760fb693c80675942 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 7 Apr 2017 16:46:51 +0300 Subject: [PATCH 0131/2705] batch15 --- basilisk/jumblr.c | 3 +- iguana/main.c | 2 +- iguana/tests/KMD.batch15 | 382 +++++++++++++++++++++++++++ iguana/tests/KMD.batch15.listunspent | 305 +++++++++++++++++++++ iguana/tests/REVS.batch15 | 17 ++ 5 files changed, 707 insertions(+), 2 deletions(-) create mode 100755 iguana/tests/KMD.batch15 create mode 100755 iguana/tests/KMD.batch15.listunspent create mode 100755 iguana/tests/REVS.batch15 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 4fc5960f0..9d9209d8e 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -628,7 +628,8 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_inf { for (i=0; i 0 ) { totalKMD = totalREVS = 0; - for (iter=3; iter<4; iter++) + for (iter=1; iter<2; iter++) for (i=0; i Date: Fri, 7 Apr 2017 16:50:15 +0300 Subject: [PATCH 0132/2705] batch15 B --- iguana/tests/KMD.batch15 | 1 + iguana/tests/KMD.batch15.listunspent | 1 + iguana/tests/REVS.batch15 | 1 + 3 files changed, 3 insertions(+) diff --git a/iguana/tests/KMD.batch15 b/iguana/tests/KMD.batch15 index f7b634c4f..236157660 100755 --- a/iguana/tests/KMD.batch15 +++ b/iguana/tests/KMD.batch15 @@ -1,3 +1,4 @@ +sleep 999999 # RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge KMD 108355.00859530 ./komodo-cli sendtoaddress RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge 108355.00859530 sleep 3 diff --git a/iguana/tests/KMD.batch15.listunspent b/iguana/tests/KMD.batch15.listunspent index 016a2f03e..4f613e38a 100755 --- a/iguana/tests/KMD.batch15.listunspent +++ b/iguana/tests/KMD.batch15.listunspent @@ -1,3 +1,4 @@ +sleep 999999 # RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge KMD 108355.00859530 curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge\",\"symbol\":\"KMD\"}" echo "108355.00859530 <- expected amount RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge" diff --git a/iguana/tests/REVS.batch15 b/iguana/tests/REVS.batch15 index 0102e91e7..3e64201d3 100755 --- a/iguana/tests/REVS.batch15 +++ b/iguana/tests/REVS.batch15 @@ -1,3 +1,4 @@ +sleep 999999 # RQedHsGydzYsynBRiizK3LNBnRUkAMRafZ KMD 5844.47004626, REVS 115.97829823 sleep 1 fiat/revs sendtoaddress RQedHsGydzYsynBRiizK3LNBnRUkAMRafZ 115.97829823 From 6c1ac1e7b7a6cc3811a8a21fef83e56e89058515 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 7 Apr 2017 17:49:02 +0300 Subject: [PATCH 0133/2705] batch15 C --- iguana/main.c | 8 +- iguana/tests/KMD.batch15.listunspent | 151 +++++++++++++-------------- 2 files changed, 79 insertions(+), 80 deletions(-) diff --git a/iguana/main.c b/iguana/main.c index 59f7230e5..be9a9908e 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -2058,7 +2058,7 @@ void komodo_ICO_batch(cJSON *array,int32_t batchid) if ( (n= cJSON_GetArraySize(array)) > 0 ) { totalKMD = totalREVS = 0; - for (iter=1; iter<2; iter++) + for (iter=0; iter<1; iter++) for (i=0; irpcport = IGUANA_RPCPORT; if ( (0) && (batchstr= OS_filestr(&batchsize,fname)) != 0 && (batchstr2= OS_filestr(&batchsize,fname2)) != 0 ) { komodo_REVS_merge(batchstr,batchstr2); @@ -2179,9 +2181,7 @@ void iguana_main(void *arg) decode_hex(CRYPTO777_PUBSECP33,33,CRYPTO777_PUBSECPSTR); iguana_ensuredirs(); iguana_Qinit(); - myinfo = SuperNET_MYINFO(0); libgfshare_init(myinfo,myinfo->logs,myinfo->exps); - myinfo->rpcport = IGUANA_RPCPORT; myinfo->dpowsock = myinfo->dexsock = myinfo->pubsock = myinfo->subsock = myinfo->reqsock = myinfo->repsock = -1; dex_init(myinfo); myinfo->psockport = 30000; diff --git a/iguana/tests/KMD.batch15.listunspent b/iguana/tests/KMD.batch15.listunspent index 4f613e38a..e24f8dd38 100755 --- a/iguana/tests/KMD.batch15.listunspent +++ b/iguana/tests/KMD.batch15.listunspent @@ -1,306 +1,305 @@ -sleep 999999 # RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge KMD 108355.00859530 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge\",\"symbol\":\"KMD\"}" echo "108355.00859530 <- expected amount RBzPz4Sd2Jt3jKVsXKwC4vwGkYG6hSekge" # RSN2ceQxBUKUynBf5BGbZU6er7uqAGUXzw KMD 23072.44878134 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RSN2ceQxBUKUynBf5BGbZU6er7uqAGUXzw\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RSN2ceQxBUKUynBf5BGbZU6er7uqAGUXzw\",\"symbol\":\"KMD\"}" echo "23072.44878134 <- expected amount RSN2ceQxBUKUynBf5BGbZU6er7uqAGUXzw" # RVMGcrxJMHST3dPZJJNNxZWJKidFYBmpTE KMD 26923.62561943 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RVMGcrxJMHST3dPZJJNNxZWJKidFYBmpTE\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RVMGcrxJMHST3dPZJJNNxZWJKidFYBmpTE\",\"symbol\":\"KMD\"}" echo "26923.62561943 <- expected amount RVMGcrxJMHST3dPZJJNNxZWJKidFYBmpTE" # RJJKtJqfC8Ytrjq9RqiYLH85qbHNkqXb43 KMD 890.85002942 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RJJKtJqfC8Ytrjq9RqiYLH85qbHNkqXb43\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RJJKtJqfC8Ytrjq9RqiYLH85qbHNkqXb43\",\"symbol\":\"KMD\"}" echo "890.85002942 <- expected amount RJJKtJqfC8Ytrjq9RqiYLH85qbHNkqXb43" # RWEGPuUx2U8V28VpxAKpuKfwcs6TN4GpKV KMD 6196.32806186 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWEGPuUx2U8V28VpxAKpuKfwcs6TN4GpKV\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWEGPuUx2U8V28VpxAKpuKfwcs6TN4GpKV\",\"symbol\":\"KMD\"}" echo "6196.32806186 <- expected amount RWEGPuUx2U8V28VpxAKpuKfwcs6TN4GpKV" # RLJ1GkGiu9jmDngdzYGNtwWffWkFYKgbuX KMD 123341.77894864 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RLJ1GkGiu9jmDngdzYGNtwWffWkFYKgbuX\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RLJ1GkGiu9jmDngdzYGNtwWffWkFYKgbuX\",\"symbol\":\"KMD\"}" echo "123341.77894864 <- expected amount RLJ1GkGiu9jmDngdzYGNtwWffWkFYKgbuX" # RKRtuN5f76BjSxPPTVbmtBSSdz938UjiJx KMD 1267.52466143 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKRtuN5f76BjSxPPTVbmtBSSdz938UjiJx\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKRtuN5f76BjSxPPTVbmtBSSdz938UjiJx\",\"symbol\":\"KMD\"}" echo "1267.52466143 <- expected amount RKRtuN5f76BjSxPPTVbmtBSSdz938UjiJx" # RNMsi23XMUGyRe1FB8rxrJ6FQV4UHyVQn9 KMD 9575.27247343 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNMsi23XMUGyRe1FB8rxrJ6FQV4UHyVQn9\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNMsi23XMUGyRe1FB8rxrJ6FQV4UHyVQn9\",\"symbol\":\"KMD\"}" echo "9575.27247343 <- expected amount RNMsi23XMUGyRe1FB8rxrJ6FQV4UHyVQn9" # RNMsi23XMUGyRe1FB8rxrJ6FQV4UHyVQn9 KMD 8123.81358037 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNMsi23XMUGyRe1FB8rxrJ6FQV4UHyVQn9\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNMsi23XMUGyRe1FB8rxrJ6FQV4UHyVQn9\",\"symbol\":\"KMD\"}" echo "8123.81358037 <- expected amount RNMsi23XMUGyRe1FB8rxrJ6FQV4UHyVQn9" # REZbCCvVVNdvg8eVkwz4SDk4sVvBfSXrE8 KMD 4989.67320242 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REZbCCvVVNdvg8eVkwz4SDk4sVvBfSXrE8\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REZbCCvVVNdvg8eVkwz4SDk4sVvBfSXrE8\",\"symbol\":\"KMD\"}" echo "4989.67320242 <- expected amount REZbCCvVVNdvg8eVkwz4SDk4sVvBfSXrE8" # RUcSLDX7nWM1oe5ftLYj3m6RE3gSsEXcGD KMD 752.38094876 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUcSLDX7nWM1oe5ftLYj3m6RE3gSsEXcGD\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUcSLDX7nWM1oe5ftLYj3m6RE3gSsEXcGD\",\"symbol\":\"KMD\"}" echo "752.38094876 <- expected amount RUcSLDX7nWM1oe5ftLYj3m6RE3gSsEXcGD" # RSs2rBgjQcZjdPLuUhEFEDNVqoUutKAqMz KMD 142854.50921654 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RSs2rBgjQcZjdPLuUhEFEDNVqoUutKAqMz\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RSs2rBgjQcZjdPLuUhEFEDNVqoUutKAqMz\",\"symbol\":\"KMD\"}" echo "142854.50921654 <- expected amount RSs2rBgjQcZjdPLuUhEFEDNVqoUutKAqMz" # RRZw29LKHAMTfw673BQHBjf1H6krpKruEV KMD 700273.96662837 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RRZw29LKHAMTfw673BQHBjf1H6krpKruEV\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RRZw29LKHAMTfw673BQHBjf1H6krpKruEV\",\"symbol\":\"KMD\"}" echo "700273.96662837 <- expected amount RRZw29LKHAMTfw673BQHBjf1H6krpKruEV" # RUcnbCSHhpHMhQbKNk5VMgmi2vn7hGGyNQ KMD 22785.43547500 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUcnbCSHhpHMhQbKNk5VMgmi2vn7hGGyNQ\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUcnbCSHhpHMhQbKNk5VMgmi2vn7hGGyNQ\",\"symbol\":\"KMD\"}" echo "22785.43547500 <- expected amount RUcnbCSHhpHMhQbKNk5VMgmi2vn7hGGyNQ" # RFxv7eb5F4hYum2pfJoWDJSBLesdzEothC KMD 49.81951692 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RFxv7eb5F4hYum2pfJoWDJSBLesdzEothC\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RFxv7eb5F4hYum2pfJoWDJSBLesdzEothC\",\"symbol\":\"KMD\"}" echo "49.81951692 <- expected amount RFxv7eb5F4hYum2pfJoWDJSBLesdzEothC" # RJD2LGt2KYdmcuLMkrwnXA18o9U5xhLXbG KMD 9768.98395745 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RJD2LGt2KYdmcuLMkrwnXA18o9U5xhLXbG\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RJD2LGt2KYdmcuLMkrwnXA18o9U5xhLXbG\",\"symbol\":\"KMD\"}" echo "9768.98395745 <- expected amount RJD2LGt2KYdmcuLMkrwnXA18o9U5xhLXbG" # RCuyPLaBmudGiTm7chbnWdBATqEvcLWbNc KMD 17899.04337446 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RCuyPLaBmudGiTm7chbnWdBATqEvcLWbNc\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RCuyPLaBmudGiTm7chbnWdBATqEvcLWbNc\",\"symbol\":\"KMD\"}" echo "17899.04337446 <- expected amount RCuyPLaBmudGiTm7chbnWdBATqEvcLWbNc" # RWtBYTabQZcJku6Z7X2u9NUyhzGUyMcba7 KMD 14691.11993791 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWtBYTabQZcJku6Z7X2u9NUyhzGUyMcba7\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWtBYTabQZcJku6Z7X2u9NUyhzGUyMcba7\",\"symbol\":\"KMD\"}" echo "14691.11993791 <- expected amount RWtBYTabQZcJku6Z7X2u9NUyhzGUyMcba7" # RJdKjpM8pm3E5Y93p5xy4XE8zQTQP5cfaY KMD 1161.97829925 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RJdKjpM8pm3E5Y93p5xy4XE8zQTQP5cfaY\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RJdKjpM8pm3E5Y93p5xy4XE8zQTQP5cfaY\",\"symbol\":\"KMD\"}" echo "1161.97829925 <- expected amount RJdKjpM8pm3E5Y93p5xy4XE8zQTQP5cfaY" # RA8iFVS6B99VfGAThL21NuBFQ1wCeqVkYW KMD 1172.24498253 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RA8iFVS6B99VfGAThL21NuBFQ1wCeqVkYW\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RA8iFVS6B99VfGAThL21NuBFQ1wCeqVkYW\",\"symbol\":\"KMD\"}" echo "1172.24498253 <- expected amount RA8iFVS6B99VfGAThL21NuBFQ1wCeqVkYW" # RTjshGhD5Nf6ZrWLxd6Kh65LrZRQzUesbx KMD 9007.57601472 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTjshGhD5Nf6ZrWLxd6Kh65LrZRQzUesbx\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTjshGhD5Nf6ZrWLxd6Kh65LrZRQzUesbx\",\"symbol\":\"KMD\"}" echo "9007.57601472 <- expected amount RTjshGhD5Nf6ZrWLxd6Kh65LrZRQzUesbx" # RQedHsGydzYsynBRiizK3LNBnRUkAMRafZ KMD 5844.47004626, REVS 115.97829823 # RQedHsGydzYsynBRiizK3LNBnRUkAMRafZ KMD 5844.47004626 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RQedHsGydzYsynBRiizK3LNBnRUkAMRafZ\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RQedHsGydzYsynBRiizK3LNBnRUkAMRafZ\",\"symbol\":\"KMD\"}" echo "5844.47004626 <- expected amount RQedHsGydzYsynBRiizK3LNBnRUkAMRafZ" # RUWP4WNfz1axrYbhLnK1mL1mYQigS9rheg KMD 5008.45159128 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUWP4WNfz1axrYbhLnK1mL1mYQigS9rheg\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUWP4WNfz1axrYbhLnK1mL1mYQigS9rheg\",\"symbol\":\"KMD\"}" echo "5008.45159128 <- expected amount RUWP4WNfz1axrYbhLnK1mL1mYQigS9rheg" # RUcnbCSHhpHMhQbKNk5VMgmi2vn7hGGyNQ KMD 7646.82608478 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUcnbCSHhpHMhQbKNk5VMgmi2vn7hGGyNQ\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUcnbCSHhpHMhQbKNk5VMgmi2vn7hGGyNQ\",\"symbol\":\"KMD\"}" echo "7646.82608478 <- expected amount RUcnbCSHhpHMhQbKNk5VMgmi2vn7hGGyNQ" # RKGh71nXHPkXZUwoKtEnwfdLsxcTKwdfbf KMD 3630.85647725 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKGh71nXHPkXZUwoKtEnwfdLsxcTKwdfbf\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKGh71nXHPkXZUwoKtEnwfdLsxcTKwdfbf\",\"symbol\":\"KMD\"}" echo "3630.85647725 <- expected amount RKGh71nXHPkXZUwoKtEnwfdLsxcTKwdfbf" # RYaL2xQsvSCaWVF5p4AUFLiM8TZsm2pVuj KMD 26.57494393 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RYaL2xQsvSCaWVF5p4AUFLiM8TZsm2pVuj\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RYaL2xQsvSCaWVF5p4AUFLiM8TZsm2pVuj\",\"symbol\":\"KMD\"}" echo "26.57494393 <- expected amount RYaL2xQsvSCaWVF5p4AUFLiM8TZsm2pVuj" # R9UwkeRo4HWP14LXKxvii7PQkyrkk8zybU KMD 0.36801433 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"R9UwkeRo4HWP14LXKxvii7PQkyrkk8zybU\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"R9UwkeRo4HWP14LXKxvii7PQkyrkk8zybU\",\"symbol\":\"KMD\"}" echo "0.36801433 <- expected amount R9UwkeRo4HWP14LXKxvii7PQkyrkk8zybU" # RE9wMd3wq3SwYYq9y7iv8r2cb7ndFc7V43 KMD 8249.37604889 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RE9wMd3wq3SwYYq9y7iv8r2cb7ndFc7V43\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RE9wMd3wq3SwYYq9y7iv8r2cb7ndFc7V43\",\"symbol\":\"KMD\"}" echo "8249.37604889 <- expected amount RE9wMd3wq3SwYYq9y7iv8r2cb7ndFc7V43" # RXZvRrVc5JhmJ3dpgFNqjPQog2RHJwSTRN KMD 2701.34236284 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RXZvRrVc5JhmJ3dpgFNqjPQog2RHJwSTRN\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RXZvRrVc5JhmJ3dpgFNqjPQog2RHJwSTRN\",\"symbol\":\"KMD\"}" echo "2701.34236284 <- expected amount RXZvRrVc5JhmJ3dpgFNqjPQog2RHJwSTRN" # RD7gYAZVD9yN5uUNyGd3TZNVXJA234pWDk KMD 9799.35032367 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RD7gYAZVD9yN5uUNyGd3TZNVXJA234pWDk\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RD7gYAZVD9yN5uUNyGd3TZNVXJA234pWDk\",\"symbol\":\"KMD\"}" echo "9799.35032367 <- expected amount RD7gYAZVD9yN5uUNyGd3TZNVXJA234pWDk" # RNsNi3L3QWXx4Sa1CyZYfCd2q6TjJcrK4L KMD 2180.13581547 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNsNi3L3QWXx4Sa1CyZYfCd2q6TjJcrK4L\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNsNi3L3QWXx4Sa1CyZYfCd2q6TjJcrK4L\",\"symbol\":\"KMD\"}" echo "2180.13581547 <- expected amount RNsNi3L3QWXx4Sa1CyZYfCd2q6TjJcrK4L" # RRsb2PKKvZQuGCxEJZFEHxydq4aktjQKnV KMD 3028.34071670 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RRsb2PKKvZQuGCxEJZFEHxydq4aktjQKnV\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RRsb2PKKvZQuGCxEJZFEHxydq4aktjQKnV\",\"symbol\":\"KMD\"}" echo "3028.34071670 <- expected amount RRsb2PKKvZQuGCxEJZFEHxydq4aktjQKnV" # RLyaf3XgjHruSeJd4oj83E8btck7kYPmVz KMD 6100.04389549 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RLyaf3XgjHruSeJd4oj83E8btck7kYPmVz\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RLyaf3XgjHruSeJd4oj83E8btck7kYPmVz\",\"symbol\":\"KMD\"}" echo "6100.04389549 <- expected amount RLyaf3XgjHruSeJd4oj83E8btck7kYPmVz" # RBBaR5v41Bew2qeybeutzN8YcFV9z2BTXZ KMD 737.35656935 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RBBaR5v41Bew2qeybeutzN8YcFV9z2BTXZ\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RBBaR5v41Bew2qeybeutzN8YcFV9z2BTXZ\",\"symbol\":\"KMD\"}" echo "737.35656935 <- expected amount RBBaR5v41Bew2qeybeutzN8YcFV9z2BTXZ" # RHfFfCbb32Ld5SYjqA7yL5tohX5U1nc919 KMD 929.58263940 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RHfFfCbb32Ld5SYjqA7yL5tohX5U1nc919\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RHfFfCbb32Ld5SYjqA7yL5tohX5U1nc919\",\"symbol\":\"KMD\"}" echo "929.58263940 <- expected amount RHfFfCbb32Ld5SYjqA7yL5tohX5U1nc919" # RT4DVxxerQye2rPf89Tfdxq6XmMuYMMDWy KMD 34677.50699205 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RT4DVxxerQye2rPf89Tfdxq6XmMuYMMDWy\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RT4DVxxerQye2rPf89Tfdxq6XmMuYMMDWy\",\"symbol\":\"KMD\"}" echo "34677.50699205 <- expected amount RT4DVxxerQye2rPf89Tfdxq6XmMuYMMDWy" # REmJva8Uc5Rhmyf4CSvVTWCkSQ5MAiXpXa KMD 26142.50314066, REVS 20.00000000 # REmJva8Uc5Rhmyf4CSvVTWCkSQ5MAiXpXa KMD 26142.50314066 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REmJva8Uc5Rhmyf4CSvVTWCkSQ5MAiXpXa\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REmJva8Uc5Rhmyf4CSvVTWCkSQ5MAiXpXa\",\"symbol\":\"KMD\"}" echo "26142.50314066 <- expected amount REmJva8Uc5Rhmyf4CSvVTWCkSQ5MAiXpXa" # RX2gT4WZR7VDiufaYGGCYoxRD3kNZmEN2V KMD 4802.84363690 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RX2gT4WZR7VDiufaYGGCYoxRD3kNZmEN2V\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RX2gT4WZR7VDiufaYGGCYoxRD3kNZmEN2V\",\"symbol\":\"KMD\"}" echo "4802.84363690 <- expected amount RX2gT4WZR7VDiufaYGGCYoxRD3kNZmEN2V" # RD592mTwrB5w4XF5RL5qVfVYCkGCuctGft KMD 1005.97291406, REVS 19.95990000 # RD592mTwrB5w4XF5RL5qVfVYCkGCuctGft KMD 1005.97291406 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RD592mTwrB5w4XF5RL5qVfVYCkGCuctGft\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RD592mTwrB5w4XF5RL5qVfVYCkGCuctGft\",\"symbol\":\"KMD\"}" echo "1005.97291406 <- expected amount RD592mTwrB5w4XF5RL5qVfVYCkGCuctGft" # RD486qQaD85849AdDPH3Xy3iyppuvxDZYf KMD 112218.69529965 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RD486qQaD85849AdDPH3Xy3iyppuvxDZYf\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RD486qQaD85849AdDPH3Xy3iyppuvxDZYf\",\"symbol\":\"KMD\"}" echo "112218.69529965 <- expected amount RD486qQaD85849AdDPH3Xy3iyppuvxDZYf" # RFPpBZpjgA1wT5mHBLRfUu4X8xr4DrLP4e KMD 3479.75699272 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RFPpBZpjgA1wT5mHBLRfUu4X8xr4DrLP4e\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RFPpBZpjgA1wT5mHBLRfUu4X8xr4DrLP4e\",\"symbol\":\"KMD\"}" echo "3479.75699272 <- expected amount RFPpBZpjgA1wT5mHBLRfUu4X8xr4DrLP4e" # RRv9LoJVCtaQYkKm92MVb2ZZWH3cthWpGN KMD 175.51057343 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RRv9LoJVCtaQYkKm92MVb2ZZWH3cthWpGN\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RRv9LoJVCtaQYkKm92MVb2ZZWH3cthWpGN\",\"symbol\":\"KMD\"}" echo "175.51057343 <- expected amount RRv9LoJVCtaQYkKm92MVb2ZZWH3cthWpGN" # RWM6u3En5J8afndTjSyAK6bw7EThdTK3a8 KMD 7477.64792521 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWM6u3En5J8afndTjSyAK6bw7EThdTK3a8\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWM6u3En5J8afndTjSyAK6bw7EThdTK3a8\",\"symbol\":\"KMD\"}" echo "7477.64792521 <- expected amount RWM6u3En5J8afndTjSyAK6bw7EThdTK3a8" # RVbyHqZRqL7QnjZdg5JPRCic5vnehjuTgn KMD 54859.12298759 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RVbyHqZRqL7QnjZdg5JPRCic5vnehjuTgn\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RVbyHqZRqL7QnjZdg5JPRCic5vnehjuTgn\",\"symbol\":\"KMD\"}" echo "54859.12298759 <- expected amount RVbyHqZRqL7QnjZdg5JPRCic5vnehjuTgn" # RHXnTT4jKiS8PGR6RrUobdVC7SxJ5gUXMo KMD 79.56270943 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RHXnTT4jKiS8PGR6RrUobdVC7SxJ5gUXMo\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RHXnTT4jKiS8PGR6RrUobdVC7SxJ5gUXMo\",\"symbol\":\"KMD\"}" echo "79.56270943 <- expected amount RHXnTT4jKiS8PGR6RrUobdVC7SxJ5gUXMo" # RLgtZmLckAP74eH5DZyG2V44mX1KMCAwCb KMD 349.07505686 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RLgtZmLckAP74eH5DZyG2V44mX1KMCAwCb\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RLgtZmLckAP74eH5DZyG2V44mX1KMCAwCb\",\"symbol\":\"KMD\"}" echo "349.07505686 <- expected amount RLgtZmLckAP74eH5DZyG2V44mX1KMCAwCb" # RJRJ2xejRZuiMPQnafPEUU2VUfTfchpHZH KMD 248.34196903 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RJRJ2xejRZuiMPQnafPEUU2VUfTfchpHZH\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RJRJ2xejRZuiMPQnafPEUU2VUfTfchpHZH\",\"symbol\":\"KMD\"}" echo "248.34196903 <- expected amount RJRJ2xejRZuiMPQnafPEUU2VUfTfchpHZH" # RDVsguQRewZQxA4CYuFaU6P1ZfzXy15m9R KMD 904.34185995 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RDVsguQRewZQxA4CYuFaU6P1ZfzXy15m9R\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RDVsguQRewZQxA4CYuFaU6P1ZfzXy15m9R\",\"symbol\":\"KMD\"}" echo "904.34185995 <- expected amount RDVsguQRewZQxA4CYuFaU6P1ZfzXy15m9R" # REhB64k55HNsga6tbJxqwioRHg7pD7mTpQ KMD 49.36918661 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REhB64k55HNsga6tbJxqwioRHg7pD7mTpQ\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REhB64k55HNsga6tbJxqwioRHg7pD7mTpQ\",\"symbol\":\"KMD\"}" echo "49.36918661 <- expected amount REhB64k55HNsga6tbJxqwioRHg7pD7mTpQ" # RKjRhiPHQJEf65CwXTjBHLQ5r2fKfpeyBC KMD 159023.63042654 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKjRhiPHQJEf65CwXTjBHLQ5r2fKfpeyBC\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKjRhiPHQJEf65CwXTjBHLQ5r2fKfpeyBC\",\"symbol\":\"KMD\"}" echo "159023.63042654 <- expected amount RKjRhiPHQJEf65CwXTjBHLQ5r2fKfpeyBC" # RC2c6CMiCrTceYdbkYzjXmavR45pwPJczo KMD 18870.52757981 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RC2c6CMiCrTceYdbkYzjXmavR45pwPJczo\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RC2c6CMiCrTceYdbkYzjXmavR45pwPJczo\",\"symbol\":\"KMD\"}" echo "18870.52757981 <- expected amount RC2c6CMiCrTceYdbkYzjXmavR45pwPJczo" # R9WDH8NDcEewJTYGPgqMkvQ7ztbtBfV8zJ KMD 3523.48691215 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"R9WDH8NDcEewJTYGPgqMkvQ7ztbtBfV8zJ\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"R9WDH8NDcEewJTYGPgqMkvQ7ztbtBfV8zJ\",\"symbol\":\"KMD\"}" echo "3523.48691215 <- expected amount R9WDH8NDcEewJTYGPgqMkvQ7ztbtBfV8zJ" # RWc6GouJggQDsBCeW1DYck629FPrDJCTP9 KMD 2607.14186398 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWc6GouJggQDsBCeW1DYck629FPrDJCTP9\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWc6GouJggQDsBCeW1DYck629FPrDJCTP9\",\"symbol\":\"KMD\"}" echo "2607.14186398 <- expected amount RWc6GouJggQDsBCeW1DYck629FPrDJCTP9" # RYU6iDdo1AfrBg6zUcCPEX8BnSL1YsxrMk KMD 3098.60879800 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RYU6iDdo1AfrBg6zUcCPEX8BnSL1YsxrMk\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RYU6iDdo1AfrBg6zUcCPEX8BnSL1YsxrMk\",\"symbol\":\"KMD\"}" echo "3098.60879800 <- expected amount RYU6iDdo1AfrBg6zUcCPEX8BnSL1YsxrMk" # RTYpGd8VFGtiDb9bJSZasTWjRRHVqYABtT KMD 3647.68227700 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTYpGd8VFGtiDb9bJSZasTWjRRHVqYABtT\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTYpGd8VFGtiDb9bJSZasTWjRRHVqYABtT\",\"symbol\":\"KMD\"}" echo "3647.68227700 <- expected amount RTYpGd8VFGtiDb9bJSZasTWjRRHVqYABtT" # RYUgPBd2MvnSEAADUmAXMSV6bBhRTA9dBH KMD 468.24354647 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RYUgPBd2MvnSEAADUmAXMSV6bBhRTA9dBH\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RYUgPBd2MvnSEAADUmAXMSV6bBhRTA9dBH\",\"symbol\":\"KMD\"}" echo "468.24354647 <- expected amount RYUgPBd2MvnSEAADUmAXMSV6bBhRTA9dBH" # RX3EPj8UoJJbQ4LnkQGqLnRSapbneckaKi KMD 2418.85149293 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RX3EPj8UoJJbQ4LnkQGqLnRSapbneckaKi\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RX3EPj8UoJJbQ4LnkQGqLnRSapbneckaKi\",\"symbol\":\"KMD\"}" echo "2418.85149293 <- expected amount RX3EPj8UoJJbQ4LnkQGqLnRSapbneckaKi" # REJYC31D8z48AJAC8CmhgKgSuVc4WwFPWh KMD 9295.82639400 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REJYC31D8z48AJAC8CmhgKgSuVc4WwFPWh\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REJYC31D8z48AJAC8CmhgKgSuVc4WwFPWh\",\"symbol\":\"KMD\"}" echo "9295.82639400 <- expected amount REJYC31D8z48AJAC8CmhgKgSuVc4WwFPWh" # RAvtq1kazCRZUvWvPsN7ioY2Vt1EYtgpuz KMD 55321.57248841 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RAvtq1kazCRZUvWvPsN7ioY2Vt1EYtgpuz\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RAvtq1kazCRZUvWvPsN7ioY2Vt1EYtgpuz\",\"symbol\":\"KMD\"}" echo "55321.57248841 <- expected amount RAvtq1kazCRZUvWvPsN7ioY2Vt1EYtgpuz" # RWXHBrpGt1dwa1rBuQj6QgQdWBdAtLwVAp KMD 367572.46866275 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWXHBrpGt1dwa1rBuQj6QgQdWBdAtLwVAp\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RWXHBrpGt1dwa1rBuQj6QgQdWBdAtLwVAp\",\"symbol\":\"KMD\"}" echo "367572.46866275 <- expected amount RWXHBrpGt1dwa1rBuQj6QgQdWBdAtLwVAp" # REpJJwmxrSetdhNp4uKUTwyyTrSpNxjM2s KMD 4.48872950 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REpJJwmxrSetdhNp4uKUTwyyTrSpNxjM2s\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"REpJJwmxrSetdhNp4uKUTwyyTrSpNxjM2s\",\"symbol\":\"KMD\"}" echo "4.48872950 <- expected amount REpJJwmxrSetdhNp4uKUTwyyTrSpNxjM2s" # RKmwwn2n1DaAqZdDXiZkobgQSKiVcUD2RP KMD 4260.58709725 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKmwwn2n1DaAqZdDXiZkobgQSKiVcUD2RP\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKmwwn2n1DaAqZdDXiZkobgQSKiVcUD2RP\",\"symbol\":\"KMD\"}" echo "4260.58709725 <- expected amount RKmwwn2n1DaAqZdDXiZkobgQSKiVcUD2RP" # RL8XNqYnfkstJPuNHPYfsPQSzccTHcqFkf KMD 2953.97870652 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RL8XNqYnfkstJPuNHPYfsPQSzccTHcqFkf\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RL8XNqYnfkstJPuNHPYfsPQSzccTHcqFkf\",\"symbol\":\"KMD\"}" echo "2953.97870652 <- expected amount RL8XNqYnfkstJPuNHPYfsPQSzccTHcqFkf" # RECqqp55ZLUccEgEwd3VTYC2awx9aVXEHi KMD 75258.40704108 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RECqqp55ZLUccEgEwd3VTYC2awx9aVXEHi\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RECqqp55ZLUccEgEwd3VTYC2awx9aVXEHi\",\"symbol\":\"KMD\"}" echo "75258.40704108 <- expected amount RECqqp55ZLUccEgEwd3VTYC2awx9aVXEHi" # RB6Ua6YzhT1nra7vhZFa15NZ2uv8ahGET3 KMD 125611.30316493, REVS 1564.97178647 # RB6Ua6YzhT1nra7vhZFa15NZ2uv8ahGET3 KMD 125611.30316493 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RB6Ua6YzhT1nra7vhZFa15NZ2uv8ahGET3\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RB6Ua6YzhT1nra7vhZFa15NZ2uv8ahGET3\",\"symbol\":\"KMD\"}" echo "125611.30316493 <- expected amount RB6Ua6YzhT1nra7vhZFa15NZ2uv8ahGET3" # RHJ55iWUQNbKcSn8shbv1RbGuip3RSRHFv KMD 693.08132289 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RHJ55iWUQNbKcSn8shbv1RbGuip3RSRHFv\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RHJ55iWUQNbKcSn8shbv1RbGuip3RSRHFv\",\"symbol\":\"KMD\"}" echo "693.08132289 <- expected amount RHJ55iWUQNbKcSn8shbv1RbGuip3RSRHFv" # RTVFC7r5K3bedTrPbXLwh63g27PKzqHBDk KMD 4535.36019149, REVS 90.00018012 # RTVFC7r5K3bedTrPbXLwh63g27PKzqHBDk KMD 4535.36019149 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTVFC7r5K3bedTrPbXLwh63g27PKzqHBDk\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTVFC7r5K3bedTrPbXLwh63g27PKzqHBDk\",\"symbol\":\"KMD\"}" echo "4535.36019149 <- expected amount RTVFC7r5K3bedTrPbXLwh63g27PKzqHBDk" # RMrm1S6pc1AZY7QvqFwmEGNoPMVxq61E7E KMD 11293.49948607 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RMrm1S6pc1AZY7QvqFwmEGNoPMVxq61E7E\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RMrm1S6pc1AZY7QvqFwmEGNoPMVxq61E7E\",\"symbol\":\"KMD\"}" echo "11293.49948607 <- expected amount RMrm1S6pc1AZY7QvqFwmEGNoPMVxq61E7E" # RQPHxw8wwm83ystB1EciD5BFKmSpQnirrE KMD 12200.87564194 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RQPHxw8wwm83ystB1EciD5BFKmSpQnirrE\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RQPHxw8wwm83ystB1EciD5BFKmSpQnirrE\",\"symbol\":\"KMD\"}" echo "12200.87564194 <- expected amount RQPHxw8wwm83ystB1EciD5BFKmSpQnirrE" # RNWxopR8G5sSkEZ8gAPHBJBrais9rT8rqd KMD 1493.46088391 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNWxopR8G5sSkEZ8gAPHBJBrais9rT8rqd\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNWxopR8G5sSkEZ8gAPHBJBrais9rT8rqd\",\"symbol\":\"KMD\"}" echo "1493.46088391 <- expected amount RNWxopR8G5sSkEZ8gAPHBJBrais9rT8rqd" # RTG2uSvYLnoxtxFeZJDFq2yPEqDvhTHhk2 KMD 46218.10752319 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTG2uSvYLnoxtxFeZJDFq2yPEqDvhTHhk2\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTG2uSvYLnoxtxFeZJDFq2yPEqDvhTHhk2\",\"symbol\":\"KMD\"}" echo "46218.10752319 <- expected amount RTG2uSvYLnoxtxFeZJDFq2yPEqDvhTHhk2" # RTmG8UyrSZPRy6Et1wZNtawB8EzCnGXzgJ KMD 11952.18753277 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTmG8UyrSZPRy6Et1wZNtawB8EzCnGXzgJ\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RTmG8UyrSZPRy6Et1wZNtawB8EzCnGXzgJ\",\"symbol\":\"KMD\"}" echo "11952.18753277 <- expected amount RTmG8UyrSZPRy6Et1wZNtawB8EzCnGXzgJ" # RCmLc2JBpPw9T9g1skg7J5Xr5kz1fyd7mx KMD 815.56545295 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RCmLc2JBpPw9T9g1skg7J5Xr5kz1fyd7mx\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RCmLc2JBpPw9T9g1skg7J5Xr5kz1fyd7mx\",\"symbol\":\"KMD\"}" echo "815.56545295 <- expected amount RCmLc2JBpPw9T9g1skg7J5Xr5kz1fyd7mx" # RNUpL2yQjAHawP2C1kt7bTiMg5YSLEfurr KMD 5212.95301692 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNUpL2yQjAHawP2C1kt7bTiMg5YSLEfurr\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNUpL2yQjAHawP2C1kt7bTiMg5YSLEfurr\",\"symbol\":\"KMD\"}" echo "5212.95301692 <- expected amount RNUpL2yQjAHawP2C1kt7bTiMg5YSLEfurr" # RKPiAqCz2qRQFb5db11uCPDRYMBFfjWVTY KMD 3159.92424349 -curl --url "http://127.0.0.1:0" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKPiAqCz2qRQFb5db11uCPDRYMBFfjWVTY\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RKPiAqCz2qRQFb5db11uCPDRYMBFfjWVTY\",\"symbol\":\"KMD\"}" echo "3159.92424349 <- expected amount RKPiAqCz2qRQFb5db11uCPDRYMBFfjWVTY" From aae9c5d45619d034e582b78507d924eb8f50ed3a Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 7 Apr 2017 17:53:45 +0300 Subject: [PATCH 0134/2705] Test --- .gitignore | 4 ++++ basilisk/tradebots_liquidity.c | 2 +- iguana/exchanges/mm.c | 18 +++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 147479f20..9a74236cc 100755 --- a/.gitignore +++ b/.gitignore @@ -262,3 +262,7 @@ iguana/DB/SWAPS/3606847984-2574036327 iguana/DB/SWAPS/2384443255-1263480722 iguana/DB/SWAPS/845549832-3630913950 + +iguana/DB/SWAPS/2050938501-203733478 + +iguana/DB/SWAPS/3434672913-3981690962 diff --git a/basilisk/tradebots_liquidity.c b/basilisk/tradebots_liquidity.c index 66fd27944..c0f232942 100755 --- a/basilisk/tradebots_liquidity.c +++ b/basilisk/tradebots_liquidity.c @@ -1142,7 +1142,7 @@ void _default_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_s void tradebot_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob) { - printf("balancing trade\n"); + printf(">>>>>>>>>>>>>>>>>> balancing trade\n"); return; if ( swap->balancingtrade == 0 ) _default_swap_balancingtrade(myinfo,swap,iambob); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 69502f02f..a90bbef8a 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -571,7 +571,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double start_DEXrel = dex_balance(rel,reladdr); while ( 1 ) { - if ( time(NULL) > lasttime+300 ) + if ( time(NULL) > lasttime+10 ) { if ( (val= get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,name,base,rel,&USD_average)) != 0. ) { @@ -634,19 +634,23 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double if ( (1) ) { if ( mmbid >= lowask || (maxbid > SMALLVAL && mmbid > maxbid) ) //mmbid < highbid || + { + printf("clear mmbid %.8f lowask %.8f maxbid %.8f\n",mmbid,lowask,maxbid); mmbid = 0.; + } if ( mmask <= highbid || (minask > SMALLVAL && mmask < minask) ) // mmask > lowask || mmask = 0.; } marketmaker_volumeset(&bidincr,&askincr,incr,buyvol,pendingbids,sellvol,pendingasks,maxexposure); printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); - if ( (aveask - avebid)/aveprice > 4*profitmargin ) - bid = highbid * (1 - 4*profitmargin), ask = lowask * (1 + 4*profitmargin); + if ( (aveask - avebid)/aveprice > profitmargin ) + bid = highbid * (1 - profitmargin), ask = lowask * (1 + profitmargin); else bid = avebid - profitmargin*aveprice, ask = avebid + profitmargin*aveprice; marketmaker_spread("DEX",base,rel,bid,incr,ask,incr,profitmargin*aveprice*0.5); if ( (pendingbids + buyvol) > (pendingasks + sellvol) ) { - bidincr *= (double)(pendingasks + sellvol) / ((pendingbids + buyvol) + (pendingasks + sellvol)); + bidincr *= sqrt((double)(pendingasks + sellvol) / ((pendingbids + buyvol) + (pendingasks + sellvol))); + //printf("bidincr %f buy.(%f + %f) sell.(%f + %f)\n",bidincr,pendingbids,buyvol,pendingasks,sellvol); if ( bidincr < 0.1*incr ) bidincr = 0.1*incr; if ( bidincr > 1. ) @@ -660,9 +664,9 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double if ( askincr > 1. ) askincr = (int32_t)askincr + 0.777; } - //printf("mmbid %.8f %.6f, mmask %.8f %.6f\n",mmbid,bidincr,mmask,askincr); - //marketmaker_spread(exchange,base,rel,mmbid,bidincr,mmask,askincr,profitmargin*aveprice*0.5); - sleep(6000); + printf("mmbid %.8f %.6f, mmask %.8f %.6f\n",mmbid,bidincr,mmask,askincr); + marketmaker_spread(exchange,base,rel,mmbid,bidincr,mmask,askincr,profitmargin*aveprice*0.5); + sleep(60); } } } From 68e53c63adf86ca1ddab94be58c9a4b09d70f628 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 7 Apr 2017 18:29:45 +0300 Subject: [PATCH 0135/2705] Test --- basilisk/basilisk.c | 2 +- basilisk/basilisk_DEX.c | 6 +++++- basilisk/jumblr.c | 2 ++ basilisk/tradebots_liquidity.c | 8 ++++++++ iguana/iguana777.h | 2 +- includes/iguana_structs.h | 2 +- 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index b2d1865b6..f1a9eb586 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1785,7 +1785,7 @@ HASH_ARRAY_STRING(InstantDEX,request,hash,vals,hexstr) jaddbits256(vals,"srchash",hash); printf("service.(%s)\n",jprint(vals,0)); memset(&R,0,sizeof(R)); - if ( basilisk_request_create(&R,vals,hash,juint(vals,"timestamp")) == 0 ) + if ( basilisk_request_create(&R,vals,hash,juint(vals,"timestamp"),juint(vals,"DEXselector")) == 0 ) { iambob = bitcoin_coinptrs(hash,&bobcoin,&alicecoin,R.src,R.dest,privkey,GENESIS_PUBKEY); if ( (optionhours= jint(vals,"optionhours")) != 0 ) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index 239514d47..d25e8d0ba 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -116,6 +116,8 @@ int32_t basilisk_rwDEXquote(int32_t rwflag,uint8_t *serialized,struct basilisk_r memcpy(rp->src,&serialized[len],sizeof(rp->src)), len += sizeof(rp->src); memcpy(rp->dest,&serialized[len],sizeof(rp->dest)), len += sizeof(rp->dest); } + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->DEXselector),&rp->DEXselector); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->extraspace),&rp->extraspace); if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) printf(" basilisk_rwDEXquote.%d: quoteid.%u mismatch calc %u rp.%p\n",rwflag,rp->quoteid,basilisk_quoteid(rp),rp); if ( basilisk_requestid(rp) != rp->requestid ) @@ -168,6 +170,7 @@ cJSON *basilisk_requestjson(struct basilisk_request *rp) jaddnum(item,"timestamp",rp->timestamp); jaddnum(item,"requestid",rp->requestid); jaddnum(item,"quoteid",rp->quoteid); + jaddnum(item,"DEXselector",rp->DEXselector); jaddnum(item,"optionhours",rp->optionhours); jaddnum(item,"profit",(double)rp->profitmargin / 1000000.); if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) @@ -196,7 +199,7 @@ cJSON *basilisk_requestjson(struct basilisk_request *rp) return(item); } -int32_t basilisk_request_create(struct basilisk_request *rp,cJSON *valsobj,bits256 desthash,uint32_t timestamp) +int32_t basilisk_request_create(struct basilisk_request *rp,cJSON *valsobj,bits256 desthash,uint32_t timestamp,int32_t DEXselector) { char *dest,*src; uint32_t i; memset(rp,0,sizeof(*rp)); @@ -216,6 +219,7 @@ int32_t basilisk_request_create(struct basilisk_request *rp,cJSON *valsobj,bits2 rp->srchash = jbits256(valsobj,"srchash"); rp->optionhours = jint(valsobj,"optionhours"); rp->profitmargin = jdouble(valsobj,"profit") * 1000000; + rp->DEXselector = DEXselector; strncpy(rp->src,src,sizeof(rp->src)-1); strncpy(rp->dest,dest,sizeof(rp->dest)-1); //if ( jstr(valsobj,"relay") != 0 ) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 9d9209d8e..6a4a2208d 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -747,6 +747,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddnum(vals,"amount",vol); jaddnum(vals,"minprice",1./(1.015 * kmdcoin->DEXinfo.btcprice)); jaddnum(vals,"usejumblr",1); + jaddnum(vals,"DEXselector",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.DEXpending += vol; if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) @@ -780,6 +781,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.KMDpending += vol; + jaddnum(vals,"DEXselector",2); if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) { printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); diff --git a/basilisk/tradebots_liquidity.c b/basilisk/tradebots_liquidity.c index c0f232942..024a554ff 100755 --- a/basilisk/tradebots_liquidity.c +++ b/basilisk/tradebots_liquidity.c @@ -1142,6 +1142,14 @@ void _default_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_s void tradebot_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob) { + struct iguana_info *kmdcoin = iguana_coinfind("KMD"); + if ( kmdcoin != 0 ) + { + if ( swap->DEXselector == 1 ) + kmdcoin->DEXinfo.DEXpending -= swap->I.req.srcamount; + else if ( swap->DEXselector == 2 ) + kmdcoin->DEXinfo.KMDpending -= swap->I.req.srcamount; + } printf(">>>>>>>>>>>>>>>>>> balancing trade\n"); return; if ( swap->balancingtrade == 0 ) diff --git a/iguana/iguana777.h b/iguana/iguana777.h index f80919773..d17555d43 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -182,7 +182,7 @@ struct basilisk_swap { struct supernet_info *myinfoptr; struct iguana_info *bobcoin,*alicecoin; void (*balancingtrade)(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob); - int32_t subsock,pushsock,connected; uint32_t lasttime,aborted; + int32_t subsock,pushsock,connected,DEXselector; uint32_t lasttime,aborted; FILE *fp; bits256 persistent_privkey,persistent_pubkey; struct basilisk_swapinfo I; diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index 76206c409..ad311d271 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -604,7 +604,7 @@ struct basilisk_request char src[8],dest[8]; //char volatile_start,message[43]; uint64_t destamount; - int32_t optionhours,profitmargin; + int32_t optionhours,profitmargin,DEXselector,extraspace; } PACKEDSTRUCT; struct basilisk_relaystatus From 5091a3dd819dd14caaafc85738ca0e485a08cfd0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 7 Apr 2017 18:32:53 +0300 Subject: [PATCH 0136/2705] Test --- iguana/main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/main.c b/iguana/main.c index be9a9908e..3ba5b0664 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -2162,6 +2162,11 @@ void iguana_main(void *arg) sprintf(fname,"REVS.raw"), sprintf(fname2,"REVS.rawtxids"); myinfo = SuperNET_MYINFO(0); myinfo->rpcport = IGUANA_RPCPORT; + decode_hex(CRYPTO777_RMD160,20,CRYPTO777_RMD160STR); + decode_hex(CRYPTO777_PUBSECP33,33,CRYPTO777_PUBSECPSTR); + iguana_ensuredirs(); + iguana_Qinit(); + libgfshare_init(myinfo,myinfo->logs,myinfo->exps); if ( (0) && (batchstr= OS_filestr(&batchsize,fname)) != 0 && (batchstr2= OS_filestr(&batchsize,fname2)) != 0 ) { komodo_REVS_merge(batchstr,batchstr2); @@ -2177,11 +2182,6 @@ void iguana_main(void *arg) free(batchstr); } #endif - decode_hex(CRYPTO777_RMD160,20,CRYPTO777_RMD160STR); - decode_hex(CRYPTO777_PUBSECP33,33,CRYPTO777_PUBSECPSTR); - iguana_ensuredirs(); - iguana_Qinit(); - libgfshare_init(myinfo,myinfo->logs,myinfo->exps); myinfo->dpowsock = myinfo->dexsock = myinfo->pubsock = myinfo->subsock = myinfo->reqsock = myinfo->repsock = -1; dex_init(myinfo); myinfo->psockport = 30000; From d68f9982d9ec85eecc3285f7028e4013a59d88cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 7 Apr 2017 18:35:57 +0300 Subject: [PATCH 0137/2705] Test --- iguana/main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/main.c b/iguana/main.c index 3ba5b0664..a012479b4 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -2160,13 +2160,6 @@ void iguana_main(void *arg) #ifdef __APPLE__ char *batchstr,*batchstr2; cJSON *batchjson; long batchsize; char fname[512],fname2[512]; int32_t batchid = 16; sprintf(fname,"REVS.raw"), sprintf(fname2,"REVS.rawtxids"); - myinfo = SuperNET_MYINFO(0); - myinfo->rpcport = IGUANA_RPCPORT; - decode_hex(CRYPTO777_RMD160,20,CRYPTO777_RMD160STR); - decode_hex(CRYPTO777_PUBSECP33,33,CRYPTO777_PUBSECPSTR); - iguana_ensuredirs(); - iguana_Qinit(); - libgfshare_init(myinfo,myinfo->logs,myinfo->exps); if ( (0) && (batchstr= OS_filestr(&batchsize,fname)) != 0 && (batchstr2= OS_filestr(&batchsize,fname2)) != 0 ) { komodo_REVS_merge(batchstr,batchstr2); @@ -2182,6 +2175,13 @@ void iguana_main(void *arg) free(batchstr); } #endif + myinfo = SuperNET_MYINFO(0); + myinfo->rpcport = IGUANA_RPCPORT; + decode_hex(CRYPTO777_RMD160,20,CRYPTO777_RMD160STR); + decode_hex(CRYPTO777_PUBSECP33,33,CRYPTO777_PUBSECPSTR); + iguana_ensuredirs(); + iguana_Qinit(); + libgfshare_init(myinfo,myinfo->logs,myinfo->exps); myinfo->dpowsock = myinfo->dexsock = myinfo->pubsock = myinfo->subsock = myinfo->reqsock = myinfo->repsock = -1; dex_init(myinfo); myinfo->psockport = 30000; From fa0ba6f0b9ad9cb8980e8d977277d29724044bc6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 7 Apr 2017 21:15:33 +0300 Subject: [PATCH 0138/2705] Test --- .gitignore | 2 ++ basilisk/jumblr.c | 1 + crypto777/iguana_utils.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9a74236cc..b5c31dd26 100755 --- a/.gitignore +++ b/.gitignore @@ -266,3 +266,5 @@ iguana/DB/SWAPS/845549832-3630913950 iguana/DB/SWAPS/2050938501-203733478 iguana/DB/SWAPS/3434672913-3981690962 + +iguana/DB/SWAPS/2840127595-1174059534 diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 6a4a2208d..90c4d5efc 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -199,6 +199,7 @@ int64_t jumblr_balance(struct supernet_info *myinfo,struct iguana_info *coin,cha { if ( (retstr= jumblr_listunspent(myinfo,coin,addr)) != 0 ) { + printf("jumblr.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(retjson)) > 0 ) diff --git a/crypto777/iguana_utils.c b/crypto777/iguana_utils.c index 115e90a98..9f41cf2ce 100755 --- a/crypto777/iguana_utils.c +++ b/crypto777/iguana_utils.c @@ -1279,7 +1279,7 @@ double get_theoretical(double *avebidp,double *aveaskp,double *highbidp,double * weighted = weighted_orderbook(avebidp,aveaskp,highbidp,lowaskp,bittrex_orderbook(base,rel,25),1./(*CMC_averagep)); if ( *CMC_averagep > SMALLVAL && weighted > SMALLVAL ) theoretical = calc_theoretical(weighted,*CMC_averagep,changes); - if ( counter++ < 100 ) + if ( 0 && counter++ < 100 ) printf("HBLA.[%.8f %.8f] AVE.[%.8f %.8f] (%s) CMC %f %f %f %f\n",*highbidp,*lowaskp,*avebidp,*aveaskp,jprint(item,0),*CMC_averagep,changes[0],changes[1],changes[2]); free_json(cmcjson); } From 3b57c4c25514b302777b99afd53e1b2f775c52a5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 7 Apr 2017 21:49:20 +0300 Subject: [PATCH 0139/2705] Test --- basilisk/jumblr.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 90c4d5efc..3e8489de2 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -35,11 +35,14 @@ int32_t jumblr_addresstype(struct supernet_info *myinfo,struct iguana_info *coin,char *addr) { - if ( addr[0] == 'z' && addr[1] == 'c' && strlen(addr) >= 40 ) - return('z'); - else if ( strlen(addr) < 40 ) - return('t'); - else return(-1); + if ( strcmp(coin->symbol,"KMD") == 0 ) + { + if ( addr[0] == 'z' && addr[1] == 'c' && strlen(addr) >= 40 ) + return('z'); + else if ( strlen(addr) < 40 ) + return('t'); + else return(-1); + } else return('t'); } struct jumblr_item *jumblr_opidfind(struct supernet_info *myinfo,char *opid) From 31edaeb7944b69d192dad7d7f1ba9402ed01a54e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 09:44:23 +0300 Subject: [PATCH 0140/2705] Test --- basilisk/jumblr.c | 4 ++-- iguana/iguana_notary.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 3e8489de2..07190826d 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -202,7 +202,7 @@ int64_t jumblr_balance(struct supernet_info *myinfo,struct iguana_info *coin,cha { if ( (retstr= jumblr_listunspent(myinfo,coin,addr)) != 0 ) { - printf("jumblr.(%s)\n",retstr); + printf("jumblr.[%s].(%s)\n",coin->symbol,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(retjson)) > 0 ) @@ -215,7 +215,7 @@ int64_t jumblr_balance(struct supernet_info *myinfo,struct iguana_info *coin,cha } else if ( (retstr= dex_getbalance(myinfo,coin,0,0,coin->symbol,addr)) != 0 ) { - //printf("retstr.(%s)\n",retstr); + printf("DEX retstr.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { balance = jdouble(retjson,"balance") * SATOSHIDEN; diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 1b75c02ba..771a569f6 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -865,6 +865,7 @@ TWO_STRINGS(dex,getbalance,symbol,address) char url[512],*retstr; cJSON *retjson; uint64_t val; if ( myinfo->DEXEXPLORER != 0 ) { + printf("DEXEXPLORER\n"); if ( symbol != 0 && address != 0 && (coin= iguana_coinfind(symbol)) != 0 && coin->DEXEXPLORER != 0 ) return(jprint(kmd_getbalance(myinfo,coin,address),1)); if ( coin != 0 ) @@ -909,7 +910,7 @@ TWO_STRINGS(dex,getbalance,symbol,address) jdelete(retjson,"unconfirmed_received"); jaddnum(retjson,"unconfirmed_received",dstr(val)); } - //printf("(%s) -> (%s)\n",retstr,jprint(retjson,0)); + printf("blocktrail.(%s) -> (%s)\n",retstr,jprint(retjson,0)); free(retstr); retstr = jprint(retjson,1); } From 82e758144c34553a194ec06e5783a6628e8c8faf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 09:54:59 +0300 Subject: [PATCH 0141/2705] Test --- crypto777/iguana_utils.c | 2 +- iguana/exchanges/bittrex.c | 4 ++-- iguana/iguana_notary.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crypto777/iguana_utils.c b/crypto777/iguana_utils.c index 9f41cf2ce..47ab6f5a4 100755 --- a/crypto777/iguana_utils.c +++ b/crypto777/iguana_utils.c @@ -1279,7 +1279,7 @@ double get_theoretical(double *avebidp,double *aveaskp,double *highbidp,double * weighted = weighted_orderbook(avebidp,aveaskp,highbidp,lowaskp,bittrex_orderbook(base,rel,25),1./(*CMC_averagep)); if ( *CMC_averagep > SMALLVAL && weighted > SMALLVAL ) theoretical = calc_theoretical(weighted,*CMC_averagep,changes); - if ( 0 && counter++ < 100 ) + if ( (0) && counter++ < 100 ) printf("HBLA.[%.8f %.8f] AVE.[%.8f %.8f] (%s) CMC %f %f %f %f\n",*highbidp,*lowaskp,*avebidp,*aveaskp,jprint(item,0),*CMC_averagep,changes[0],changes[1],changes[2]); free_json(cmcjson); } diff --git a/iguana/exchanges/bittrex.c b/iguana/exchanges/bittrex.c index dd7d4be26..d0e5025e9 100755 --- a/iguana/exchanges/bittrex.c +++ b/iguana/exchanges/bittrex.c @@ -179,13 +179,13 @@ uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,cha uuidstr.buf[j++] = uuidstr.buf[i]; uuidstr.buf[j] = 0; n = (int32_t)strlen(uuidstr.buf); - printf("-> uuidstr.(%s).%d\n",uuidstr.buf,n); + //printf("-> uuidstr.(%s).%d\n",uuidstr.buf,n); decode_hex(databuf,n/2,uuidstr.buf); if ( n >= 16 ) for (i=0; i<8; i++) databuf[i] ^= databuf[8 + i]; memcpy(&txid,databuf,8); - printf("-> %llx\n",(long long)txid); + //printf("-> %llx\n",(long long)txid); } free_json(json); } diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 771a569f6..f46626938 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -865,7 +865,7 @@ TWO_STRINGS(dex,getbalance,symbol,address) char url[512],*retstr; cJSON *retjson; uint64_t val; if ( myinfo->DEXEXPLORER != 0 ) { - printf("DEXEXPLORER\n"); + //printf("DEXEXPLORER\n"); if ( symbol != 0 && address != 0 && (coin= iguana_coinfind(symbol)) != 0 && coin->DEXEXPLORER != 0 ) return(jprint(kmd_getbalance(myinfo,coin,address),1)); if ( coin != 0 ) @@ -910,7 +910,7 @@ TWO_STRINGS(dex,getbalance,symbol,address) jdelete(retjson,"unconfirmed_received"); jaddnum(retjson,"unconfirmed_received",dstr(val)); } - printf("blocktrail.(%s) -> (%s)\n",retstr,jprint(retjson,0)); + //printf("blocktrail.(%s) -> (%s)\n",retstr,jprint(retjson,0)); free(retstr); retstr = jprint(retjson,1); } From df06e9c9796578f35e41404a44b8d7ec18943463 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 11:48:47 +0300 Subject: [PATCH 0142/2705] Test --- basilisk/basilisk_DEX.c | 1 + basilisk/jumblr.c | 4 ++-- basilisk/smartaddress.c | 4 +--- basilisk/tradebots_liquidity.c | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index d25e8d0ba..c430f292e 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -479,6 +479,7 @@ char *basilisk_respond_accept(struct supernet_info *myinfo,bits256 privkey,uint3 retstr = clonestr("{\"error\":\"couldnt find to requestid to choose\"}"); return(retstr); } + cJSON *basilisk_unspents(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr) { cJSON *unspents=0,*array=0; char *retstr; diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 07190826d..4624d147e 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -215,7 +215,7 @@ int64_t jumblr_balance(struct supernet_info *myinfo,struct iguana_info *coin,cha } else if ( (retstr= dex_getbalance(myinfo,coin,0,0,coin->symbol,addr)) != 0 ) { - printf("DEX retstr.(%s)\n",retstr); + //printf("DEX retstr.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { balance = jdouble(retjson,"balance") * SATOSHIDEN; @@ -714,7 +714,7 @@ void jumblr_CMCname(char *CMCname,char *symbol) void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) { double vol,avail; struct iguana_info *kmdcoin,*coinbtc = 0; - if ( myinfo->IAMNOTARY != 0 ) + if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 ) return; if ( (kmdcoin= iguana_coinfind("KMD")) == 0 || (coinbtc= iguana_coinfind("BTC")) == 0 ) return; diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index ff9707b0c..39fcab19a 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -17,8 +17,7 @@ int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *BTCaddr,char *KMDaddr) { - struct smartaddress *ap; - int32_t i; + char coinaddr[64]; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; int32_t i; if ( myinfo->numsmartaddrs < sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs) ) { for (i=0; inumsmartaddrs; i++) @@ -29,7 +28,6 @@ int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *BTCa bitcoin_pubkey33(myinfo->ctx,ap->pubkey33,privkey); calc_rmd160_sha256(ap->rmd160,ap->pubkey33,33); ap->pubkey = curve25519(privkey,curve25519_basepoint9()); - char coinaddr[64]; uint8_t addrtype,rmd160[20]; bitcoin_address(coinaddr,0,ap->pubkey33,33); for (i=0; i<20; i++) printf("%02x",ap->rmd160[i]); diff --git a/basilisk/tradebots_liquidity.c b/basilisk/tradebots_liquidity.c index 024a554ff..76cda30bc 100755 --- a/basilisk/tradebots_liquidity.c +++ b/basilisk/tradebots_liquidity.c @@ -984,7 +984,7 @@ void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 } else tradebot_monitor(myinfo,0,0,0,li.exchange,li.base,li.rel,0.); } myinfo->linfos[i] = li; - printf("Set linfo[%d] %s (%s/%s) profitmargin %.6f bid %.8f ask %.8f minvol %.6f maxvol %.6f ref %.8f <- (%s)\n",i,li.exchange,li.base,li.rel,li.profit,li.bid,li.ask,li.minvol,li.maxvol,li.refprice,jprint(vals,0)); + //printf("Set linfo[%d] %s (%s/%s) profitmargin %.6f bid %.8f ask %.8f minvol %.6f maxvol %.6f ref %.8f <- (%s)\n",i,li.exchange,li.base,li.rel,li.profit,li.bid,li.ask,li.minvol,li.maxvol,li.refprice,jprint(vals,0)); return; } } @@ -1150,7 +1150,7 @@ void tradebot_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_s else if ( swap->DEXselector == 2 ) kmdcoin->DEXinfo.KMDpending -= swap->I.req.srcamount; } - printf(">>>>>>>>>>>>>>>>>> balancing trade\n"); + printf(">>>>>>>>>>>>>>>>>> balancing trade done by marketmaker\n"); return; if ( swap->balancingtrade == 0 ) _default_swap_balancingtrade(myinfo,swap,iambob); From 99fc60025a79a5610197eddbb7b763ea44c81c73 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 12:16:41 +0300 Subject: [PATCH 0143/2705] Test --- iguana/exchanges/mm.c | 55 +++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index a90bbef8a..18925951f 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -40,6 +40,7 @@ char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", // end of currencies }; double PAXPRICES[sizeof(CURRENCIES)/sizeof(*CURRENCIES)]; +uint32_t PAXACTIVE; char *DEX_amlp(char *blocktrail) { @@ -505,7 +506,7 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double jaddnum(vals,"minvol",vol*0.1 > 100 ? 100 : vol * 0.1); sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"tradebot\",\"method\":\"liquidity\",\"targetcoin\":\"%s\",\"vals\":%s}",base,jprint(vals,1)); - printf("(%s)\n",postdata); + //printf("(%s)\n",postdata); if ( (retstr= bitcoind_RPC(0,"tradebot",url,0,"liqudity",postdata)) != 0 ) { //printf("(%s) -> (%s)\n",postdata,retstr); @@ -514,6 +515,8 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double spread_ratio = .5 * ((ask - bid) / (bid + ask)); for (i=0; i SMALLVAL ) { vals = cJSON_CreateObject(); @@ -530,7 +533,7 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double free(retstr); } } -break; +//break; } } else printf("unsupported ask only for DEX %s/%s\n",base,rel); } @@ -571,7 +574,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double start_DEXrel = dex_balance(rel,reladdr); while ( 1 ) { - if ( time(NULL) > lasttime+10 ) + if ( time(NULL) > lasttime+60 ) { if ( (val= get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,name,base,rel,&USD_average)) != 0. ) { @@ -630,7 +633,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double marketmaker_prune(exchange,base,rel,1,mmbid - theoretical*profitmargin,mmask + theoretical*profitmargin,0.); // if new prices crosses existing order, cancel old order first marketmaker_prune(exchange,base,rel,-1,mmbid,mmask,0.); - printf("(%.8f %.8f) ",mmbid,mmask); + //printf("(%.8f %.8f) ",mmbid,mmask); if ( (1) ) { if ( mmbid >= lowask || (maxbid > SMALLVAL && mmbid > maxbid) ) //mmbid < highbid || @@ -642,7 +645,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double mmask = 0.; } marketmaker_volumeset(&bidincr,&askincr,incr,buyvol,pendingbids,sellvol,pendingasks,maxexposure); - printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); + //printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); if ( (aveask - avebid)/aveprice > profitmargin ) bid = highbid * (1 - profitmargin), ask = lowask * (1 + profitmargin); else bid = avebid - profitmargin*aveprice, ask = avebid + profitmargin*aveprice; @@ -664,7 +667,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double if ( askincr > 1. ) askincr = (int32_t)askincr + 0.777; } - printf("mmbid %.8f %.6f, mmask %.8f %.6f\n",mmbid,bidincr,mmask,askincr); + //printf("mmbid %.8f %.6f, mmask %.8f %.6f\n",mmbid,bidincr,mmask,askincr); marketmaker_spread(exchange,base,rel,mmbid,bidincr,mmask,askincr,profitmargin*aveprice*0.5); sleep(60); } @@ -673,9 +676,9 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double int main(int argc, const char * argv[]) { - char *base,*rel,*name,*exchange,*apikey,*apisecret,*blocktrail; + char *base,*rel,*name,*exchange,*apikey,*apisecret,*blocktrail,*retstr,*baseaddr,*reladdr,*passphrase; double profitmargin,maxexposure,incrratio,start_rel,start_base,minask,maxbid; - cJSON *retjson,*addrjson; char *retstr,*baseaddr,*reladdr,*passphrase; + cJSON *retjson,*loginjson; int32_t i; if ( argc > 1 && (retjson= cJSON_Parse(argv[1])) != 0 ) { minask = jdouble(retjson,"minask"); @@ -693,34 +696,50 @@ int main(int argc, const char * argv[]) rel = jstr(retjson,"rel"); blocktrail = jstr(retjson,"blocktrail"); exchange = jstr(retjson,"exchange"); + PAXACTIVE = juint(retjson,"paxactive"); if ( profitmargin < 0. || maxexposure <= 0. || incrratio <= 0. || apikey == 0 || apisecret == 0 || base == 0 || name == 0 || rel == 0 || exchange == 0 || blocktrail == 0 ) { printf("illegal parameter (%s)\n",jprint(retjson,0)); exit(-1); } + free_json(retjson); if ( (retstr= iguana_walletpassphrase(passphrase,999999)) != 0 ) { - printf("%s\n",DEX_apikeypair(exchange,apikey,apisecret)); - printf("%s %s\n",base,DEX_balance(exchange,base,"")); - printf("%s %s\n",rel,DEX_balance(exchange,rel,"")); - marketmaker_pendinginit(exchange,base,rel); - if ( (addrjson= cJSON_Parse(retstr)) != 0 ) + //printf("login.(%s)\n",retstr); + if ( (loginjson= cJSON_Parse(retstr)) != 0 ) { - baseaddr = jstr(addrjson,base); - reladdr = jstr(addrjson,rel); + if ( PAXACTIVE != 0 ) + { + for (i=0; i<32; i++) + { + if ( ((1< Date: Sat, 8 Apr 2017 12:18:23 +0300 Subject: [PATCH 0144/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 18925951f..d5b57a2fd 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -705,7 +705,7 @@ int main(int argc, const char * argv[]) free_json(retjson); if ( (retstr= iguana_walletpassphrase(passphrase,999999)) != 0 ) { - //printf("login.(%s)\n",retstr); + printf("(%s/%s) login.(%s)\n",base,rel,retstr); if ( (loginjson= cJSON_Parse(retstr)) != 0 ) { if ( PAXACTIVE != 0 ) From 24d0916aa46b8aaf8b65997e3a96b6c396441c53 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 12:19:08 +0300 Subject: [PATCH 0145/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index d5b57a2fd..56cbdb816 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -702,7 +702,6 @@ int main(int argc, const char * argv[]) printf("illegal parameter (%s)\n",jprint(retjson,0)); exit(-1); } - free_json(retjson); if ( (retstr= iguana_walletpassphrase(passphrase,999999)) != 0 ) { printf("(%s/%s) login.(%s)\n",base,rel,retstr); @@ -740,6 +739,7 @@ int main(int argc, const char * argv[]) } else printf("ERROR parsing.(%s)\n",retstr); free(retstr); } + free_json(retjson); } return 0; } From 4bbe5ff33525a0d818597f9b9f5d49f4906c9cfd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 13:48:57 +0300 Subject: [PATCH 0146/2705] Test --- basilisk/basilisk_swap.c | 133 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 6 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 08ae1266d..847093f8d 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1791,6 +1791,7 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); } fprintf(fp,",\"lock\":%u",locktime); + fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); if ( bits256_nonz(triggertxid) != 0 ) fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); fprintf(fp,"}\n"); @@ -1822,12 +1823,14 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis sendlen += rawtx->I.redeemlen; } memset(triggertxid.bytes,0,sizeof(triggertxid)); + if ( rawtx == &swap->myfee ) + basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); if ( swap->I.iambob != 0 ) { if ( rawtx == &swap->bobdeposit ) { basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->bobrefund,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); } else if ( rawtx == &swap->bobpayment ) { @@ -1835,7 +1838,7 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); } else if ( rawtx == &swap->bobspend ) - basilisk_dontforget(myinfo,swap,&swap->bobspend,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); } else { @@ -1846,7 +1849,6 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis else if ( rawtx == &swap->alicespend ) { basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); - //basilisk_alicepayment_spend(myinfo,swap,&swap->alicereclaim); basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); } } @@ -2619,9 +2621,114 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 return(swap); } +cJSON *basilisk_nullretjson(cJSON *retjson) +{ + char *outstr; + if ( retjson != 0 ) + { + outstr = jprint(retjson,0); + if ( strcmp(outstr,"{}") == 0 ) + { + free_json(retjson); + retjson = 0; + } + free(outstr); + } + return(retjson); +} + +cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 trigger,int32_t vout) +{ + char *retstr; cJSON *retjson=0; struct iguana_info *coin; + if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 ) + { + if ( (retstr= _dex_gettxout(myinfo,symbol,trigger,vout)) != 0 ) + { + retjson = cJSON_Parse(retstr); + free(retstr); + } + } else retjson = dpow_gettxout(myinfo,coin,trigger,vout); + return(basilisk_nullretjson(retjson)); +} + +cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid) +{ + char *retstr; cJSON *retjson=0; struct iguana_info *coin; + if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 ) + { + if ( (retstr= _dex_getrawtransaction(myinfo,symbol,txid)) != 0 ) + { + retjson = cJSON_Parse(retstr); + free(retstr); + } + } else retjson = dpow_gettransaction(myinfo,coin,txid); + return(basilisk_nullretjson(retjson)); +} + +char *txnames[] = { "myfee", "bobdeposit", "bobpayment", "alicepayment", "bobrefund", "bobreclaim", "bobspend", "alicespend", "alicereclaim" }; + +cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) +{ + int32_t i; char fname[512],*fstr,*symbol,str[65],str2[65]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 txid,trigger; uint32_t t,addflag; uint64_t value; + item = cJSON_CreateObject(); + array = cJSON_CreateArray(); + for (i=0; i t ) + { + txid = jbits256(txobj,"txid"); + if ( jobj(txobj,"trigger") != 0 ) + { + trigger = jbits256(txobj,"trigger"); + if ( (triggerobj= basilisk_swapgettxout(myinfo,symbol,trigger,0)) == 0 ) + { + printf("%s trigger.(%s) spent! extract priv\n",bits256_str(str2,txid),bits256_str(str,trigger)); + addflag = 1; + } else free_json(triggerobj); + } + else + { + if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + { + printf("%s ready to broadcast\n",bits256_str(str2,txid)); + addflag = 1; + } else free_json(sentobj); + } + } + if ( addflag == 0 ) + { + value = jdouble(txobj,"amount") * SATOSHIDEN; + if ( strcmp(symbol,"KMD") == 0 ) + KMDtotals[i] += value; + else if ( strcmp(symbol,"BTC") == 0 ) + BTCtotals[i] += value; + free_json(txobj); + } else jaddi(array,txobj); + } else free_json(txobj); + } + free(fstr); + } + } + jaddnum(item,"requestid",requestid); + jaddnum(item,"quoteid",quoteid); + jadd(item,"txs",array); + return(item); +} + char *basilisk_swaplist(struct supernet_info *myinfo) { - char fname[512]; FILE *fp; struct basilisk_request R; int32_t optionduration; uint32_t quoteid,requestid,statebits; cJSON *retjson,*array; bits256 privkey; + char fname[512]; FILE *fp; cJSON *retjson,*array,*totalsobj; uint32_t quoteid,requestid; uint64_t KMDtotals[16],BTCtotals[16]; int32_t i; + memset(KMDtotals,0,sizeof(KMDtotals)); + memset(BTCtotals,0,sizeof(BTCtotals)); + //,statebits; int32_t optionduration; struct basilisk_request R; bits256 privkey; retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); @@ -2629,15 +2736,29 @@ char *basilisk_swaplist(struct supernet_info *myinfo) { while ( fread(&requestid,1,sizeof(requestid),fp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),fp) == sizeof(quoteid) ) { - if ( basilisk_swap_load(requestid,quoteid,&privkey,&R,&statebits,&optionduration) == 0 ) + jaddi(array,basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)); + /*if ( basilisk_swap_load(requestid,quoteid,&privkey,&R,&statebits,&optionduration) == 0 ) { jaddi(array,basilisk_requestjson(&R)); - } + }*/ } fclose(fp); } jaddstr(retjson,"result","success"); jadd(retjson,"swaps",array); + if ( cJSON_GetArraySize(array) > 0 ) + { + totalsobj = cJSON_CreateObject(); + for (i=0; i Date: Sat, 8 Apr 2017 13:52:21 +0300 Subject: [PATCH 0147/2705] Test --- iguana/exchanges/mm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 56cbdb816..a84c048aa 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -723,8 +723,6 @@ int main(int argc, const char * argv[]) printf("Need to activate both %s and %s before marketmaker\n",base,rel); exit(1); } - printf("%s %s\n",base,DEX_balance(exchange,base,"")); - printf("%s %s\n",rel,DEX_balance(exchange,rel,"")); marketmaker_pendinginit(exchange,base,rel); if ( baseaddr != 0 && reladdr != 0 ) { From ee5e216e2e698e7795758b6cffe6484479c57236 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 13:53:24 +0300 Subject: [PATCH 0148/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index a84c048aa..480270f2d 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -733,7 +733,7 @@ int main(int argc, const char * argv[]) marketmaker(minask,maxbid,baseaddr,reladdr,start_base,start_rel,profitmargin,maxexposure,incrratio,exchange,name,base,rel); } free_json(loginjson); - //printf("%s\n",DEX_apikeypair(exchange,apikey,apisecret)); + printf("%s\n",DEX_apikeypair(exchange,apikey,apisecret)); } else printf("ERROR parsing.(%s)\n",retstr); free(retstr); } From 5923a9a68aa6554eb9ea7e213ca5051bb76bcfef Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 13:54:17 +0300 Subject: [PATCH 0149/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 480270f2d..e586c9ba9 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -733,7 +733,7 @@ int main(int argc, const char * argv[]) marketmaker(minask,maxbid,baseaddr,reladdr,start_base,start_rel,profitmargin,maxexposure,incrratio,exchange,name,base,rel); } free_json(loginjson); - printf("%s\n",DEX_apikeypair(exchange,apikey,apisecret)); + printf("(%s) (%s) %s\n",apikey,apisecret,DEX_apikeypair(exchange,apikey,apisecret)); } else printf("ERROR parsing.(%s)\n",retstr); free(retstr); } From b1b2d261d6a3530c7c160ff360ae62d2f2e90f33 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 13:55:07 +0300 Subject: [PATCH 0150/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index e586c9ba9..ca7d53276 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -723,6 +723,7 @@ int main(int argc, const char * argv[]) printf("Need to activate both %s and %s before marketmaker\n",base,rel); exit(1); } + printf(">>>>>>> (%s) (%s) %s\n",apikey,apisecret,DEX_apikeypair(exchange,apikey,apisecret)); marketmaker_pendinginit(exchange,base,rel); if ( baseaddr != 0 && reladdr != 0 ) { @@ -733,7 +734,6 @@ int main(int argc, const char * argv[]) marketmaker(minask,maxbid,baseaddr,reladdr,start_base,start_rel,profitmargin,maxexposure,incrratio,exchange,name,base,rel); } free_json(loginjson); - printf("(%s) (%s) %s\n",apikey,apisecret,DEX_apikeypair(exchange,apikey,apisecret)); } else printf("ERROR parsing.(%s)\n",retstr); free(retstr); } From b789f73c36a7336de79af100fd7238715365f84d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 13:57:19 +0300 Subject: [PATCH 0151/2705] Test --- iguana/exchanges/mm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index ca7d53276..7bf9418d2 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -645,7 +645,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double mmask = 0.; } marketmaker_volumeset(&bidincr,&askincr,incr,buyvol,pendingbids,sellvol,pendingasks,maxexposure); - //printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); + printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); if ( (aveask - avebid)/aveprice > profitmargin ) bid = highbid * (1 - profitmargin), ask = lowask * (1 + profitmargin); else bid = avebid - profitmargin*aveprice, ask = avebid + profitmargin*aveprice; @@ -723,7 +723,7 @@ int main(int argc, const char * argv[]) printf("Need to activate both %s and %s before marketmaker\n",base,rel); exit(1); } - printf(">>>>>>> (%s) (%s) %s\n",apikey,apisecret,DEX_apikeypair(exchange,apikey,apisecret)); + printf("%s\n",DEX_apikeypair(exchange,apikey,apisecret)); marketmaker_pendinginit(exchange,base,rel); if ( baseaddr != 0 && reladdr != 0 ) { From d664b5b563fa83276f5e726382ad449974b8ff5b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:03:42 +0300 Subject: [PATCH 0152/2705] Test --- iguana/exchanges/mm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 7bf9418d2..f9c3586e5 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -42,6 +42,14 @@ char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", double PAXPRICES[sizeof(CURRENCIES)/sizeof(*CURRENCIES)]; uint32_t PAXACTIVE; +char *DEX_swapstatus() +{ + char url[512],postdata[1024]; + sprintf(url,"%s/?",IGUANA_URL); + sprintf(postdata,"{\"agent\":\"basilisk\",\"method\":\"swapstatus\"}"); + return(bitcoind_RPC(0,"basilisk",url,0,"swapstatus",postdata)); +} + char *DEX_amlp(char *blocktrail) { char url[512],postdata[1024]; @@ -567,7 +575,7 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double start_BASE,double start_REL,double profitmargin,double maxexposure,double ratioincr,char *exchange,char *name,char *base,char *rel) { static uint32_t counter; - cJSON *fiatjson; double bid,ask,start_DEXbase,start_DEXrel,USD_average=0.,DEX_base = 0.,DEX_rel = 0.,balance_base=0.,balance_rel=0.,mmbid,mmask,usdprice=0.,CMC_average=0.,aveprice,incr,pendingbids,pendingasks,buyvol,sellvol,bidincr,askincr,filledprice,avebid=0.,aveask=0.,val,changes[3],highbid=0.,lowask=0.,theoretical = 0.; uint32_t lasttime = 0; + cJSON *fiatjson; char *retstr; double bid,ask,start_DEXbase,start_DEXrel,USD_average=0.,DEX_base = 0.,DEX_rel = 0.,balance_base=0.,balance_rel=0.,mmbid,mmask,usdprice=0.,CMC_average=0.,aveprice,incr,pendingbids,pendingasks,buyvol,sellvol,bidincr,askincr,filledprice,avebid=0.,aveask=0.,val,changes[3],highbid=0.,lowask=0.,theoretical = 0.; uint32_t lasttime = 0; incr = maxexposure * ratioincr; buyvol = sellvol = 0.; start_DEXbase = dex_balance(base,baseaddr); @@ -646,6 +654,8 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double } marketmaker_volumeset(&bidincr,&askincr,incr,buyvol,pendingbids,sellvol,pendingasks,maxexposure); printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); + if ( (retstr= DEX_swapstatus()) != 0 ) + printf("%s\n",retstr), free(retstr); if ( (aveask - avebid)/aveprice > profitmargin ) bid = highbid * (1 - profitmargin), ask = lowask * (1 + profitmargin); else bid = avebid - profitmargin*aveprice, ask = avebid + profitmargin*aveprice; From 60d96942f413deae1672daf21975b5a87e8433a0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:07:05 +0300 Subject: [PATCH 0153/2705] Test --- iguana/exchanges/mm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index f9c3586e5..f1f42db65 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -46,8 +46,8 @@ char *DEX_swapstatus() { char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); - sprintf(postdata,"{\"agent\":\"basilisk\",\"method\":\"swapstatus\"}"); - return(bitcoind_RPC(0,"basilisk",url,0,"swapstatus",postdata)); + sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"getswaplist\"}"); + return(bitcoind_RPC(0,"InstantDEX",url,0,"getswaplist",postdata)); } char *DEX_amlp(char *blocktrail) From a94fc002d1bc310654b4f342b1c00685d8d11323 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:09:13 +0300 Subject: [PATCH 0154/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index f1f42db65..bc7bfe8f5 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -677,7 +677,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double if ( askincr > 1. ) askincr = (int32_t)askincr + 0.777; } - //printf("mmbid %.8f %.6f, mmask %.8f %.6f\n",mmbid,bidincr,mmask,askincr); + printf("mmbid %.8f %.6f, mmask %.8f %.6f\n",mmbid,bidincr,mmask,askincr); marketmaker_spread(exchange,base,rel,mmbid,bidincr,mmask,askincr,profitmargin*aveprice*0.5); sleep(60); } From 75a1336716656de3c9ada186966152bf6bfde647 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:11:09 +0300 Subject: [PATCH 0155/2705] Test --- iguana/exchanges/mm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index bc7bfe8f5..584e420c8 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -485,7 +485,10 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double if ( bid > SMALLVAL && bidvol > SMALLVAL && ptr->dir > 0 && fabs(bid - ptr->price) < separation ) nearflags[0]++; if ( ask > SMALLVAL && askvol > SMALLVAL && ptr->dir < 0 && fabs(ask - ptr->price) < separation ) + { + printf("%.8f near %.8f\n",ask,ptr->price); nearflags[1]++; + } } } } From f593fc5aa50a89a76e126c2c615e55cedaee22b6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:13:25 +0300 Subject: [PATCH 0156/2705] Test --- iguana/exchanges/mm.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 584e420c8..99964c4f3 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -483,7 +483,10 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double if ( ptr->pending != 0 && ptr->cancelstarted == 0 ) { if ( bid > SMALLVAL && bidvol > SMALLVAL && ptr->dir > 0 && fabs(bid - ptr->price) < separation ) + { + printf("bid %.8f near %.8f\n",bid,ptr->price); nearflags[0]++; + } if ( ask > SMALLVAL && askvol > SMALLVAL && ptr->dir < 0 && fabs(ask - ptr->price) < separation ) { printf("%.8f near %.8f\n",ask,ptr->price); @@ -492,7 +495,7 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double } } } - //printf("spread.%s (%.8f %.6f) (%.8f %.6f)\n",exchange,bid,bidvol,ask,askvol); + printf("spread.%s (%.8f %.6f) (%.8f %.6f)\n",exchange,bid,bidvol,ask,askvol); if ( bid > SMALLVAL && bidvol > SMALLVAL && nearflags[0] == 0 ) { if ( strcmp("DEX",exchange) == 0 && strcmp(base,"KMD") == 0 && strcmp(rel,"BTC") == 0 ) @@ -550,20 +553,20 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double } else if ( (retstr= DEX_trade(exchange,base,rel,1,bid,bidvol)) != 0 ) { - //printf("DEX_trade.(%s)\n",retstr); + printf("DEX_trade.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { marketmaker_queue(exchange,base,rel,1,bid,bidvol,retjson); free_json(retjson); } free(retstr); - } + } else printf("skip bid %s %.8f vol %f\n",exchange,bid,bidvol); } if ( ask > SMALLVAL && askvol > SMALLVAL && nearflags[1] == 0 && strcmp("DEX",exchange) != 0 ) { if ( (retstr= DEX_trade(exchange,base,rel,-1,ask,askvol)) != 0 ) { - //printf("DEX_trade.(%s)\n",retstr); + printf("DEX_trade.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { marketmaker_queue(exchange,base,rel,-1,ask,askvol,retjson); @@ -571,7 +574,7 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double } free(retstr); } - } + } else printf("skip ask %s %.8f vol %f\n",exchange,bid,bidvol); return(n); } From c17164c7099458642accfa349bc60f6e2ac958c6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:16:47 +0300 Subject: [PATCH 0157/2705] Test --- iguana/exchanges/mm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 99964c4f3..5b4c9ce3c 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -484,18 +484,18 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double { if ( bid > SMALLVAL && bidvol > SMALLVAL && ptr->dir > 0 && fabs(bid - ptr->price) < separation ) { - printf("bid %.8f near %.8f\n",bid,ptr->price); + //printf("bid %.8f near %.8f\n",bid,ptr->price); nearflags[0]++; } if ( ask > SMALLVAL && askvol > SMALLVAL && ptr->dir < 0 && fabs(ask - ptr->price) < separation ) { - printf("%.8f near %.8f\n",ask,ptr->price); + //printf("%.8f near %.8f\n",ask,ptr->price); nearflags[1]++; } } } } - printf("spread.%s (%.8f %.6f) (%.8f %.6f)\n",exchange,bid,bidvol,ask,askvol); + //printf("spread.%s (%.8f %.6f) (%.8f %.6f)\n",exchange,bid,bidvol,ask,askvol); if ( bid > SMALLVAL && bidvol > SMALLVAL && nearflags[0] == 0 ) { if ( strcmp("DEX",exchange) == 0 && strcmp(base,"KMD") == 0 && strcmp(rel,"BTC") == 0 ) @@ -553,20 +553,20 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double } else if ( (retstr= DEX_trade(exchange,base,rel,1,bid,bidvol)) != 0 ) { - printf("DEX_trade.(%s)\n",retstr); + //printf("DEX_trade.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { marketmaker_queue(exchange,base,rel,1,bid,bidvol,retjson); free_json(retjson); } free(retstr); - } else printf("skip bid %s %.8f vol %f\n",exchange,bid,bidvol); + } //else printf("skip bid %s %.8f vol %f\n",exchange,bid,bidvol); } if ( ask > SMALLVAL && askvol > SMALLVAL && nearflags[1] == 0 && strcmp("DEX",exchange) != 0 ) { if ( (retstr= DEX_trade(exchange,base,rel,-1,ask,askvol)) != 0 ) { - printf("DEX_trade.(%s)\n",retstr); + //printf("DEX_trade.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { marketmaker_queue(exchange,base,rel,-1,ask,askvol,retjson); @@ -574,7 +574,7 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double } free(retstr); } - } else printf("skip ask %s %.8f vol %f\n",exchange,bid,bidvol); + } //else printf("skip ask %s %.8f vol %f\n",exchange,bid,bidvol); return(n); } From 8f91630771ad1320f8605cd369e9a34962050344 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:23:41 +0300 Subject: [PATCH 0158/2705] Test --- iguana/exchanges/mm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 5b4c9ce3c..9990f0331 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -668,8 +668,8 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double marketmaker_spread("DEX",base,rel,bid,incr,ask,incr,profitmargin*aveprice*0.5); if ( (pendingbids + buyvol) > (pendingasks + sellvol) ) { - bidincr *= sqrt((double)(pendingasks + sellvol) / ((pendingbids + buyvol) + (pendingasks + sellvol))); - //printf("bidincr %f buy.(%f + %f) sell.(%f + %f)\n",bidincr,pendingbids,buyvol,pendingasks,sellvol); + bidincr *= ((double)(pendingasks + sellvol) / ((pendingbids + buyvol) + (pendingasks + sellvol))); + printf("bidincr %f buy.(%f + %f) sell.(%f + %f)\n",bidincr,pendingbids,buyvol,pendingasks,sellvol); if ( bidincr < 0.1*incr ) bidincr = 0.1*incr; if ( bidincr > 1. ) @@ -683,7 +683,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double if ( askincr > 1. ) askincr = (int32_t)askincr + 0.777; } - printf("mmbid %.8f %.6f, mmask %.8f %.6f\n",mmbid,bidincr,mmask,askincr); + //printf("mmbid %.8f %.6f, mmask %.8f %.6f\n",mmbid,bidincr,mmask,askincr); marketmaker_spread(exchange,base,rel,mmbid,bidincr,mmask,askincr,profitmargin*aveprice*0.5); sleep(60); } From 6077c784112a8ca5c21d807d4b452a2f08a4b028 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:26:34 +0300 Subject: [PATCH 0159/2705] Test --- iguana/exchanges/mm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 9990f0331..3ab5e98e0 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -666,7 +666,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double bid = highbid * (1 - profitmargin), ask = lowask * (1 + profitmargin); else bid = avebid - profitmargin*aveprice, ask = avebid + profitmargin*aveprice; marketmaker_spread("DEX",base,rel,bid,incr,ask,incr,profitmargin*aveprice*0.5); - if ( (pendingbids + buyvol) > (pendingasks + sellvol) ) + if ( (pendingbids + buyvol) > (pendingasks + sellvol) && (pendingbids + buyvol) > bidincr ) { bidincr *= ((double)(pendingasks + sellvol) / ((pendingbids + buyvol) + (pendingasks + sellvol))); printf("bidincr %f buy.(%f + %f) sell.(%f + %f)\n",bidincr,pendingbids,buyvol,pendingasks,sellvol); @@ -675,7 +675,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double if ( bidincr > 1. ) bidincr = (int32_t)bidincr + 0.777; } - if ( (pendingbids + buyvol) < (pendingasks + sellvol) ) + if ( (pendingbids + buyvol) < (pendingasks + sellvol) && (pendingasks + sellvol) > askincr ) { askincr *= (double)(pendingbids + buyvol) / ((pendingbids + buyvol) + (pendingasks + sellvol)); if ( askincr < 0.1*incr ) From 8ff9093c644b7b2b3a09be215723d292ff9de4cb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 14:35:27 +0300 Subject: [PATCH 0160/2705] Test --- basilisk/basilisk_swap.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 847093f8d..b357e8c59 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2759,6 +2759,13 @@ char *basilisk_swaplist(struct supernet_info *myinfo) jaddnum(totalsobj,txnames[i],dstr(KMDtotals[i])); jadd(retjson,"KMDtotals",totalsobj); } + array = cJSON_CreateArray(); + for (i=0; ilinfos)/sizeof(*myinfo->linfos); i++) + { + if ( myinfo->linfos[i].base[0] != 0 && myinfo->linfos[i].rel[0] != 0 ) + jaddi(array,linfo_json(&myinfo->linfos[i])); + } + jadd(retjson,"quotes",array); return(jprint(retjson,1)); } From da8ea2de953a89ca35084a15d4a2cf2f1a1cfc12 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 16:05:50 +0300 Subject: [PATCH 0161/2705] Test --- iguana/exchanges/mm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 3ab5e98e0..81e7dc728 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -41,6 +41,7 @@ char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", }; double PAXPRICES[sizeof(CURRENCIES)/sizeof(*CURRENCIES)]; uint32_t PAXACTIVE; +char DEX_baseaddr[16],DEX_reladdr[16]; char *DEX_swapstatus() { @@ -662,6 +663,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); if ( (retstr= DEX_swapstatus()) != 0 ) printf("%s\n",retstr), free(retstr); + printf("%s %.8f, %s %.8f\n",base,DEX_balance("DEX",base,DEX_baseaddr),rel,DEX_balance("DEX",rel,DEX_reladdr)); if ( (aveask - avebid)/aveprice > profitmargin ) bid = highbid * (1 - profitmargin), ask = lowask * (1 + profitmargin); else bid = avebid - profitmargin*aveprice, ask = avebid + profitmargin*aveprice; @@ -744,6 +746,8 @@ int main(int argc, const char * argv[]) if ( baseaddr != 0 && reladdr != 0 ) { printf("PAXACTIVE.%08x %s\n",PAXACTIVE,DEX_amlp(blocktrail)); + strcpy(DEX_baseaddr,baseaddr); + strcpy(DEX_reladdr,reladdr); printf("%s.%s %s\n",base,baseaddr,DEX_balance("DEX",base,baseaddr)); printf("%s.%s %s\n",rel,reladdr,DEX_balance("DEX",rel,reladdr)); // initialize state using DEX_pendingorders, etc. From 546f5f9ba848d2cb4aa33e418961dba55b92c26c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 16:06:59 +0300 Subject: [PATCH 0162/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 81e7dc728..9ebf491aa 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -663,7 +663,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); if ( (retstr= DEX_swapstatus()) != 0 ) printf("%s\n",retstr), free(retstr); - printf("%s %.8f, %s %.8f\n",base,DEX_balance("DEX",base,DEX_baseaddr),rel,DEX_balance("DEX",rel,DEX_reladdr)); + printf("%s %s, %s %s\n",base,DEX_balance("DEX",base,DEX_baseaddr),rel,DEX_balance("DEX",rel,DEX_reladdr)); if ( (aveask - avebid)/aveprice > profitmargin ) bid = highbid * (1 - profitmargin), ask = lowask * (1 + profitmargin); else bid = avebid - profitmargin*aveprice, ask = avebid + profitmargin*aveprice; From 424a28cdd354f5a41f4b51bb7a50b8bbbede38ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 16:11:16 +0300 Subject: [PATCH 0163/2705] Test --- iguana/exchanges/mm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 9ebf491aa..dd3c4fb43 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -295,9 +295,11 @@ void marketmaker_queue(char *exchange,char *base,char *rel,int32_t dir,double pr void marketmaker_pendingupdate(char *exchange,char *base,char *rel) { char *retstr; cJSON *retjson,*obj; int32_t i; struct mmpending_order *ptr; + printf("update.(%s %s %s)\n",exchange,base,rel); for (i=0; iexchange) != 0 || strcmp(base,ptr->base) != 0 || strcmp(rel,ptr->rel) != 0 ) continue; if ( ptr->completed == 0 && (retstr= DEX_orderstatus(exchange,ptr->orderid)) != 0 ) From 11106bf433881a1ca3e9c1f2f3a3d635a3e78850 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 16:12:52 +0300 Subject: [PATCH 0164/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index dd3c4fb43..d43363c03 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -24,6 +24,7 @@ #include "OS_portable.h" #define MAX(a,b) ((a) > (b) ? (a) : (b)) +char DEX_baseaddr[64],DEX_reladdr[64]; struct mmpending_order { double price,volume; @@ -41,7 +42,6 @@ char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", }; double PAXPRICES[sizeof(CURRENCIES)/sizeof(*CURRENCIES)]; uint32_t PAXACTIVE; -char DEX_baseaddr[16],DEX_reladdr[16]; char *DEX_swapstatus() { From ce51515c8a668d47778fa526640dd3c94482fad0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 16:14:57 +0300 Subject: [PATCH 0165/2705] Test --- iguana/exchanges/mm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index d43363c03..48f349535 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -295,11 +295,9 @@ void marketmaker_queue(char *exchange,char *base,char *rel,int32_t dir,double pr void marketmaker_pendingupdate(char *exchange,char *base,char *rel) { char *retstr; cJSON *retjson,*obj; int32_t i; struct mmpending_order *ptr; - printf("update.(%s %s %s)\n",exchange,base,rel); for (i=0; iexchange) != 0 || strcmp(base,ptr->base) != 0 || strcmp(rel,ptr->rel) != 0 ) continue; if ( ptr->completed == 0 && (retstr= DEX_orderstatus(exchange,ptr->orderid)) != 0 ) @@ -748,8 +746,8 @@ int main(int argc, const char * argv[]) if ( baseaddr != 0 && reladdr != 0 ) { printf("PAXACTIVE.%08x %s\n",PAXACTIVE,DEX_amlp(blocktrail)); - strcpy(DEX_baseaddr,baseaddr); - strcpy(DEX_reladdr,reladdr); + strncpy(DEX_baseaddr,baseaddr,sizeof(DEX_baseaddr)-1); + strncpy(DEX_reladdr,reladdr,sizeof(DEX_reladdr)-1); printf("%s.%s %s\n",base,baseaddr,DEX_balance("DEX",base,baseaddr)); printf("%s.%s %s\n",rel,reladdr,DEX_balance("DEX",rel,reladdr)); // initialize state using DEX_pendingorders, etc. From cdcc5d090a6f4d082bf81a002649178dd09b3f18 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 16:18:38 +0300 Subject: [PATCH 0166/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 48f349535..137a84011 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -663,7 +663,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double printf("AVE.(%.8f %.8f) hbla %.8f %.8f bid %.8f ask %.8f theory %.8f buys.(%.6f %.6f) sells.(%.6f %.6f) incr.(%.6f %.6f) balances.(%.8f + %.8f, %.8f + %.8f) test %f\n",avebid,aveask,highbid,lowask,mmbid,mmask,theoretical,buyvol,pendingbids,sellvol,pendingasks,bidincr,askincr,balance_base,DEX_base,balance_rel,DEX_rel,(aveask - avebid)/aveprice); if ( (retstr= DEX_swapstatus()) != 0 ) printf("%s\n",retstr), free(retstr); - printf("%s %s, %s %s\n",base,DEX_balance("DEX",base,DEX_baseaddr),rel,DEX_balance("DEX",rel,DEX_reladdr)); + printf("%s %s %s, %s %s %s\n",base,DEX_baseaddr,DEX_balance("DEX",base,DEX_baseaddr),rel,DEX_reladdr,DEX_balance("DEX",rel,DEX_reladdr)); if ( (aveask - avebid)/aveprice > profitmargin ) bid = highbid * (1 - profitmargin), ask = lowask * (1 + profitmargin); else bid = avebid - profitmargin*aveprice, ask = avebid + profitmargin*aveprice; From 04f0146676209a45d6bdbea0e3f87f955e6fd909 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 17:18:15 +0300 Subject: [PATCH 0167/2705] Test --- basilisk/basilisk_DEX.c | 8 ++++---- iguana/main.c | 3 +++ includes/iguana_structs.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index c430f292e..bed30428b 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -116,8 +116,8 @@ int32_t basilisk_rwDEXquote(int32_t rwflag,uint8_t *serialized,struct basilisk_r memcpy(rp->src,&serialized[len],sizeof(rp->src)), len += sizeof(rp->src); memcpy(rp->dest,&serialized[len],sizeof(rp->dest)), len += sizeof(rp->dest); } - len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->DEXselector),&rp->DEXselector); - len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->extraspace),&rp->extraspace); + //len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->DEXselector),&rp->DEXselector); + //len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->extraspace),&rp->extraspace); if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) printf(" basilisk_rwDEXquote.%d: quoteid.%u mismatch calc %u rp.%p\n",rwflag,rp->quoteid,basilisk_quoteid(rp),rp); if ( basilisk_requestid(rp) != rp->requestid ) @@ -170,7 +170,7 @@ cJSON *basilisk_requestjson(struct basilisk_request *rp) jaddnum(item,"timestamp",rp->timestamp); jaddnum(item,"requestid",rp->requestid); jaddnum(item,"quoteid",rp->quoteid); - jaddnum(item,"DEXselector",rp->DEXselector); + //jaddnum(item,"DEXselector",rp->DEXselector); jaddnum(item,"optionhours",rp->optionhours); jaddnum(item,"profit",(double)rp->profitmargin / 1000000.); if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) @@ -219,7 +219,7 @@ int32_t basilisk_request_create(struct basilisk_request *rp,cJSON *valsobj,bits2 rp->srchash = jbits256(valsobj,"srchash"); rp->optionhours = jint(valsobj,"optionhours"); rp->profitmargin = jdouble(valsobj,"profit") * 1000000; - rp->DEXselector = DEXselector; + //rp->DEXselector = DEXselector; strncpy(rp->src,src,sizeof(rp->src)-1); strncpy(rp->dest,dest,sizeof(rp->dest)-1); //if ( jstr(valsobj,"relay") != 0 ) diff --git a/iguana/main.c b/iguana/main.c index a012479b4..4be566b58 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -755,6 +755,9 @@ void jumblr_loop(void *ptr) { if ( (coin= iguana_coinfind("KMD")) != 0 ) { +#ifdef __APPLE__ + jumblr_DEXcheck(myinfo,coin); +#endif if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index ad311d271..463faf0f5 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -604,7 +604,7 @@ struct basilisk_request char src[8],dest[8]; //char volatile_start,message[43]; uint64_t destamount; - int32_t optionhours,profitmargin,DEXselector,extraspace; + int32_t optionhours,profitmargin;//,DEXselector,extraspace; } PACKEDSTRUCT; struct basilisk_relaystatus From ab8198cc10b3c708fe852ea92257dc5b59e296d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 17:57:12 +0300 Subject: [PATCH 0168/2705] Test --- basilisk/basilisk.h | 4 ++-- basilisk/basilisk_swap.c | 2 +- basilisk/jumblr.c | 6 +++--- iguana/main.c | 5 +++-- includes/iguana_funcs.h | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index b15b9032f..7fa412906 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -16,8 +16,8 @@ #ifndef H_BASILISK_H #define H_BASILISK_H -#define BASILISK_DISABLESENDTX -#define BASILISK_DISABLEWAITTX +//#define BASILISK_DISABLESENDTX +//#define BASILISK_DISABLEWAITTX #include "../iguana/iguana777.h" diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b357e8c59..662e8c456 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2223,7 +2223,7 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, return; if ( swap->pushsock < 0 && swap->subsock < 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) { - timeout = 100; + timeout = 1000; nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); timeout = 1; nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 4624d147e..f6bcdd688 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -711,7 +711,7 @@ void jumblr_CMCname(char *CMCname,char *symbol) strcpy(CMCname,"komodo"); } -void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) +void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32_t toKMD) { double vol,avail; struct iguana_info *kmdcoin,*coinbtc = 0; if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 ) @@ -732,7 +732,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) + if ( toKMD != 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { avail = (btcavail - kmdcoin->DEXinfo.DEXpending); printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); @@ -763,7 +763,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin) // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - if ( 1 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (100. + kmdcoin->DEXinfo.KMDpending) ) + if ( toKMD == 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (100. + kmdcoin->DEXinfo.KMDpending) ) { avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR,avail); diff --git a/iguana/main.c b/iguana/main.c index 4be566b58..ceaacb6ab 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -756,13 +756,14 @@ void jumblr_loop(void *ptr) if ( (coin= iguana_coinfind("KMD")) != 0 ) { #ifdef __APPLE__ - jumblr_DEXcheck(myinfo,coin); + if ( (n++ % 10) == 0 ) + jumblr_DEXcheck(myinfo,coin,!((n/10)&1)); #endif if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC if ( (n++ % 10) == 0 ) - jumblr_DEXcheck(myinfo,coin); + jumblr_DEXcheck(myinfo,coin,!((n/10)&1)); t = (uint32_t)time(NULL); if ( (t % (120 * mult)) < 60 ) { diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index 6be0f931a..b8061eb61 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -629,7 +629,7 @@ int32_t iguana_staker_sort(struct iguana_info *coin,bits256 *hash2p,uint8_t *ref bits256 mpz_div64(bits256 hash,uint64_t divval); void iguana_walletinitcheck(struct supernet_info *myinfo,struct iguana_info *coin); void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval); -void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin); +void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32_t toKMD); bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,uint8_t pubtype,char *KMDaddr,char *prefix); char *jumblr_importprivkey(struct supernet_info *myinfo,struct iguana_info *coin,char *wifstr); int64_t iguana_esttxfee(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx,char *signedtx,int32_t numvins); From 0760965fad9e49e16c493e61f57e8d959cd0c0c5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 18:17:28 +0300 Subject: [PATCH 0169/2705] Test --- .gitignore | 6 ++++++ basilisk/basilisk_swap.c | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b5c31dd26..1c1b6daa8 100755 --- a/.gitignore +++ b/.gitignore @@ -268,3 +268,9 @@ iguana/DB/SWAPS/2050938501-203733478 iguana/DB/SWAPS/3434672913-3981690962 iguana/DB/SWAPS/2840127595-1174059534 + +iguana/DB/SWAPS/2448551545-1211445977 + +*.alicepayment + +*.myfee diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 662e8c456..5d80dd650 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1578,8 +1578,21 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv free(swap); return(0); } - swap->I.bobconfirms = (1*0 + sqrt(dstr(swap->I.bobsatoshis) * .1)); - swap->I.aliceconfirms = swap->I.bobconfirms * 3; + if ( strcmp("BTC",swap->bobcoin->symbol) == 0 ) + { + swap->I.bobconfirms = (1 + sqrt(dstr(swap->I.bobsatoshis) * .1)); + swap->I.aliceconfirms = swap->I.bobconfirms * 3; + } + else if ( strcmp("BTC",swap->alicecoin->symbol) == 0 ) + { + swap->I.aliceconfirms = (1 + sqrt(dstr(swap->I.alicesatoshis) * .1)); + swap->I.bobconfirms = swap->I.bobconfirms * 3; + } + else + { + swap->I.bobconfirms = 3; + swap->I.aliceconfirms = 3; + } if ( swap->I.bobconfirms == 0 ) swap->I.bobconfirms = swap->bobcoin->chain->minconfirms; if ( swap->I.aliceconfirms == 0 ) From 4eea0856de413e2880fdfff709814b07abfed381 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 19:09:33 +0300 Subject: [PATCH 0170/2705] Test --- basilisk/basilisk_swap.c | 99 ++-------------------------------------- 1 file changed, 5 insertions(+), 94 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 5d80dd650..ddefea947 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -19,6 +19,7 @@ make sure to broadcast deposit before claiming refund, or to just skip it if nei */ #define DEX_SLEEP 5 +#define BASILISK_DEFAULT_NUMCONFIRMS 5 // Todo: monitor blockchains, ie complete extracting scriptsig // mode to autocreate required outputs @@ -819,96 +820,6 @@ int32_t basilisk_alicepayment_spend(struct supernet_info *myinfo,struct basilisk return(-1); } -/*int32_t basilisk_bobpayment_spendclone(struct supernet_info *myinfo,struct iguana_info *bobcoin,struct basilisk_rawtx *dest,struct basilisk_rawtx *src,uint32_t swapstarted,uint8_t *changepubkey33,uint32_t quoteid,uint64_t amount,bits256 privAm,bits256 myprivs0,uint8_t *data,int32_t datalen,int32_t jumblrflag) -{ - bits256 revAm; uint8_t userdata[512]; int32_t i,len,numconfirms = 0,retval = -1; uint32_t sequenceid = 0xffffffff; - basilisk_rawtx_setparms("bobpayment",quoteid,src,bobcoin,numconfirms,0,amount,3,0,jumblrflag); - dest->I.suppress_pubkeys = 1; - basilisk_rawtx_gen("bobpayment",myinfo,swapstarted,changepubkey33,1,1,src,src->I.locktime,src->spendscript,src->I.spendlen,bobcoin->chain->txfee,1,0); - if ( basilisk_rawtx_spendscript(0,bobcoin->longestchain,src,0,data,datalen,0) == 0 ) - { - memset(revAm.bytes,0,sizeof(revAm)); - for (i=0; i<32; i++) - revAm.bytes[i] = privAm.bytes[31-i]; - len = basilisk_swapuserdata(userdata,revAm,0,myprivs0,src->redeemscript,src->I.redeemlen); - if ( (retval= _basilisk_rawtx_sign(myinfo,bobcoin->longestchain,swapstarted,src->I.locktime,sequenceid,dest,src,myprivs0,0,userdata,len,1)) == 0 ) - { - } - } - return(retval); -} - -int32_t basilisk_bobpayment_reclaimclone(struct supernet_info *myinfo,struct iguana_info *bobcoin,struct basilisk_rawtx *dest,struct basilisk_rawtx *src,uint32_t swapstarted,uint8_t *changepubkey33,uint32_t quoteid,uint64_t amount,bits256 myprivs1,uint8_t *data,int32_t datalen,int32_t jumblrflag) -{ - bits256 zero; uint8_t userdata[512]; int32_t len,numconfirms = 0,retval = -1; uint32_t sequenceid = 0xffffffff; - basilisk_rawtx_setparms("bobpayment",quoteid,src,bobcoin,numconfirms,0,amount,3,0,jumblrflag); - dest->I.suppress_pubkeys = 1; - basilisk_rawtx_gen("bobpayment",myinfo,swapstarted,changepubkey33,1,1,src,src->I.locktime,src->spendscript,src->I.spendlen,bobcoin->chain->txfee,1,0); - if ( basilisk_rawtx_spendscript(0,bobcoin->longestchain,src,0,data,datalen,0) == 0 ) - { - memset(zero.bytes,0,sizeof(zero)); - len = basilisk_swapuserdata(userdata,zero,1,myprivs1,src->redeemscript,src->I.redeemlen); - if ( (retval= _basilisk_rawtx_sign(myinfo,bobcoin->longestchain,swapstarted,src->I.locktime,sequenceid,dest,src,myprivs1,0,userdata,len,1)) == 0 ) - { - } - } - return(retval); -} - -int32_t basilisk_bobdeposit_refundclone(struct supernet_info *myinfo,struct iguana_info *bobcoin,struct basilisk_rawtx *dest,struct basilisk_rawtx *src,uint32_t swapstarted,uint8_t *changepubkey33,uint32_t quoteid,uint64_t amount,bits256 myprivs0,bits256 privBn,uint8_t *data,int32_t datalen,int32_t jumblrflag) -{ - uint8_t userdata[512]; int32_t len,numconfirms = 0,retval = -1; uint32_t sequenceid = 0xffffffff; - basilisk_rawtx_setparms("bobdeposit",quoteid,src,bobcoin,numconfirms,0,amount,4,0,jumblrflag); - dest->I.suppress_pubkeys = 1; - basilisk_rawtx_gen("bobdeposit",myinfo,swapstarted,changepubkey33,1,1,src,src->I.locktime,src->spendscript,src->I.spendlen,bobcoin->chain->txfee,1,0); - if ( basilisk_rawtx_spendscript(0,bobcoin->longestchain,src,0,data,datalen,0) == 0 ) - { - len = basilisk_swapuserdata(userdata,privBn,0,myprivs0,src->redeemscript,src->I.redeemlen); - if ( (retval= _basilisk_rawtx_sign(myinfo,bobcoin->longestchain,swapstarted,src->I.locktime,sequenceid,dest,src,myprivs0,0,userdata,len,0)) == 0 ) - { - } - } - return(retval); -} - -int32_t basilisk_bobdeposit_claimclone(struct supernet_info *myinfo,struct iguana_info *bobcoin,struct basilisk_rawtx *dest,struct basilisk_rawtx *src,uint32_t swapstarted,uint8_t *changepubkey33,uint32_t quoteid,uint64_t amount,bits256 myprivs0,uint8_t *data,int32_t datalen,int32_t jumblrflag) -{ - bits256 zero; uint8_t userdata[512]; int32_t len,numconfirms = 0,retval = -1; uint32_t sequenceid = 0xffffffff; - basilisk_rawtx_setparms("bobdeposit",quoteid,src,bobcoin,numconfirms,0,amount,4,0,jumblrflag); - dest->I.suppress_pubkeys = 1; - basilisk_rawtx_gen("bobdeposit",myinfo,swapstarted,changepubkey33,1,1,src,src->I.locktime,src->spendscript,src->I.spendlen,bobcoin->chain->txfee,1,0); - if ( basilisk_rawtx_spendscript(0,bobcoin->longestchain,src,0,data,datalen,0) == 0 ) - { - memset(zero.bytes,0,sizeof(zero)); - len = basilisk_swapuserdata(userdata,zero,1,myprivs0,src->redeemscript,src->I.redeemlen); - if ( (retval= _basilisk_rawtx_sign(myinfo,bobcoin->longestchain,swapstarted,src->I.locktime,sequenceid,dest,src,myprivs0,0,userdata,len,1)) == 0 ) - { - } - } - return(retval); -} - -//basilisk_alicepayment_clone(myinfo,&dest,&src,swapstarted,changepubkey33,alicecoin,quoteid,amount,privAm,pubAm,privBn,pubBn); - -int32_t basilisk_alicepayment_spendclone(struct supernet_info *myinfo,struct iguana_info *alicecoin,struct basilisk_rawtx *dest,struct basilisk_rawtx *src,uint32_t swapstarted,uint8_t *changepubkey33,uint32_t quoteid,uint64_t amount,bits256 privAm,bits256 privBn,int32_t jumblrflag) -{ - uint8_t pubAm33[33],pubBn33[33]; bits256 pubAm,pubBn; int32_t retval,numconfirms = 0; uint32_t sequenceid = 0xffffffff; - bitcoin_pubkey33(myinfo->ctx,pubAm33,privAm); - memcpy(pubAm.bytes,pubAm33+1,32); - bitcoin_pubkey33(myinfo->ctx,pubBn33,privBn); - memcpy(pubBn.bytes,pubBn33+1,32); - memset(src,0,sizeof(*src)); - memset(dest,0,sizeof(*dest)); - basilisk_rawtx_setparms("alicepayment",quoteid,src,alicecoin,numconfirms,0,amount,2,0,jumblrflag); - src->I.spendlen = basilisk_alicescript(src->redeemscript,&src->I.redeemlen,src->spendscript,0,src->I.destaddr,alicecoin->chain->p2shtype,pubAm,pubBn); - basilisk_rawtx_gen("alicepayment",myinfo,swapstarted,changepubkey33,0,1,src,src->I.locktime,src->spendscript,src->I.spendlen,alicecoin->chain->txfee,1,0); - if ( (retval= _basilisk_rawtx_sign(myinfo,alicecoin->longestchain,swapstarted,src->I.locktime,sequenceid,dest,src,privAm,&privBn,0,0,1)) == 0 ) - { - - } - return(retval); -}*/ - int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) { struct basilisk_swap *swap = ptr; @@ -1581,17 +1492,17 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv if ( strcmp("BTC",swap->bobcoin->symbol) == 0 ) { swap->I.bobconfirms = (1 + sqrt(dstr(swap->I.bobsatoshis) * .1)); - swap->I.aliceconfirms = swap->I.bobconfirms * 3; + swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); } else if ( strcmp("BTC",swap->alicecoin->symbol) == 0 ) { swap->I.aliceconfirms = (1 + sqrt(dstr(swap->I.alicesatoshis) * .1)); - swap->I.bobconfirms = swap->I.bobconfirms * 3; + swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); } else { - swap->I.bobconfirms = 3; - swap->I.aliceconfirms = 3; + swap->I.bobconfirms = BASILISK_DEFAULT_NUMCONFIRMS; + swap->I.aliceconfirms = BASILISK_DEFAULT_NUMCONFIRMS; } if ( swap->I.bobconfirms == 0 ) swap->I.bobconfirms = swap->bobcoin->chain->minconfirms; From 0894505da7822099769455486d2fd1347697b4a1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 19:39:53 +0300 Subject: [PATCH 0171/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ddefea947..599c41474 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -294,7 +294,7 @@ int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap * jaddstr(argjson,"coin",rawtx->coin->symbol); if ( (valstr= basilisk_value(myinfo,rawtx->coin,0,0,swap->persistent_pubkey,argjson,0)) != 0 ) { - //char str[65]; printf("%s %s valstr.(%s)\n",rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); + char str[65]; printf("basilisk_numconfirms %s %s valstr.(%s)\n",rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); if ( (valuearray= cJSON_Parse(valstr)) != 0 ) { if ( is_cJSON_Array(valuearray) != 0 ) From 8d42c859db5c1ff5fb62d5c8bb479dd2b7ac70ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 8 Apr 2017 19:52:15 +0300 Subject: [PATCH 0172/2705] Test --- .gitignore | 2 ++ basilisk/basilisk.c | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 1c1b6daa8..fa5790727 100755 --- a/.gitignore +++ b/.gitignore @@ -274,3 +274,5 @@ iguana/DB/SWAPS/2448551545-1211445977 *.alicepayment *.myfee + +iguana/DB/SWAPS/1313312572-123661666 diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index f1a9eb586..09737092b 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1222,17 +1222,20 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) } free_json(txoutjson); return(jprint(retjson,1)); - } else return(clonestr("{\"error\":\"null return from gettxout\"}")); + } //else return(clonestr("{\"error\":\"null return from gettxout\"}")); } - if ( (basilisktag= juint(vals,"basilisktag")) == 0 ) - basilisktag = rand(); - if ( (timeoutmillis= juint(vals,"timeout")) <= 0 ) - timeoutmillis = BASILISK_TIMEOUT; - if ( coin->FULLNODE > 0 && (ptr= basilisk_bitcoinvalue(&Lptr,myinfo,coin,remoteaddr,basilisktag,timeoutmillis,vals)) != 0 ) + else { - retstr = ptr->retstr, ptr->retstr = 0; - ptr->finished = OS_milliseconds() + 10000; - return(retstr); + if ( (basilisktag= juint(vals,"basilisktag")) == 0 ) + basilisktag = rand(); + if ( (timeoutmillis= juint(vals,"timeout")) <= 0 ) + timeoutmillis = BASILISK_TIMEOUT; + if ( coin->FULLNODE > 0 && (ptr= basilisk_bitcoinvalue(&Lptr,myinfo,coin,remoteaddr,basilisktag,timeoutmillis,vals)) != 0 ) + { + retstr = ptr->retstr, ptr->retstr = 0; + ptr->finished = OS_milliseconds() + 10000; + return(retstr); + } } } if ( myinfo->reqsock >= 0 ) From b753039736fc794511cc603cb8a4e7216197507f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 10:12:52 +0300 Subject: [PATCH 0173/2705] Test --- .gitignore | 6 ++++++ basilisk/basilisk.h | 4 ++-- basilisk/basilisk_swap.c | 20 ++++++++++++++------ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index fa5790727..e0bb44855 100755 --- a/.gitignore +++ b/.gitignore @@ -276,3 +276,9 @@ iguana/DB/SWAPS/2448551545-1211445977 *.myfee iguana/DB/SWAPS/1313312572-123661666 + +iguana/DB/SWAPS/3408402932-4088991610 + +iguana/DB/SWAPS/3772541120-2007204891 + +iguana/DB/SWAPS/784303571-1929722462 diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index 7fa412906..b15b9032f 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -16,8 +16,8 @@ #ifndef H_BASILISK_H #define H_BASILISK_H -//#define BASILISK_DISABLESENDTX -//#define BASILISK_DISABLEWAITTX +#define BASILISK_DISABLESENDTX +#define BASILISK_DISABLEWAITTX #include "../iguana/iguana777.h" diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 599c41474..f6f5c50a7 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -18,7 +18,7 @@ make sure to broadcast deposit before claiming refund, or to just skip it if neither is done */ -#define DEX_SLEEP 5 +#define DEX_SLEEP 15 #define BASILISK_DEFAULT_NUMCONFIRMS 5 // Todo: monitor blockchains, ie complete extracting scriptsig @@ -2596,12 +2596,14 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 int32_t i; char fname[512],*fstr,*symbol,str[65],str2[65]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 txid,trigger; uint32_t t,addflag; uint64_t value; item = cJSON_CreateObject(); array = cJSON_CreateArray(); + printf("R.%u Q.%u\n",requestid,quoteid); for (i=0; i Date: Sun, 9 Apr 2017 10:20:56 +0300 Subject: [PATCH 0174/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f6f5c50a7..ebb3473bb 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2630,7 +2630,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } else { - //printf("%s txid %s\n",symbol,bits256_str(str,txid)); + printf("%s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); free_json(sentobj); } } From 98579806760b11197e163ddc933af168063c817c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 10:32:04 +0300 Subject: [PATCH 0175/2705] Test --- basilisk/basilisk_swap.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ebb3473bb..c2dc490f3 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1768,7 +1768,7 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis { if ( rawtx == &swap->alicepayment ) { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); } else if ( rawtx == &swap->alicespend ) { @@ -2593,7 +2593,7 @@ char *txnames[] = { "myfee", "bobdeposit", "bobpayment", "alicepayment", "bobref cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t i; char fname[512],*fstr,*symbol,str[65],str2[65]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 txid,trigger; uint32_t t,addflag; uint64_t value; + int32_t i; char fname[512],*fstr,*symbol,str[65],str2[65]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 checktxid,txid,trigger; uint32_t t,addflag; uint64_t value; item = cJSON_CreateObject(); array = cJSON_CreateArray(); printf("R.%u Q.%u\n",requestid,quoteid); @@ -2630,7 +2630,12 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } else { - printf("%s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); + checktxid = jbits256(sentobj,"txid"); + if ( bits256_cmp(checktxid,txid) != 0 ) + { + printf("%s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); + addflag = 1; + } free_json(sentobj); } } From 2d4462d638f22d24cb8635a13d937a2849286991 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 10:44:05 +0300 Subject: [PATCH 0176/2705] Test --- basilisk/basilisk_swap.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index c2dc490f3..be32515fb 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2593,7 +2593,7 @@ char *txnames[] = { "myfee", "bobdeposit", "bobpayment", "alicepayment", "bobref cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t i; char fname[512],*fstr,*symbol,str[65],str2[65]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 checktxid,txid,trigger; uint32_t t,addflag; uint64_t value; + int32_t i; char fname[512],*fstr,*symbol,str[65],str2[65],*txbytes,*retstr; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 checktxid,txid,trigger; uint32_t t,addflag; uint64_t value; item = cJSON_CreateObject(); array = cJSON_CreateArray(); printf("R.%u Q.%u\n",requestid,quoteid); @@ -2638,6 +2638,14 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } free_json(sentobj); } + if ( addflag != 0 && (txbytes= jstr(txobj,"tx")) != 0 ) + { + if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) + { + printf("RETSTR.(%s)\n",retstr); + free(retstr); + } + } } } //else printf("%s t %u\n",symbol,t); if ( addflag == 0 ) @@ -2648,7 +2656,11 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 else if ( strcmp(symbol,"BTC") == 0 ) BTCtotals[i] += value; free_json(txobj); - } else jaddi(array,txobj); + } + else + { + jaddi(array,txobj); + } } else free_json(txobj); } //else printf("no symbol\n"); free(fstr); From ab0cc67a4270cd12a53142ede787887268f88777 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 10:54:21 +0300 Subject: [PATCH 0177/2705] Test --- basilisk/basilisk_swap.c | 2 +- iguana/dpow/dpow_network.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index be32515fb..f76c13e68 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2642,7 +2642,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) { - printf("RETSTR.(%s)\n",retstr); + printf("%s RETSTR.(%s)\n",txbytes,retstr); free(retstr); } } diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index e5283d42a..c8ff26a98 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1088,11 +1088,13 @@ char *_dex_getbestblockhash(struct supernet_info *myinfo,char *symbol) char *_dex_sendrawtransaction(struct supernet_info *myinfo,char *symbol,char *signedtx) { - struct dex_request dexreq; + struct dex_request dexreq; char *retstr; memset(&dexreq,0,sizeof(dexreq)); safecopy(dexreq.name,symbol,sizeof(dexreq.name)); dexreq.func = 'S'; - return(_dex_sendrequeststr(myinfo,&dexreq,signedtx,0,3,"*")); + retstr = _dex_sendrequeststr(myinfo,&dexreq,signedtx,0,1,"*"); + printf("RET.(%s)\n",retstr); + return(retstr); } char *_dex_importaddress(struct supernet_info *myinfo,char *symbol,char *address) From 63eaf6b3fcbab065582bada3c823641dd1260b24 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 12:25:54 +0300 Subject: [PATCH 0178/2705] Test --- basilisk/basilisk.h | 6 ++++ basilisk/basilisk_swap.c | 61 ++++++++++++++++++++++++++++++++++++-- iguana/dpow/dpow_network.c | 2 +- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index b15b9032f..bfcb49aab 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -79,6 +79,12 @@ struct basilisk_swapinfo int32_t choosei,otherchoosei,cutverified,otherverifiedcut,numpubs,havestate,otherhavestate,pad2; uint8_t secretAm[20],secretBn[20]; uint8_t secretAm256[32],secretBn256[32]; + uint8_t userdata_aliceclaim[256],userdata_aliceclaimlen; + uint8_t userdata_alicereclaim[256],userdata_alicereclaimlen; + uint8_t userdata_alicespend[256],userdata_alicespendlen; + uint8_t userdata_bobspend[256],userdata_bobspendlen; + uint8_t userdata_bobreclaim[256],userdata_bobreclaimlen; + uint8_t userdata_bobrefund[256],userdata_bobrefundlen; }; struct basilisk_value { bits256 txid; int64_t value; int32_t height; int16_t vout; char coinaddr[64]; }; diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f76c13e68..7311560f8 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -715,6 +715,8 @@ int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_ if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_aliceclaim,userdata,len); + swap->I.userdata_aliceclaimlen = len; if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) { for (i=0; ibobdeposit.I.datalen; i++) @@ -735,6 +737,8 @@ int32_t basilisk_bobdeposit_refund(struct supernet_info *myinfo,struct basilisk_ { uint8_t userdata[512]; int32_t i,retval,len = 0; char str[65]; len = basilisk_swapuserdata(userdata,swap->I.privBn,0,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_bobrefund,userdata,len); + swap->I.userdata_bobrefundlen = len; if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0)) == 0 ) { for (i=0; ibobrefund.I.datalen; i++) @@ -758,6 +762,8 @@ int32_t basilisk_bobpayment_reclaim(struct supernet_info *myinfo,struct basilisk uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; printf("basilisk_bobpayment_reclaim\n"); len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_bobreclaim,userdata,len); + swap->I.userdata_bobreclaimlen = len; if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1)) == 0 ) { for (i=0; ibobreclaim.I.datalen; i++) @@ -778,6 +784,8 @@ int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,void *ptr,uint8_t * for (i=0; i<32; i++) revAm.bytes[i] = swap->I.privAm.bytes[31-i]; len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_alicespend,userdata,len); + swap->I.userdata_alicespendlen = len; char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) { @@ -807,6 +815,16 @@ int32_t basilisk_alicepayment_spend(struct supernet_info *myinfo,struct basilisk printf("alicepayment_spend\n"); swap->alicepayment.I.spendlen = basilisk_alicescript(swap->alicepayment.redeemscript,&swap->alicepayment.I.redeemlen,swap->alicepayment.spendscript,0,swap->alicepayment.I.destaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); printf("alicepayment_spend len.%d\n",swap->alicepayment.I.spendlen); + if ( swap->I.iambob == 0 ) + { + memcpy(swap->I.userdata_alicereclaim,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); + swap->I.userdata_alicereclaimlen = swap->alicepayment.I.spendlen; + } + else + { + memcpy(swap->I.userdata_bobspend,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); + swap->I.userdata_bobspendlen = swap->alicepayment.I.spendlen; + } if ( (retval= basilisk_rawtx_sign(myinfo,swap->alicecoin->longestchain,swap,dest,&swap->alicepayment,swap->I.privAm,&swap->I.privBn,0,0,1)) == 0 ) { for (i=0; iI.datalen; i++) @@ -1216,7 +1234,7 @@ int32_t basilisk_privBn_extract(struct supernet_info *myinfo,struct basilisk_swa } if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) { - char str[65]; printf("have privBn.%s\n",bits256_str(str,swap->I.privBn)); + char str[65]; printf("got privBn.%s\n",bits256_str(str,swap->I.privBn)); return(basilisk_alicepayment_spend(myinfo,swap,&swap->alicereclaim)); } return(-1); @@ -1230,7 +1248,7 @@ int32_t basilisk_privAm_extract(struct supernet_info *myinfo,struct basilisk_swa } if ( bits256_nonz(swap->I.privAm) != 0 && swap->bobspend.I.datalen == 0 ) { - char str[65]; printf("have privAm.%s\n",bits256_str(str,swap->I.privAm)); + char str[65]; printf("got privAm.%s\n",bits256_str(str,swap->I.privAm)); return(basilisk_alicepayment_spend(myinfo,swap,&swap->bobspend)); } return(-1); @@ -1700,6 +1718,18 @@ int32_t basilisk_verify_privkeys(struct supernet_info *myinfo,void *ptr,uint8_t return(errs); } +void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,int32_t scriptlen) +{ + int32_t i; char scriptstr[513]; + if ( scriptlen != 0 ) + { + for (i=0; itxbytes[i]); fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); } + for (i=0; i<2; i++) + if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) + fprintf(fp,"\",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); + if ( bits256_nonz(swap->I.privAm) != 0 ) + fprintf(fp,"\",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); + if ( bits256_nonz(swap->I.privBn) != 0 ) + fprintf(fp,"\",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); fprintf(fp,",\"lock\":%u",locktime); fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); if ( bits256_nonz(triggertxid) != 0 ) fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); + basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); + basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); + basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); + basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); + basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); + basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen); fprintf(fp,"}\n"); fclose(fp); } @@ -1762,7 +1805,14 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); } else if ( rawtx == &swap->bobspend ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); + } + else if ( rawtx == &swap->bobreclaim ) + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); + else if ( rawtx == &swap->bobrefund ) + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); } else { @@ -1772,7 +1822,12 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis } else if ( rawtx == &swap->alicespend ) { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); + } + else if ( rawtx == &swap->alicereclaim ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); } } @@ -2642,7 +2697,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) { - printf("%s RETSTR.(%s)\n",txbytes,retstr); + //printf("%s RETSTR.(%s)\n",txbytes,retstr); free(retstr); } } diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index c8ff26a98..0b7089332 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1093,7 +1093,7 @@ char *_dex_sendrawtransaction(struct supernet_info *myinfo,char *symbol,char *si safecopy(dexreq.name,symbol,sizeof(dexreq.name)); dexreq.func = 'S'; retstr = _dex_sendrequeststr(myinfo,&dexreq,signedtx,0,1,"*"); - printf("RET.(%s)\n",retstr); + //printf("RET.(%s)\n",retstr); return(retstr); } From ffe26dd334c00dcce7dcd9a2e0b63f97304e75c8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 13:13:07 +0300 Subject: [PATCH 0179/2705] test --- basilisk/basilisk.h | 2 +- basilisk/basilisk_swap.c | 24 ++++++++++++++++++++---- basilisk/jumblr.c | 6 +++--- iguana/DB/SWAPS/2809686646-301730922 | Bin 0 -> 168 bytes 4 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 iguana/DB/SWAPS/2809686646-301730922 diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index bfcb49aab..da79eebb4 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -60,7 +60,7 @@ struct basilisk_rawtx struct iguana_msgtx msgtx; struct basilisk_rawtxinfo I; struct iguana_info *coin; - char vinstr[8192]; + char vinstr[8192],p2shaddr[64]; cJSON *vins; uint8_t txbytes[16384],spendscript[512],redeemscript[1024],extraspace[4096]; }; diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 7311560f8..f0f8e80da 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -673,6 +673,7 @@ int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,str { decode_hex(rawtx->spendscript,hexlen,hexstr); rawtx->I.spendlen = hexlen; + bitcoin_address(rawtx->p2shaddr,rawtx->coin->chain->p2shtype,rawtx->spendscript,hexlen); if ( swap != 0 ) basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment retval = 0; @@ -875,6 +876,7 @@ int32_t basilisk_bobscripts_set(struct supernet_info *myinfo,struct basilisk_swa if ( depositflag == 0 ) { swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); + bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobpayment.I.rmd160,20); //for (i=0; ibobpayment.redeemlen; i++) // printf("%02x",swap->bobpayment.redeemscript[i]); //printf(" <- bobpayment.%d\n",i); @@ -910,6 +912,7 @@ int32_t basilisk_bobscripts_set(struct supernet_info *myinfo,struct basilisk_swa else { swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); + bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobdeposit.I.rmd160,20); if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) { for (i=0; i<3; i++) @@ -1509,12 +1512,12 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv } if ( strcmp("BTC",swap->bobcoin->symbol) == 0 ) { - swap->I.bobconfirms = (1 + sqrt(dstr(swap->I.bobsatoshis) * .1)); + swap->I.bobconfirms = (1*0 + sqrt(dstr(swap->I.bobsatoshis) * .1)); swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); } else if ( strcmp("BTC",swap->alicecoin->symbol) == 0 ) { - swap->I.aliceconfirms = (1 + sqrt(dstr(swap->I.alicesatoshis) * .1)); + swap->I.aliceconfirms = (1*0 + sqrt(dstr(swap->I.alicesatoshis) * .1)); swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); } else @@ -1552,13 +1555,13 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv basilisk_rawtx_setparms("bobreclaim",swap->I.req.quoteid,&swap->bobreclaim,swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,bobpub33,jumblrflag); swap->bobreclaim.I.suppress_pubkeys = 1; swap->bobreclaim.I.locktime = swap->I.started + swap->I.putduration + 1; - basilisk_rawtx_setparms("alicepayment",swap->I.req.quoteid,&swap->alicepayment,swap->alicecoin,swap->I.aliceconfirms,0,swap->I.alicesatoshis+swap->alicecoin->txfee,2,0,jumblrflag); basilisk_rawtx_setparms("bobspend",swap->I.req.quoteid,&swap->bobspend,swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,bobpub33,jumblrflag); swap->bobspend.I.suppress_pubkeys = 1; basilisk_rawtx_setparms("alicereclaim",swap->I.req.quoteid,&swap->alicereclaim,swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,alicepub33,jumblrflag); swap->alicereclaim.I.suppress_pubkeys = 1; printf("IAMBOB.%d\n",swap->I.iambob); + return(swap); } // end of alice/bob code @@ -1732,7 +1735,7 @@ void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,in void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx,int32_t locktime,bits256 triggertxid) { - char fname[512],str[65]; FILE *fp; int32_t i; + char fname[512],str[65],msigaddr[64]; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); if ( (fp= fopen(fname,"wb")) != 0 ) { @@ -1755,12 +1758,25 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); if ( bits256_nonz(triggertxid) != 0 ) fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); + if ( swap->bobdeposit.p2shaddr[0] != 0 ) + fprintf(fp,",\"Bdeposit\":\"%s\"",swap->bobdeposit.p2shaddr); + if ( swap->bobpayment.p2shaddr[0] != 0 ) + fprintf(fp,",\"Bpayment\":\"%s\"",swap->bobpayment.p2shaddr); + if ( swap->alicepayment.p2shaddr[0] != 0 ) + fprintf(fp,",\"Apayment\":\"%s\"",swap->alicepayment.p2shaddr); + if ( swap->bobdeposit.p2shaddr[0] != 0 ) + fprintf(fp,",\"deposit\":\"%s\"",swap->bobdeposit.p2shaddr); basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen); + if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) + { + basilisk_alicescript(redeemscript,&len,script,0,msigaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + fprintf(fp,"\",\"Adest\":\"%s\"",msigaddr); + } fprintf(fp,"}\n"); fclose(fp); } diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index f6bcdd688..9bb346163 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -727,7 +727,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 if ( coin->CMCname[0] != 0 ) jumblr_DEXupdate(myinfo,coin,coin->symbol,coin->CMCname,kmdcoin->DEXinfo.btcprice,kmdcoin->DEXinfo.avail); } - if ( myinfo->IAMLP == 0 && kmdcoin->DEXinfo.btcprice > SMALLVAL ) + if ( myinfo->numswaps == 0 && myinfo->IAMLP == 0 && kmdcoin->DEXinfo.btcprice > SMALLVAL ) { double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); @@ -749,7 +749,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",1./(1.015 * kmdcoin->DEXinfo.btcprice)); + jaddnum(vals,"minprice",1./(1.02 * kmdcoin->DEXinfo.btcprice)); jaddnum(vals,"usejumblr",1); jaddnum(vals,"DEXselector",1); memset(hash.bytes,0,sizeof(hash)); @@ -781,7 +781,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",vol); //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.015); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.02); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.KMDpending += vol; diff --git a/iguana/DB/SWAPS/2809686646-301730922 b/iguana/DB/SWAPS/2809686646-301730922 new file mode 100644 index 0000000000000000000000000000000000000000..5ba7d059d15c1b3bd368b291139833d552ac9692 GIT binary patch literal 168 zcmcZ*zG>cSKK4T`M!(*shrhp|z}eJrSU0Tb>%HKkT>DR!mt|Ef?_zotk;U^za4C>h z-7Uoc0*ezw_c8(L9`)Z}+g`n0P=0fE+ry4?H_f8s6*z?V>=4hY{H@Dx;b7fg$QYaA zwaRDCxp$8`cP`~U`KEsT>NXkQh@usbTU^qdLY%?odHcG6Y1d4 Date: Sun, 9 Apr 2017 13:14:27 +0300 Subject: [PATCH 0180/2705] Test --- iguana/DB/SWAPS/2809686646-301730922 | Bin 168 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 iguana/DB/SWAPS/2809686646-301730922 diff --git a/iguana/DB/SWAPS/2809686646-301730922 b/iguana/DB/SWAPS/2809686646-301730922 deleted file mode 100644 index 5ba7d059d15c1b3bd368b291139833d552ac9692..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168 zcmcZ*zG>cSKK4T`M!(*shrhp|z}eJrSU0Tb>%HKkT>DR!mt|Ef?_zotk;U^za4C>h z-7Uoc0*ezw_c8(L9`)Z}+g`n0P=0fE+ry4?H_f8s6*z?V>=4hY{H@Dx;b7fg$QYaA zwaRDCxp$8`cP`~U`KEsT>NXkQh@usbTU^qdLY%?odHcG6Y1d4 Date: Sun, 9 Apr 2017 13:27:28 +0300 Subject: [PATCH 0181/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index e0bb44855..873950923 100755 --- a/.gitignore +++ b/.gitignore @@ -282,3 +282,5 @@ iguana/DB/SWAPS/3408402932-4088991610 iguana/DB/SWAPS/3772541120-2007204891 iguana/DB/SWAPS/784303571-1929722462 + +iguana/DB/SWAPS/3221116355-3522779294 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f0f8e80da..21f0bb3ce 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1164,7 +1164,7 @@ int32_t basilisk_swapget(struct supernet_info *myinfo,struct basilisk_swap *swap if ( swap->subsock >= 0 ) nn_close(swap->subsock), swap->subsock = -1; swap->connected = 0; - basilisk_psockinit(myinfo,swap,0); + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); } mp = &swap->messages[i]; if ( msgbits != 0x80000000 ) @@ -1199,7 +1199,7 @@ uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *sw nn_close(swap->pushsock), swap->pushsock = -1; if ( swap->subsock >= 0 ) nn_close(swap->subsock), swap->subsock = -1; - swap->connected = 0; + swap->connected = swap->I.iambob != 0 ? -1 : 0; } } //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); @@ -2232,7 +2232,7 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, return; } sprintf(keystr,"%08x-%08x",swap->I.req.requestid,swap->I.req.quoteid); - if ( (retstr= _dex_kvsearch(myinfo,"KV",keystr)) != 0 ) + if ( swap->connected == 0 && (retstr= _dex_kvsearch(myinfo,"KV",keystr)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { @@ -2258,7 +2258,7 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, printf("KVsearch.(%s) connected.%d socks.(%d %d)\n",retstr,swap->connected,swap->pushsock,swap->subsock); free(retstr); } - if ( swap->connected == 0 && amlp != 0 ) + if ( swap->connected <= 0 && amlp != 0 ) { if ( (retstr= _dex_psock(myinfo,"{}")) != 0 ) { @@ -2349,7 +2349,7 @@ void basilisk_swaploop(void *_swap) dex_channelsend(myinfo,swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); if ( swap->connected == 0 ) basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); - if ( swap->connected != 0 ) + if ( swap->connected > 0 ) { printf("A r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); basilisk_sendstate(myinfo,swap,data,maxlen); From 507058a1e9135d6f70f69888dac6c2b6d87aa1f0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 13:49:16 +0300 Subject: [PATCH 0182/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 18 +++++++----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 873950923..98cef6708 100755 --- a/.gitignore +++ b/.gitignore @@ -284,3 +284,5 @@ iguana/DB/SWAPS/3772541120-2007204891 iguana/DB/SWAPS/784303571-1929722462 iguana/DB/SWAPS/3221116355-3522779294 + +iguana/DB/SWAPS/1703578312-1139459191 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 21f0bb3ce..d784cc97e 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -876,7 +876,7 @@ int32_t basilisk_bobscripts_set(struct supernet_info *myinfo,struct basilisk_swa if ( depositflag == 0 ) { swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); - bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobpayment.I.rmd160,20); + bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); //for (i=0; ibobpayment.redeemlen; i++) // printf("%02x",swap->bobpayment.redeemscript[i]); //printf(" <- bobpayment.%d\n",i); @@ -912,7 +912,7 @@ int32_t basilisk_bobscripts_set(struct supernet_info *myinfo,struct basilisk_swa else { swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); - bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobdeposit.I.rmd160,20); + bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) { for (i=0; i<3; i++) @@ -1762,21 +1762,17 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,",\"Bdeposit\":\"%s\"",swap->bobdeposit.p2shaddr); if ( swap->bobpayment.p2shaddr[0] != 0 ) fprintf(fp,",\"Bpayment\":\"%s\"",swap->bobpayment.p2shaddr); - if ( swap->alicepayment.p2shaddr[0] != 0 ) - fprintf(fp,",\"Apayment\":\"%s\"",swap->alicepayment.p2shaddr); - if ( swap->bobdeposit.p2shaddr[0] != 0 ) - fprintf(fp,",\"deposit\":\"%s\"",swap->bobdeposit.p2shaddr); + if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) + { + basilisk_alicescript(redeemscript,&len,script,0,msigaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + fprintf(fp,"\",\"Apayment\":\"%s\"",msigaddr); + } basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen); - if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) - { - basilisk_alicescript(redeemscript,&len,script,0,msigaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); - fprintf(fp,"\",\"Adest\":\"%s\"",msigaddr); - } fprintf(fp,"}\n"); fclose(fp); } From 9038dc7ad3717c8d55d44364bb797d30f5ad6058 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 14:10:47 +0300 Subject: [PATCH 0183/2705] Test --- .gitignore | 2 + basilisk/basilisk_swap.c | 213 ++++++++++++++++++++------------------- 2 files changed, 114 insertions(+), 101 deletions(-) diff --git a/.gitignore b/.gitignore index 98cef6708..b321cb4e5 100755 --- a/.gitignore +++ b/.gitignore @@ -286,3 +286,5 @@ iguana/DB/SWAPS/784303571-1929722462 iguana/DB/SWAPS/3221116355-3522779294 iguana/DB/SWAPS/1703578312-1139459191 + +iguana/DB/SWAPS/1192374491-1050242469 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index d784cc97e..76072d688 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -710,11 +710,116 @@ int32_t basilisk_swapuserdata(uint8_t *userdata,bits256 privkey,int32_t ifpath,b OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF*/ +void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,int32_t scriptlen) +{ + int32_t i; char scriptstr[513]; + if ( scriptlen != 0 ) + { + for (i=0; iI.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); + if ( rawtx->I.datalen > 0 ) + { + fprintf(fp,",\"tx\":\""); + for (i=0; iI.datalen; i++) + fprintf(fp,"%02x",rawtx->txbytes[i]); + fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); + } + for (i=0; i<2; i++) + if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) + fprintf(fp,"\",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); + if ( bits256_nonz(swap->I.privAm) != 0 ) + fprintf(fp,"\",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); + if ( bits256_nonz(swap->I.privBn) != 0 ) + fprintf(fp,"\",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); + fprintf(fp,",\"lock\":%u",locktime); + fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); + if ( bits256_nonz(triggertxid) != 0 ) + fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); + if ( swap->bobdeposit.p2shaddr[0] != 0 ) + fprintf(fp,",\"Bdeposit\":\"%s\"",swap->bobdeposit.p2shaddr); + if ( swap->bobpayment.p2shaddr[0] != 0 ) + fprintf(fp,",\"Bpayment\":\"%s\"",swap->bobpayment.p2shaddr); + if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) + { + basilisk_alicescript(redeemscript,&len,script,0,msigaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + fprintf(fp,"\",\"Apayment\":\"%s\"",msigaddr); + } + basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); + basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); + basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); + basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); + basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); + basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen); + fprintf(fp,"}\n"); + fclose(fp); + } +} + +void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +{ + bits256 triggertxid; + memset(triggertxid.bytes,0,sizeof(triggertxid)); + if ( rawtx == &swap->myfee ) + basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); + if ( swap->I.iambob != 0 ) + { + if ( rawtx == &swap->bobdeposit ) + { + basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + } + else if ( rawtx == &swap->bobpayment ) + { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); + } + else if ( rawtx == &swap->bobspend ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); + } + else if ( rawtx == &swap->bobreclaim ) + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); + else if ( rawtx == &swap->bobrefund ) + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + } + else + { + if ( rawtx == &swap->alicepayment ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + } + else if ( rawtx == &swap->alicespend ) + { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); + } + else if ( rawtx == &swap->alicereclaim ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); + } + } +} + int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) { uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { + basilisk_dontforget_update(myinfo,swap,&swap->bobdeposit); len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_aliceclaim,userdata,len); swap->I.userdata_aliceclaimlen = len; @@ -782,6 +887,7 @@ int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,void *ptr,uint8_t * memset(revAm.bytes,0,sizeof(revAm)); if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { + basilisk_dontforget_update(myinfo,swap,&swap->bobpayment); for (i=0; i<32; i++) revAm.bytes[i] = swap->I.privAm.bytes[31-i]; len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); @@ -843,7 +949,10 @@ int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t { struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->alicecoin->longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) + { + basilisk_dontforget_update(myinfo,swap,&swap->alicepayment); return(0); + } else return(-1); } @@ -995,7 +1104,7 @@ void basilisk_swapgotdata(struct supernet_info *myinfo,struct basilisk_swap *swa for (i=0; inummessages; i++) if ( crc32 == swap->messages[i].crc32 && msgbits == swap->messages[i].msgbits && bits256_cmp(srchash,swap->messages[i].srchash) == 0 && bits256_cmp(desthash,swap->messages[i].desthash) == 0 ) return; - printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); + //printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); swap->messages = realloc(swap->messages,sizeof(*swap->messages) * (swap->nummessages + 1)); mp = &swap->messages[swap->nummessages++]; mp->crc32 = crc32; @@ -1721,66 +1830,9 @@ int32_t basilisk_verify_privkeys(struct supernet_info *myinfo,void *ptr,uint8_t return(errs); } -void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,int32_t scriptlen) -{ - int32_t i; char scriptstr[513]; - if ( scriptlen != 0 ) - { - for (i=0; iI.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); - if ( (fp= fopen(fname,"wb")) != 0 ) - { - fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); - if ( rawtx->I.datalen > 0 ) - { - fprintf(fp,",\"tx\":\""); - for (i=0; iI.datalen; i++) - fprintf(fp,"%02x",rawtx->txbytes[i]); - fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); - } - for (i=0; i<2; i++) - if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) - fprintf(fp,"\",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); - if ( bits256_nonz(swap->I.privAm) != 0 ) - fprintf(fp,"\",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); - if ( bits256_nonz(swap->I.privBn) != 0 ) - fprintf(fp,"\",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); - fprintf(fp,",\"lock\":%u",locktime); - fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); - if ( bits256_nonz(triggertxid) != 0 ) - fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); - if ( swap->bobdeposit.p2shaddr[0] != 0 ) - fprintf(fp,",\"Bdeposit\":\"%s\"",swap->bobdeposit.p2shaddr); - if ( swap->bobpayment.p2shaddr[0] != 0 ) - fprintf(fp,",\"Bpayment\":\"%s\"",swap->bobpayment.p2shaddr); - if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) - { - basilisk_alicescript(redeemscript,&len,script,0,msigaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); - fprintf(fp,"\",\"Apayment\":\"%s\"",msigaddr); - } - basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); - basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); - basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); - basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); - basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); - basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen); - fprintf(fp,"}\n"); - fclose(fp); - } -} - uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) { - uint8_t sendbuf[32768]; int32_t sendlen; bits256 triggertxid; + uint8_t sendbuf[32768]; int32_t sendlen; if ( basilisk_swapdata_rawtx(myinfo,swap,data,maxlen,rawtx) != 0 ) { if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) @@ -1801,48 +1853,7 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis memcpy(&sendbuf[sendlen],rawtx->redeemscript,rawtx->I.redeemlen); sendlen += rawtx->I.redeemlen; } - memset(triggertxid.bytes,0,sizeof(triggertxid)); - if ( rawtx == &swap->myfee ) - basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); - if ( swap->I.iambob != 0 ) - { - if ( rawtx == &swap->bobdeposit ) - { - basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); - } - else if ( rawtx == &swap->bobpayment ) - { - basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); - } - else if ( rawtx == &swap->bobspend ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); - } - else if ( rawtx == &swap->bobreclaim ) - basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); - else if ( rawtx == &swap->bobrefund ) - basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); - } - else - { - if ( rawtx == &swap->alicepayment ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - } - else if ( rawtx == &swap->alicespend ) - { - basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); - } - else if ( rawtx == &swap->alicereclaim ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); - } - } + basilisk_dontforget_update(myinfo,swap,rawtx); //printf("sendlen.%d datalen.%d redeemlen.%d\n",sendlen,rawtx->datalen,rawtx->redeemlen); if ( suppress_swapsend == 0 ) return(basilisk_swapsend(myinfo,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs)); From f9c249b9d9daa54f2fbd7c153d49395fec3e7654 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 9 Apr 2017 14:28:16 +0300 Subject: [PATCH 0184/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b321cb4e5..59f2efbbd 100755 --- a/.gitignore +++ b/.gitignore @@ -288,3 +288,5 @@ iguana/DB/SWAPS/3221116355-3522779294 iguana/DB/SWAPS/1703578312-1139459191 iguana/DB/SWAPS/1192374491-1050242469 + +iguana/DB/SWAPS/4244307493-1619487751 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 76072d688..0736a486f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -773,7 +773,7 @@ void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swa memset(triggertxid.bytes,0,sizeof(triggertxid)); if ( rawtx == &swap->myfee ) basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); - if ( swap->I.iambob != 0 ) + //if ( swap->I.iambob != 0 ) { if ( rawtx == &swap->bobdeposit ) { @@ -795,7 +795,7 @@ void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swa else if ( rawtx == &swap->bobrefund ) basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); } - else + //else { if ( rawtx == &swap->alicepayment ) { From 95df5c98cf8ffa9bc0b342a3615b4ff5c6da6749 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 10 Apr 2017 15:23:36 +0300 Subject: [PATCH 0185/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 29 ++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 59f2efbbd..edc6f8020 100755 --- a/.gitignore +++ b/.gitignore @@ -290,3 +290,5 @@ iguana/DB/SWAPS/1703578312-1139459191 iguana/DB/SWAPS/1192374491-1050242469 iguana/DB/SWAPS/4244307493-1619487751 + +iguana/DB/SWAPS/3213119432-553439289 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0736a486f..81b7c50ad 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -685,6 +685,16 @@ int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,str return(retval); } +void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) +{ + cJSON *txobj; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; int32_t suppress_pubkeys = 0; + if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + free_json(txobj); + } +} + int32_t basilisk_swapuserdata(uint8_t *userdata,bits256 privkey,int32_t ifpath,bits256 signpriv,uint8_t *redeemscript,int32_t redeemlen) { int32_t i,len = 0; @@ -724,8 +734,9 @@ void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,in void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx,int32_t locktime,bits256 triggertxid) { - char fname[512],str[65],msigaddr[64]; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; + char fname[512],str[65],coinaddr[64]; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); + coinaddr[0] = 0; if ( (fp= fopen(fname,"wb")) != 0 ) { fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); @@ -735,6 +746,14 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap for (i=0; iI.datalen; i++) fprintf(fp,"%02x",rawtx->txbytes[i]); fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); + if ( rawtx == &swap->bobdeposit || rawtx == &swap->bobpayment ) + { + basilisk_swap_coinaddr(myinfo,swap,swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); + if ( coinaddr[0] != 0 ) + { + fprintf(fp,",\"%s\":\"%s\"",rawtx == &swap->bobdeposit ? "Bdeposit" : "Bpayment",coinaddr); + } + } } for (i=0; i<2; i++) if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) @@ -747,14 +766,10 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); if ( bits256_nonz(triggertxid) != 0 ) fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); - if ( swap->bobdeposit.p2shaddr[0] != 0 ) - fprintf(fp,",\"Bdeposit\":\"%s\"",swap->bobdeposit.p2shaddr); - if ( swap->bobpayment.p2shaddr[0] != 0 ) - fprintf(fp,",\"Bpayment\":\"%s\"",swap->bobpayment.p2shaddr); if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) { - basilisk_alicescript(redeemscript,&len,script,0,msigaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); - fprintf(fp,"\",\"Apayment\":\"%s\"",msigaddr); + basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + fprintf(fp,"\",\"Apayment\":\"%s\"",coinaddr); } basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); From 31ac3e1e53081a2fb3e53c976fa27f76774e2c45 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 10 Apr 2017 15:58:36 +0300 Subject: [PATCH 0186/2705] Test --- .gitignore | 4 ++++ basilisk/basilisk_swap.c | 13 +++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index edc6f8020..febd7f310 100755 --- a/.gitignore +++ b/.gitignore @@ -292,3 +292,7 @@ iguana/DB/SWAPS/1192374491-1050242469 iguana/DB/SWAPS/4244307493-1619487751 iguana/DB/SWAPS/3213119432-553439289 + +iguana/DB/SWAPS/3854521391-612984356 + +iguana/DB/SWAPS/3611231334-1171171579 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 81b7c50ad..22c18b1d6 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -687,10 +687,19 @@ int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,str void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) { - cJSON *txobj; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; int32_t suppress_pubkeys = 0; + cJSON *txobj,*vouts,*vout,*addresses; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { - char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) + { + vout = jitem(vouts,0); + if ( (addresses= jarray(&m,vout,"addresses")) != 0 && (addr= jstri(addresses,0)) != 0 ) + { + safecopy(coinaddr,addr,64); + printf("extracted.(%s)\n",coinaddr); + } + } free_json(txobj); } } From 63c00bb6539adf521ba076388a9826e68f865462 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 10 Apr 2017 16:06:44 +0300 Subject: [PATCH 0187/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index febd7f310..0fbdfff1f 100755 --- a/.gitignore +++ b/.gitignore @@ -296,3 +296,5 @@ iguana/DB/SWAPS/3213119432-553439289 iguana/DB/SWAPS/3854521391-612984356 iguana/DB/SWAPS/3611231334-1171171579 + +iguana/DB/SWAPS/1505015888-2633757068 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 22c18b1d6..ee9923147 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -687,17 +687,21 @@ int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,str void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) { - cJSON *txobj,*vouts,*vout,*addresses; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; + cJSON *txobj,*vouts,*vout,*addresses,*item; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) { vout = jitem(vouts,0); - if ( (addresses= jarray(&m,vout,"addresses")) != 0 && (addr= jstri(addresses,0)) != 0 ) + if ( (addresses= jarray(&m,vout,"addresses")) != 0 ) { - safecopy(coinaddr,addr,64); - printf("extracted.(%s)\n",coinaddr); + item = jitem(addresses,0); + if ( (addr= jstr(item,0)) != 0 ) + { + safecopy(coinaddr,addr,64); + printf("extracted.(%s)\n",coinaddr); + } } } free_json(txobj); From de757faa7d7749ae6ac96bd51e8797c19a999d59 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 10 Apr 2017 16:12:03 +0300 Subject: [PATCH 0188/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0fbdfff1f..a3f55af61 100755 --- a/.gitignore +++ b/.gitignore @@ -298,3 +298,5 @@ iguana/DB/SWAPS/3854521391-612984356 iguana/DB/SWAPS/3611231334-1171171579 iguana/DB/SWAPS/1505015888-2633757068 + +iguana/DB/SWAPS/3430299677-3087427598 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ee9923147..a44448fab 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -690,13 +690,15 @@ void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *s cJSON *txobj,*vouts,*vout,*addresses,*item; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { - //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) { vout = jitem(vouts,0); + printf("VOUT.(%s)\n",jprint(vout,0)); if ( (addresses= jarray(&m,vout,"addresses")) != 0 ) { item = jitem(addresses,0); + printf("item.(%s)\n",jprint(item,0)); if ( (addr= jstr(item,0)) != 0 ) { safecopy(coinaddr,addr,64); From a30a668ee14339ed68efe3cfd2a862a91989f8a3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 10 Apr 2017 16:15:50 +0300 Subject: [PATCH 0189/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a3f55af61..6c933d9cb 100755 --- a/.gitignore +++ b/.gitignore @@ -300,3 +300,5 @@ iguana/DB/SWAPS/3611231334-1171171579 iguana/DB/SWAPS/1505015888-2633757068 iguana/DB/SWAPS/3430299677-3087427598 + +iguana/DB/SWAPS/2275651697-591036515 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a44448fab..8e8eb7319 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -687,7 +687,7 @@ int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,str void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) { - cJSON *txobj,*vouts,*vout,*addresses,*item; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; + cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); @@ -695,7 +695,7 @@ void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *s { vout = jitem(vouts,0); printf("VOUT.(%s)\n",jprint(vout,0)); - if ( (addresses= jarray(&m,vout,"addresses")) != 0 ) + if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) { item = jitem(addresses,0); printf("item.(%s)\n",jprint(item,0)); From 3196f245df56e38796ad782bd6f80ff7009f6927 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 10 Apr 2017 16:37:54 +0300 Subject: [PATCH 0190/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 16 +++++++++++----- iguana/iguana777.h | 1 + 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 6c933d9cb..bab559bfd 100755 --- a/.gitignore +++ b/.gitignore @@ -302,3 +302,5 @@ iguana/DB/SWAPS/1505015888-2633757068 iguana/DB/SWAPS/3430299677-3087427598 iguana/DB/SWAPS/2275651697-591036515 + +iguana/DB/SWAPS/2180638961-896149751 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 8e8eb7319..7106a2c49 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -690,19 +690,19 @@ void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *s cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { - char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) { vout = jitem(vouts,0); - printf("VOUT.(%s)\n",jprint(vout,0)); + //printf("VOUT.(%s)\n",jprint(vout,0)); if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) { item = jitem(addresses,0); - printf("item.(%s)\n",jprint(item,0)); + //printf("item.(%s)\n",jprint(item,0)); if ( (addr= jstr(item,0)) != 0 ) { safecopy(coinaddr,addr,64); - printf("extracted.(%s)\n",coinaddr); + //printf("extracted.(%s)\n",coinaddr); } } } @@ -766,10 +766,16 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap basilisk_swap_coinaddr(myinfo,swap,swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); if ( coinaddr[0] != 0 ) { - fprintf(fp,",\"%s\":\"%s\"",rawtx == &swap->bobdeposit ? "Bdeposit" : "Bpayment",coinaddr); + if ( rawtx == &swap->bobdeposit ) + safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); + else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); } } } + if ( swap->Bdeposit[0] != 0 ) + fprintf(fp,",\"%s\":\"%s\"","Bdeposit",swap->Bdeposit); + if ( swap->Bpayment[0] != 0 ) + fprintf(fp,",\"%s\":\"%s\"","Bpayment",swap->Bpayment); for (i=0; i<2; i++) if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) fprintf(fp,"\",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); diff --git a/iguana/iguana777.h b/iguana/iguana777.h index d17555d43..f83fe19c5 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -189,6 +189,7 @@ struct basilisk_swap struct basilisk_rawtx bobdeposit,bobpayment,alicepayment,myfee,otherfee,aliceclaim,alicespend,bobreclaim,bobspend,bobrefund,alicereclaim; bits256 privkeys[INSTANTDEX_DECKSIZE]; struct basilisk_swapmessage *messages; int32_t nummessages; + char Bdeposit[64],Bpayment[64]; uint64_t otherdeck[INSTANTDEX_DECKSIZE][2],deck[INSTANTDEX_DECKSIZE][2]; uint8_t persistent_pubkey33[33],pad[15],verifybuf[65536]; From 63bdc5fe9b289eb8f287a2ff7a068e3a4d24a0ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 10 Apr 2017 16:58:49 +0300 Subject: [PATCH 0191/2705] Test --- .gitignore | 4 ++++ basilisk/basilisk_swap.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bab559bfd..62c1f4100 100755 --- a/.gitignore +++ b/.gitignore @@ -304,3 +304,7 @@ iguana/DB/SWAPS/3430299677-3087427598 iguana/DB/SWAPS/2275651697-591036515 iguana/DB/SWAPS/2180638961-896149751 + +iguana/DB/SWAPS/2349180798-2344225091 + +iguana/DB/SWAPS/1395238080-4120976642 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 7106a2c49..4786d0b20 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2315,7 +2315,7 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, if ( nn_connect(pushsock,pushaddr) >= 0 && nn_connect(subsock,subaddr) >= 0 ) { swap->connected = 1; - sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\"}",pushaddr,subaddr); + sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f]}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); datalen = (int32_t)strlen((char *)data) + 1; printf("datalen.%d (%s)\n",datalen,(char *)data); init_hexbytes_noT(databuf,data,datalen); From d7d90599ea61624142d776ae9ebc62b597eb83f2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 10 Apr 2017 17:35:11 +0300 Subject: [PATCH 0192/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 1 + 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 62c1f4100..b47852ed9 100755 --- a/.gitignore +++ b/.gitignore @@ -308,3 +308,5 @@ iguana/DB/SWAPS/2180638961-896149751 iguana/DB/SWAPS/2349180798-2344225091 iguana/DB/SWAPS/1395238080-4120976642 + +iguana/DB/SWAPS/1914406677-1452353494 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 4786d0b20..249086275 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1345,6 +1345,7 @@ uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *sw if ( swap->subsock >= 0 ) nn_close(swap->subsock), swap->subsock = -1; swap->connected = swap->I.iambob != 0 ? -1 : 0; + swap->aborted = (uint32_t)time(NULL); } } //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); From af162c15a78536d211dd3a4b52f62719b157c753 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 11 Apr 2017 09:09:08 +0300 Subject: [PATCH 0193/2705] Test --- basilisk/basilisk.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index da79eebb4..044ff75fa 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -16,8 +16,8 @@ #ifndef H_BASILISK_H #define H_BASILISK_H -#define BASILISK_DISABLESENDTX -#define BASILISK_DISABLEWAITTX +//#define BASILISK_DISABLESENDTX +//#define BASILISK_DISABLEWAITTX #include "../iguana/iguana777.h" From 79ba974215270333f4ec164d419163ac3fea38cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 11 Apr 2017 09:28:44 +0300 Subject: [PATCH 0194/2705] Test --- basilisk/jumblr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 9bb346163..1d31bd20b 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -749,7 +749,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",1./(1.02 * kmdcoin->DEXinfo.btcprice)); + jaddnum(vals,"minprice",1./(1.03 * kmdcoin->DEXinfo.btcprice)); jaddnum(vals,"usejumblr",1); jaddnum(vals,"DEXselector",1); memset(hash.bytes,0,sizeof(hash)); @@ -781,7 +781,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",vol); //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.02); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.03); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.KMDpending += vol; From 1f2edd02c7483f3dd540168048fda75d8498c45c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 11 Apr 2017 19:05:24 +0300 Subject: [PATCH 0195/2705] Test --- .gitignore | 4 + basilisk/basilisk.h | 4 +- basilisk/basilisk_swap.c | 341 ++++++++++++++++++++++++++++++--------- 3 files changed, 270 insertions(+), 79 deletions(-) diff --git a/.gitignore b/.gitignore index b47852ed9..cde494c19 100755 --- a/.gitignore +++ b/.gitignore @@ -310,3 +310,7 @@ iguana/DB/SWAPS/2349180798-2344225091 iguana/DB/SWAPS/1395238080-4120976642 iguana/DB/SWAPS/1914406677-1452353494 + +iguana/DB/SWAPS/3193054754-2514575257 + +iguana/DB/SWAPS/3004995589-1950720855 diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index 044ff75fa..da79eebb4 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -16,8 +16,8 @@ #ifndef H_BASILISK_H #define H_BASILISK_H -//#define BASILISK_DISABLESENDTX -//#define BASILISK_DISABLEWAITTX +#define BASILISK_DISABLESENDTX +#define BASILISK_DISABLEWAITTX #include "../iguana/iguana777.h" diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 249086275..448dadef4 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -757,7 +757,10 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); if ( rawtx->I.datalen > 0 ) { - fprintf(fp,",\"tx\":\""); + fprintf(fp,",\"dest33\":\""); + for (i=0; i<33; i++) + fprintf(fp,"%02x",swap->persistent_pubkey33[i]); + fprintf(fp,"\",\"tx\":\""); for (i=0; iI.datalen; i++) fprintf(fp,"%02x",rawtx->txbytes[i]); fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); @@ -783,6 +786,10 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,"\",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); if ( bits256_nonz(swap->I.privBn) != 0 ) fprintf(fp,"\",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); + fprintf(fp,",\"expiration\":%u",swap->I.expiration); + fprintf(fp,",\"iambob\":%d",swap->I.iambob); + fprintf(fp,",\"bobcoin\":\"%s\"",swap->bobcoin->symbol); + fprintf(fp,",\"alicecoin\":\"%s\"",swap->alicecoin->symbol); fprintf(fp,",\"lock\":%u",locktime); fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); if ( bits256_nonz(triggertxid) != 0 ) @@ -801,6 +808,38 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,"}\n"); fclose(fp); } + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%x,\"otherstate\":%x,\"expiration\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration); + if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + fprintf(fp,",\"Bdeposit\":\"%s\"",bits256_str(str,swap->bobdeposit.I.actualtxid)); + if ( bits256_nonz(swap->bobrefund.I.actualtxid) != 0 ) + fprintf(fp,",\"Brefund\":\"%s\"",bits256_str(str,swap->bobrefund.I.actualtxid)); + if ( bits256_nonz(swap->aliceclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Aclaim\":\"%s\"",bits256_str(str,swap->aliceclaim.I.actualtxid)); + + if ( bits256_nonz(swap->bobpayment.I.actualtxid) != 0 ) + fprintf(fp,",\"Bpayment\":\"%s\"",bits256_str(str,swap->bobpayment.I.actualtxid)); + if ( bits256_nonz(swap->alicespend.I.actualtxid) != 0 ) + fprintf(fp,",\"Aspend\":\"%s\"",bits256_str(str,swap->alicespend.I.actualtxid)); + if ( bits256_nonz(swap->bobreclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Breclaim\":\"%s\"",bits256_str(str,swap->bobreclaim.I.actualtxid)); + + if ( bits256_nonz(swap->alicepayment.I.actualtxid) != 0 ) + fprintf(fp,",\"Apayment\":\"%s\"",bits256_str(str,swap->alicepayment.I.actualtxid)); + if ( bits256_nonz(swap->bobspend.I.actualtxid) != 0 ) + fprintf(fp,",\"Bspend\":\"%s\"",bits256_str(str,swap->bobspend.I.actualtxid)); + if ( bits256_nonz(swap->alicereclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Areclaim\":\"%s\"",bits256_str(str,swap->alicereclaim.I.actualtxid)); + + if ( bits256_nonz(swap->otherfee.I.actualtxid) != 0 ) + fprintf(fp,",\"otherfee\":\"%s\"",bits256_str(str,swap->otherfee.I.actualtxid)); + if ( bits256_nonz(swap->myfee.I.actualtxid) != 0 ) + fprintf(fp,",\"myfee\":\"%s\"",bits256_str(str,swap->myfee.I.actualtxid)); + fprintf(fp,"}\n"); + fclose(fp); + } } void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) @@ -809,45 +848,46 @@ void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swa memset(triggertxid.bytes,0,sizeof(triggertxid)); if ( rawtx == &swap->myfee ) basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); - //if ( swap->I.iambob != 0 ) + else if ( rawtx == &swap->otherfee ) + basilisk_dontforget(myinfo,swap,&swap->otherfee,0,triggertxid); + else if ( rawtx == &swap->bobdeposit ) { - if ( rawtx == &swap->bobdeposit ) - { - basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); - } - else if ( rawtx == &swap->bobpayment ) - { - basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); - } - else if ( rawtx == &swap->bobspend ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); - } - else if ( rawtx == &swap->bobreclaim ) - basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); - else if ( rawtx == &swap->bobrefund ) - basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); } - //else + else if ( rawtx == &swap->bobrefund ) + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + else if ( rawtx == &swap->aliceclaim ) { - if ( rawtx == &swap->alicepayment ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - } - else if ( rawtx == &swap->alicespend ) - { - basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); - } - else if ( rawtx == &swap->alicereclaim ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); - } + basilisk_dontforget(myinfo,swap,&swap->bobrefund,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->aliceclaim,0,swap->bobrefund.I.actualtxid); + } + else if ( rawtx == &swap->alicepayment ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + } + else if ( rawtx == &swap->bobspend ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); + } + else if ( rawtx == &swap->alicereclaim ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); + } + else if ( rawtx == &swap->bobpayment ) + { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); + } + else if ( rawtx == &swap->alicespend ) + { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); } + else if ( rawtx == &swap->bobreclaim ) + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); } int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) @@ -1161,7 +1201,7 @@ void basilisk_swapgotdata(struct supernet_info *myinfo,struct basilisk_swap *swa FILE *basilisk_swap_save(struct supernet_info *myinfo,struct basilisk_swap *swap,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { - FILE *fp=0; char fname[512]; + FILE *fp=0; /*char fname[512]; sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,rp->requestid,rp->quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"rb+")) == 0 ) { @@ -1176,7 +1216,7 @@ FILE *basilisk_swap_save(struct supernet_info *myinfo,struct basilisk_swap *swap } else if ( reinit != 0 ) { - } + }*/ return(fp); } @@ -1480,12 +1520,9 @@ void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx * rawtx->I.vouttype = vouttype; // 0 -> fee, 1 -> std, 2 -> 2of2, 3 -> bobpayment, 4 -> bobdeposit if ( rawtx->I.vouttype == 0 ) { - if ( jumblrflag == 0 ) - { - if ( strcmp(coin->symbol,"BTC") == 0 && (quoteid % 10) == 0 ) - decode_hex(rawtx->I.rmd160,20,TIERNOLAN_RMD160); - else decode_hex(rawtx->I.rmd160,20,INSTANTDEX_RMD160); - } else decode_hex(rawtx->I.rmd160,20,JUMBLR_RMD160); + if ( strcmp(coin->symbol,"BTC") == 0 && (quoteid % 10) == 0 ) + decode_hex(rawtx->I.rmd160,20,TIERNOLAN_RMD160); + else decode_hex(rawtx->I.rmd160,20,INSTANTDEX_RMD160); bitcoin_address(rawtx->I.destaddr,rawtx->coin->chain->pubtype,rawtx->I.rmd160,20); } if ( pubkey33 != 0 ) @@ -2704,28 +2741,125 @@ cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid return(basilisk_nullretjson(retjson)); } -char *txnames[] = { "myfee", "bobdeposit", "bobpayment", "alicepayment", "bobrefund", "bobreclaim", "bobspend", "alicespend", "alicereclaim" }; +void basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname,char *symbol,char *txbytes) +{ + char *retstr; + if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) + { + printf("[%s] %s RETSTR.(%s)\n",txname,txbytes,retstr); + free(retstr); + } +} + +#define BASILISK_ALICESPEND 0 +#define BASILISK_BOBSPEND 1 +#define BASILISK_BOBPAYMENT 2 +#define BASILISK_ALICEPAYMENT 3 +#define BASILISK_BOBDEPOSIT 4 +#define BASILISK_OTHERFEE 5 +#define BASILISK_MYFEE 6 +#define BASILISK_BOBREFUND 7 +#define BASILISK_BOBRECLAIM 8 +#define BASILISK_ALICERECLAIM 9 +#define BASILISK_ALICECLAIM 10 + +char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t i; char fname[512],*fstr,*symbol,str[65],str2[65],*txbytes,*retstr; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 checktxid,txid,trigger; uint32_t t,addflag; uint64_t value; + int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,needflag,addflag,iambob = -1; uint64_t srcamount,destamount,value; uint32_t expiration=0,t,r,q,state,otherstate; char *srcstr,*deststr,src[64],dest[64],fname[512],*fstr,*symbol,str[65],str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 checktxid,txid,trigger,privkey,privAm,privBn,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + memset(txids,0,sizeof(txids)); + memset(txbytes,0,sizeof(txbytes)); + memset(sentflags,0,sizeof(sentflags)); + memset(myprivs,0,sizeof(myprivs)); + privAm = privBn = myprivs[0]; + bobcoin[0] = alicecoin[0] = 0; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + if ( (fstr= OS_filestr(&fsize,fname)) != 0 ) + { + if ( (item= cJSON_Parse(fstr)) != 0 ) + { + iambob = jint(item,"iambob"); + if ( (srcstr= jstr(item,"src")) != 0 ) + safecopy(src,srcstr,sizeof(src)); + if ( (deststr= jstr(item,"dest")) != 0 ) + safecopy(dest,deststr,sizeof(dest)); + r = juint(item,"requestid"); + q = juint(item,"quoteid"); + expiration = juint(item,"expiration"); + state = jint(item,"state"); + otherstate = jint(item,"otherstate"); + srcamount = SATOSHIDEN * jdouble(item,"srcamount"); + destamount = SATOSHIDEN * jdouble(item,"destamount"); + txids[BASILISK_BOBDEPOSIT] = jbits256(item,"Bdeposit"); + txids[BASILISK_BOBREFUND] = jbits256(item,"Brefund"); + txids[BASILISK_ALICECLAIM] = jbits256(item,"Aclaim"); + txids[BASILISK_BOBPAYMENT] = jbits256(item,"Bpayment"); + txids[BASILISK_ALICESPEND] = jbits256(item,"Aspend"); + txids[BASILISK_BOBRECLAIM] = jbits256(item,"Breclaim"); + txids[BASILISK_ALICEPAYMENT] = jbits256(item,"Apayment"); + txids[BASILISK_BOBSPEND] = jbits256(item,"Bspend"); + txids[BASILISK_ALICERECLAIM] = jbits256(item,"Areclaim"); + txids[BASILISK_MYFEE] = jbits256(item,"myfee"); + txids[BASILISK_OTHERFEE] = jbits256(item,"otherfee"); + free_json(item); + } + free(fstr); + } item = cJSON_CreateObject(); array = cJSON_CreateArray(); - printf("R.%u Q.%u\n",requestid,quoteid); + //printf("R.%u Q.%u\n",requestid,quoteid); for (i=0; i t ) { - txid = jbits256(txobj,"txid"); if ( jobj(txobj,"trigger") != 0 ) { trigger = jbits256(txobj,"trigger"); @@ -2738,52 +2872,105 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } else { - if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) - { - printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); - addflag = 1; - } - else - { - checktxid = jbits256(sentobj,"txid"); - if ( bits256_cmp(checktxid,txid) != 0 ) - { - printf("%s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); - addflag = 1; - } - free_json(sentobj); - } - if ( addflag != 0 && (txbytes= jstr(txobj,"tx")) != 0 ) + /*if ( sentflags[i] == 0 && () != 0 ) { if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) { //printf("%s RETSTR.(%s)\n",txbytes,retstr); free(retstr); } - } + }*/ } } //else printf("%s t %u\n",symbol,t); - if ( addflag == 0 ) + jaddi(array,txobj); + } + } //else printf("no symbol\n"); + free(fstr); + } + } + if ( bobcoin[0] != 0 && alicecoin[0] != 0 ) + { + printf("iambob.%d src.%s dest.%s bob.%s alice.%s\n",iambob,src,dest,bobcoin,alicecoin); + if ( iambob == 0 ) + { + if ( sentflags[BASILISK_ALICESPEND] != 0 ) + jaddnum(item,"spent",1); + else + { + if ( sentflags[BASILISK_BOBPAYMENT] != 0 ) + { + if ( txbytes[BASILISK_ALICESPEND] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"alicespend",alicecoin,txbytes[BASILISK_ALICESPEND]); + else if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) { - value = jdouble(txobj,"amount") * SATOSHIDEN; - if ( strcmp(symbol,"KMD") == 0 ) - KMDtotals[i] += value; - else if ( strcmp(symbol,"BTC") == 0 ) - BTCtotals[i] += value; - free_json(txobj); + } + } + } + if ( sentflags[BASILISK_ALICECLAIM] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) + { + if ( time(NULL) > expiration ) + { + if ( txbytes[BASILISK_ALICECLAIM] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); else { - jaddi(array,txobj); + // claim bobdeposit } - } else free_json(txobj); - } //else printf("no symbol\n"); - free(fstr); + } + } + if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) + { + if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); + else if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + // 2of2 spend of alicepayment + } + } + } + else if ( iambob == 1 ) + { + if ( sentflags[BASILISK_BOBSPEND] != 0 ) + jaddnum(item,"spent",1); + else if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) + { + if ( txbytes[BASILISK_BOBSPEND] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); + else if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + // privAm, privBn 2of2 msig + } + } + if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) + { + if ( sentflags[BASILISK_BOBSPEND] != 0 || time(NULL) > expiration-INSTANTDEX_LOCKTIME/2 ) + { + if ( txbytes[BASILISK_BOBREFUND] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); + else + { + // bobrefund + } + } + } + if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) + { + if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); + else + { + // bobreclaim + } + } } } jaddnum(item,"requestid",requestid); jaddnum(item,"quoteid",quoteid); jadd(item,"txs",array); + for (i=0; i Date: Tue, 11 Apr 2017 19:12:40 +0300 Subject: [PATCH 0196/2705] Test --- basilisk/basilisk_swap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 448dadef4..2417244b1 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2833,7 +2833,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( bits256_nonz(privkey) != 0 ) privBn = privkey; if ( jobj(txobj,"tx") != 0 ) + { txbytes[i] = clonestr(jstr(txobj,"tx")); + printf("[%s] TX.(%s)\n",txnames[i],txbytes[i]); + } if ( (symbol= jstr(txobj,"coin")) != 0 ) { if ( i == BASILISK_ALICESPEND || i == BASILISK_BOBPAYMENT || i == BASILISK_BOBDEPOSIT || i == BASILISK_BOBREFUND || i == BASILISK_BOBRECLAIM || i == BASILISK_ALICECLAIM ) From 73ca018893516f4315174b56682f94f17f385fc9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 11 Apr 2017 19:14:58 +0300 Subject: [PATCH 0197/2705] Test --- basilisk/basilisk_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2417244b1..183bd9a23 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2818,6 +2818,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 //printf("%s\n",fname); if ( (txobj= cJSON_Parse(fstr)) != 0 ) { + printf("TXOBJ.(%s)\n",jprint(txobj,0)); iambob = jint(txobj,"iambob"); txid = jbits256(txobj,"txid"); privkey = jbits256(txobj,"myprivs0"); From 3390713972e3e926874b8c9860bf400e245b37c7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 11 Apr 2017 19:16:55 +0300 Subject: [PATCH 0198/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 183bd9a23..988f71252 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2815,7 +2815,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,requestid,quoteid,txnames[i]), OS_compatible_path(fname); if ( (fstr= OS_filestr(&fsize,fname)) != 0 ) { - //printf("%s\n",fname); + printf("%s -> (%s)\n",fname,fstr); if ( (txobj= cJSON_Parse(fstr)) != 0 ) { printf("TXOBJ.(%s)\n",jprint(txobj,0)); From b36cddb2210c757141d657b61fba90f8cfe4c3c8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 14:59:16 +0300 Subject: [PATCH 0199/2705] Test --- .gitignore | 2 + basilisk/basilisk_swap.c | 334 +++++++++++++++++++++++++++++---------- 2 files changed, 256 insertions(+), 80 deletions(-) diff --git a/.gitignore b/.gitignore index cde494c19..e6a48c8bf 100755 --- a/.gitignore +++ b/.gitignore @@ -314,3 +314,5 @@ iguana/DB/SWAPS/1914406677-1452353494 iguana/DB/SWAPS/3193054754-2514575257 iguana/DB/SWAPS/3004995589-1950720855 + +iguana/3193054754-2514575257 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 988f71252..3c44402fb 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -169,26 +169,24 @@ bits256 basilisk_revealkey(bits256 privkey,bits256 pubkey) return(reveal); } -int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeemlenp,uint8_t *script,int32_t n,uint32_t *locktimep,int32_t *secretstartp,struct basilisk_swapinfo *swap,int32_t depositflag) +int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp,uint8_t *redeemscript,uint32_t locktime,bits256 pubA0,bits256 pubB0,bits256 pubB1,bits256 privAm,bits256 privBn,uint8_t *secretAm,uint8_t *secretAm256,uint8_t *secretBn,uint8_t *secretBn256) { - uint8_t pubkeyA[33],pubkeyB[33],*secret160,*secret256; bits256 privkey,cltvpub,destpub; int32_t i; + int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],*secret160,*secret256; if ( depositflag != 0 ) { - *locktimep = swap->started + swap->putduration + swap->callduration; - pubkeyA[0] = 0x02, cltvpub = swap->pubA0; - pubkeyB[0] = 0x03, destpub = swap->pubB0; - privkey = swap->privBn; - secret160 = swap->secretBn; - secret256 = swap->secretBn256; + pubkeyA[0] = 0x02, cltvpub = pubA0; + pubkeyB[0] = 0x03, destpub = pubB0; + privkey = privBn; + secret160 = secretBn; + secret256 = secretBn256; } else { - *locktimep = swap->started + swap->putduration; - pubkeyA[0] = 0x03, cltvpub = swap->pubB1; - pubkeyB[0] = 0x02, destpub = swap->pubA0; - privkey = swap->privAm; - secret160 = swap->secretAm; - secret256 = swap->secretAm256; + pubkeyA[0] = 0x03, cltvpub = pubB1; + pubkeyB[0] = 0x02, destpub = pubA0; + privkey = privAm; + secret160 = secretAm; + secret256 = secretAm256; } //for (i=0; i<32; i++) // printf("%02x",secret256[i]); @@ -203,7 +201,7 @@ int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeem memcpy(pubkeyA+1,cltvpub.bytes,sizeof(cltvpub)); memcpy(pubkeyB+1,destpub.bytes,sizeof(destpub)); redeemscript[n++] = SCRIPT_OP_IF; - n = bitcoin_checklocktimeverify(redeemscript,n,*locktimep); + n = bitcoin_checklocktimeverify(redeemscript,n,locktime); #ifdef DISABLE_CHECKSIG n = bitcoin_secret256spend(redeemscript,n,cltvpub); #else @@ -220,16 +218,16 @@ int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeem revcalc_rmd160_sha256(bufA,privkey); calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); /*if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) - printf("MATCHES BUFA\n"); - else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) - printf("MATCHES BUFB\n"); - else printf("secret160 matches neither\n"); - for (i=0; i<20; i++) - printf("%02x",bufA[i]); - printf(" <- revcalc\n"); - for (i=0; i<20; i++) - printf("%02x",bufB[i]); - printf(" <- calc\n");*/ + printf("MATCHES BUFA\n"); + else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) + printf("MATCHES BUFB\n"); + else printf("secret160 matches neither\n"); + for (i=0; i<20; i++) + printf("%02x",bufA[i]); + printf(" <- revcalc\n"); + for (i=0; i<20; i++) + printf("%02x",bufB[i]); + printf(" <- calc\n");*/ memcpy(secret160,bufB,20); } n = bitcoin_secret160verify(redeemscript,n,secret160); @@ -247,12 +245,23 @@ int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeem n = bitcoin_pubkeyspend(redeemscript,n,pubkeyB); #endif redeemscript[n++] = SCRIPT_OP_ENDIF; - *redeemlenp = n; - calc_rmd160_sha256(rmd160,redeemscript,n); - n = bitcoin_p2shspend(script,0,rmd160); - //for (i=0; istarted + swap->putduration + swap->callduration; + else *locktimep = swap->started + swap->putduration; + n = basilisk_swap_bobredeemscript(depositflag,secretstartp,redeemscript,*locktimep,swap->pubA0,swap->pubB0,swap->pubB1,swap->privAm,swap->privBn,swap->secretAm,swap->secretAm256,swap->secretBn,swap->secretBn256); + if ( n > 0 ) + { + calc_rmd160_sha256(rmd160,redeemscript,n); + n = bitcoin_p2shspend(script,0,rmd160); + //for (i=0; iname,rawtx->coin->symbol); if ( rawtx->I.datalen > 0 ) { - fprintf(fp,",\"dest33\":\""); - for (i=0; i<33; i++) - fprintf(fp,"%02x",swap->persistent_pubkey33[i]); - fprintf(fp,"\",\"tx\":\""); + fprintf(fp,",\"tx\":\""); for (i=0; iI.datalen; i++) fprintf(fp,"%02x",rawtx->txbytes[i]); fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); @@ -781,11 +787,17 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,",\"%s\":\"%s\"","Bpayment",swap->Bpayment); for (i=0; i<2; i++) if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) - fprintf(fp,"\",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); + fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); if ( bits256_nonz(swap->I.privAm) != 0 ) - fprintf(fp,"\",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); + fprintf(fp,",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); if ( bits256_nonz(swap->I.privBn) != 0 ) - fprintf(fp,"\",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); + fprintf(fp,",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); + if ( bits256_nonz(swap->I.pubA0) != 0 ) + fprintf(fp,",\"pubA0\":\"%s\"",bits256_str(str,swap->I.pubA0)); + if ( bits256_nonz(swap->I.pubB0) != 0 ) + fprintf(fp,",\"pubB0\":\"%s\"",bits256_str(str,swap->I.pubB0)); + if ( bits256_nonz(swap->I.pubB1) != 0 ) + fprintf(fp,",\"pubB1\":\"%s\"",bits256_str(str,swap->I.pubB1)); fprintf(fp,",\"expiration\":%u",swap->I.expiration); fprintf(fp,",\"iambob\":%d",swap->I.iambob); fprintf(fp,",\"bobcoin\":\"%s\"",swap->bobcoin->symbol); @@ -797,7 +809,7 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) { basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); - fprintf(fp,"\",\"Apayment\":\"%s\"",coinaddr); + fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); } basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); @@ -811,7 +823,7 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"wb")) != 0 ) { - fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%x,\"otherstate\":%x,\"expiration\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration); + fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%x,\"otherstate\":%x,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) fprintf(fp,",\"Bdeposit\":\"%s\"",bits256_str(str,swap->bobdeposit.I.actualtxid)); if ( bits256_nonz(swap->bobrefund.I.actualtxid) != 0 ) @@ -837,7 +849,10 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,",\"otherfee\":\"%s\"",bits256_str(str,swap->otherfee.I.actualtxid)); if ( bits256_nonz(swap->myfee.I.actualtxid) != 0 ) fprintf(fp,",\"myfee\":\"%s\"",bits256_str(str,swap->myfee.I.actualtxid)); - fprintf(fp,"}\n"); + fprintf(fp,",\"dest33\":\""); + for (i=0; i<33; i++) + fprintf(fp,"%02x",swap->persistent_pubkey33[i]); + fprintf(fp,"\"}\n"); fclose(fp); } } @@ -2751,6 +2766,96 @@ void basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname, } } +char *basilisk_swap_bobtxspend(struct supernet_info *myinfo,char *symbol,bits256 privkey,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) +{ + char *rawtxbytes=0,*signedtx=0,hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff; struct iguana_info *coin; uint64_t amount=100000; bits256 txid,signedtxid; + printf("bobtxspend.%s\n",symbol); + if ( (coin= iguana_coinfind(symbol)) == 0 ) + return(0); + height = coin->longestchain; + timestamp = (uint32_t)time(NULL); + V = calloc(256,sizeof(*V)); + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); + privkeys = cJSON_CreateArray(); + bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 1; + V[0].suppress_pubkeys = suppress_pubkeys; + V[0].ignore_cltverr = ignore_cltverr; + if ( redeemlen != 0 ) + memcpy(V[0].p2shscript,redeemscript,redeemlen), V[0].p2shlen = redeemlen; + txobj = bitcoin_txcreate(coin->symbol,coin->chain->isPoS,locktime,1,timestamp); + vins = cJSON_CreateArray(); + item = cJSON_CreateObject(); + if ( userdata != 0 && userdatalen > 0 ) + { + memcpy(V[0].userdata,userdata,userdatalen); + V[0].userdatalen = userdatalen; + init_hexbytes_noT(hexstr,userdata,userdatalen); + jaddstr(item,"userdata",hexstr); + } + printf("rawtx B\n"); + jaddbits256(item,"txid",utxotxid); + jaddnum(item,"vout",vout); + sobj = cJSON_CreateObject(); + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + init_hexbytes_noT(hexstr,spendscript,spendlen); + jaddstr(sobj,"hex",hexstr); + jadd(item,"scriptPubKey",sobj); + jaddnum(item,"suppress",suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); + if ( redeemlen != 0 ) + { + init_hexbytes_noT(hexstr,redeemscript,redeemlen); + jaddstr(item,"redeemScript",hexstr); + } + jaddi(vins,item); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + txobj = bitcoin_txoutput(txobj,spendscript,spendlen,amount); + if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) + { + printf("rawtx.(%s) vins.(%s)\n",rawtxbytes,jprint(vins,0)); + if ( signedtx != 0 || (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) != 0 ) + printf("couldnt sign transaction\n"); + else printf("error signing\n"); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(txobj); + free(V); + return(signedtx); +} + +char *basilisk_swap_Aspend(struct supernet_info *myinfo,char *coin,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) +{ + char *signedtx = 0; + return(signedtx); +} + +bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *coin,bits256 utxotxid,int32_t vout) +{ + bits256 txid; + // listtransactions or listspents + return(txid); +} + +bits256 basilisk_swap_privAm_extract(struct supernet_info *myinfo,char *coin,bits256 utxotxid,int32_t vout) +{ + bits256 privAm; + return(privAm); +} + +bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,char *coin,bits256 utxotxid,int32_t vout) +{ + bits256 privBn; + return(privBn); +} + + #define BASILISK_ALICESPEND 0 #define BASILISK_BOBSPEND 1 #define BASILISK_BOBPAYMENT 2 @@ -2762,18 +2867,24 @@ void basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname, #define BASILISK_BOBRECLAIM 8 #define BASILISK_ALICERECLAIM 9 #define BASILISK_ALICECLAIM 10 - +//0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0 char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,needflag,addflag,iambob = -1; uint64_t srcamount,destamount,value; uint32_t expiration=0,t,r,q,state,otherstate; char *srcstr,*deststr,src[64],dest[64],fname[512],*fstr,*symbol,str[65],str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 checktxid,txid,trigger,privkey,privAm,privBn,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount,value; uint8_t secretAm[32],secretAm256[32],secretBn[32],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *srcstr,*deststr,src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str[65],str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 checktxid,txid,trigger,privkey,pubA0,pubB0,pubB1,privAm,privBn,zero,revAm,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; memset(txids,0,sizeof(txids)); + memset(secretAm,0,sizeof(secretAm)); + memset(secretAm256,0,sizeof(secretAm256)); + memset(secretBn,0,sizeof(secretBn)); + memset(secretBn256,0,sizeof(secretBn256)); + memset(pubkey33,0,sizeof(pubkey33)); memset(txbytes,0,sizeof(txbytes)); memset(sentflags,0,sizeof(sentflags)); memset(myprivs,0,sizeof(myprivs)); - privAm = privBn = myprivs[0]; - bobcoin[0] = alicecoin[0] = 0; + revAm = zero = pubA0 = pubB0 = pubB1 = privAm = privBn = myprivs[0]; + plocktime = dlocktime = 0; + src[0] = dest[0] = bobcoin[0] = alicecoin[0] = 0; sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); if ( (fstr= OS_filestr(&fsize,fname)) != 0 ) { @@ -2784,8 +2895,15 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 safecopy(src,srcstr,sizeof(src)); if ( (deststr= jstr(item,"dest")) != 0 ) safecopy(dest,deststr,sizeof(dest)); + if ( (dest33= jstr(item,"dest33")) != 0 ) + decode_hex(pubkey33,33,dest33); + plocktime = juint(item,"plocktime"); + dlocktime = juint(item,"dlocktime"); r = juint(item,"requestid"); q = juint(item,"quoteid"); + pubA0 = jbits256(item,"pubA0"); + pubB0 = jbits256(item,"pubB0"); + pubB1 = jbits256(item,"pubB1"); expiration = juint(item,"expiration"); state = jint(item,"state"); otherstate = jint(item,"otherstate"); @@ -2815,12 +2933,15 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,requestid,quoteid,txnames[i]), OS_compatible_path(fname); if ( (fstr= OS_filestr(&fsize,fname)) != 0 ) { - printf("%s -> (%s)\n",fname,fstr); + //printf("%s -> (%s)\n",fname,fstr); if ( (txobj= cJSON_Parse(fstr)) != 0 ) { - printf("TXOBJ.(%s)\n",jprint(txobj,0)); + //printf("TXOBJ.(%s)\n",jprint(txobj,0)); iambob = jint(txobj,"iambob"); txid = jbits256(txobj,"txid"); + if ( bits256_nonz(txid) == 0 ) + continue; + txids[i] = txid; privkey = jbits256(txobj,"myprivs0"); if ( bits256_nonz(privkey) != 0 ) myprivs[0] = privkey; @@ -2836,7 +2957,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( jobj(txobj,"tx") != 0 ) { txbytes[i] = clonestr(jstr(txobj,"tx")); - printf("[%s] TX.(%s)\n",txnames[i],txbytes[i]); + //printf("[%s] TX.(%s)\n",txnames[i],txbytes[i]); } if ( (symbol= jstr(txobj,"coin")) != 0 ) { @@ -2849,9 +2970,11 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 else { checktxid = jbits256(sentobj,"txid"); - if ( bits256_cmp(checktxid,txid) != 0 ) - printf("%s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); - else sentflags[i] = 1; + if ( bits256_cmp(checktxid,txid) == 0 ) + { + //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); + sentflags[i] = 1; + } free_json(sentobj); } if ( sentflags[i] != 0 ) @@ -2886,7 +3009,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 }*/ } } //else printf("%s t %u\n",symbol,t); - jaddi(array,txobj); + if ( sentflags[i] == 0 || addflag != 0 ) + jaddi(array,txobj); } } //else printf("no symbol\n"); free(fstr); @@ -2897,84 +3021,134 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("iambob.%d src.%s dest.%s bob.%s alice.%s\n",iambob,src,dest,bobcoin,alicecoin); if ( iambob == 0 ) { - if ( sentflags[BASILISK_ALICESPEND] != 0 ) - jaddnum(item,"spent",1); - else + if ( sentflags[BASILISK_ALICESPEND] == 0 ) { if ( sentflags[BASILISK_BOBPAYMENT] != 0 ) { - if ( txbytes[BASILISK_ALICESPEND] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"alicespend",alicecoin,txbytes[BASILISK_ALICESPEND]); - else if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) + if ( txbytes[BASILISK_ALICESPEND] == 0 ) { - + printf("create alicespend\n"); + if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) + { + printf("have bobpayment txid\n"); + // alicespend + revcalc_rmd160_sha256(secretAm,privAm); + vcalc_sha256(0,secretAm256,privAm.bytes,sizeof(privAm)); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + for (j=0; j<32; j++) + revAm.bytes[j] = privAm.bytes[31-j]; + len = basilisk_swapuserdata(userdata,revAm,0,myprivs[0],redeemscript,redeemlen); + txbytes[BASILISK_ALICESPEND] = basilisk_swap_bobtxspend(myinfo,alicecoin,myprivs[0],redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33); + } } - } + if ( txbytes[BASILISK_ALICESPEND] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"alicespend",alicecoin,txbytes[BASILISK_ALICESPEND]); + } } if ( sentflags[BASILISK_ALICECLAIM] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) { if ( time(NULL) > expiration ) { - if ( txbytes[BASILISK_ALICECLAIM] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); - else + if ( txbytes[BASILISK_ALICECLAIM] == 0 ) { // claim bobdeposit + revcalc_rmd160_sha256(secretBn,privBn); + vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); + redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); + // myprivs[0] } + if ( txbytes[BASILISK_ALICECLAIM] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); } } if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) { - if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); - else if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) { - // 2of2 spend of alicepayment + if ( bits256_nonz(privBn) == 0 ) + { + if ( bits256_nonz(txids[BASILISK_BOBREFUND]) == 0 ) + txids[BASILISK_BOBREFUND] = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBDEPOSIT],0); + if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) + privBn = basilisk_swap_privBn_extract(myinfo,bobcoin,txids[BASILISK_BOBREFUND],0); + } + if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + txbytes[BASILISK_ALICERECLAIM] = basilisk_swap_Aspend(myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33); } + if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); } } else if ( iambob == 1 ) { - if ( sentflags[BASILISK_BOBSPEND] != 0 ) - jaddnum(item,"spent",1); - else if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) + if ( sentflags[BASILISK_BOBSPEND] == 0 ) { - if ( txbytes[BASILISK_BOBSPEND] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); - else if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) { - // privAm, privBn 2of2 msig + if ( txbytes[BASILISK_BOBSPEND] == 0 ) + { + if ( bits256_nonz(privAm) == 0 ) + { + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) + txids[BASILISK_ALICESPEND] = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBPAYMENT],0); + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) + privAm = basilisk_swap_privAm_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); + } + if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + txbytes[BASILISK_BOBSPEND] = basilisk_swap_Aspend(myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33); + } + if ( txbytes[BASILISK_BOBSPEND] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); } } if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) { if ( sentflags[BASILISK_BOBSPEND] != 0 || time(NULL) > expiration-INSTANTDEX_LOCKTIME/2 ) { - if ( txbytes[BASILISK_BOBREFUND] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); - else + if ( txbytes[BASILISK_BOBREFUND] == 0 ) { // bobrefund + printf("unexpected missing BOBREFUND txbytes\n"); + revcalc_rmd160_sha256(secretBn,privBn); + vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); + redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); + // myprivs[0] } + if ( txbytes[BASILISK_BOBREFUND] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); } } if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) { - if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); - else + if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) { // bobreclaim + printf("unexpected missing BOBRECLAIM txbytes\n"); + revcalc_rmd160_sha256(secretAm,privAm); + vcalc_sha256(0,secretAm256,privAm.bytes,sizeof(privAm)); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); + // myprivs[1] } + if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) + basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); } } } jaddnum(item,"requestid",requestid); jaddnum(item,"quoteid",quoteid); jadd(item,"txs",array); + array = cJSON_CreateArray(); for (i=0; i Date: Wed, 12 Apr 2017 15:08:01 +0300 Subject: [PATCH 0200/2705] Test --- basilisk/basilisk_swap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3c44402fb..0f439f77b 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2769,8 +2769,8 @@ void basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname, char *basilisk_swap_bobtxspend(struct supernet_info *myinfo,char *symbol,bits256 privkey,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) { char *rawtxbytes=0,*signedtx=0,hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff; struct iguana_info *coin; uint64_t amount=100000; bits256 txid,signedtxid; - printf("bobtxspend.%s\n",symbol); - if ( (coin= iguana_coinfind(symbol)) == 0 ) + printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); height = coin->longestchain; timestamp = (uint32_t)time(NULL); @@ -2780,6 +2780,7 @@ char *basilisk_swap_bobtxspend(struct supernet_info *myinfo,char *symbol,bits256 privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeys,wifstr); + printf("wif.%s\n",wifstr); V[0].N = V[0].M = 1; V[0].suppress_pubkeys = suppress_pubkeys; V[0].ignore_cltverr = ignore_cltverr; From 6402acbef5465d749cef515d20491b19ecfba8de Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 15:16:01 +0300 Subject: [PATCH 0201/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0f439f77b..f463bd55c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2990,13 +2990,13 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( jobj(txobj,"trigger") != 0 ) { - trigger = jbits256(txobj,"trigger"); + /*trigger = jbits256(txobj,"trigger"); //printf("%s trigger %s\n",symbol,bits256_str(str,trigger)); if ( (triggerobj= basilisk_swapgettxout(myinfo,symbol,trigger,0)) == 0 ) { printf("%s %s trigger.(%s) spent! extract priv\n",symbol,bits256_str(str2,txid),bits256_str(str,trigger)); addflag = 1; - } else free_json(triggerobj); + } else free_json(triggerobj);*/ } else { From 212852960974cca71794d10d94035455c505ecb3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 16:54:31 +0300 Subject: [PATCH 0202/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 28 +++++++++++++-------------- basilisk/jumblr.c | 14 ++++++++------ iguana/DB/SWAPS/3448271011-3628813832 | 1 + iguana/DB/SWAPS/403615495-1237768524 | 1 + 5 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 iguana/DB/SWAPS/3448271011-3628813832 create mode 100644 iguana/DB/SWAPS/403615495-1237768524 diff --git a/.gitignore b/.gitignore index e6a48c8bf..f7e9dde70 100755 --- a/.gitignore +++ b/.gitignore @@ -316,3 +316,5 @@ iguana/DB/SWAPS/3193054754-2514575257 iguana/DB/SWAPS/3004995589-1950720855 iguana/3193054754-2514575257 + +iguana/DB/SWAPS/2912654530-2125064238 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f463bd55c..b7a6399c1 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -188,9 +188,9 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, secret160 = secretAm; secret256 = secretAm256; } - //for (i=0; i<32; i++) - // printf("%02x",secret256[i]); - //printf(" <- secret256 depositflag.%d\n",depositflag); + for (i=0; i<32; i++) + printf("%02x",secret256[i]); + printf(" <- secret256 depositflag.%d nonz.%d\n",depositflag,bits256_nonz(privkey)); if ( bits256_nonz(cltvpub) == 0 || bits256_nonz(destpub) == 0 ) return(-1); for (i=0; i<20; i++) @@ -217,17 +217,17 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, uint8_t bufA[20],bufB[20]; revcalc_rmd160_sha256(bufA,privkey); calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); - /*if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) - printf("MATCHES BUFA\n"); - else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) - printf("MATCHES BUFB\n"); - else printf("secret160 matches neither\n"); - for (i=0; i<20; i++) - printf("%02x",bufA[i]); - printf(" <- revcalc\n"); - for (i=0; i<20; i++) - printf("%02x",bufB[i]); - printf(" <- calc\n");*/ + if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) + printf("MATCHES BUFA\n"); + else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) + printf("MATCHES BUFB\n"); + else printf("secret160 matches neither\n"); + for (i=0; i<20; i++) + printf("%02x",bufA[i]); + printf(" <- revcalc\n"); + for (i=0; i<20; i++) + printf("%02x",bufB[i]); + printf(" <- calc\n"); memcpy(secret160,bufB,20); } n = bitcoin_secret160verify(redeemscript,n,secret160); diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 1d31bd20b..382733c6c 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -714,11 +714,13 @@ void jumblr_CMCname(char *CMCname,char *symbol) void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32_t toKMD) { double vol,avail; struct iguana_info *kmdcoin,*coinbtc = 0; + kmdcoin = iguana_coinfind("KMD"); + coinbtc = iguana_coinfind("BTC"); + printf("jumblr_DEXcheck numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 ) return; - if ( (kmdcoin= iguana_coinfind("KMD")) == 0 || (coinbtc= iguana_coinfind("BTC")) == 0 ) + if ( kmdcoin == 0 || coinbtc == 0 ) return; - //printf("jumblr_DEXcheck\n"); jumblr_DEXupdate(myinfo,kmdcoin,"KMD","komodo",0.,0.); if ( strcmp(coin->symbol,"KMD") != 0 && kmdcoin->DEXinfo.btcprice > 0. ) { @@ -749,7 +751,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",1./(1.03 * kmdcoin->DEXinfo.btcprice)); + jaddnum(vals,"minprice",1./(1.05 * kmdcoin->DEXinfo.btcprice)); jaddnum(vals,"usejumblr",1); jaddnum(vals,"DEXselector",1); memset(hash.bytes,0,sizeof(hash)); @@ -781,7 +783,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",vol); //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.03); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.05); jaddnum(vals,"usejumblr",1); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.KMDpending += vol; @@ -793,8 +795,8 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } free_json(vals); } - } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - } //else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); + } else printf("btcavail %.8f pending %.8f\n",btcavail,kmdcoin->DEXinfo.KMDpending); + } else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); } void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval) diff --git a/iguana/DB/SWAPS/3448271011-3628813832 b/iguana/DB/SWAPS/3448271011-3628813832 new file mode 100644 index 000000000..a9b0f0115 --- /dev/null +++ b/iguana/DB/SWAPS/3448271011-3628813832 @@ -0,0 +1 @@ +{"src":"BTC","srcamount":0.01438678,"dest":"KMD","destamount":117.03798516,"requestid":3448271011,"quoteid":3628813832,"iambob":0,"state":eff,"otherstate":31bf,"expiration":1492020667,"dlocktime":1492020684,"plocktime":1492012884,"Bdeposit":"1a520ea71ab9ba336fb0f856584a821bad1e18e4c38903239c48767661d88b8a","Bpayment":"94f89299746bd5f922bf1b2e4b2ed6ff20f283097404b222b974ec3817102ee3","Apayment":"a19713d5af24960cb46291a6c6299c55f09fa0234eb4b5d3c1bf19f582db1beb","myfee":"04c03c66e57abdbee650d76c82f1b0ca18cbacd722d201e445f47843041a3ecf","dest33":"0231a71ac00aed93b79f5b751d6b498cb1151314a18607328d5e79aec71deac205"} diff --git a/iguana/DB/SWAPS/403615495-1237768524 b/iguana/DB/SWAPS/403615495-1237768524 new file mode 100644 index 000000000..6affe21ae --- /dev/null +++ b/iguana/DB/SWAPS/403615495-1237768524 @@ -0,0 +1 @@ +{"src":"BTC","srcamount":0.01410523,"dest":"KMD","destamount":118.62156235,"requestid":403615495,"quoteid":1237768524,"iambob":0,"state":eff,"otherstate":31bf,"expiration":1492019879,"dlocktime":1492019880,"plocktime":1492012080,"Bdeposit":"8d2a84a5f6acfaeee96fad7e9a613a08768f0b1455acd50912447361dd94c90b","Bpayment":"2ea1d52713cf4871047406d2a6cbbdbf783b8a3a457cb8fe03ad224382742ff5","Apayment":"acced616731fe15ddd3cd219b0f33a41ec382825ed968905e25cff555f74c660","myfee":"1de9e50a8758b032be8eb47cdea688e326bf9fa174eb92bce8e0ebf5faba4ebe","dest33":"0231a71ac00aed93b79f5b751d6b498cb1151314a18607328d5e79aec71deac205"} From 280332453a00fb3d2671320c9e852029760fa5b2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 16:57:29 +0300 Subject: [PATCH 0203/2705] Test --- .gitignore | 12 ++++++++++++ iguana/DB/SWAPS/3448271011-3628813832 | 1 - iguana/DB/SWAPS/403615495-1237768524 | 1 - 3 files changed, 12 insertions(+), 2 deletions(-) delete mode 100644 iguana/DB/SWAPS/3448271011-3628813832 delete mode 100644 iguana/DB/SWAPS/403615495-1237768524 diff --git a/.gitignore b/.gitignore index f7e9dde70..a0ca80108 100755 --- a/.gitignore +++ b/.gitignore @@ -318,3 +318,15 @@ iguana/DB/SWAPS/3004995589-1950720855 iguana/3193054754-2514575257 iguana/DB/SWAPS/2912654530-2125064238 + +iguana/DB/SWAPS/3448271011-3628813832 + +iguana/DB/SWAPS/3448271011-3628813832 + +iguana/DB/SWAPS/403615495-1237768524 + +iguana/DB/SWAPS/3448271011-3628813832 + +iguana/DB/SWAPS/403615495-1237768524 + +iguana/DB/SWAPS/3448271011-3628813832 diff --git a/iguana/DB/SWAPS/3448271011-3628813832 b/iguana/DB/SWAPS/3448271011-3628813832 deleted file mode 100644 index a9b0f0115..000000000 --- a/iguana/DB/SWAPS/3448271011-3628813832 +++ /dev/null @@ -1 +0,0 @@ -{"src":"BTC","srcamount":0.01438678,"dest":"KMD","destamount":117.03798516,"requestid":3448271011,"quoteid":3628813832,"iambob":0,"state":eff,"otherstate":31bf,"expiration":1492020667,"dlocktime":1492020684,"plocktime":1492012884,"Bdeposit":"1a520ea71ab9ba336fb0f856584a821bad1e18e4c38903239c48767661d88b8a","Bpayment":"94f89299746bd5f922bf1b2e4b2ed6ff20f283097404b222b974ec3817102ee3","Apayment":"a19713d5af24960cb46291a6c6299c55f09fa0234eb4b5d3c1bf19f582db1beb","myfee":"04c03c66e57abdbee650d76c82f1b0ca18cbacd722d201e445f47843041a3ecf","dest33":"0231a71ac00aed93b79f5b751d6b498cb1151314a18607328d5e79aec71deac205"} diff --git a/iguana/DB/SWAPS/403615495-1237768524 b/iguana/DB/SWAPS/403615495-1237768524 deleted file mode 100644 index 6affe21ae..000000000 --- a/iguana/DB/SWAPS/403615495-1237768524 +++ /dev/null @@ -1 +0,0 @@ -{"src":"BTC","srcamount":0.01410523,"dest":"KMD","destamount":118.62156235,"requestid":403615495,"quoteid":1237768524,"iambob":0,"state":eff,"otherstate":31bf,"expiration":1492019879,"dlocktime":1492019880,"plocktime":1492012080,"Bdeposit":"8d2a84a5f6acfaeee96fad7e9a613a08768f0b1455acd50912447361dd94c90b","Bpayment":"2ea1d52713cf4871047406d2a6cbbdbf783b8a3a457cb8fe03ad224382742ff5","Apayment":"acced616731fe15ddd3cd219b0f33a41ec382825ed968905e25cff555f74c660","myfee":"1de9e50a8758b032be8eb47cdea688e326bf9fa174eb92bce8e0ebf5faba4ebe","dest33":"0231a71ac00aed93b79f5b751d6b498cb1151314a18607328d5e79aec71deac205"} From 86538a7b343bd61a4eb77067a8704d8233b74778 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 17:03:28 +0300 Subject: [PATCH 0204/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a0ca80108..2f7bbcaa2 100755 --- a/.gitignore +++ b/.gitignore @@ -330,3 +330,5 @@ iguana/DB/SWAPS/3448271011-3628813832 iguana/DB/SWAPS/403615495-1237768524 iguana/DB/SWAPS/3448271011-3628813832 + +iguana/DB/SWAPS/246664144-1570119145 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b7a6399c1..c47c9eeaf 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -172,7 +172,7 @@ bits256 basilisk_revealkey(bits256 privkey,bits256 pubkey) int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp,uint8_t *redeemscript,uint32_t locktime,bits256 pubA0,bits256 pubB0,bits256 pubB1,bits256 privAm,bits256 privBn,uint8_t *secretAm,uint8_t *secretAm256,uint8_t *secretBn,uint8_t *secretBn256) { int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],*secret160,*secret256; - if ( depositflag != 0 ) + if ( depositflag == 0 ) { pubkeyA[0] = 0x02, cltvpub = pubA0; pubkeyB[0] = 0x03, destpub = pubB0; From 8ad0e7f3812f8272e76e40a91cc1a14df5f7e787 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 17:09:02 +0300 Subject: [PATCH 0205/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 2f7bbcaa2..728443e15 100755 --- a/.gitignore +++ b/.gitignore @@ -332,3 +332,5 @@ iguana/DB/SWAPS/403615495-1237768524 iguana/DB/SWAPS/3448271011-3628813832 iguana/DB/SWAPS/246664144-1570119145 + +iguana/DB/SWAPS/171316098-410428064 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index c47c9eeaf..3f91da078 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -172,7 +172,7 @@ bits256 basilisk_revealkey(bits256 privkey,bits256 pubkey) int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp,uint8_t *redeemscript,uint32_t locktime,bits256 pubA0,bits256 pubB0,bits256 pubB1,bits256 privAm,bits256 privBn,uint8_t *secretAm,uint8_t *secretAm256,uint8_t *secretBn,uint8_t *secretBn256) { int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],*secret160,*secret256; - if ( depositflag == 0 ) + if ( depositflag != 0 ) { pubkeyA[0] = 0x02, cltvpub = pubA0; pubkeyB[0] = 0x03, destpub = pubB0; @@ -214,9 +214,9 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, { if ( 1 && bits256_nonz(privkey) != 0 ) { - uint8_t bufA[20],bufB[20]; + uint8_t bufA[20];//,bufB[20]; revcalc_rmd160_sha256(bufA,privkey); - calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); + /*calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) printf("MATCHES BUFA\n"); else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) @@ -228,7 +228,8 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, for (i=0; i<20; i++) printf("%02x",bufB[i]); printf(" <- calc\n"); - memcpy(secret160,bufB,20); + memcpy(secret160,bufB,20);*/ + memcpy(secret160,bufA,20); } n = bitcoin_secret160verify(redeemscript,n,secret160); } From feedc515fbfc9a72640003e6cc9a80a4b8b705f1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 17:18:54 +0300 Subject: [PATCH 0206/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 728443e15..c652b21a7 100755 --- a/.gitignore +++ b/.gitignore @@ -334,3 +334,5 @@ iguana/DB/SWAPS/3448271011-3628813832 iguana/DB/SWAPS/246664144-1570119145 iguana/DB/SWAPS/171316098-410428064 + +iguana/DB/SWAPS/178665381-1950467641 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3f91da078..2778d5642 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -214,10 +214,10 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, { if ( 1 && bits256_nonz(privkey) != 0 ) { - uint8_t bufA[20];//,bufB[20]; + uint8_t bufA[20],bufB[20]; revcalc_rmd160_sha256(bufA,privkey); - /*calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); - if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) + calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); + /*if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) printf("MATCHES BUFA\n"); else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) printf("MATCHES BUFB\n"); @@ -227,9 +227,8 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, printf(" <- revcalc\n"); for (i=0; i<20; i++) printf("%02x",bufB[i]); - printf(" <- calc\n"); - memcpy(secret160,bufB,20);*/ - memcpy(secret160,bufA,20); + printf(" <- calc\n");*/ + memcpy(secret160,bufB,20); } n = bitcoin_secret160verify(redeemscript,n,secret160); } @@ -254,7 +253,7 @@ int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeem if ( depositflag != 0 ) *locktimep = swap->started + swap->putduration + swap->callduration; else *locktimep = swap->started + swap->putduration; - n = basilisk_swap_bobredeemscript(depositflag,secretstartp,redeemscript,*locktimep,swap->pubA0,swap->pubB0,swap->pubB1,swap->privAm,swap->privBn,swap->secretAm,swap->secretAm256,swap->secretBn,swap->secretBn256); + *redeemlenp = n = basilisk_swap_bobredeemscript(depositflag,secretstartp,redeemscript,*locktimep,swap->pubA0,swap->pubB0,swap->pubB1,swap->privAm,swap->privBn,swap->secretAm,swap->secretAm256,swap->secretBn,swap->secretBn256); if ( n > 0 ) { calc_rmd160_sha256(rmd160,redeemscript,n); From 4fb406649b8f003fcfdfcf208aa689b1a8caf6e2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 17:33:30 +0300 Subject: [PATCH 0207/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 52 ++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index c652b21a7..5ce7840c7 100755 --- a/.gitignore +++ b/.gitignore @@ -336,3 +336,5 @@ iguana/DB/SWAPS/246664144-1570119145 iguana/DB/SWAPS/171316098-410428064 iguana/DB/SWAPS/178665381-1950467641 + +iguana/DB/SWAPS/4126499968-376410338 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2778d5642..6ce719e60 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -785,19 +785,6 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap fprintf(fp,",\"%s\":\"%s\"","Bdeposit",swap->Bdeposit); if ( swap->Bpayment[0] != 0 ) fprintf(fp,",\"%s\":\"%s\"","Bpayment",swap->Bpayment); - for (i=0; i<2; i++) - if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) - fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); - if ( bits256_nonz(swap->I.privAm) != 0 ) - fprintf(fp,",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); - if ( bits256_nonz(swap->I.privBn) != 0 ) - fprintf(fp,",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); - if ( bits256_nonz(swap->I.pubA0) != 0 ) - fprintf(fp,",\"pubA0\":\"%s\"",bits256_str(str,swap->I.pubA0)); - if ( bits256_nonz(swap->I.pubB0) != 0 ) - fprintf(fp,",\"pubB0\":\"%s\"",bits256_str(str,swap->I.pubB0)); - if ( bits256_nonz(swap->I.pubB1) != 0 ) - fprintf(fp,",\"pubB1\":\"%s\"",bits256_str(str,swap->I.pubB1)); fprintf(fp,",\"expiration\":%u",swap->I.expiration); fprintf(fp,",\"iambob\":%d",swap->I.iambob); fprintf(fp,",\"bobcoin\":\"%s\"",swap->bobcoin->symbol); @@ -824,6 +811,19 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap if ( (fp= fopen(fname,"wb")) != 0 ) { fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%x,\"otherstate\":%x,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); + for (i=0; i<2; i++) + if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) + fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); + if ( bits256_nonz(swap->I.privAm) != 0 ) + fprintf(fp,",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); + if ( bits256_nonz(swap->I.privBn) != 0 ) + fprintf(fp,",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); + if ( bits256_nonz(swap->I.pubA0) != 0 ) + fprintf(fp,",\"pubA0\":\"%s\"",bits256_str(str,swap->I.pubA0)); + if ( bits256_nonz(swap->I.pubB0) != 0 ) + fprintf(fp,",\"pubB0\":\"%s\"",bits256_str(str,swap->I.pubB0)); + if ( bits256_nonz(swap->I.pubB1) != 0 ) + fprintf(fp,",\"pubB1\":\"%s\"",bits256_str(str,swap->I.pubB1)); if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) fprintf(fp,",\"Bdeposit\":\"%s\"",bits256_str(str,swap->bobdeposit.I.actualtxid)); if ( bits256_nonz(swap->bobrefund.I.actualtxid) != 0 ) @@ -2905,6 +2905,18 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 pubA0 = jbits256(item,"pubA0"); pubB0 = jbits256(item,"pubB0"); pubB1 = jbits256(item,"pubB1"); + privkey = jbits256(item,"myprivs0"); + if ( bits256_nonz(privkey) != 0 ) + myprivs[0] = privkey; + privkey = jbits256(item,"myprivs1"); + if ( bits256_nonz(privkey) != 0 ) + myprivs[1] = privkey; + privkey = jbits256(item,"privAm"); + if ( bits256_nonz(privkey) != 0 ) + privAm = privkey; + privkey = jbits256(item,"privBn"); + if ( bits256_nonz(privkey) != 0 ) + privBn = privkey; expiration = juint(item,"expiration"); state = jint(item,"state"); otherstate = jint(item,"otherstate"); @@ -2943,18 +2955,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( bits256_nonz(txid) == 0 ) continue; txids[i] = txid; - privkey = jbits256(txobj,"myprivs0"); - if ( bits256_nonz(privkey) != 0 ) - myprivs[0] = privkey; - privkey = jbits256(txobj,"myprivs1"); - if ( bits256_nonz(privkey) != 0 ) - myprivs[1] = privkey; - privkey = jbits256(txobj,"privAm"); - if ( bits256_nonz(privkey) != 0 ) - privAm = privkey; - privkey = jbits256(txobj,"privBn"); - if ( bits256_nonz(privkey) != 0 ) - privBn = privkey; if ( jobj(txobj,"tx") != 0 ) { txbytes[i] = clonestr(jstr(txobj,"tx")); @@ -3031,7 +3031,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("create alicespend\n"); if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) { - printf("have bobpayment txid\n"); + printf("have bobpayment txid %u-%u\n",requestid,quoteid); // alicespend revcalc_rmd160_sha256(secretAm,privAm); vcalc_sha256(0,secretAm256,privAm.bytes,sizeof(privAm)); From 1d6a16b83021aa108ed924494a29dda587fa4aad Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 12 Apr 2017 18:04:26 +0300 Subject: [PATCH 0208/2705] Test --- .gitignore | 4 +++ basilisk/basilisk_swap.c | 55 +++++++++++++++++++++------------------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index 5ce7840c7..a0b017d4d 100755 --- a/.gitignore +++ b/.gitignore @@ -338,3 +338,7 @@ iguana/DB/SWAPS/171316098-410428064 iguana/DB/SWAPS/178665381-1950467641 iguana/DB/SWAPS/4126499968-376410338 + +iguana/DB/SWAPS/1518259123-2214130634 + +iguana/DB/SWAPS/152114847-907489057 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 6ce719e60..5a12d5f7a 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -798,19 +798,19 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); } - basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); + /*basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); - basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen); + basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen);*/ fprintf(fp,"}\n"); fclose(fp); } sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"wb")) != 0 ) { - fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%x,\"otherstate\":%x,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); + fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%u,\"otherstate\":%u,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); for (i=0; i<2; i++) if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); @@ -1307,7 +1307,7 @@ void basilisk_swaps_init(struct supernet_info *myinfo) } } } - } + } else myinfo->swapsfp = fopen(fname,"wb+"); } void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t amlp); @@ -2678,25 +2678,26 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 { //for (i=0; iI.req); i++) // fprintf(stderr,"%02x",((uint8_t *)&swap->I.req)[i]); - fprintf(stderr," M.%d N.%d launch.%d %d %p\n",m,n,myinfo->numswaps,(int32_t)(sizeof(myinfo->swaps)/sizeof(*myinfo->swaps)),&swap->I.req); + fprintf(stderr," M.%d N.%d launch.%d %d %p reinit.%d\n",m,n,myinfo->numswaps,(int32_t)(sizeof(myinfo->swaps)/sizeof(*myinfo->swaps)),&swap->I.req,reinit); if ( (swap->fp= basilisk_swap_save(myinfo,swap,privkey,rp,statebits,optionduration,reinit)) != 0 ) { - if ( reinit == 0 ) + } + if ( reinit == 0 ) + { + if ( myinfo->swapsfp == 0 ) { - if ( myinfo->swapsfp == 0 ) - { - char fname[512]; - sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); - if ( (myinfo->swapsfp= fopen(fname,"rb+")) == 0 ) - myinfo->swapsfp = fopen(fname,"wb+"); - else fseek(myinfo->swapsfp,0,SEEK_END); - } - if ( myinfo->swapsfp != 0 ) - { - fwrite(&rp->requestid,1,sizeof(rp->requestid),myinfo->swapsfp); - fwrite(&rp->quoteid,1,sizeof(rp->quoteid),myinfo->swapsfp); - fflush(myinfo->swapsfp); - } + char fname[512]; + sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); + if ( (myinfo->swapsfp= fopen(fname,"rb+")) == 0 ) + myinfo->swapsfp = fopen(fname,"wb+"); + else fseek(myinfo->swapsfp,0,SEEK_END); + printf("LIST fp.%p\n",myinfo->swapsfp); + } + if ( myinfo->swapsfp != 0 ) + { + fwrite(&rp->requestid,1,sizeof(rp->requestid),myinfo->swapsfp); + fwrite(&rp->quoteid,1,sizeof(rp->quoteid),myinfo->swapsfp); + fflush(myinfo->swapsfp); } } if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) @@ -2939,14 +2940,14 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } item = cJSON_CreateObject(); array = cJSON_CreateArray(); - //printf("R.%u Q.%u\n",requestid,quoteid); + printf("R.%u Q.%u\n",requestid,quoteid); for (i=0; i (%s)\n",fname,fstr); + printf("%s -> (%s)\n",fname,fstr); if ( (txobj= cJSON_Parse(fstr)) != 0 ) { //printf("TXOBJ.(%s)\n",jprint(txobj,0)); @@ -3017,16 +3018,18 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 free(fstr); } } + printf("iambob.%d src.%s dest.%s bob.%s alice.%s\n",iambob,src,dest,bobcoin,alicecoin); + strcpy(bobcoin,"KMD"); + strcpy(alicecoin,"BTC"); if ( bobcoin[0] != 0 && alicecoin[0] != 0 ) { - printf("iambob.%d src.%s dest.%s bob.%s alice.%s\n",iambob,src,dest,bobcoin,alicecoin); if ( iambob == 0 ) { - if ( sentflags[BASILISK_ALICESPEND] == 0 ) + if ( 1 || sentflags[BASILISK_ALICESPEND] == 0 ) { - if ( sentflags[BASILISK_BOBPAYMENT] != 0 ) + if ( 1 || sentflags[BASILISK_BOBPAYMENT] != 0 ) { - if ( txbytes[BASILISK_ALICESPEND] == 0 ) + if ( 1 || txbytes[BASILISK_ALICESPEND] == 0 ) { printf("create alicespend\n"); if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) From 6b156b00c45d04739d6e432d95933c576bb19f44 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 17:33:47 +0300 Subject: [PATCH 0209/2705] Test --- .gitignore | 2 + basilisk/basilisk_swap.c | 136 +++++++++++++++++++++++++++------------ iguana/tests/dexgetO | 2 +- 3 files changed, 99 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index a0b017d4d..f82814161 100755 --- a/.gitignore +++ b/.gitignore @@ -342,3 +342,5 @@ iguana/DB/SWAPS/4126499968-376410338 iguana/DB/SWAPS/1518259123-2214130634 iguana/DB/SWAPS/152114847-907489057 + +iguana/DB/SWAPS/61119357-1960547076 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 5a12d5f7a..ffbba9487 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -217,7 +217,7 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, uint8_t bufA[20],bufB[20]; revcalc_rmd160_sha256(bufA,privkey); calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); - /*if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) + if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) printf("MATCHES BUFA\n"); else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) printf("MATCHES BUFB\n"); @@ -227,7 +227,7 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, printf(" <- revcalc\n"); for (i=0; i<20; i++) printf("%02x",bufB[i]); - printf(" <- calc\n");*/ + printf(" <- calc\n"); memcpy(secret160,bufB,20); } n = bitcoin_secret160verify(redeemscript,n,secret160); @@ -428,7 +428,7 @@ int32_t _basilisk_rawtx_sign(struct supernet_info *myinfo,int32_t height,uint32_ free(signedtx); if ( dest->I.completed != 0 ) retval = 0; - else printf("couldnt sign transaction %s\n",rawtx->name); + else printf("couldnt complete sign transaction %s\n",rawtx->name); } else printf("error signing\n"); free(rawtxbytes); } else printf("error making rawtx\n"); @@ -547,6 +547,8 @@ int32_t _basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swap jadd64bits(valsobj,"satoshis",rawtx->I.amount); jadd64bits(valsobj,"txfee",txfee); jaddnum(valsobj,"minconf",minconf); + if ( locktime == 0 ) + locktime = (uint32_t)time(NULL) - 777; jaddnum(valsobj,"locktime",locktime); jaddnum(valsobj,"timeout",30000); jaddnum(valsobj,"timestamp",swapstarted+delay); @@ -2767,12 +2769,30 @@ void basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname, } } -char *basilisk_swap_bobtxspend(struct supernet_info *myinfo,char *symbol,bits256 privkey,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) +char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) { - char *rawtxbytes=0,*signedtx=0,hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff; struct iguana_info *coin; uint64_t amount=100000; bits256 txid,signedtxid; - printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL)-777,sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); + if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) + { + printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); + return(0); + } + if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + { + printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); + free_json(utxoobj); + return(0); + } else free_json(utxoobj); + if ( destamount > 10000 ) + destamount -= 10000; + if ( strcmp(symbol,"BTC") == 0 ) + { + if ( destamount > 40000 ) + destamount -= 40000; + } height = coin->longestchain; timestamp = (uint32_t)time(NULL); V = calloc(256,sizeof(*V)); @@ -2781,8 +2801,14 @@ char *basilisk_swap_bobtxspend(struct supernet_info *myinfo,char *symbol,bits256 privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeys,wifstr); - printf("wif.%s\n",wifstr); - V[0].N = V[0].M = 1; + if ( privkey2p != 0 ) + { + V[0].signers[1].privkey = *privkey2p; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[1].pubkey,*privkey2p); + bitcoin_priv2wif(wifstr,*privkey2p,coin->chain->wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 2; + } else V[0].N = V[0].M = 1; V[0].suppress_pubkeys = suppress_pubkeys; V[0].ignore_cltverr = ignore_cltverr; if ( redeemlen != 0 ) @@ -2797,7 +2823,6 @@ char *basilisk_swap_bobtxspend(struct supernet_info *myinfo,char *symbol,bits256 init_hexbytes_noT(hexstr,userdata,userdatalen); jaddstr(item,"userdata",hexstr); } - printf("rawtx B\n"); jaddbits256(item,"txid",utxotxid); jaddnum(item,"vout",vout); sobj = cJSON_CreateObject(); @@ -2817,13 +2842,14 @@ char *basilisk_swap_bobtxspend(struct supernet_info *myinfo,char *symbol,bits256 jaddi(vins,item); jdelete(txobj,"vin"); jadd(txobj,"vin",vins); - txobj = bitcoin_txoutput(txobj,spendscript,spendlen,amount); + txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) { - printf("rawtx.(%s) vins.(%s)\n",rawtxbytes,jprint(vins,0)); - if ( signedtx != 0 || (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) != 0 ) + //printf("rawtx.(%s) vins.(%s)\n",rawtxbytes,jprint(vins,0)); + if ( (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction\n"); - else printf("error signing\n"); + else if ( completed == 0 ) + printf("incomplete signing\n"); free(rawtxbytes); } else printf("error making rawtx\n"); free_json(privkeys); @@ -2832,9 +2858,16 @@ char *basilisk_swap_bobtxspend(struct supernet_info *myinfo,char *symbol,bits256 return(signedtx); } -char *basilisk_swap_Aspend(struct supernet_info *myinfo,char *coin,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) +char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) { - char *signedtx = 0; + char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen,len = 0; uint8_t userdata[256],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); + if ( coin != 0 ) + { + pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); + pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); + spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); + signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,userdata,len,utxotxid,vout,pubkey33); + } return(signedtx); } @@ -2842,18 +2875,28 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *coin,bits256 { bits256 txid; // listtransactions or listspents + memset(&txid,0,sizeof(txid)); return(txid); } bits256 basilisk_swap_privAm_extract(struct supernet_info *myinfo,char *coin,bits256 utxotxid,int32_t vout) { bits256 privAm; + memset(&privAm,0,sizeof(privAm)); return(privAm); } bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,char *coin,bits256 utxotxid,int32_t vout) { - bits256 privBn; + bits256 privBn; // from Bob refund of Bob deposit + memset(&privBn,0,sizeof(privBn)); + return(privBn); +} + +bits256 basilisk_swap_privBn_extract2(struct supernet_info *myinfo,char *coin,bits256 utxotxid,int32_t vout) +{ + bits256 privBn; // from Bob spend of Alice payment + memset(&privBn,0,sizeof(privBn)); return(privBn); } @@ -2874,7 +2917,7 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount,value; uint8_t secretAm[32],secretAm256[32],secretBn[32],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *srcstr,*deststr,src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str[65],str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*triggerobj,*sentobj,*array; bits256 checktxid,txid,trigger,privkey,pubA0,pubB0,pubB1,privAm,privBn,zero,revAm,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[32],secretAm256[32],secretBn[32],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,zero,privkey,revAm,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); memset(secretAm256,0,sizeof(secretAm256)); @@ -2917,7 +2960,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 privAm = privkey; privkey = jbits256(item,"privBn"); if ( bits256_nonz(privkey) != 0 ) + { privBn = privkey; + printf("set privBn <- %s\n",bits256_str(str,privBn)); + } expiration = juint(item,"expiration"); state = jint(item,"state"); otherstate = jint(item,"otherstate"); @@ -2940,14 +2986,14 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } item = cJSON_CreateObject(); array = cJSON_CreateArray(); - printf("R.%u Q.%u\n",requestid,quoteid); + //printf("R.%u Q.%u\n",requestid,quoteid); for (i=0; i (%s)\n",fname,fstr); + //printf("%s -> (%s)\n",fname,fstr); if ( (txobj= cJSON_Parse(fstr)) != 0 ) { //printf("TXOBJ.(%s)\n",jprint(txobj,0)); @@ -3025,27 +3071,24 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( iambob == 0 ) { - if ( 1 || sentflags[BASILISK_ALICESPEND] == 0 ) + if ( sentflags[BASILISK_ALICESPEND] == 0 ) { - if ( 1 || sentflags[BASILISK_BOBPAYMENT] != 0 ) + if ( sentflags[BASILISK_BOBPAYMENT] != 0 ) { - if ( 1 || txbytes[BASILISK_ALICESPEND] == 0 ) + if ( txbytes[BASILISK_ALICESPEND] == 0 ) { - printf("create alicespend\n"); if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) { - printf("have bobpayment txid %u-%u\n",requestid,quoteid); // alicespend revcalc_rmd160_sha256(secretAm,privAm); vcalc_sha256(0,secretAm256,privAm.bytes,sizeof(privAm)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); - for (j=0; j<32; j++) - revAm.bytes[j] = privAm.bytes[31-j]; - len = basilisk_swapuserdata(userdata,revAm,0,myprivs[0],redeemscript,redeemlen); - txbytes[BASILISK_ALICESPEND] = basilisk_swap_bobtxspend(myinfo,alicecoin,myprivs[0],redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33); + len = basilisk_swapuserdata(userdata,privAm,0,myprivs[0],redeemscript,redeemlen); + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33)) != 0 ) + printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } - if ( txbytes[BASILISK_ALICESPEND] != 0 ) + if ( 0 && txbytes[BASILISK_ALICESPEND] != 0 ) // tested! basilisk_swap_sendrawtransaction(myinfo,"alicespend",alicecoin,txbytes[BASILISK_ALICESPEND]); } } @@ -3053,18 +3096,26 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( time(NULL) > expiration ) { - if ( txbytes[BASILISK_ALICECLAIM] == 0 ) + if ( bits256_nonz(privBn) == 0 ) + { + if ( bits256_nonz(txids[BASILISK_BOBSPEND]) == 0 ) + txids[BASILISK_BOBSPEND] = basilisk_swap_spendtxid(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT],0); + if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) + privBn = basilisk_swap_privBn_extract2(myinfo,alicecoin,txids[BASILISK_BOBSPEND],0); + } + if ( txbytes[BASILISK_ALICECLAIM] == 0 && bits256_nonz(privBn) != 0 ) { // claim bobdeposit revcalc_rmd160_sha256(secretBn,privBn); vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - // myprivs[0] + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,alicecoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) + printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } - if ( txbytes[BASILISK_ALICECLAIM] != 0 ) + if ( 0 && txbytes[BASILISK_ALICECLAIM] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); - } + } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); } if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) { @@ -3078,9 +3129,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 privBn = basilisk_swap_privBn_extract(myinfo,bobcoin,txids[BASILISK_BOBREFUND],0); } if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) - txbytes[BASILISK_ALICERECLAIM] = basilisk_swap_Aspend(myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33); + if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) + printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); } - if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) + if ( 0 && txbytes[BASILISK_ALICERECLAIM] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); } } @@ -3100,9 +3152,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 privAm = basilisk_swap_privAm_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); } if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) - txbytes[BASILISK_BOBSPEND] = basilisk_swap_Aspend(myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33); + if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) + printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); } - if ( txbytes[BASILISK_BOBSPEND] != 0 ) + if ( 0 && txbytes[BASILISK_BOBSPEND] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); } } @@ -3118,9 +3171,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - // myprivs[0] + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) + printf("privBn.(%s) bobrefund.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } - if ( txbytes[BASILISK_BOBREFUND] != 0 ) + if ( 0 && txbytes[BASILISK_BOBREFUND] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); } } @@ -3135,8 +3189,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); // myprivs[1] + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33)) != 0 ) + printf("privBn.(%s) bobreclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_BOBRECLAIM]); } - if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) + if ( 0 && txbytes[BASILISK_BOBRECLAIM] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); } } diff --git a/iguana/tests/dexgetO b/iguana/tests/dexgetO index 49348a577..8f3ab668e 100755 --- a/iguana/tests/dexgetO +++ b/iguana/tests/dexgetO @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"gettxout\",\"vout\":0,\"txid\":\"3b0f38d8cf4b3a89b6c83003410abdb773422d814ce93d68730c00c91e770995\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"gettxout\",\"vout\":0,\"txid\":\"8661a47003ce3d1712dee5798432475b6b7abb65ba88c4f26eb37446b9038973\",\"symbol\":\"BTC\"}" From 2817ea888e3f3b7bdfaa0da9453afb3609746fec Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 17:37:57 +0300 Subject: [PATCH 0210/2705] Test --- basilisk/basilisk_swap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ffbba9487..2043f8431 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3163,7 +3163,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( sentflags[BASILISK_BOBSPEND] != 0 || time(NULL) > expiration-INSTANTDEX_LOCKTIME/2 ) { - if ( txbytes[BASILISK_BOBREFUND] == 0 ) + if ( 1 || txbytes[BASILISK_BOBREFUND] == 0 ) { // bobrefund printf("unexpected missing BOBREFUND txbytes\n"); @@ -3180,10 +3180,9 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) { - if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) + if ( txbytes[BASILISK_BOBRECLAIM] == 0 && bits256_nonz(privAm) != 0 ) { // bobreclaim - printf("unexpected missing BOBRECLAIM txbytes\n"); revcalc_rmd160_sha256(secretAm,privAm); vcalc_sha256(0,secretAm256,privAm.bytes,sizeof(privAm)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); From 34e470c3c47e5133dabb580c4e196bd8ac26a9ff Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 17:41:17 +0300 Subject: [PATCH 0211/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2043f8431..c834bb958 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3161,7 +3161,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) { - if ( sentflags[BASILISK_BOBSPEND] != 0 || time(NULL) > expiration-INSTANTDEX_LOCKTIME/2 ) + if ( 1 || sentflags[BASILISK_BOBSPEND] != 0 || time(NULL) > expiration-INSTANTDEX_LOCKTIME/2 ) { if ( 1 || txbytes[BASILISK_BOBREFUND] == 0 ) { @@ -3176,7 +3176,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } if ( 0 && txbytes[BASILISK_BOBREFUND] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); - } + } else printf("time %u < expiration %u\n",(uint32_t)time(NULL),expiration-INSTANTDEX_LOCKTIME/2); } if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) { From e62090b86c830ed18745f027b9b556d780028999 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 17:46:41 +0300 Subject: [PATCH 0212/2705] Test --- basilisk/basilisk_swap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index c834bb958..4c57ffaca 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2917,7 +2917,7 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[32],secretAm256[32],secretBn[32],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,zero,privkey,revAm,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[32],secretAm256[32],secretBn[32],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); memset(secretAm256,0,sizeof(secretAm256)); @@ -2927,7 +2927,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 memset(txbytes,0,sizeof(txbytes)); memset(sentflags,0,sizeof(sentflags)); memset(myprivs,0,sizeof(myprivs)); - revAm = zero = pubA0 = pubB0 = pubB1 = privAm = privBn = myprivs[0]; + rev = zero = pubA0 = pubB0 = pubB1 = privAm = privBn = myprivs[0]; plocktime = dlocktime = 0; src[0] = dest[0] = bobcoin[0] = alicecoin[0] = 0; sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); @@ -3166,11 +3166,12 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( 1 || txbytes[BASILISK_BOBREFUND] == 0 ) { // bobrefund - printf("unexpected missing BOBREFUND txbytes\n"); revcalc_rmd160_sha256(secretBn,privBn); vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); + int32_t j; for (j=0; j<32; j++) + rev.bytes[i] = privBn.bytes[31-i]; + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) printf("privBn.(%s) bobrefund.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } From f4e35349656d0017ea9bea903adfe07994a48d93 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 17:59:04 +0300 Subject: [PATCH 0213/2705] Test --- basilisk/basilisk_swap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 4c57ffaca..0ce68ce93 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3064,7 +3064,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 free(fstr); } } - printf("iambob.%d src.%s dest.%s bob.%s alice.%s\n",iambob,src,dest,bobcoin,alicecoin); + printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); strcpy(bobcoin,"KMD"); strcpy(alicecoin,"BTC"); if ( bobcoin[0] != 0 && alicecoin[0] != 0 ) @@ -3138,6 +3138,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } else if ( iambob == 1 ) { + printf("privAm.(%s)\n",bits256_str(str,privAm)); + printf("pubB0.(%s)\n",bits256_str(str,pubB0)); if ( sentflags[BASILISK_BOBSPEND] == 0 ) { if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) @@ -3173,7 +3175,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 rev.bytes[i] = privBn.bytes[31-i]; len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) - printf("privBn.(%s) bobrefund.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); + printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_ALICECLAIM]); } if ( 0 && txbytes[BASILISK_BOBREFUND] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); From ada00a1d7c8da089f9529851206a90081f44d5e1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 18:11:33 +0300 Subject: [PATCH 0214/2705] Test --- basilisk/basilisk_swap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0ce68ce93..8f71ffa1f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3140,6 +3140,9 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { printf("privAm.(%s)\n",bits256_str(str,privAm)); printf("pubB0.(%s)\n",bits256_str(str,pubB0)); + printf("myprivs0.(%s)\n",bits256_str(str,myprivs[0])); + printf("myprivs1.(%s)\n",bits256_str(str,myprivs[1])); + printf("privBn.(%s)\n",bits256_str(str,privBn)); if ( sentflags[BASILISK_BOBSPEND] == 0 ) { if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) @@ -3173,7 +3176,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); int32_t j; for (j=0; j<32; j++) rev.bytes[i] = privBn.bytes[31-i]; - len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_ALICECLAIM]); } From 2ac7b45f7c3d3724d2b740148d82e54ab5b687f6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 18:15:06 +0300 Subject: [PATCH 0215/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 8f71ffa1f..1d491ca1b 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3178,7 +3178,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 rev.bytes[i] = privBn.bytes[31-i]; len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) - printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_ALICECLAIM]); + printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( 0 && txbytes[BASILISK_BOBREFUND] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); From 6a0b557bc6da779366dec202d3b779e630c59a06 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 22:10:12 +0300 Subject: [PATCH 0216/2705] Test --- basilisk/basilisk_swap.c | 249 ++++++++++++++++++++++--------- iguana/tests/dexlisttransactions | 2 +- 2 files changed, 180 insertions(+), 71 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 1d491ca1b..1b81fe1ee 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -760,9 +760,10 @@ void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,in void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx,int32_t locktime,bits256 triggertxid) { - char fname[512],str[65],coinaddr[64]; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; + char zeroes[32],fname[512],str[65],coinaddr[64],secretAmstr[41],secretAm256str[65],secretBnstr[41],secretBn256str[65]; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); - coinaddr[0] = 0; + coinaddr[0] = secretAmstr[0] = secretAm256str[0] = secretBnstr[0] = secretBn256str[0] = 0; + memset(zeroes,0,sizeof(zeroes)); if ( (fp= fopen(fname,"wb")) != 0 ) { fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); @@ -813,6 +814,26 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap if ( (fp= fopen(fname,"wb")) != 0 ) { fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%u,\"otherstate\":%u,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); + if ( memcmp(zeroes,swap->I.secretAm,20) != 0 ) + { + init_hexbytes_noT(secretAmstr,swap->I.secretAm,20); + fprintf(fp,",\"secretAm\":\"%s\"",secretAmstr); + } + if ( memcmp(zeroes,swap->I.secretAm256,32) != 0 ) + { + init_hexbytes_noT(secretAm256str,swap->I.secretAm256,32); + fprintf(fp,",\"secretAm256\":\"%s\"",secretAm256str); + } + if ( memcmp(zeroes,swap->I.secretBn,20) != 0 ) + { + init_hexbytes_noT(secretBnstr,swap->I.secretBn,20); + fprintf(fp,",\"secretBn\":\"%s\"",secretBnstr); + } + if ( memcmp(zeroes,swap->I.secretBn256,32) != 0 ) + { + init_hexbytes_noT(secretBn256str,swap->I.secretBn256,32); + fprintf(fp,",\"secretBn256\":\"%s\"",secretBn256str); + } for (i=0; i<2; i++) if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); @@ -2759,14 +2780,60 @@ cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid return(basilisk_nullretjson(retjson)); } -void basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname,char *symbol,char *txbytes) +int32_t basilisk_swap_getcoinaddr(struct supernet_info *myinfo,char *symbol,char *coinaddr,bits256 txid,int32_t vout) { - char *retstr; + cJSON *retjson,*vouts,*item,*skey,*addresses; int32_t n,m; char *addr; + coinaddr[0] = 0; + if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + if ( (vouts= jarray(&n,retjson,"vout")) != 0 && vout < n ) + { + item = jitem(vouts,vout); + if ( (skey= jobj(item,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + { + item = jitem(addresses,0); + //printf("item.(%s)\n",jprint(item,0)); + if ( (addr= jstr(item,0)) != 0 ) + safecopy(coinaddr,addr,64); + } + } + free_json(retjson); + } + return(coinaddr[0] != 0); +} + +int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uint8_t *script,int32_t maxlen,bits256 txid,int32_t vini) +{ + cJSON *retjson,*vins,*item,*skey; int32_t n,scriptlen = 0; char *hexstr; + if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + if ( (vins= jarray(&n,retjson,"vin")) != 0 && vini < n ) + { + item = jitem(vins,vini); + if ( (skey= jobj(item,"scriptSig")) != 0 && (hexstr= jstr(skey,"hex")) != 0 && (scriptlen= (int32_t)strlen(hexstr)) < maxlen*2 ) + { + scriptlen >>= 1; + decode_hex(script,scriptlen,hexstr); + char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); + } + } + free_json(retjson); + } + return(scriptlen); +} + +bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname,char *symbol,char *txbytes) +{ + char *retstr; bits256 txid; + memset(&txid,0,sizeof(txid)); if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) { - printf("[%s] %s RETSTR.(%s)\n",txname,txbytes,retstr); + if ( is_hexstr(retstr,64) == 64 ) + decode_hex(txid.bytes,32,retstr); + char str[65]; printf("[%s] %s RETSTR.(%s) %s\n",txname,txbytes,retstr,bits256_str(str,txid)); free(retstr); } + return(txid); } char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) @@ -2861,7 +2928,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) { char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen,len = 0; uint8_t userdata[256],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); - if ( coin != 0 ) + if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); @@ -2871,36 +2938,65 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, return(signedtx); } -bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *coin,bits256 utxotxid,int32_t vout) +bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,bits256 utxotxid,int32_t vout) { - bits256 txid; + bits256 spendtxid,txid; char *retstr; cJSON *array,*item; int32_t i,n; char coinaddr[64]; // listtransactions or listspents - memset(&txid,0,sizeof(txid)); - return(txid); + memset(&spendtxid,0,sizeof(spendtxid)); + if ( iguana_isnotarychain(symbol) >= 0 ) + { + //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] + basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + if ( coinaddr[0] != 0 && (retstr= _dex_listtransactions(myinfo,symbol,coinaddr,100,0)) != 0 ) + { + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i 0 ) + { + siglen = script[0]; + for (i=0; i<32; i++) + privBn.bytes[31 - i] = script[siglen+1+i]; + char str[65]; printf("extracted privBn.(%s)\n",bits256_str(str,privBn)); + } return(privBn); } - #define BASILISK_ALICESPEND 0 #define BASILISK_BOBSPEND 1 #define BASILISK_BOBPAYMENT 2 @@ -2917,7 +3013,7 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[32],secretAm256[32],secretBn[32],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); memset(secretAm256,0,sizeof(secretAm256)); @@ -2936,6 +3032,14 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( (item= cJSON_Parse(fstr)) != 0 ) { iambob = jint(item,"iambob"); + if ( (secretstr= jstr(item,"secretAm")) != 0 && strlen(secretstr) == 40 ) + decode_hex(secretAm,20,secretstr); + if ( (secretstr= jstr(item,"secretAm256")) != 0 && strlen(secretstr) == 32 ) + decode_hex(secretAm256,32,secretstr); + if ( (secretstr= jstr(item,"secretBn")) != 0 && strlen(secretstr) == 40 ) + decode_hex(secretBn,20,secretstr); + if ( (secretstr= jstr(item,"secretBn256")) != 0 && strlen(secretstr) == 32 ) + decode_hex(secretBn256,32,secretstr); if ( (srcstr= jstr(item,"src")) != 0 ) safecopy(src,srcstr,sizeof(src)); if ( (deststr= jstr(item,"dest")) != 0 ) @@ -3080,38 +3184,38 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) { // alicespend - revcalc_rmd160_sha256(secretAm,privAm); - vcalc_sha256(0,secretAm256,privAm.bytes,sizeof(privAm)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,privAm,0,myprivs[0],redeemscript,redeemlen); + for (j=0; j<32; j++) + rev.bytes[j] = privAm.bytes[31 - j]; + revcalc_rmd160_sha256(secretAm,rev);//privAm); + vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } - if ( 0 && txbytes[BASILISK_ALICESPEND] != 0 ) // tested! - basilisk_swap_sendrawtransaction(myinfo,"alicespend",alicecoin,txbytes[BASILISK_ALICESPEND]); - } + if ( txbytes[BASILISK_ALICESPEND] != 0 ) + { + txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction(myinfo,"alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested! + sentflags[BASILISK_ALICESPEND] = 1; + } + } } if ( sentflags[BASILISK_ALICECLAIM] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) { if ( time(NULL) > expiration ) { - if ( bits256_nonz(privBn) == 0 ) - { - if ( bits256_nonz(txids[BASILISK_BOBSPEND]) == 0 ) - txids[BASILISK_BOBSPEND] = basilisk_swap_spendtxid(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT],0); - if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) - privBn = basilisk_swap_privBn_extract2(myinfo,alicecoin,txids[BASILISK_BOBSPEND],0); - } - if ( txbytes[BASILISK_ALICECLAIM] == 0 && bits256_nonz(privBn) != 0 ) + if ( txbytes[BASILISK_ALICECLAIM] == 0 ) { // claim bobdeposit - revcalc_rmd160_sha256(secretBn,privBn); - vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,alicecoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) - printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); + if ( redeemlen > 0 ) + { + len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,alicecoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) + printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); + } } if ( 0 && txbytes[BASILISK_ALICECLAIM] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); @@ -3126,7 +3230,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( bits256_nonz(txids[BASILISK_BOBREFUND]) == 0 ) txids[BASILISK_BOBREFUND] = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBDEPOSIT],0); if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) - privBn = basilisk_swap_privBn_extract(myinfo,bobcoin,txids[BASILISK_BOBREFUND],0); + privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_BOBREFUND],0); } if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) @@ -3147,59 +3251,64 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) { - if ( txbytes[BASILISK_BOBSPEND] == 0 ) + if ( txbytes[BASILISK_BOBSPEND] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) { if ( bits256_nonz(privAm) == 0 ) { if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) txids[BASILISK_ALICESPEND] = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBPAYMENT],0); if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) - privAm = basilisk_swap_privAm_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); + privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); } - if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); } - if ( 0 && txbytes[BASILISK_BOBSPEND] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); + if ( txbytes[BASILISK_BOBSPEND] != 0 ) + { + txids[BASILISK_BOBSPEND] = basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); + if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) + sentflags[BASILISK_BOBSPEND] = 1; + } + } + } + if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) + { + if ( txbytes[BASILISK_BOBRECLAIM] == 0 )//&& bits256_nonz(privAm) != 0 ) + { + // bobreclaim + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + if ( redeemlen > 0 ) + { + len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33)) != 0 ) + printf("privBn.(%s) bobreclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_BOBRECLAIM]); + } + } + if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) + { + txids[BASILISK_BOBRECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); + if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) + sentflags[BASILISK_BOBRECLAIM] = 1; } } if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) { - if ( 1 || sentflags[BASILISK_BOBSPEND] != 0 || time(NULL) > expiration-INSTANTDEX_LOCKTIME/2 ) + if ( sentflags[BASILISK_BOBSPEND] != 0 || sentflags[BASILISK_BOBRECLAIM] != 0 ) { - if ( 1 || txbytes[BASILISK_BOBREFUND] == 0 ) + if ( txbytes[BASILISK_BOBREFUND] == 0 ) { - // bobrefund revcalc_rmd160_sha256(secretBn,privBn); vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); - int32_t j; for (j=0; j<32; j++) - rev.bytes[i] = privBn.bytes[31-i]; len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } - if ( 0 && txbytes[BASILISK_BOBREFUND] != 0 ) + if ( txbytes[BASILISK_BOBREFUND] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); } else printf("time %u < expiration %u\n",(uint32_t)time(NULL),expiration-INSTANTDEX_LOCKTIME/2); } - if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) - { - if ( txbytes[BASILISK_BOBRECLAIM] == 0 && bits256_nonz(privAm) != 0 ) - { - // bobreclaim - revcalc_rmd160_sha256(secretAm,privAm); - vcalc_sha256(0,secretAm256,privAm.bytes,sizeof(privAm)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - // myprivs[1] - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33)) != 0 ) - printf("privBn.(%s) bobreclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_BOBRECLAIM]); - } - if ( 0 && txbytes[BASILISK_BOBRECLAIM] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); - } } } jaddnum(item,"requestid",requestid); diff --git a/iguana/tests/dexlisttransactions b/iguana/tests/dexlisttransactions index d53a0ff46..c12c56d96 100755 --- a/iguana/tests/dexlisttransactions +++ b/iguana/tests/dexlisttransactions @@ -1,5 +1,5 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"1Pc27firvEwPoDzPzYdJKZ5hoZK4T1tf6z\",\"count\":100,\"skip\":0,\"symbol\":\"BTC\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"bZY6LMGHXbpLkyw14uW5XbRsH8LB5MhnLe\",\"count\":100,\"skip\":0,\"symbol\":\"KMD\"}" #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"RRyBxbrAPRUBCUpiJgJZYrkxqrh8x5ta9Z\",\"count\":100,\"skip\":0,\"symbol\":\"MVP\"}" #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"RMGpGoX82M1ZUUbHxZ3JKHacxY9NYVakqr\",\"count\":100,\"skip\":0,\"symbol\":\"USD\"}" #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"RMGpGoX82M1ZUUbHxZ3JKHacxY9NYVakqr\",\"count\":100,\"skip\":0,\"symbol\":\"MVP\"}" From 8b5ae9c8e0ee89a5118e5cffb902c7f931eec596 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 22:14:11 +0300 Subject: [PATCH 0217/2705] Test --- basilisk/basilisk_swap.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 1b81fe1ee..c4a54f873 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3249,16 +3249,15 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("privBn.(%s)\n",bits256_str(str,privBn)); if ( sentflags[BASILISK_BOBSPEND] == 0 ) { - if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) + txids[BASILISK_ALICESPEND] = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBPAYMENT],0); + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) { - if ( txbytes[BASILISK_BOBSPEND] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) + if ( txbytes[BASILISK_BOBSPEND] == 0 ) { if ( bits256_nonz(privAm) == 0 ) { - if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) - txids[BASILISK_ALICESPEND] = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBPAYMENT],0); - if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) - privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); + privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) From 3d898dfe60924a484b961efc1b88dfa895c8beba Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 22:21:38 +0300 Subject: [PATCH 0218/2705] Test --- basilisk/basilisk_swap.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index c4a54f873..2c8e33980 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2976,13 +2976,6 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,bits25 return(spendtxid); } -bits256 basilisk_swap_privalice_extract(struct supernet_info *myinfo,char *symbol,bits256 utxotxid,int32_t vout) -{ - bits256 privAm; - memset(&privAm,0,sizeof(privAm)); - return(privAm); -} - bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol,bits256 spendtxid,int32_t vini) { bits256 privBn; int32_t i,scriptlen,siglen; uint8_t script[1024]; // from Bob refund of Bob deposit @@ -2991,7 +2984,7 @@ bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol, { siglen = script[0]; for (i=0; i<32; i++) - privBn.bytes[31 - i] = script[siglen+1+i]; + privBn.bytes[i] = script[siglen+2+i]; char str[65]; printf("extracted privBn.(%s)\n",bits256_str(str,privBn)); } return(privBn); @@ -3273,7 +3266,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) { - if ( txbytes[BASILISK_BOBRECLAIM] == 0 )//&& bits256_nonz(privAm) != 0 ) + if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) { // bobreclaim redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); @@ -3306,7 +3299,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } if ( txbytes[BASILISK_BOBREFUND] != 0 ) basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); - } else printf("time %u < expiration %u\n",(uint32_t)time(NULL),expiration-INSTANTDEX_LOCKTIME/2); + } } } } From a634607eb20a71d71d59eba011f6514a18b5c7bb Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 22:31:37 +0300 Subject: [PATCH 0219/2705] Test --- basilisk/basilisk_swap.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2c8e33980..e036604d0 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2839,7 +2839,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) { char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL)-777,sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; - //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) @@ -2933,6 +2933,7 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); + printf("redeemlen.%d spendlen.%d\n",redeemlen,spendlen); signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,userdata,len,utxotxid,vout,pubkey33); } return(signedtx); @@ -2978,16 +2979,16 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,bits25 bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol,bits256 spendtxid,int32_t vini) { - bits256 privBn; int32_t i,scriptlen,siglen; uint8_t script[1024]; // from Bob refund of Bob deposit - memset(&privBn,0,sizeof(privBn)); + bits256 privkey; int32_t i,scriptlen,siglen; uint8_t script[1024]; // from Bob refund of Bob deposit + memset(&privkey,0,sizeof(privkey)); if ( (scriptlen= basilisk_swap_getsigscript(myinfo,symbol,script,(int32_t)sizeof(script),spendtxid,vini)) > 0 ) { siglen = script[0]; for (i=0; i<32; i++) - privBn.bytes[i] = script[siglen+2+i]; - char str[65]; printf("extracted privBn.(%s)\n",bits256_str(str,privBn)); + privkey.bytes[i] = script[siglen+2+i]; + char str[65]; printf("extracted privbob.(%s)\n",bits256_str(str,privkey)); } - return(privBn); + return(privkey); } #define BASILISK_ALICESPEND 0 From 0588b9ba06742ba771a7bf821e3e15d30054674b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 22:36:39 +0300 Subject: [PATCH 0220/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index e036604d0..1fff2f75c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2912,7 +2912,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) { - //printf("rawtx.(%s) vins.(%s)\n",rawtxbytes,jprint(vins,0)); + printf("rawtx.(%s) vins.(%s)\n",rawtxbytes,jprint(vins,0)); if ( (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction\n"); else if ( completed == 0 ) @@ -2933,7 +2933,7 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); - printf("redeemlen.%d spendlen.%d\n",redeemlen,spendlen); + char str[65]; printf("utxo.(%s) redeemlen.%d spendlen.%d\n",bits256_str(str,utxotxid),redeemlen,spendlen); signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,userdata,len,utxotxid,vout,pubkey33); } return(signedtx); From f13b6a2d15e5c4e9dd196070d3c0afc78401ebdd Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 22:42:03 +0300 Subject: [PATCH 0221/2705] Test --- basilisk/basilisk_swap.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 1fff2f75c..cf33813b3 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2759,10 +2759,16 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t { if ( (retstr= _dex_gettxout(myinfo,symbol,trigger,vout)) != 0 ) { + printf("dexgettxout.(%s)\n",retstr); retjson = cJSON_Parse(retstr); free(retstr); } - } else retjson = dpow_gettxout(myinfo,coin,trigger,vout); + } + else + { + retjson = dpow_gettxout(myinfo,coin,trigger,vout); + printf("dpowgettxout.(%s)\n",jprint(retjson,0)); + } return(basilisk_nullretjson(retjson)); } From 230e2b73ca894be1b36b51e87c808831df3cfda1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 22:44:16 +0300 Subject: [PATCH 0222/2705] test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index cf33813b3..ae967e04c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2755,7 +2755,7 @@ cJSON *basilisk_nullretjson(cJSON *retjson) cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 trigger,int32_t vout) { char *retstr; cJSON *retjson=0; struct iguana_info *coin; - if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 ) + if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 || iguana_isnotarychain(symbol) >= 0 ) { if ( (retstr= _dex_gettxout(myinfo,symbol,trigger,vout)) != 0 ) { From f9ed6d5750c3e0e1ae007030d611b099280c6893 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 13 Apr 2017 22:55:37 +0300 Subject: [PATCH 0223/2705] Test --- basilisk/basilisk_swap.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ae967e04c..762d3fde0 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2767,6 +2767,7 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t else { retjson = dpow_gettxout(myinfo,coin,trigger,vout); + printf("need to verify passthru has this info\n"); printf("dpowgettxout.(%s)\n",jprint(retjson,0)); } return(basilisk_nullretjson(retjson)); @@ -2933,11 +2934,17 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) { - char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen,len = 0; uint8_t userdata[256],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); + char msigaddr[64],*signedtx = 0; bits256 rev; int32_t i,spendlen,redeemlen,len = 0; uint8_t userdata[256],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); - pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); + rev = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); + memset(&pubAm,0,sizeof(pubAm)); + memset(&pubBn,0,sizeof(pubBn)); + for (i=0; i<32; i++) + pubAm.bytes[i] = rev.bytes[31-i]; + rev = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); + for (i=0; i<32; i++) + pubBn.bytes[i] = rev.bytes[31-i]; spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); char str[65]; printf("utxo.(%s) redeemlen.%d spendlen.%d\n",bits256_str(str,utxotxid),redeemlen,spendlen); signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,userdata,len,utxotxid,vout,pubkey33); From 26250e7392be74cc55898ac027165bffc9383699 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 02:30:55 +0300 Subject: [PATCH 0224/2705] Test --- basilisk/basilisk_swap.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 762d3fde0..3d9ab93e4 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2934,19 +2934,13 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) { - char msigaddr[64],*signedtx = 0; bits256 rev; int32_t i,spendlen,redeemlen,len = 0; uint8_t userdata[256],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); + char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen,len = 0; uint8_t userdata[256],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - rev = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); - memset(&pubAm,0,sizeof(pubAm)); - memset(&pubBn,0,sizeof(pubBn)); - for (i=0; i<32; i++) - pubAm.bytes[i] = rev.bytes[31-i]; - rev = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); - for (i=0; i<32; i++) - pubBn.bytes[i] = rev.bytes[31-i]; + pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); + pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); - char str[65]; printf("utxo.(%s) redeemlen.%d spendlen.%d\n",bits256_str(str,utxotxid),redeemlen,spendlen); + char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,userdata,len,utxotxid,vout,pubkey33); } return(signedtx); @@ -3178,6 +3172,11 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); strcpy(bobcoin,"KMD"); strcpy(alicecoin,"BTC"); + printf("privAm.(%s)\n",bits256_str(str,privAm)); + printf("pubB0.(%s)\n",bits256_str(str,pubB0)); + printf("myprivs0.(%s)\n",bits256_str(str,myprivs[0])); + printf("myprivs1.(%s)\n",bits256_str(str,myprivs[1])); + printf("privBn.(%s)\n",bits256_str(str,privBn)); if ( bobcoin[0] != 0 && alicecoin[0] != 0 ) { if ( iambob == 0 ) @@ -3249,11 +3248,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } else if ( iambob == 1 ) { - printf("privAm.(%s)\n",bits256_str(str,privAm)); - printf("pubB0.(%s)\n",bits256_str(str,pubB0)); - printf("myprivs0.(%s)\n",bits256_str(str,myprivs[0])); - printf("myprivs1.(%s)\n",bits256_str(str,myprivs[1])); - printf("privBn.(%s)\n",bits256_str(str,privBn)); if ( sentflags[BASILISK_BOBSPEND] == 0 ) { if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) @@ -3265,6 +3259,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( bits256_nonz(privAm) == 0 ) { privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); + printf("privAm.(%s) <<<<<<<<<<<<\n",bits256_str(str,privAm)); } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) From 30fc374d900a61ff5ce29228209e9a2f2db948eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 02:34:02 +0300 Subject: [PATCH 0225/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3d9ab93e4..6d3e9ecf4 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2992,7 +2992,7 @@ bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol, { siglen = script[0]; for (i=0; i<32; i++) - privkey.bytes[i] = script[siglen+2+i]; + privkey.bytes[31 - i] = script[siglen+2+i]; char str[65]; printf("extracted privbob.(%s)\n",bits256_str(str,privkey)); } return(privkey); From 9f6872bac1240013a844ea96161bf83605b07b58 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 02:55:52 +0300 Subject: [PATCH 0226/2705] Test --- basilisk/basilisk_swap.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 6d3e9ecf4..5c0d0154d 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1751,6 +1751,7 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv if ( swap->I.aliceconfirms == 0 ) swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms; jumblrflag = (bits256_cmp(pubkey25519,myinfo->jumblr_pubkey) == 0 || bits256_cmp(pubkey25519,myinfo->jumblr_depositkey) == 0); + printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address\n",jumblrflag); if ( swap->I.iambob != 0 ) { basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_DECKSIZE,0,0,jumblrflag); @@ -2759,7 +2760,7 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t { if ( (retstr= _dex_gettxout(myinfo,symbol,trigger,vout)) != 0 ) { - printf("dexgettxout.(%s)\n",retstr); + //printf("dexgettxout.(%s)\n",retstr); retjson = cJSON_Parse(retstr); free(retstr); } @@ -2934,14 +2935,20 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) { - char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen,len = 0; uint8_t userdata[256],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); + char msigaddr[64],*signedtx = 0; int32_t i,spendlen,redeemlen; uint8_t redeemscript[512],spendscript[128]; bits256 pubAm,pubBn,rev; struct iguana_info *coin = iguana_coinfind(symbol); if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); - char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); - signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,userdata,len,utxotxid,vout,pubkey33); + //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); + rev = privAm; + for (i=0; i<32; i++) + privAm.bytes[i] = rev.bytes[31 - i]; + rev = privBn; + for (i=0; i<32; i++) + privBn.bytes[i] = rev.bytes[31 - i]; + signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33); } return(signedtx); } @@ -3259,7 +3266,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( bits256_nonz(privAm) == 0 ) { privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); - printf("privAm.(%s) <<<<<<<<<<<<\n",bits256_str(str,privAm)); } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) From f466929363d673897b0039887c2ffb7913d17d90 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:00:58 +0300 Subject: [PATCH 0227/2705] Test --- basilisk/basilisk_swap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 5c0d0154d..f92517785 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2935,19 +2935,19 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) { - char msigaddr[64],*signedtx = 0; int32_t i,spendlen,redeemlen; uint8_t redeemscript[512],spendscript[128]; bits256 pubAm,pubBn,rev; struct iguana_info *coin = iguana_coinfind(symbol); + char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); - rev = privAm; + /*rev = privAm; for (i=0; i<32; i++) privAm.bytes[i] = rev.bytes[31 - i]; rev = privBn; for (i=0; i<32; i++) - privBn.bytes[i] = rev.bytes[31 - i]; + privBn.bytes[i] = rev.bytes[31 - i];*/ signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33); } return(signedtx); From b806e19747b1465e3748e9bdc2606ed1ae68642c Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:10:19 +0300 Subject: [PATCH 0228/2705] Test --- iguana/iguana_sign.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index a26f1d3e5..b91dc252d 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -1006,7 +1006,7 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,int32_t height,bits256 *sign if ( signtx != 0 && bits256_nonz(vp->signers[j].privkey) != 0 ) { siglen = bitcoin_sign(coin->ctx,coin->symbol,sig,sigtxid,vp->signers[j].privkey,0); - if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) <= 0 ) + //if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) <= 0 ) bitcoin_pubkey33(coin->ctx,vp->signers[j].pubkey,vp->signers[j].privkey); sig[siglen++] = sighash; vp->signers[j].siglen = siglen; From e2bdf67b7e04ee5263f18ace34d0bc9ec2153e29 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:14:57 +0300 Subject: [PATCH 0229/2705] Test --- iguana/iguana_sign.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index b91dc252d..efd8343cc 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -976,7 +976,7 @@ int32_t iguana_msgtx_Vset(struct iguana_info *coin,uint8_t *serialized,int32_t m int32_t bitcoin_verifyvins(struct iguana_info *coin,int32_t height,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxlen,struct vin_info *V,uint32_t sighash,int32_t signtx,int32_t suppress_pubkeys) { - bits256 sigtxid; uint8_t *sig,*script; struct vin_info *vp; char vpnstr[64]; int32_t scriptlen,complete=0,plen,j,vini=0,flag=0,siglen,numvouts,numsigs; + bits256 sigtxid; uint8_t *sig,*script; struct vin_info *vp; char vpnstr[64]; int32_t scriptlen,complete=0,j,vini=0,flag=0,siglen,numvouts,numsigs; numvouts = msgtx->tx_out; vpnstr[0] = 0; *signedtx = 0; @@ -1034,13 +1034,13 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,int32_t height,bits256 *sign { flag++; numsigs++; - /*int32_t z; + int32_t z; for (z=0; zsigners[j].pubkey[z]); - printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M);*/ + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M); } } if ( numsigs >= vp->M ) From 706989ac468fc8b2948ec9841fcbaa2d11d1d751 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:19:20 +0300 Subject: [PATCH 0230/2705] Test --- iguana/iguana_interpreter.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/iguana_interpreter.c b/iguana/iguana_interpreter.c index 341f92b55..8e70c52ea 100755 --- a/iguana/iguana_interpreter.c +++ b/iguana/iguana_interpreter.c @@ -785,7 +785,7 @@ int32_t iguana_checkmultisig(struct iguana_info *coin,struct iguana_interpreter printf("iguana_checkmultisig n.%d != N.%d\n",n,N); return(0); } - //printf("n.%d stackdepth.%d\n",n,stacks->stackdepth); +printf("n.%d stackdepth.%d\n",n,stacks->stackdepth); for (i=0; istackdepth <= 0 ) @@ -794,9 +794,9 @@ int32_t iguana_checkmultisig(struct iguana_info *coin,struct iguana_interpreter if ( len == bitcoin_pubkeylen(pubkeys[i]) ) { numsigners++; - //for (j=0; j<33; j++) - // printf("%02x",pubkeys[i][j]); - //printf(" <- pubkey.[%d]\n",i); + for (j=0; j<33; j++) + printf("%02x",pubkeys[i][j]); + printf(" <- pubkey.[%d]\n",i); } else { @@ -810,7 +810,7 @@ int32_t iguana_checkmultisig(struct iguana_info *coin,struct iguana_interpreter if ( stacks->stackdepth <= 0 ) return(0); m = (int32_t)iguana_num(iguana_pop(stacks)); - //printf("m.%d stackdepth.%d\n",m,stacks->stackdepth); +printf("m.%d stackdepth.%d\n",m,stacks->stackdepth); if ( m != M ) { @@ -830,7 +830,7 @@ int32_t iguana_checkmultisig(struct iguana_info *coin,struct iguana_interpreter } if ( i == numsigners ) { - //char str[65]; printf("sigtxid.(%s)\n",bits256_str(str,txhash2)); + char str[65]; printf("depth.%d sigtxid.(%s)\n",stacks->stackdepth,bits256_str(str,txhash2)); if ( stacks->stackdepth > 0 ) iguana_pop(stacks); // for backward compatibility j = numsigners-1; @@ -849,7 +849,7 @@ int32_t iguana_checkmultisig(struct iguana_info *coin,struct iguana_interpreter } } } - //printf("valid.%d j.%d M.%d N.%d numsigners.%d\n",valid,j,M,N,numsigners); + printf("valid.%d j.%d M.%d N.%d numsigners.%d\n",valid,j,M,N,numsigners); return(0); } From b073930420f8c2827d63bd11ec559602452a05da Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:24:00 +0300 Subject: [PATCH 0231/2705] Test --- basilisk/basilisk_swap.c | 8 ++++---- iguana/iguana_interpreter.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f92517785..3b3ca97c3 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2871,11 +2871,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym height = coin->longestchain; timestamp = (uint32_t)time(NULL); V = calloc(256,sizeof(*V)); - V[0].signers[0].privkey = privkey; - bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); privkeys = cJSON_CreateArray(); - bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); - jaddistr(privkeys,wifstr); if ( privkey2p != 0 ) { V[0].signers[1].privkey = *privkey2p; @@ -2884,6 +2880,10 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym jaddistr(privkeys,wifstr); V[0].N = V[0].M = 2; } else V[0].N = V[0].M = 1; + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); + bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); + jaddistr(privkeys,wifstr); V[0].suppress_pubkeys = suppress_pubkeys; V[0].ignore_cltverr = ignore_cltverr; if ( redeemlen != 0 ) diff --git a/iguana/iguana_interpreter.c b/iguana/iguana_interpreter.c index 8e70c52ea..9b4c06095 100755 --- a/iguana/iguana_interpreter.c +++ b/iguana/iguana_interpreter.c @@ -785,7 +785,7 @@ int32_t iguana_checkmultisig(struct iguana_info *coin,struct iguana_interpreter printf("iguana_checkmultisig n.%d != N.%d\n",n,N); return(0); } -printf("n.%d stackdepth.%d\n",n,stacks->stackdepth); +//printf("n.%d stackdepth.%d\n",n,stacks->stackdepth); for (i=0; istackdepth <= 0 ) @@ -810,7 +810,7 @@ printf("n.%d stackdepth.%d\n",n,stacks->stackdepth); if ( stacks->stackdepth <= 0 ) return(0); m = (int32_t)iguana_num(iguana_pop(stacks)); -printf("m.%d stackdepth.%d\n",m,stacks->stackdepth); +//printf("m.%d stackdepth.%d\n",m,stacks->stackdepth); if ( m != M ) { @@ -830,7 +830,7 @@ printf("m.%d stackdepth.%d\n",m,stacks->stackdepth); } if ( i == numsigners ) { - char str[65]; printf("depth.%d sigtxid.(%s)\n",stacks->stackdepth,bits256_str(str,txhash2)); + //char str[65]; printf("depth.%d sigtxid.(%s)\n",stacks->stackdepth,bits256_str(str,txhash2)); if ( stacks->stackdepth > 0 ) iguana_pop(stacks); // for backward compatibility j = numsigners-1; @@ -849,7 +849,7 @@ printf("m.%d stackdepth.%d\n",m,stacks->stackdepth); } } } - printf("valid.%d j.%d M.%d N.%d numsigners.%d\n",valid,j,M,N,numsigners); + printf("checkmultisig: valid.%d j.%d M.%d N.%d numsigners.%d\n",valid,j,M,N,numsigners); return(0); } From 1f1c4a9e582288e7209924bdb972ba77ecd2be92 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:29:08 +0300 Subject: [PATCH 0232/2705] Test --- basilisk/basilisk_swap.c | 8 ++++---- iguana/iguana_interpreter.c | 6 +++--- iguana/iguana_sign.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3b3ca97c3..9367fffd2 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2822,7 +2822,7 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin { scriptlen >>= 1; decode_hex(script,scriptlen,hexstr); - char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); + //char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); } } free_json(retjson); @@ -2836,7 +2836,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna memset(&txid,0,sizeof(txid)); if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) { - if ( is_hexstr(retstr,64) == 64 ) + if ( is_hexstr(retstr,0) == 64 ) decode_hex(txid.bytes,32,retstr); char str[65]; printf("[%s] %s RETSTR.(%s) %s\n",txname,txbytes,retstr,bits256_str(str,txid)); free(retstr); @@ -2847,7 +2847,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) { char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL)-777,sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; - printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) @@ -2920,7 +2920,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) { - printf("rawtx.(%s) vins.(%s)\n",rawtxbytes,jprint(vins,0)); + //printf("rawtx.(%s) vins.(%s)\n",rawtxbytes,jprint(vins,0)); if ( (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction\n"); else if ( completed == 0 ) diff --git a/iguana/iguana_interpreter.c b/iguana/iguana_interpreter.c index 9b4c06095..d979752f6 100755 --- a/iguana/iguana_interpreter.c +++ b/iguana/iguana_interpreter.c @@ -794,9 +794,9 @@ int32_t iguana_checkmultisig(struct iguana_info *coin,struct iguana_interpreter if ( len == bitcoin_pubkeylen(pubkeys[i]) ) { numsigners++; - for (j=0; j<33; j++) - printf("%02x",pubkeys[i][j]); - printf(" <- pubkey.[%d]\n",i); + //for (j=0; j<33; j++) + // printf("%02x",pubkeys[i][j]); + //printf(" <- pubkey.[%d]\n",i); } else { diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index efd8343cc..c84f33293 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -1034,13 +1034,13 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,int32_t height,bits256 *sign { flag++; numsigs++; - int32_t z; + /*int32_t z; for (z=0; zsigners[j].pubkey[z]); - printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M); + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M);*/ } } if ( numsigs >= vp->M ) @@ -1482,7 +1482,7 @@ int32_t iguana_signrawtransaction(struct supernet_info *myinfo,struct iguana_inf { printf("iguana_interpreter %d error.(%s)\n",tmp,signedtx); complete = 0; - } else printf("%s signed\n",bits256_str(str,*signedtxidp)); + } //else printf("%s signed\n",bits256_str(str,*signedtxidp)); } else printf("complete.%d\n",complete); } else printf("rwmsgtx error\n"); } else fprintf(stderr,"no inputs in vins.(%s)\n",vins!=0?jprint(vins,0):"null"); From 3db883705a68d0187c9438e019e35bb38269d232 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:44:35 +0300 Subject: [PATCH 0233/2705] Test --- basilisk/basilisk_swap.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 9367fffd2..0c6977adb 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2903,6 +2903,13 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym sobj = cJSON_CreateObject(); bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); + int32_t i; for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" destaddr.(%s)\n",destaddr); + calc_rmd160_sha256(rmd160,pubkey33,33); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- vs direct calc\n"); spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); jaddstr(sobj,"hex",hexstr); From d12349709ba6e618bb56c87c671dfc11bc408a95 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:49:11 +0300 Subject: [PATCH 0234/2705] Test --- basilisk/basilisk_swap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0c6977adb..60becea5f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2850,7 +2850,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); - if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) + if ( 0 && (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) { printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); @@ -3059,7 +3059,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 safecopy(src,srcstr,sizeof(src)); if ( (deststr= jstr(item,"dest")) != 0 ) safecopy(dest,deststr,sizeof(dest)); - if ( (dest33= jstr(item,"dest33")) != 0 ) + if ( (dest33= jstr(item,"dest33")) != 0 && strlen(dest33) == 66 ) decode_hex(pubkey33,33,dest33); plocktime = juint(item,"plocktime"); dlocktime = juint(item,"dlocktime"); @@ -3184,8 +3184,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } } printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); - strcpy(bobcoin,"KMD"); - strcpy(alicecoin,"BTC"); + //strcpy(bobcoin,"KMD"); + //strcpy(alicecoin,"BTC"); printf("privAm.(%s)\n",bits256_str(str,privAm)); printf("pubB0.(%s)\n",bits256_str(str,pubB0)); printf("myprivs0.(%s)\n",bits256_str(str,myprivs[0])); From e76ace6c1a66cd176fde2d4017d2b9b3c7f695d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:51:13 +0300 Subject: [PATCH 0235/2705] Test --- basilisk/basilisk_swap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 60becea5f..24d2e51fc 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2855,7 +2855,8 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); } - if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + destamount = 1000000; + if ( destamount == 0 && (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); free_json(utxoobj); From 8277c428f6fa2ca533dc6ad6ae8b9b912e8d44ce Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:53:44 +0300 Subject: [PATCH 0236/2705] Test --- basilisk/basilisk_swap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 24d2e51fc..bd1caa2da 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2904,7 +2904,11 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym sobj = cJSON_CreateObject(); bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); - int32_t i; for (i=0; i<20; i++) + int32_t i; + for (i=0; i<33; i++) + printf("%02x",pubkey33[i]); + printf(" pubkey33 ->\n"); + for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" destaddr.(%s)\n",destaddr); calc_rmd160_sha256(rmd160,pubkey33,33); From 4d45bb1ef6a62f8b67abe59d320b7ff2fcfa651f Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 03:57:15 +0300 Subject: [PATCH 0237/2705] Test --- basilisk/basilisk_swap.c | 5 +++++ iguana/iguana_sign.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index bd1caa2da..7b2f424e7 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3065,7 +3065,12 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( (deststr= jstr(item,"dest")) != 0 ) safecopy(dest,deststr,sizeof(dest)); if ( (dest33= jstr(item,"dest33")) != 0 && strlen(dest33) == 66 ) + { decode_hex(pubkey33,33,dest33); + for (i=0; i<33; i++) + printf("%02x",pubkey33[i]); + printf(" <- %s dest33\n",dest33); + } plocktime = juint(item,"plocktime"); dlocktime = juint(item,"dlocktime"); r = juint(item,"requestid"); diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index c84f33293..3e96145c2 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -1477,7 +1477,7 @@ int32_t iguana_signrawtransaction(struct supernet_info *myinfo,struct iguana_inf //printf("finalized.%d\n",finalized); if ( (complete= bitcoin_verifyvins(coin,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) { - int32_t tmp; char str[65]; + int32_t tmp; //char str[65]; if ( (tmp= iguana_interpreter(coin,0,iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) { printf("iguana_interpreter %d error.(%s)\n",tmp,signedtx); From ad18cb2725259beb4c1966bd788ad886cfe1f6fb Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 04:02:33 +0300 Subject: [PATCH 0238/2705] Test --- basilisk/basilisk_swap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 7b2f424e7..63ba41309 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3054,11 +3054,11 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 iambob = jint(item,"iambob"); if ( (secretstr= jstr(item,"secretAm")) != 0 && strlen(secretstr) == 40 ) decode_hex(secretAm,20,secretstr); - if ( (secretstr= jstr(item,"secretAm256")) != 0 && strlen(secretstr) == 32 ) + if ( (secretstr= jstr(item,"secretAm256")) != 0 && strlen(secretstr) == 64 ) decode_hex(secretAm256,32,secretstr); if ( (secretstr= jstr(item,"secretBn")) != 0 && strlen(secretstr) == 40 ) decode_hex(secretBn,20,secretstr); - if ( (secretstr= jstr(item,"secretBn256")) != 0 && strlen(secretstr) == 32 ) + if ( (secretstr= jstr(item,"secretBn256")) != 0 && strlen(secretstr) == 64 ) decode_hex(secretBn256,32,secretstr); if ( (srcstr= jstr(item,"src")) != 0 ) safecopy(src,srcstr,sizeof(src)); @@ -3116,8 +3116,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 item = cJSON_CreateObject(); array = cJSON_CreateArray(); //printf("R.%u Q.%u\n",requestid,quoteid); + for (j=0; j<33; j++) printf("%02x",pubkey33[j]); printf(" <- pubkey33 A\n"); for (i=0; i Date: Fri, 14 Apr 2017 04:06:27 +0300 Subject: [PATCH 0239/2705] Test --- basilisk/basilisk_swap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 63ba41309..ca9118ec0 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2947,11 +2947,11 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) { - char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); + char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,privAm); - pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,privBn); + pubAm = bitcoin_pubkey33(myinfo->ctx,tmp33,privAm); + pubBn = bitcoin_pubkey33(myinfo->ctx,tmp33,privBn); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); /*rev = privAm; @@ -3116,10 +3116,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 item = cJSON_CreateObject(); array = cJSON_CreateArray(); //printf("R.%u Q.%u\n",requestid,quoteid); - for (j=0; j<33; j++) printf("%02x",pubkey33[j]); printf(" <- pubkey33 A\n"); for (i=0; i Date: Fri, 14 Apr 2017 04:17:29 +0300 Subject: [PATCH 0240/2705] Test --- basilisk/basilisk_swap.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ca9118ec0..a0f66be50 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2850,13 +2850,12 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); - if ( 0 && (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) + if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) { printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); } - destamount = 1000000; - if ( destamount == 0 && (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); free_json(utxoobj); @@ -2904,7 +2903,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym sobj = cJSON_CreateObject(); bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); - int32_t i; + /*int32_t i; for (i=0; i<33; i++) printf("%02x",pubkey33[i]); printf(" pubkey33 ->\n"); @@ -2914,7 +2913,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym calc_rmd160_sha256(rmd160,pubkey33,33); for (i=0; i<20; i++) printf("%02x",rmd160[i]); - printf(" <- vs direct calc\n"); + printf(" <- vs direct calc\n");*/ spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); jaddstr(sobj,"hex",hexstr); @@ -3033,7 +3032,7 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); memset(secretAm256,0,sizeof(secretAm256)); @@ -3247,8 +3246,12 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } - if ( 0 && txbytes[BASILISK_ALICECLAIM] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); + if ( txbytes[BASILISK_ALICECLAIM] != 0 ) + { + txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); + if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) + sentflags[BASILISK_ALICECLAIM] = 1; + } } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); } if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) @@ -3263,19 +3266,26 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_BOBREFUND],0); } if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); + } + } + if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) + { + txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); + if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) + sentflags[BASILISK_ALICERECLAIM] = 1; } - if ( 0 && txbytes[BASILISK_ALICERECLAIM] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); } } else if ( iambob == 1 ) { + paymentspent = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBPAYMENT],0); if ( sentflags[BASILISK_BOBSPEND] == 0 ) { if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) - txids[BASILISK_ALICESPEND] = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBPAYMENT],0); + txids[BASILISK_ALICESPEND] = paymentspent; // check destaddr if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) { if ( txbytes[BASILISK_BOBSPEND] == 0 ) @@ -3293,7 +3303,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( txbytes[BASILISK_BOBSPEND] != 0 ) { txids[BASILISK_BOBSPEND] = basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); - if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) + if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) // tested sentflags[BASILISK_BOBSPEND] = 1; } } @@ -3320,7 +3330,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) { - if ( sentflags[BASILISK_BOBSPEND] != 0 || sentflags[BASILISK_BOBRECLAIM] != 0 ) + if ( bits256_nonz(paymentspent) != 0 ) { if ( txbytes[BASILISK_BOBREFUND] == 0 ) { From 429ce213cbdb4170498a74698c5a41ef594a2c25 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 04:23:26 +0300 Subject: [PATCH 0241/2705] Test --- basilisk/basilisk_swap.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a0f66be50..159083dd9 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3030,6 +3030,8 @@ bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol, //0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0 char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; +// add blocktrail presence requirement for BTC + cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; @@ -3208,7 +3210,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( sentflags[BASILISK_BOBPAYMENT] != 0 ) { - if ( txbytes[BASILISK_ALICESPEND] == 0 ) + //if ( txbytes[BASILISK_ALICESPEND] == 0 ) { if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) { @@ -3235,7 +3237,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( time(NULL) > expiration ) { - if ( txbytes[BASILISK_ALICECLAIM] == 0 ) + //if ( txbytes[BASILISK_ALICECLAIM] == 0 ) { // claim bobdeposit redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); @@ -3256,7 +3258,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) { - if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) + //if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) { if ( bits256_nonz(privBn) == 0 ) { @@ -3288,7 +3290,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 txids[BASILISK_ALICESPEND] = paymentspent; // check destaddr if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) { - if ( txbytes[BASILISK_BOBSPEND] == 0 ) + //if ( txbytes[BASILISK_BOBSPEND] == 0 ) { if ( bits256_nonz(privAm) == 0 ) { @@ -3310,7 +3312,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) { - if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) + //if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) { // bobreclaim redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); @@ -3332,7 +3334,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( bits256_nonz(paymentspent) != 0 ) { - if ( txbytes[BASILISK_BOBREFUND] == 0 ) + //if ( txbytes[BASILISK_BOBREFUND] == 0 ) { revcalc_rmd160_sha256(secretBn,privBn); vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); @@ -3342,7 +3344,11 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) - basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); + { + txids[BASILISK_BOBREFUND] = basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); + if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) + sentflags[BASILISK_BOBREFUND] = 1; + } } } } From 7db22dc28f57e5e07e0c6cb429c2162fd107da47 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 04:28:35 +0300 Subject: [PATCH 0242/2705] Test --- basilisk/basilisk_swap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 159083dd9..9a439ad6b 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2850,7 +2850,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); - if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) + /*if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) { printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); @@ -2860,7 +2860,8 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); free_json(utxoobj); return(0); - } else free_json(utxoobj); + } else free_json(utxoobj);*/ + destamount = 1000000; if ( destamount > 10000 ) destamount -= 10000; if ( strcmp(symbol,"BTC") == 0 ) @@ -3228,7 +3229,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( txbytes[BASILISK_ALICESPEND] != 0 ) { txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction(myinfo,"alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); - if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested! + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested sentflags[BASILISK_ALICESPEND] = 1; } } @@ -3346,7 +3347,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( txbytes[BASILISK_BOBREFUND] != 0 ) { txids[BASILISK_BOBREFUND] = basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); - if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) + if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) // tested sentflags[BASILISK_BOBREFUND] = 1; } } From b248e73cf1a9fbfc647553da6659e383b85ab269 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 14 Apr 2017 08:32:45 +0300 Subject: [PATCH 0243/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 39 ++++++++++++++++++++++++++------------- basilisk/jumblr.c | 9 +++++---- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index f82814161..9daaaad53 100755 --- a/.gitignore +++ b/.gitignore @@ -344,3 +344,5 @@ iguana/DB/SWAPS/1518259123-2214130634 iguana/DB/SWAPS/152114847-907489057 iguana/DB/SWAPS/61119357-1960547076 + +iguana/DB/SWAPS/26534791-3105729230 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 9a439ad6b..f791e02c6 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2850,7 +2850,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); - /*if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) + if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) { printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); @@ -2860,7 +2860,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); free_json(utxoobj); return(0); - } else free_json(utxoobj);*/ + } else free_json(utxoobj); destamount = 1000000; if ( destamount > 10000 ) destamount -= 10000; @@ -2976,6 +2976,7 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,bits25 basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); if ( coinaddr[0] != 0 && (retstr= _dex_listtransactions(myinfo,symbol,coinaddr,100,0)) != 0 ) { + //printf("listtransactions.(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -3017,6 +3018,18 @@ bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol, return(privkey); } +bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,bits256 *bobrefundp,char *bobcoin,bits256 bobdeposit,bits256 privBn) +{ + if ( bits256_nonz(privBn) == 0 ) + { + if ( bits256_nonz(bobdeposit) != 0 ) + *bobrefundp = basilisk_swap_spendtxid(myinfo,bobcoin,bobdeposit,0); + if ( bits256_nonz(*bobrefundp) != 0 ) + privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,*bobrefundp,0); + } + return(privBn); +} + #define BASILISK_ALICESPEND 0 #define BASILISK_BOBSPEND 1 #define BASILISK_BOBPAYMENT 2 @@ -3032,6 +3045,7 @@ bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol, char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; // add blocktrail presence requirement for BTC +// swap termination and txprocessed preventions cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { @@ -3240,7 +3254,12 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { //if ( txbytes[BASILISK_ALICECLAIM] == 0 ) { - // claim bobdeposit + /*privBn = basilisk_swap_privBn_extract(myinfo,&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); + if ( bits256_nonz(privBn) != 0 ) + { + revcalc_rmd160_sha256(secretBn,privBn); + vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); + }*/ redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); if ( redeemlen > 0 ) { @@ -3252,7 +3271,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( txbytes[BASILISK_ALICECLAIM] != 0 ) { txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); - if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) + if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // txcreate tested sentflags[BASILISK_ALICECLAIM] = 1; } } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); @@ -3261,13 +3280,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { //if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) { - if ( bits256_nonz(privBn) == 0 ) - { - if ( bits256_nonz(txids[BASILISK_BOBREFUND]) == 0 ) - txids[BASILISK_BOBREFUND] = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBDEPOSIT],0); - if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) - privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_BOBREFUND],0); - } + privBn = basilisk_swap_privBn_extract(myinfo,&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) @@ -3277,7 +3290,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) { txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); - if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) + if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // txcreate tested sentflags[BASILISK_ALICERECLAIM] = 1; } } @@ -3288,7 +3301,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( sentflags[BASILISK_BOBSPEND] == 0 ) { if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) - txids[BASILISK_ALICESPEND] = paymentspent; // check destaddr + txids[BASILISK_ALICESPEND] = paymentspent; // check destaddr to determine alice/bob if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) { //if ( txbytes[BASILISK_BOBSPEND] == 0 ) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 382733c6c..b71e527fe 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -738,11 +738,12 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 { avail = (btcavail - kmdcoin->DEXinfo.DEXpending); printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); - if ( avail >= (100. * minbtc) ) + /*if ( avail >= (100. * minbtc) ) vol = (100. * minbtc); else if ( avail >= (10. * minbtc) ) vol = (10. * minbtc); - else if ( avail >= minbtc ) + else*/ + if ( avail >= minbtc ) vol = minbtc; else vol = 0.; if ( vol > 0. ) @@ -769,11 +770,11 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 { avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR,avail); - if ( avail > 10000. ) + /*if ( avail > 10000. ) vol = 10000.; else if ( avail > 1000. ) vol = 1000.; - else if ( avail >= 100. ) + else*/ if ( avail >= 100. ) vol = 100.; else vol = 0.; if ( vol > 0. ) From 502faeb4390e48e2ccf5dc6a9130137970ddb0d4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 10:39:53 +0300 Subject: [PATCH 0244/2705] Test --- basilisk/basilisk_swap.c | 6 +++--- iguana/iguana_sign.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f791e02c6..5e1d1e8bb 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3240,7 +3240,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } - if ( txbytes[BASILISK_ALICESPEND] != 0 ) + if ( 0 && txbytes[BASILISK_ALICESPEND] != 0 ) { txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction(myinfo,"alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested @@ -3268,7 +3268,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } - if ( txbytes[BASILISK_ALICECLAIM] != 0 ) + if ( 0 && txbytes[BASILISK_ALICECLAIM] != 0 ) { txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // txcreate tested @@ -3287,7 +3287,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); } } - if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) + if ( 0 && txbytes[BASILISK_ALICERECLAIM] != 0 ) { txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // txcreate tested diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index 3e96145c2..3743821da 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -1010,14 +1010,14 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,int32_t height,bits256 *sign bitcoin_pubkey33(coin->ctx,vp->signers[j].pubkey,vp->signers[j].privkey); sig[siglen++] = sighash; vp->signers[j].siglen = siglen; - /*char str[65]; printf("SIGTXID.(%s) ",bits256_str(str,sigtxid)); + char str[65]; printf("SIGTXID.(%s) ",bits256_str(str,sigtxid)); int32_t i; for (i=0; isigners[j].pubkey[i]); // s2 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1; - printf(" SIGNEDTX.[%02x] siglen.%d priv.%s\n",sig[siglen-1],siglen,bits256_str(str,vp->signers[j].privkey));*/ + printf(" SIGNEDTX.[%02x] siglen.%d priv.%s\n",sig[siglen-1],siglen,bits256_str(str,vp->signers[j].privkey)); } if ( sig == 0 || siglen == 0 ) { From dde9769590eb47c3c32d60931a33c9368182a2f3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 10:45:39 +0300 Subject: [PATCH 0245/2705] Test --- iguana/iguana_interpreter.c | 2 +- iguana/iguana_sign.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/iguana_interpreter.c b/iguana/iguana_interpreter.c index d979752f6..0fd780fe1 100755 --- a/iguana/iguana_interpreter.c +++ b/iguana/iguana_interpreter.c @@ -734,7 +734,7 @@ int32_t iguana_checksig(struct iguana_info *coin,struct iguana_stackdata pubkeya if ( (retval= (bitcoin_verify(coin->ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0)) == 0 ) { } - if ( (0) ) + if ( (1) ) { int32_t i; char str[65]; for (i=0; isigners[j].pubkey[z]); - printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M);*/ + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M); } } if ( numsigs >= vp->M ) From 246de73e3b3e03d89ccd167999243d19bde61ebe Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 11:53:18 +0300 Subject: [PATCH 0246/2705] Test --- basilisk/basilisk_swap.c | 254 +++++++++++++++++++++++++-------------- 1 file changed, 163 insertions(+), 91 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 5e1d1e8bb..670a2ce08 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2788,23 +2788,33 @@ cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid return(basilisk_nullretjson(retjson)); } -int32_t basilisk_swap_getcoinaddr(struct supernet_info *myinfo,char *symbol,char *coinaddr,bits256 txid,int32_t vout) +int32_t basilisk_swap_txdestaddr(char *destaddr,bits256 txid,int32_t vout,cJSON *txobj) { - cJSON *retjson,*vouts,*item,*skey,*addresses; int32_t n,m; char *addr; - coinaddr[0] = 0; - if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + int32_t n,m,retval = -1; cJSON *vouts,*item,*addresses,*skey; char *addr; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && vout < n ) { - if ( (vouts= jarray(&n,retjson,"vout")) != 0 && vout < n ) + item = jitem(vouts,vout); + if ( (skey= jobj(item,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) { - item = jitem(vouts,vout); - if ( (skey= jobj(item,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + item = jitem(addresses,0); + //printf("item.(%s)\n",jprint(item,0)); + if ( (addr= jstr(item,0)) != 0 ) { - item = jitem(addresses,0); - //printf("item.(%s)\n",jprint(item,0)); - if ( (addr= jstr(item,0)) != 0 ) - safecopy(coinaddr,addr,64); + safecopy(destaddr,addr,64); + retval = 0; } } + } + return(retval); +} + +int32_t basilisk_swap_getcoinaddr(struct supernet_info *myinfo,char *symbol,char *coinaddr,bits256 txid,int32_t vout) +{ + cJSON *retjson; + coinaddr[0] = 0; + if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + basilisk_swap_txdestaddr(coinaddr,txid,vout,retjson); free_json(retjson); } return(coinaddr[0] != 0); @@ -2830,6 +2840,47 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin return(scriptlen); } +bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) +{ + bits256 spendtxid,txid; char *retstr; cJSON *array,*item; int32_t i,n; char coinaddr[64]; + // listtransactions or listspents + destaddr[0] = 0; + memset(&spendtxid,0,sizeof(spendtxid)); + if ( iguana_isnotarychain(symbol) >= 0 ) + { + //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] + basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + if ( coinaddr[0] != 0 && (retstr= _dex_listtransactions(myinfo,symbol,coinaddr,100,0)) != 0 ) + { + //printf("listtransactions.(%s)\n",retstr); + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i %s\n",bits256_str(str,spendtxid),destaddr); + break; + } + } + } + } + free(retstr); + } + } + else + { + printf("need to find spendtxid the hard way\n"); + } + return(spendtxid); +} + bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname,char *symbol,char *txbytes) { char *retstr; bits256 txid; @@ -2937,6 +2988,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("couldnt sign transaction\n"); else if ( completed == 0 ) printf("incomplete signing\n"); + else printf("%s -> %s\n",name,bits256_str(str,signedtxid)); free(rawtxbytes); } else printf("error making rawtx\n"); free_json(privkeys); @@ -2965,45 +3017,6 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, return(signedtx); } -bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,bits256 utxotxid,int32_t vout) -{ - bits256 spendtxid,txid; char *retstr; cJSON *array,*item; int32_t i,n; char coinaddr[64]; - // listtransactions or listspents - memset(&spendtxid,0,sizeof(spendtxid)); - if ( iguana_isnotarychain(symbol) >= 0 ) - { - //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] - basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); - if ( coinaddr[0] != 0 && (retstr= _dex_listtransactions(myinfo,symbol,coinaddr,100,0)) != 0 ) - { - //printf("listtransactions.(%s)\n",retstr); - if ( (array= cJSON_Parse(retstr)) != 0 ) - { - if ( (n= cJSON_GetArraySize(array)) > 0 ) - { - for (i=0; i %s\n",bits256_str(str,txid),destaddr); + *alicespentp = 1; + } + else if ( bobaddr != 0 && strcmp(destaddr,bobaddr) == 0 ) + { + printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + *bobspentp = 1; + } + else + { + if ( aliceaddr != 0 && bobspentp == 0 ) + *bobspentp = 1; + else if ( bobaddr != 0 && alicespentp == 0 ) + *alicespentp = 1; + printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + } + } + } + return(spendtxid); +} + #define BASILISK_ALICESPEND 0 #define BASILISK_BOBSPEND 1 #define BASILISK_BOBPAYMENT 2 @@ -3045,11 +3092,16 @@ bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,bits256 *bobre char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; // add blocktrail presence requirement for BTC -// swap termination and txprocessed preventions cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,t,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],*Adest,*Bdest,destaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb")) != 0 ) + { + fclose(fp); + return(cJSON_Parse("{\"result\":\"success\",\"status\":\"already finished\"}")); + } memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); memset(secretAm256,0,sizeof(secretAm256)); @@ -3059,7 +3111,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 memset(txbytes,0,sizeof(txbytes)); memset(sentflags,0,sizeof(sentflags)); memset(myprivs,0,sizeof(myprivs)); - rev = zero = pubA0 = pubB0 = pubB1 = privAm = privBn = myprivs[0]; + Apaymentspent = paymentspent = depositspent = rev = zero = pubA0 = pubB0 = pubB1 = privAm = privBn = myprivs[0]; plocktime = dlocktime = 0; src[0] = dest[0] = bobcoin[0] = alicecoin[0] = 0; sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); @@ -3178,30 +3230,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 else if ( strcmp(symbol,"BTC") == 0 ) BTCtotals[i] += value; } - if ( (t= juint(txobj,"lock")) == 0 || time(NULL) > t ) - { - if ( jobj(txobj,"trigger") != 0 ) - { - /*trigger = jbits256(txobj,"trigger"); - //printf("%s trigger %s\n",symbol,bits256_str(str,trigger)); - if ( (triggerobj= basilisk_swapgettxout(myinfo,symbol,trigger,0)) == 0 ) - { - printf("%s %s trigger.(%s) spent! extract priv\n",symbol,bits256_str(str2,txid),bits256_str(str,trigger)); - addflag = 1; - } else free_json(triggerobj);*/ - } - else - { - /*if ( sentflags[i] == 0 && () != 0 ) - { - if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) - { - //printf("%s RETSTR.(%s)\n",txbytes,retstr); - free(retstr); - } - }*/ - } - } //else printf("%s t %u\n",symbol,t); if ( sentflags[i] == 0 || addflag != 0 ) jaddi(array,txobj); } @@ -3212,18 +3240,63 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); //strcpy(bobcoin,"KMD"); //strcpy(alicecoin,"BTC"); - printf("privAm.(%s)\n",bits256_str(str,privAm)); + destaddr[0] = 0; + Adest = Bdest = 0; + if ( iambob == 0 ) + { + if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + Adest = destaddr; + } + } + else + { + if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + { + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + Bdest = destaddr; + } + } + /*printf("privAm.(%s)\n",bits256_str(str,privAm)); printf("pubB0.(%s)\n",bits256_str(str,pubB0)); printf("myprivs0.(%s)\n",bits256_str(str,myprivs[0])); printf("myprivs1.(%s)\n",bits256_str(str,myprivs[1])); - printf("privBn.(%s)\n",bits256_str(str,privBn)); - if ( bobcoin[0] != 0 && alicecoin[0] != 0 ) - { + printf("privBn.(%s)\n",bits256_str(str,privBn));*/ + printf("Apaymentspent.(%s)\n",bits256_str(str,Apaymentspent)); + printf("paymentspent.(%s)\n",bits256_str(str,paymentspent)); + printf("depositspent.(%s)\n",bits256_str(str,depositspent)); + if ( bobcoin[0] != 0 && alicecoin[0] != 0 && (Adest != 0 || Bdest != 0) ) + { + paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,&sentflags[BASILISK_BOBPAYMENT],&sentflags[BASILISK_ALICESPEND],&sentflags[BASILISK_BOBRECLAIM],txids[BASILISK_BOBPAYMENT],0,Adest,Bdest); + Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,&sentflags[BASILISK_ALICEPAYMENT],&sentflags[BASILISK_ALICERECLAIM],&sentflags[BASILISK_BOBSPEND],txids[BASILISK_ALICEPAYMENT],0,Adest,Bdest); + depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,&sentflags[BASILISK_BOBDEPOSIT],&sentflags[BASILISK_ALICECLAIM],&sentflags[BASILISK_BOBREFUND],txids[BASILISK_BOBDEPOSIT],0,Adest,Bdest); + if ( bits256_nonz(paymentspent) != 0 && bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) + { + printf("SWAP %u-%u finished!\n",requestid,quoteid); + sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + jaddstr(item,"result","success"); + jaddstr(item,"status","finished"); + jaddnum(item,"requestid",requestid); + jaddnum(item,"quoteid",quoteid); + bits256_str(str,paymentspent), jaddbits256(item,"paymentspent",paymentspent); + bits256_str(str,Apaymentspent), jaddbits256(item,"Apaymentspent",Apaymentspent); + bits256_str(str,depositspent), jaddbits256(item,"depositspent",depositspent); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + char *itemstr; + itemstr = jprint(item,0); + fprintf(fp,"%s\n",itemstr); + free(itemstr); + fclose(fp); + } + return(item); + } if ( iambob == 0 ) { if ( sentflags[BASILISK_ALICESPEND] == 0 ) { - if ( sentflags[BASILISK_BOBPAYMENT] != 0 ) + if ( sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(paymentspent) == 0 ) { //if ( txbytes[BASILISK_ALICESPEND] == 0 ) { @@ -3248,7 +3321,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } } } - if ( sentflags[BASILISK_ALICECLAIM] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) + if ( sentflags[BASILISK_ALICECLAIM] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 && bits256_nonz(depositspent) == 0 ) { if ( time(NULL) > expiration ) { @@ -3264,11 +3337,11 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,alicecoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } - if ( 0 && txbytes[BASILISK_ALICECLAIM] != 0 ) + if ( txbytes[BASILISK_ALICECLAIM] != 0 ) { txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // txcreate tested @@ -3276,7 +3349,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); } - if ( sentflags[BASILISK_ALICEPAYMENT] != 0 ) + if ( sentflags[BASILISK_ALICEPAYMENT] != 0 && bits256_nonz(Apaymentspent) == 0 ) { //if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) { @@ -3297,8 +3370,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } else if ( iambob == 1 ) { - paymentspent = basilisk_swap_spendtxid(myinfo,bobcoin,txids[BASILISK_BOBPAYMENT],0); - if ( sentflags[BASILISK_BOBSPEND] == 0 ) + if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) { if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) txids[BASILISK_ALICESPEND] = paymentspent; // check destaddr to determine alice/bob @@ -3324,7 +3396,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } } } - if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration ) + if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration && bits256_nonz(paymentspent) == 0 ) { //if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) { @@ -3344,7 +3416,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 sentflags[BASILISK_BOBRECLAIM] = 1; } } - if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 ) + if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 && bits256_nonz(depositspent) == 0 ) { if ( bits256_nonz(paymentspent) != 0 ) { From 319dba0697721704455b8822fe2b967436d38514 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 11:57:52 +0300 Subject: [PATCH 0247/2705] Test --- basilisk/basilisk_swap.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 670a2ce08..ad2f0a704 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2883,14 +2883,22 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname,char *symbol,char *txbytes) { - char *retstr; bits256 txid; + char *retstr; bits256 txid; int32_t i,sentflag = 0; memset(&txid,0,sizeof(txid)); - if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) + for (i=0; i<3; i++) { - if ( is_hexstr(retstr,0) == 64 ) - decode_hex(txid.bytes,32,retstr); - char str[65]; printf("[%s] %s RETSTR.(%s) %s\n",txname,txbytes,retstr,bits256_str(str,txid)); - free(retstr); + if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) + { + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + sentflag = 1; + } + char str[65]; printf("[%s] %s RETSTR.(%s) %s.%s\n",txname,txbytes,retstr,symbol,bits256_str(str,txid)); + free(retstr); + } + if ( sentflag != 0 ) + break; } return(txid); } From 6b6f6f8588d9d8037cd0362ca4bd20e365fd09cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:01:22 +0300 Subject: [PATCH 0248/2705] Test --- basilisk/basilisk_swap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ad2f0a704..40f3cdf5a 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2920,7 +2920,6 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym free_json(utxoobj); return(0); } else free_json(utxoobj); - destamount = 1000000; if ( destamount > 10000 ) destamount -= 10000; if ( strcmp(symbol,"BTC") == 0 ) From 7796aba28d6a8c7c4d7ac83e11e9f7879811e955 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:08:41 +0300 Subject: [PATCH 0249/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 40f3cdf5a..6c1dec869 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2905,7 +2905,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL)-777,sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL),sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 7fa130bab0d20287f8782ec2f65a3d47ea6e8751 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:13:51 +0300 Subject: [PATCH 0250/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 6c1dec869..0aeb26ad5 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2905,7 +2905,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL),sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From e88c03de28840ad246abc70ae63c3c77bf44a1e6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:18:28 +0300 Subject: [PATCH 0251/2705] Test --- basilisk/basilisk_swap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0aeb26ad5..eb7ebb274 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2903,9 +2903,9 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna return(txid); } -char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33) +char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t uselocktime) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = uselocktime * (uint32_t)time(NULL),sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); @@ -3019,7 +3019,7 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, rev = privBn; for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ - signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33); + signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,strcmp(symbol,"KMD") == 0); } return(signedtx); } @@ -3316,7 +3316,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,strcmp(bobcoin,"KMD") == 0)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } @@ -3344,7 +3344,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0)) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } @@ -3412,7 +3412,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33)) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0)) != 0 ) printf("privBn.(%s) bobreclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_BOBRECLAIM]); } } @@ -3433,7 +3433,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33)) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,strcmp(bobcoin,"KMD") == 0)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) From c068af5c570be4a27fa1922e8928ac8b841903f7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:30:38 +0300 Subject: [PATCH 0252/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index eb7ebb274..815900596 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2905,7 +2905,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t uselocktime) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = uselocktime * (uint32_t)time(NULL),sequenceid = 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = uselocktime * (uint32_t)time(NULL),sequenceid = !uselocktime * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); @@ -2990,7 +2990,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) { - //printf("rawtx.(%s) vins.(%s)\n",rawtxbytes,jprint(vins,0)); + printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); if ( (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction\n"); else if ( completed == 0 ) From bdbf05fa7b778dfd15f21c88efc2b072f452980b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:32:43 +0300 Subject: [PATCH 0253/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 815900596..8d56ff0fa 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2905,7 +2905,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t uselocktime) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = uselocktime * (uint32_t)time(NULL),sequenceid = !uselocktime * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = uselocktime * (uint32_t)time(NULL),sequenceid = uselocktime * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 1eadd2b8a38270fe2b2161057e8067f96a86c27d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:33:28 +0300 Subject: [PATCH 0254/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 8d56ff0fa..6098017ed 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2905,7 +2905,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t uselocktime) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = uselocktime * (uint32_t)time(NULL),sequenceid = uselocktime * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL),sequenceid = uselocktime * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 98752b0fd89f6e6f70145505503a9d291f214a59 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:33:42 +0300 Subject: [PATCH 0255/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 6098017ed..f2ccb2eb4 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2905,7 +2905,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t uselocktime) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL),sequenceid = uselocktime * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = uselocktime * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From f186753ab36a45ba135f990ad91b3a6fad8e3f2f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 12:46:31 +0300 Subject: [PATCH 0256/2705] Test --- basilisk/basilisk_swap.c | 41 +++++++++++++++++++++---------------- iguana/iguana_interpreter.c | 2 +- iguana/iguana_sign.c | 10 ++++----- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f2ccb2eb4..c63bf9761 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -188,9 +188,9 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, secret160 = secretAm; secret256 = secretAm256; } - for (i=0; i<32; i++) - printf("%02x",secret256[i]); - printf(" <- secret256 depositflag.%d nonz.%d\n",depositflag,bits256_nonz(privkey)); + //for (i=0; i<32; i++) + // printf("%02x",secret256[i]); + //printf(" <- secret256 depositflag.%d nonz.%d\n",depositflag,bits256_nonz(privkey)); if ( bits256_nonz(cltvpub) == 0 || bits256_nonz(destpub) == 0 ) return(-1); for (i=0; i<20; i++) @@ -217,7 +217,7 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, uint8_t bufA[20],bufB[20]; revcalc_rmd160_sha256(bufA,privkey); calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); - if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) + /*if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) printf("MATCHES BUFA\n"); else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) printf("MATCHES BUFB\n"); @@ -227,7 +227,7 @@ int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp, printf(" <- revcalc\n"); for (i=0; i<20; i++) printf("%02x",bufB[i]); - printf(" <- calc\n"); + printf(" <- calc\n");*/ memcpy(secret160,bufB,20); } n = bitcoin_secret160verify(redeemscript,n,secret160); @@ -2864,9 +2864,12 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * if ( bits256_cmp(txid,utxotxid) == 0 ) { spendtxid = jbits256(item,"spendtxid"); - basilisk_swap_getcoinaddr(myinfo,symbol,destaddr,spendtxid,0); - char str[65]; printf("found spendtxid.(%s) -> %s\n",bits256_str(str,spendtxid),destaddr); - break; + if ( bits256_nonz(spendtxid) != 0 ) + { + basilisk_swap_getcoinaddr(myinfo,symbol,destaddr,spendtxid,0); + char str[65]; printf("found spendtxid.(%s) -> %s\n",bits256_str(str,spendtxid),destaddr); + break; + } } } } @@ -2903,9 +2906,9 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna return(txid); } -char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t uselocktime) +char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = uselocktime * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = finalseqid * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); @@ -2914,6 +2917,8 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); } + if ( strcmp(symbol,"KMD") != 0 ) + locktime = 0; if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); @@ -2990,7 +2995,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) { - printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); + //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); if ( (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction\n"); else if ( completed == 0 ) @@ -3019,7 +3024,7 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, rev = privBn; for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ - signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,strcmp(symbol,"KMD") == 0); + signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1); } return(signedtx); } @@ -3316,11 +3321,11 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,strcmp(bobcoin,"KMD") == 0)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } - if ( 0 && txbytes[BASILISK_ALICESPEND] != 0 ) + if ( txbytes[BASILISK_ALICESPEND] != 0 ) { txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction(myinfo,"alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested @@ -3351,7 +3356,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( txbytes[BASILISK_ALICECLAIM] != 0 ) { txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); - if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // txcreate tested + if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // tested sentflags[BASILISK_ALICECLAIM] = 1; } } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); @@ -3367,7 +3372,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); } } - if ( 0 && txbytes[BASILISK_ALICERECLAIM] != 0 ) + if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) { txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // txcreate tested @@ -3419,7 +3424,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) { txids[BASILISK_BOBRECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); - if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) + if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) // tested sentflags[BASILISK_BOBRECLAIM] = 1; } } @@ -3433,7 +3438,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,strcmp(bobcoin,"KMD") == 0)) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) diff --git a/iguana/iguana_interpreter.c b/iguana/iguana_interpreter.c index 0fd780fe1..d979752f6 100755 --- a/iguana/iguana_interpreter.c +++ b/iguana/iguana_interpreter.c @@ -734,7 +734,7 @@ int32_t iguana_checksig(struct iguana_info *coin,struct iguana_stackdata pubkeya if ( (retval= (bitcoin_verify(coin->ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0)) == 0 ) { } - if ( (1) ) + if ( (0) ) { int32_t i; char str[65]; for (i=0; ictx,vp->signers[j].pubkey,vp->signers[j].privkey); sig[siglen++] = sighash; vp->signers[j].siglen = siglen; - char str[65]; printf("SIGTXID.(%s) ",bits256_str(str,sigtxid)); + /*char str[65]; printf("SIGTXID.(%s) ",bits256_str(str,sigtxid)); int32_t i; for (i=0; isigners[j].pubkey[i]); // s2 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1; - printf(" SIGNEDTX.[%02x] siglen.%d priv.%s\n",sig[siglen-1],siglen,bits256_str(str,vp->signers[j].privkey)); + printf(" SIGNEDTX.[%02x] siglen.%d priv.%s\n",sig[siglen-1],siglen,bits256_str(str,vp->signers[j].privkey));*/ } if ( sig == 0 || siglen == 0 ) { @@ -1034,13 +1034,13 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,int32_t height,bits256 *sign { flag++; numsigs++; - int32_t z; + /*int32_t z; for (z=0; zsigners[j].pubkey[z]); - printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M); + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M);*/ } } if ( numsigs >= vp->M ) From 30b43a977758e3cf9649003d0636f92e97ee7ff9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 13:45:46 +0300 Subject: [PATCH 0257/2705] Test --- basilisk/basilisk_swap.c | 141 ++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 61 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index c63bf9761..6fc893805 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2867,7 +2867,7 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * if ( bits256_nonz(spendtxid) != 0 ) { basilisk_swap_getcoinaddr(myinfo,symbol,destaddr,spendtxid,0); - char str[65]; printf("found spendtxid.(%s) -> %s\n",bits256_str(str,spendtxid),destaddr); + //char str[65]; printf("found spendtxid.(%s) -> %s\n",bits256_str(str,spendtxid),destaddr); break; } } @@ -3016,6 +3016,9 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, { pubAm = bitcoin_pubkey33(myinfo->ctx,tmp33,privAm); pubBn = bitcoin_pubkey33(myinfo->ctx,tmp33,privBn); + char str[65]; + printf("pubAm.(%s)\n",bits256_str(str,pubAm)); + printf("pubBn.(%s)\n",bits256_str(str,pubBn)); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); /*rev = privAm; @@ -3056,36 +3059,50 @@ bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,bits256 *bobre return(privBn); } -bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int32_t *sentflagp,int32_t *alicespentp,int32_t *bobspentp,bits256 txid,int32_t vout,char *aliceaddr,char *bobaddr) +bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int32_t *sentflags,bits256 *txids,int32_t utxoind,int32_t alicespent,int32_t bobspent,int32_t vout,char *aliceaddr,char *bobaddr) { - bits256 spendtxid; char destaddr[64],str[65]; + bits256 spendtxid,txid; char destaddr[64],str[65]; + txid = txids[utxoind]; memset(&spendtxid,0,sizeof(spendtxid)); + if ( aliceaddr != 0 ) + printf("aliceaddr.(%s)\n",aliceaddr); + if ( bobaddr != 0 ) + printf("bobaddr.(%s)\n",bobaddr); if ( bits256_nonz(txid) != 0 ) { spendtxid = basilisk_swap_spendtxid(myinfo,symbol,destaddr,txid,vout); if ( bits256_nonz(spendtxid) != 0 ) { - *sentflagp = 1; + sentflags[utxoind] = 1; if ( aliceaddr != 0 && strcmp(destaddr,aliceaddr) == 0 ) { - printf("ALICE spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); - *alicespentp = 1; + //printf("ALICE spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + sentflags[alicespent] = 1; + txids[alicespent] = spendtxid; } else if ( bobaddr != 0 && strcmp(destaddr,bobaddr) == 0 ) { - printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); - *bobspentp = 1; + //printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + sentflags[bobspent] = 1; + txids[bobspent] = spendtxid; } else { - if ( aliceaddr != 0 && bobspentp == 0 ) - *bobspentp = 1; - else if ( bobaddr != 0 && alicespentp == 0 ) - *alicespentp = 1; - printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + //char str[65]; + //printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + if ( aliceaddr != 0 ) + { + sentflags[bobspent] = 1; + txids[bobspent] = spendtxid; + } + else if ( bobaddr != 0 ) + { + sentflags[alicespent] = 1; + txids[alicespent] = spendtxid; + } } } - } + } else printf("utxoind.%d null txid\n",utxoind); return(spendtxid); } @@ -3107,7 +3124,7 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],*Adest,*Bdest,destaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,finishedflag = 0,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"rb")) != 0 ) { @@ -3147,9 +3164,9 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( (dest33= jstr(item,"dest33")) != 0 && strlen(dest33) == 66 ) { decode_hex(pubkey33,33,dest33); - for (i=0; i<33; i++) - printf("%02x",pubkey33[i]); - printf(" <- %s dest33\n",dest33); + //for (i=0; i<33; i++) + // printf("%02x",pubkey33[i]); + //printf(" <- %s dest33\n",dest33); } plocktime = juint(item,"plocktime"); dlocktime = juint(item,"dlocktime"); @@ -3223,7 +3240,9 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 else if ( i == BASILISK_BOBSPEND || i == BASILISK_ALICEPAYMENT || i == BASILISK_ALICERECLAIM ) safecopy(alicecoin,symbol,sizeof(alicecoin)); if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + { printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + } else { checktxid = jbits256(sentobj,"txid"); @@ -3252,11 +3271,16 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); //strcpy(bobcoin,"KMD"); //strcpy(alicecoin,"BTC"); - destaddr[0] = 0; - Adest = Bdest = 0; + Adestaddr[0] = destaddr[0] = 0; + Adest = Bdest = AAdest = ABdest = 0; if ( iambob == 0 ) { if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + AAdest = Adestaddr; + } + if ( (coin= iguana_coinfind(bobcoin)) != 0 ) { bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); Adest = destaddr; @@ -3269,42 +3293,27 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); Bdest = destaddr; } + if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + ABdest = Adestaddr; + } } - /*printf("privAm.(%s)\n",bits256_str(str,privAm)); - printf("pubB0.(%s)\n",bits256_str(str,pubB0)); - printf("myprivs0.(%s)\n",bits256_str(str,myprivs[0])); - printf("myprivs1.(%s)\n",bits256_str(str,myprivs[1])); - printf("privBn.(%s)\n",bits256_str(str,privBn));*/ - printf("Apaymentspent.(%s)\n",bits256_str(str,Apaymentspent)); - printf("paymentspent.(%s)\n",bits256_str(str,paymentspent)); - printf("depositspent.(%s)\n",bits256_str(str,depositspent)); - if ( bobcoin[0] != 0 && alicecoin[0] != 0 && (Adest != 0 || Bdest != 0) ) + //printf("privAm.(%s) %p/%p\n",bits256_str(str,privAm),Adest,AAdest); + //printf("privBn.(%s) %p/%p\n",bits256_str(str,privBn),Bdest,ABdest); + if ( bobcoin[0] != 0 && alicecoin[0] != 0 ) { - paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,&sentflags[BASILISK_BOBPAYMENT],&sentflags[BASILISK_ALICESPEND],&sentflags[BASILISK_BOBRECLAIM],txids[BASILISK_BOBPAYMENT],0,Adest,Bdest); - Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,&sentflags[BASILISK_ALICEPAYMENT],&sentflags[BASILISK_ALICERECLAIM],&sentflags[BASILISK_BOBSPEND],txids[BASILISK_ALICEPAYMENT],0,Adest,Bdest); - depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,&sentflags[BASILISK_BOBDEPOSIT],&sentflags[BASILISK_ALICECLAIM],&sentflags[BASILISK_BOBREFUND],txids[BASILISK_BOBDEPOSIT],0,Adest,Bdest); + paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBPAYMENT,BASILISK_ALICESPEND,BASILISK_BOBRECLAIM,0,Adest,Bdest); + Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,sentflags,txids,BASILISK_ALICEPAYMENT,BASILISK_ALICERECLAIM,BASILISK_BOBSPEND,0,AAdest,ABdest); + depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBDEPOSIT,BASILISK_ALICECLAIM,BASILISK_BOBREFUND,0,Adest,Bdest); + printf("Apaymentspent.(%s) alice.%d bob.%d\n",bits256_str(str,Apaymentspent),sentflags[BASILISK_ALICERECLAIM],sentflags[BASILISK_BOBSPEND]); + printf("paymentspent.(%s) alice.%d bob.%d\n",bits256_str(str,paymentspent),sentflags[BASILISK_ALICESPEND],sentflags[BASILISK_BOBRECLAIM]); + printf("depositspent.(%s) alice.%d bob.%d\n",bits256_str(str,depositspent),sentflags[BASILISK_ALICECLAIM],sentflags[BASILISK_BOBREFUND]); if ( bits256_nonz(paymentspent) != 0 && bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) { - printf("SWAP %u-%u finished!\n",requestid,quoteid); - sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); - jaddstr(item,"result","success"); - jaddstr(item,"status","finished"); - jaddnum(item,"requestid",requestid); - jaddnum(item,"quoteid",quoteid); - bits256_str(str,paymentspent), jaddbits256(item,"paymentspent",paymentspent); - bits256_str(str,Apaymentspent), jaddbits256(item,"Apaymentspent",Apaymentspent); - bits256_str(str,depositspent), jaddbits256(item,"depositspent",depositspent); - if ( (fp= fopen(fname,"wb")) != 0 ) - { - char *itemstr; - itemstr = jprint(item,0); - fprintf(fp,"%s\n",itemstr); - free(itemstr); - fclose(fp); - } - return(item); + finishedflag = 1; } - if ( iambob == 0 ) + if ( finishedflag == 0 && iambob == 0 ) { if ( sentflags[BASILISK_ALICESPEND] == 0 ) { @@ -3339,12 +3348,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { //if ( txbytes[BASILISK_ALICECLAIM] == 0 ) { - /*privBn = basilisk_swap_privBn_extract(myinfo,&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); - if ( bits256_nonz(privBn) != 0 ) - { - revcalc_rmd160_sha256(secretBn,privBn); - vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); - }*/ redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); if ( redeemlen > 0 ) { @@ -3361,7 +3364,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); } - if ( sentflags[BASILISK_ALICEPAYMENT] != 0 && bits256_nonz(Apaymentspent) == 0 ) + if ( sentflags[BASILISK_ALICEPAYMENT] != 0 && bits256_nonz(Apaymentspent) == 0 && sentflags[BASILISK_ALICECLAIM] == 0 ) { //if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) { @@ -3380,12 +3383,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } } } - else if ( iambob == 1 ) + else if ( finishedflag == 0 && iambob == 1 ) { if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) { - if ( bits256_nonz(txids[BASILISK_ALICESPEND]) == 0 ) - txids[BASILISK_ALICESPEND] = paymentspent; // check destaddr to determine alice/bob if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) { //if ( txbytes[BASILISK_BOBSPEND] == 0 ) @@ -3463,6 +3464,24 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 free(txbytes[i]); } jadd(item,"sentflags",array); + jaddstr(item,"result","success"); + jaddstr(item,"status","finished"); + bits256_str(str,paymentspent), jaddbits256(item,"paymentspent",paymentspent); + bits256_str(str,Apaymentspent), jaddbits256(item,"Apaymentspent",Apaymentspent); + bits256_str(str,depositspent), jaddbits256(item,"depositspent",depositspent); + if ( finishedflag != 0 ) + { + printf("SWAP %u-%u finished!\n",requestid,quoteid); + sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + char *itemstr; + itemstr = jprint(item,0); + fprintf(fp,"%s\n",itemstr); + free(itemstr); + fclose(fp); + } + } return(item); } From 94f26d9bf6c543d3c8f4b1e8bc0a5e11222d8133 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:04:01 +0300 Subject: [PATCH 0258/2705] Test --- basilisk/basilisk_swap.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 6fc893805..2d9163fc9 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -106,6 +106,16 @@ Alice spends bobdeposit in 2*INSTANTDEX_LOCKTIME //Bobdeposit includes a covered put option for alicecoin, duration INSTANTDEX_LOCKTIME //alicepayment includes a covered call option for alicecoin, duration (2*INSTANTDEX_LOCKTIME - elapsed) + +/* in case of following states, some funds remain unclaimable, but all identified cases are due to one or both sides not spending when they were the only eligible party: + + Bob failed to claim deposit during exclusive period and since alice put in the claim, the alicepayment is unspendable. if alice is nice, she can send privAm to Bob. +Apaymentspent.(0000000000000000000000000000000000000000000000000000000000000000) alice.0 bob.0 +paymentspent.(f91da4e001360b95276448e7b01904d9ee4d15862c5af7f5c7a918df26030315) alice.0 bob.1 +depositspent.(f34e04ad74e290f63f3d0bccb7d0d50abfa54eea58de38816fdc596a19767add) alice.1 bob.0 + + */ + int32_t basilisk_istrustedbob(struct supernet_info *myinfo,struct basilisk_swap *swap) { // for BTC and if trusted LP @@ -3061,7 +3071,7 @@ bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,bits256 *bobre bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int32_t *sentflags,bits256 *txids,int32_t utxoind,int32_t alicespent,int32_t bobspent,int32_t vout,char *aliceaddr,char *bobaddr) { - bits256 spendtxid,txid; char destaddr[64],str[65]; + bits256 spendtxid,txid; char destaddr[64]; txid = txids[utxoind]; memset(&spendtxid,0,sizeof(spendtxid)); if ( aliceaddr != 0 ) From 4cd3fe41366bb6d7e8f22247d600b2c72e160a74 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:06:23 +0300 Subject: [PATCH 0259/2705] Test --- basilisk/basilisk_swap.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2d9163fc9..ff58415d3 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3074,10 +3074,10 @@ bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int3 bits256 spendtxid,txid; char destaddr[64]; txid = txids[utxoind]; memset(&spendtxid,0,sizeof(spendtxid)); - if ( aliceaddr != 0 ) + /*if ( aliceaddr != 0 ) printf("aliceaddr.(%s)\n",aliceaddr); if ( bobaddr != 0 ) - printf("bobaddr.(%s)\n",bobaddr); + printf("bobaddr.(%s)\n",bobaddr);*/ if ( bits256_nonz(txid) != 0 ) { spendtxid = basilisk_swap_spendtxid(myinfo,symbol,destaddr,txid,vout); @@ -3193,7 +3193,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 myprivs[1] = privkey; privkey = jbits256(item,"privAm"); if ( bits256_nonz(privkey) != 0 ) + { privAm = privkey; + printf("set privAm <- %s\n",bits256_str(str,privAm)); + } privkey = jbits256(item,"privBn"); if ( bits256_nonz(privkey) != 0 ) { From e8f1052a572180264424493991d00a1dfa6ba9d8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:10:23 +0300 Subject: [PATCH 0260/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ff58415d3..3f3055331 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3400,7 +3400,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) { - if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 || bits256_nonz(privAm) != 0 ) { //if ( txbytes[BASILISK_BOBSPEND] == 0 ) { From 2ca1706328456ed55509d81c7f6f10cd315ec165 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:26:21 +0300 Subject: [PATCH 0261/2705] Test --- basilisk/basilisk_swap.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3f3055331..9fbdfb77e 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3351,7 +3351,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction(myinfo,"alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested + { sentflags[BASILISK_ALICESPEND] = 1; + paymentspent = txids[BASILISK_ALICESPEND]; + } } } } @@ -3373,7 +3376,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // tested + { sentflags[BASILISK_ALICECLAIM] = 1; + depositspent = txids[BASILISK_ALICECLAIM]; + } } } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); } @@ -3392,7 +3398,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // txcreate tested + { sentflags[BASILISK_ALICERECLAIM] = 1; + Apaymentspent = txids[BASILISK_ALICERECLAIM]; + } } } } @@ -3418,7 +3427,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { txids[BASILISK_BOBSPEND] = basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) // tested + { sentflags[BASILISK_BOBSPEND] = 1; + Apaymentspent = txids[BASILISK_BOBSPEND]; + } } } } @@ -3439,7 +3451,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { txids[BASILISK_BOBRECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) // tested + { sentflags[BASILISK_BOBRECLAIM] = 1; + paymentspent = txids[BASILISK_BOBRECLAIM]; + } } } if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 && bits256_nonz(depositspent) == 0 ) @@ -3459,12 +3474,25 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { txids[BASILISK_BOBREFUND] = basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) // tested + { sentflags[BASILISK_BOBREFUND] = 1; + depositspent = txids[BASILISK_BOBREFUND]; + } } } } } } + if ( sentflags[BASILISK_ALICESPEND] != 0 || sentflags[BASILISK_BOBRECLAIM] != 0 ) + sentflags[BASILISK_BOBPAYMENT] = 1; + if ( sentflags[BASILISK_ALICERECLAIM] != 0 || sentflags[BASILISK_BOBSPEND] != 0 ) + sentflags[BASILISK_ALICEPAYMENT] = 1; + if ( sentflags[BASILISK_ALICECLAIM] != 0 || sentflags[BASILISK_BOBREFUND] != 0 ) + sentflags[BASILISK_BOBDEPOSIT] = 1; + if ( bits256_nonz(paymentspent) != 0 && bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) + { + finishedflag = 1; + } jaddnum(item,"requestid",requestid); jaddnum(item,"quoteid",quoteid); jadd(item,"txs",array); From f7ab70342c6f16a7536f1832d0049c3f3900a778 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:32:52 +0300 Subject: [PATCH 0262/2705] Test --- basilisk/basilisk_swap.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 9fbdfb77e..ff6989dd9 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3407,6 +3407,16 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } else if ( finishedflag == 0 && iambob == 1 ) { + if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) + { + if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) + sentflags[BASILISK_ALICEPAYMENT] = 1; + else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) + { + sentflags[BASILISK_ALICEPAYMENT] = 1; + free_json(sentobj); + } + } if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) { if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 || bits256_nonz(privAm) != 0 ) From 02093fdfca29784089a3283d7114fa653301fa3e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:37:13 +0300 Subject: [PATCH 0263/2705] Test --- basilisk/basilisk_swap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ff6989dd9..e13e216a0 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3195,13 +3195,13 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 if ( bits256_nonz(privkey) != 0 ) { privAm = privkey; - printf("set privAm <- %s\n",bits256_str(str,privAm)); + //printf("set privAm <- %s\n",bits256_str(str,privAm)); } privkey = jbits256(item,"privBn"); if ( bits256_nonz(privkey) != 0 ) { privBn = privkey; - printf("set privBn <- %s\n",bits256_str(str,privBn)); + //printf("set privBn <- %s\n",bits256_str(str,privBn)); } expiration = juint(item,"expiration"); state = jint(item,"state"); @@ -3409,6 +3409,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) { + printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) sentflags[BASILISK_ALICEPAYMENT] = 1; else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) From 45622646bb6a857cb4102a3d8be73b48bcb29811 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:41:44 +0300 Subject: [PATCH 0264/2705] Test --- basilisk/basilisk_swap.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index e13e216a0..87a9b18b3 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3026,9 +3026,9 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, { pubAm = bitcoin_pubkey33(myinfo->ctx,tmp33,privAm); pubBn = bitcoin_pubkey33(myinfo->ctx,tmp33,privBn); - char str[65]; - printf("pubAm.(%s)\n",bits256_str(str,pubAm)); - printf("pubBn.(%s)\n",bits256_str(str,pubBn)); + //char str[65]; + //printf("pubAm.(%s)\n",bits256_str(str,pubAm)); + //printf("pubBn.(%s)\n",bits256_str(str,pubBn)); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); /*rev = privAm; @@ -3080,26 +3080,26 @@ bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int3 printf("bobaddr.(%s)\n",bobaddr);*/ if ( bits256_nonz(txid) != 0 ) { + char str[65]; spendtxid = basilisk_swap_spendtxid(myinfo,symbol,destaddr,txid,vout); if ( bits256_nonz(spendtxid) != 0 ) { sentflags[utxoind] = 1; if ( aliceaddr != 0 && strcmp(destaddr,aliceaddr) == 0 ) { - //printf("ALICE spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + printf("ALICE spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); sentflags[alicespent] = 1; txids[alicespent] = spendtxid; } else if ( bobaddr != 0 && strcmp(destaddr,bobaddr) == 0 ) { - //printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); sentflags[bobspent] = 1; txids[bobspent] = spendtxid; } else { - //char str[65]; - //printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); if ( aliceaddr != 0 ) { sentflags[bobspent] = 1; @@ -3316,6 +3316,17 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 //printf("privBn.(%s) %p/%p\n",bits256_str(str,privBn),Bdest,ABdest); if ( bobcoin[0] != 0 && alicecoin[0] != 0 ) { + if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) + { + printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); + if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) + sentflags[BASILISK_ALICEPAYMENT] = 1; + else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) + { + sentflags[BASILISK_ALICEPAYMENT] = 1; + free_json(sentobj); + } + } paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBPAYMENT,BASILISK_ALICESPEND,BASILISK_BOBRECLAIM,0,Adest,Bdest); Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,sentflags,txids,BASILISK_ALICEPAYMENT,BASILISK_ALICERECLAIM,BASILISK_BOBSPEND,0,AAdest,ABdest); depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBDEPOSIT,BASILISK_ALICECLAIM,BASILISK_BOBREFUND,0,Adest,Bdest); @@ -3407,17 +3418,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } else if ( finishedflag == 0 && iambob == 1 ) { - if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) - { - printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); - if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) - sentflags[BASILISK_ALICEPAYMENT] = 1; - else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) - { - sentflags[BASILISK_ALICEPAYMENT] = 1; - free_json(sentobj); - } - } if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) { if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 || bits256_nonz(privAm) != 0 ) From 66873b26877d49d782330c10d08356e175d5e3eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:42:26 +0300 Subject: [PATCH 0265/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 87a9b18b3..fd04a7435 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2862,7 +2862,7 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); if ( coinaddr[0] != 0 && (retstr= _dex_listtransactions(myinfo,symbol,coinaddr,100,0)) != 0 ) { - //printf("listtransactions.(%s)\n",retstr); + printf("listtransactions.(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) From 928f7930aa4703848667caad06e3d1ed4bbedc91 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:48:04 +0300 Subject: [PATCH 0266/2705] Test --- basilisk/basilisk_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index fd04a7435..97cac9221 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2860,6 +2860,7 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * { //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + printf("spendtxid dest.(%s)\n",coinaddr); if ( coinaddr[0] != 0 && (retstr= _dex_listtransactions(myinfo,symbol,coinaddr,100,0)) != 0 ) { printf("listtransactions.(%s)\n",retstr); From 344cc49ee8dc4b8eb1acc20c2ff7550f8fb984ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:52:06 +0300 Subject: [PATCH 0267/2705] Test --- basilisk/basilisk_swap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 97cac9221..a5d601f56 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2787,7 +2787,7 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid) { char *retstr; cJSON *retjson=0; struct iguana_info *coin; - if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 ) + if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 || iguana_isnotarychain(symbol) >= 0 ) { if ( (retstr= _dex_getrawtransaction(myinfo,symbol,txid)) != 0 ) { @@ -2856,6 +2856,7 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * // listtransactions or listspents destaddr[0] = 0; memset(&spendtxid,0,sizeof(spendtxid)); + char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); if ( iguana_isnotarychain(symbol) >= 0 ) { //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] From b38ebb87a996df0dfa72060f78ccd159ad84dd55 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:56:37 +0300 Subject: [PATCH 0268/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a5d601f56..da4dd1943 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2768,7 +2768,7 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t char *retstr; cJSON *retjson=0; struct iguana_info *coin; if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 || iguana_isnotarychain(symbol) >= 0 ) { - if ( (retstr= _dex_gettxout(myinfo,symbol,trigger,vout)) != 0 ) + if ( (retstr= dex_gettxout(myinfo,0,0,0,trigger,symbol,vout)) != 0 ) { //printf("dexgettxout.(%s)\n",retstr); retjson = cJSON_Parse(retstr); @@ -2789,7 +2789,7 @@ cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid char *retstr; cJSON *retjson=0; struct iguana_info *coin; if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 || iguana_isnotarychain(symbol) >= 0 ) { - if ( (retstr= _dex_getrawtransaction(myinfo,symbol,txid)) != 0 ) + if ( (retstr= dex_gettransaction(myinfo,0,0,0,txid,symbol)) != 0 ) { retjson = cJSON_Parse(retstr); free(retstr); From b46c3aa09f026245c9dca0a4744004686225a020 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 14:57:46 +0300 Subject: [PATCH 0269/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index da4dd1943..0cd252948 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2862,7 +2862,7 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); printf("spendtxid dest.(%s)\n",coinaddr); - if ( coinaddr[0] != 0 && (retstr= _dex_listtransactions(myinfo,symbol,coinaddr,100,0)) != 0 ) + if ( coinaddr[0] != 0 && (retstr= dex_listtransactions(myinfo,0,0,0,symbol,coinaddr,100,0)) != 0 ) { printf("listtransactions.(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) From 2ed5d38cb50adfaece8ed4d7c0465cb680185884 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 15:11:17 +0300 Subject: [PATCH 0270/2705] Test --- basilisk/basilisk_swap.c | 6 +++++- iguana/iguana_notary.c | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0cd252948..3f9661982 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2774,6 +2774,8 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t retjson = cJSON_Parse(retstr); free(retstr); } + if ( strcmp("BTC",symbol) == 0 ) + printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); } else { @@ -2794,6 +2796,8 @@ cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid retjson = cJSON_Parse(retstr); free(retstr); } + if ( strcmp("BTC",symbol) == 0 ) + printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); } else retjson = dpow_gettransaction(myinfo,coin,txid); return(basilisk_nullretjson(retjson)); } @@ -2861,7 +2865,7 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * { //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); - printf("spendtxid dest.(%s)\n",coinaddr); + printf("spendtxid %s dest.(%s)\n",symbol,coinaddr); if ( coinaddr[0] != 0 && (retstr= dex_listtransactions(myinfo,0,0,0,symbol,coinaddr,100,0)) != 0 ) { printf("listtransactions.(%s)\n",retstr); diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index f46626938..21be3fd60 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -605,17 +605,29 @@ TWOINTS_AND_ARRAY(dpow,ratify,minsigs,timestamp,ratified) HASH_AND_STRING(dex,gettransaction,txid,symbol) { + /*char str[65],url[1024],*retstr; + if ( symbol != 0 && strcmp(symbol,"BTC") == 0 && (coin= iguana_coinfind("BTC")) != 0 && myinfo->blocktrail_apikey[0] != 0 ) + { + sprintf(url,"https://api.blocktrail.com/v1/btc/transaction/%s?api_key=%s",bits256_str(str,txid),myinfo->blocktrail_apikey); + + sprintf(url,"https://api.blocktrail.com/v1/btc/address/%s/unspent-outputs?api_key=%s",address,myinfo->blocktrail_apikey); + }*/ return(_dex_getrawtransaction(myinfo,symbol,txid)); } HASH_AND_STRING_AND_INT(dex,gettxout,txid,symbol,vout) { + /*char str[65],url[1024],*retstr; + if ( symbol != 0 && strcmp(symbol,"BTC") == 0 && (coin= iguana_coinfind("BTC")) != 0 && myinfo->blocktrail_apikey[0] != 0 ) + { + sprintf(url,"https://api.blocktrail.com/v1/btc/transaction/%s?api_key=%s",bits256_str(str,txid),myinfo->blocktrail_apikey); + }*/ return(_dex_gettxout(myinfo,symbol,txid,vout)); } TWO_STRINGS(dex,listunspent,symbol,address) { - if ( symbol != 0 && strcmp(symbol,"BTC") == 0 && (coin= iguana_coinfind("BTC")) != 0 && coin->FULLNODE == 0 && myinfo->blocktrail_apikey[0] != 0 ) + if ( symbol != 0 && strcmp(symbol,"BTC") == 0 && (coin= iguana_coinfind("BTC")) != 0 && myinfo->blocktrail_apikey[0] != 0 ) { char url[1024],*retstr,*coinaddr,*script; int32_t i,n,vout; cJSON *retjson,*data,*item,*item3,*data3; bits256 txid; uint64_t val; sprintf(url,"https://api.blocktrail.com/v1/btc/address/%s/unspent-outputs?api_key=%s",address,myinfo->blocktrail_apikey); @@ -672,7 +684,7 @@ TWO_STRINGS(dex,listunspent,symbol,address) TWO_STRINGS_AND_TWO_DOUBLES(dex,listtransactions,symbol,address,count,skip) { - if ( symbol != 0 && strcmp(symbol,"BTC") == 0 && (coin= iguana_coinfind("BTC")) != 0 && coin->FULLNODE == 0 && myinfo->blocktrail_apikey[0] != 0 ) + if ( symbol != 0 && strcmp(symbol,"BTC") == 0 && (coin= iguana_coinfind("BTC")) != 0 && myinfo->blocktrail_apikey[0] != 0 ) { char url[1024],*retstr,*retstr2; cJSON *retjson,*retjson2,*retjson3,*data,*data2; int32_t i,n; sprintf(url,"https://api.blocktrail.com/v1/btc/address/%s/transactions?api_key=%s",address,myinfo->blocktrail_apikey); From ada7814088b3ab11c24e451dbc42955e8fe7e8eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 15:26:55 +0300 Subject: [PATCH 0271/2705] Test --- basilisk/basilisk_swap.c | 28 ++++++++++++++++++++++------ iguana/iguana_notary.c | 2 +- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3f9661982..ed1be2ccd 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2775,7 +2775,7 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t free(retstr); } if ( strcmp("BTC",symbol) == 0 ) - printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); + printf("%s gettxout.(%s)\n",symbol,jprint(retjson,0)); } else { @@ -2796,8 +2796,8 @@ cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid retjson = cJSON_Parse(retstr); free(retstr); } - if ( strcmp("BTC",symbol) == 0 ) - printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); + //if ( strcmp("BTC",symbol) == 0 ) + // printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); } else retjson = dpow_gettransaction(myinfo,coin,txid); return(basilisk_nullretjson(retjson)); } @@ -2811,12 +2811,12 @@ int32_t basilisk_swap_txdestaddr(char *destaddr,bits256 txid,int32_t vout,cJSON if ( (skey= jobj(item,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) { item = jitem(addresses,0); - //printf("item.(%s)\n",jprint(item,0)); if ( (addr= jstr(item,0)) != 0 ) { safecopy(destaddr,addr,64); retval = 0; } + printf("item.(%s) -> dest.(%s)\n",jprint(item,0),destaddr); } } return(retval); @@ -2856,7 +2856,7 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) { - bits256 spendtxid,txid; char *retstr; cJSON *array,*item; int32_t i,n; char coinaddr[64]; + bits256 spendtxid,txid; char *retstr,*addr; cJSON *array,*item,*inputs; int32_t i,n,m; char coinaddr[64]; // listtransactions or listspents destaddr[0] = 0; memset(&spendtxid,0,sizeof(spendtxid)); @@ -2877,7 +2877,23 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * { item = jitem(array,i); txid = jbits256(item,"txid"); - if ( bits256_cmp(txid,utxotxid) == 0 ) + if ( bits256_nonz(txid) == 0 ) + { + spendtxid = jbits256(item,"hash"); + if ( (array= jarray(&m,item,"inputs")) != 0 && m == 1 ) + { + txid = jbits256(jitem(array,0),"output_hash"); + if ( bits256_cmp(txid,utxotxid) == 0 ) + { + if ( (array= jarray(&m,item,"outputs")) != 0 && m == 1 && (addr= jstr(jitem(array,0),"address")) != 0 ) + { + strcpy(destaddr,addr); + break; + } + } + } + } + else if ( bits256_cmp(txid,utxotxid) == 0 ) { spendtxid = jbits256(item,"spendtxid"); if ( bits256_nonz(spendtxid) != 0 ) diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 21be3fd60..1cc427321 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -703,7 +703,7 @@ TWO_STRINGS_AND_TWO_DOUBLES(dex,listtransactions,symbol,address,count,skip) for (i=0; i (%s)\n",retstr,retstr2,jprint(retjson3,0)); + //printf("combined (%s) and (%s) -> (%s)\n",retstr,retstr2,jprint(retjson3,0)); free(retstr); free(retstr2); free_json(retjson); From d1f970c05b9e24f2994058db9c6848842ae14292 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 15:32:06 +0300 Subject: [PATCH 0272/2705] Test --- basilisk/basilisk_swap.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ed1be2ccd..86e4e217d 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2856,7 +2856,7 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) { - bits256 spendtxid,txid; char *retstr,*addr; cJSON *array,*item,*inputs; int32_t i,n,m; char coinaddr[64]; + bits256 spendtxid,txid; char *retstr,*addr; cJSON *array,*array2,*item; int32_t i,n,m; char coinaddr[64]; // listtransactions or listspents destaddr[0] = 0; memset(&spendtxid,0,sizeof(spendtxid)); @@ -2880,14 +2880,17 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * if ( bits256_nonz(txid) == 0 ) { spendtxid = jbits256(item,"hash"); - if ( (array= jarray(&m,item,"inputs")) != 0 && m == 1 ) + if ( (array2= jarray(&m,item,"inputs")) != 0 && m == 1 ) { - txid = jbits256(jitem(array,0),"output_hash"); + printf("found inputs with %s\n",bits256_str(str,spendtxid)); + txid = jbits256(jitem(array2,0),"output_hash"); if ( bits256_cmp(txid,utxotxid) == 0 ) { - if ( (array= jarray(&m,item,"outputs")) != 0 && m == 1 && (addr= jstr(jitem(array,0),"address")) != 0 ) + printf("matched %s\n",bits256_str(str,txid)); + if ( (array2= jarray(&m,item,"outputs")) != 0 && m == 1 && (addr= jstr(jitem(array2,0),"address")) != 0 ) { strcpy(destaddr,addr); + printf("set addr.(%s)\n",addr); break; } } From 6b5033d2cb9fea2bac8ecd18d9acf8c5468fd3b2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 15:34:11 +0300 Subject: [PATCH 0273/2705] Test --- basilisk/basilisk_swap.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 86e4e217d..be0924726 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2860,15 +2860,15 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * // listtransactions or listspents destaddr[0] = 0; memset(&spendtxid,0,sizeof(spendtxid)); - char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); + //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); if ( iguana_isnotarychain(symbol) >= 0 ) { //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); - printf("spendtxid %s dest.(%s)\n",symbol,coinaddr); + //printf("spendtxid %s dest.(%s)\n",symbol,coinaddr); if ( coinaddr[0] != 0 && (retstr= dex_listtransactions(myinfo,0,0,0,symbol,coinaddr,100,0)) != 0 ) { - printf("listtransactions.(%s)\n",retstr); + //printf("listtransactions.(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -2882,15 +2882,15 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * spendtxid = jbits256(item,"hash"); if ( (array2= jarray(&m,item,"inputs")) != 0 && m == 1 ) { - printf("found inputs with %s\n",bits256_str(str,spendtxid)); + //printf("found inputs with %s\n",bits256_str(str,spendtxid)); txid = jbits256(jitem(array2,0),"output_hash"); if ( bits256_cmp(txid,utxotxid) == 0 ) { - printf("matched %s\n",bits256_str(str,txid)); + //printf("matched %s\n",bits256_str(str,txid)); if ( (array2= jarray(&m,item,"outputs")) != 0 && m == 1 && (addr= jstr(jitem(array2,0),"address")) != 0 ) { strcpy(destaddr,addr); - printf("set addr.(%s)\n",addr); + //printf("set addr.(%s)\n",addr); break; } } From 80fdaa04a04e53fa4224538f6c14e874509e9fec Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 15:37:03 +0300 Subject: [PATCH 0274/2705] Test --- basilisk/basilisk_swap.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index be0924726..423bcf85e 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3159,12 +3159,11 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,finishedflag = 0,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,str2[65],*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,finishedflag = 0,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"rb")) != 0 ) { - fclose(fp); - return(cJSON_Parse("{\"result\":\"success\",\"status\":\"already finished\"}")); + finishedflag = 1; } memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); @@ -3279,7 +3278,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 safecopy(alicecoin,symbol,sizeof(alicecoin)); if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) { - printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); } else { @@ -3306,7 +3305,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 free(fstr); } } - printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); + //printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); //strcpy(bobcoin,"KMD"); //strcpy(alicecoin,"BTC"); Adestaddr[0] = destaddr[0] = 0; @@ -3343,7 +3342,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 { if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) { - printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); + //printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) sentflags[BASILISK_ALICEPAYMENT] = 1; else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) From e3baac2558d02a4aa13a9fae1ec8628b26d5f77d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 15:40:01 +0300 Subject: [PATCH 0275/2705] Test --- basilisk/basilisk_swap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 423bcf85e..a27d2cdd6 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2816,7 +2816,7 @@ int32_t basilisk_swap_txdestaddr(char *destaddr,bits256 txid,int32_t vout,cJSON safecopy(destaddr,addr,64); retval = 0; } - printf("item.(%s) -> dest.(%s)\n",jprint(item,0),destaddr); + //printf("item.(%s) -> dest.(%s)\n",jprint(item,0),destaddr); } } return(retval); @@ -3112,19 +3112,19 @@ bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int3 sentflags[utxoind] = 1; if ( aliceaddr != 0 && strcmp(destaddr,aliceaddr) == 0 ) { - printf("ALICE spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + //printf("ALICE spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); sentflags[alicespent] = 1; txids[alicespent] = spendtxid; } else if ( bobaddr != 0 && strcmp(destaddr,bobaddr) == 0 ) { - printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + //printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); sentflags[bobspent] = 1; txids[bobspent] = spendtxid; } else { - printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + //printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); if ( aliceaddr != 0 ) { sentflags[bobspent] = 1; From 3b5d0f81deca399ce88bbc9a9f13afa942517a22 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 17:49:40 +0300 Subject: [PATCH 0276/2705] Test --- .gitignore | 2 + basilisk/basilisk_swap.c | 113 +++++++++++++++++++++++++++++++-------- 2 files changed, 93 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 9daaaad53..0b111b91f 100755 --- a/.gitignore +++ b/.gitignore @@ -346,3 +346,5 @@ iguana/DB/SWAPS/152114847-907489057 iguana/DB/SWAPS/61119357-1960547076 iguana/DB/SWAPS/26534791-3105729230 + +*.finished diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a27d2cdd6..d32bc7143 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2643,6 +2643,17 @@ void basilisk_swaploop(void *_swap) free(data); } +cJSON *basilisk_swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + cJSON *item = cJSON_CreateObject(); + jaddnum(item,"requestid",swap->I.req.requestid); + jaddnum(item,"quoteid",swap->I.req.quoteid); + jaddnum(item,"state",swap->I.statebits); + jaddnum(item,"otherstate",swap->I.otherstatebits); + jadd(item,"request",basilisk_requestjson(&swap->I.req)); + return(item); +} + struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { int32_t i,m,n; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct basilisk_swap *swap = 0; @@ -2747,6 +2758,8 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 return(swap); } +/////////////// remember functions + cJSON *basilisk_nullretjson(cJSON *retjson) { char *outstr; @@ -3105,7 +3118,7 @@ bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int3 printf("bobaddr.(%s)\n",bobaddr);*/ if ( bits256_nonz(txid) != 0 ) { - char str[65]; + //char str[65]; spendtxid = basilisk_swap_spendtxid(myinfo,symbol,destaddr,txid,vout); if ( bits256_nonz(spendtxid) != 0 ) { @@ -3157,14 +3170,15 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob // add blocktrail presence requirement for BTC -cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) +cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,finishedflag = 0,iambob = -1; uint64_t srcamount,destamount=0,value; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"rb")) != 0 ) { finishedflag = 1; } + memset(values,0,sizeof(values)); memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); memset(secretAm256,0,sizeof(secretAm256)); @@ -3283,6 +3297,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 else { checktxid = jbits256(sentobj,"txid"); + if ( bits256_nonz(checktxid) == 0 ) + checktxid = jbits256(sentobj,"hash"); if ( bits256_cmp(checktxid,txid) == 0 ) { //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); @@ -3290,16 +3306,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 } free_json(sentobj); } - if ( sentflags[i] != 0 ) - { - value = jdouble(txobj,"amount") * SATOSHIDEN; - if ( strcmp(symbol,"KMD") == 0 ) - KMDtotals[i] += value; - else if ( strcmp(symbol,"BTC") == 0 ) - BTCtotals[i] += value; - } - if ( sentflags[i] == 0 || addflag != 0 ) - jaddi(array,txobj); + values[i] = value = jdouble(txobj,"amount") * SATOSHIDEN; + //printf("%s %.8f\n",txnames[i],dstr(value)); + //if ( sentflags[i] == 0 || addflag != 0 ) + // jaddi(array,txobj); } } //else printf("no symbol\n"); free(fstr); @@ -3354,9 +3364,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBPAYMENT,BASILISK_ALICESPEND,BASILISK_BOBRECLAIM,0,Adest,Bdest); Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,sentflags,txids,BASILISK_ALICEPAYMENT,BASILISK_ALICERECLAIM,BASILISK_BOBSPEND,0,AAdest,ABdest); depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBDEPOSIT,BASILISK_ALICECLAIM,BASILISK_BOBREFUND,0,Adest,Bdest); - printf("Apaymentspent.(%s) alice.%d bob.%d\n",bits256_str(str,Apaymentspent),sentflags[BASILISK_ALICERECLAIM],sentflags[BASILISK_BOBSPEND]); - printf("paymentspent.(%s) alice.%d bob.%d\n",bits256_str(str,paymentspent),sentflags[BASILISK_ALICESPEND],sentflags[BASILISK_BOBRECLAIM]); - printf("depositspent.(%s) alice.%d bob.%d\n",bits256_str(str,depositspent),sentflags[BASILISK_ALICECLAIM],sentflags[BASILISK_BOBREFUND]); if ( bits256_nonz(paymentspent) != 0 && bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) { finishedflag = 1; @@ -3524,6 +3531,62 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 sentflags[BASILISK_ALICEPAYMENT] = 1; if ( sentflags[BASILISK_ALICECLAIM] != 0 || sentflags[BASILISK_BOBREFUND] != 0 ) sentflags[BASILISK_BOBDEPOSIT] = 1; + printf("Apaymentspent.(%s) alice.%d bob.%d %s %.8f\n",bits256_str(str,Apaymentspent),sentflags[BASILISK_ALICERECLAIM],sentflags[BASILISK_BOBSPEND],alicecoin,dstr(values[BASILISK_ALICEPAYMENT])); + printf("paymentspent.(%s) alice.%d bob.%d %s %.8f\n",bits256_str(str,paymentspent),sentflags[BASILISK_ALICESPEND],sentflags[BASILISK_BOBRECLAIM],bobcoin,dstr(values[BASILISK_BOBPAYMENT])); + printf("depositspent.(%s) alice.%d bob.%d %s %.8f\n",bits256_str(str,depositspent),sentflags[BASILISK_ALICECLAIM],sentflags[BASILISK_BOBREFUND],bobcoin,dstr(values[BASILISK_BOBDEPOSIT])); + values[BASILISK_OTHERFEE] = 0; + if ( iambob == 0 ) + { + if ( strcmp(alicecoin,"BTC") == 0 ) + { + BTCtotals[BASILISK_ALICEPAYMENT] -= values[BASILISK_ALICEPAYMENT] * sentflags[BASILISK_ALICEPAYMENT]; + BTCtotals[BASILISK_ALICERECLAIM] += values[BASILISK_ALICEPAYMENT] * sentflags[BASILISK_ALICERECLAIM]; + BTCtotals[BASILISK_MYFEE] -= values[BASILISK_MYFEE] * sentflags[BASILISK_MYFEE]; + } + else if ( strcmp(alicecoin,"KMD") == 0 ) + { + KMDtotals[BASILISK_ALICEPAYMENT] -= values[BASILISK_ALICEPAYMENT] * sentflags[BASILISK_ALICEPAYMENT]; + KMDtotals[BASILISK_ALICERECLAIM] += values[BASILISK_ALICEPAYMENT] * sentflags[BASILISK_ALICERECLAIM]; + KMDtotals[BASILISK_MYFEE] -= values[BASILISK_MYFEE] * sentflags[BASILISK_MYFEE]; + } + if ( strcmp(bobcoin,"KMD") == 0 ) + { + KMDtotals[BASILISK_ALICESPEND] += values[BASILISK_BOBPAYMENT] * sentflags[BASILISK_ALICESPEND]; + KMDtotals[BASILISK_ALICECLAIM] += values[BASILISK_BOBDEPOSIT] * sentflags[BASILISK_ALICECLAIM]; + } + else if ( strcmp(bobcoin,"BTC") == 0 ) + { + BTCtotals[BASILISK_ALICESPEND] += values[BASILISK_BOBPAYMENT] * sentflags[BASILISK_ALICESPEND]; + BTCtotals[BASILISK_ALICECLAIM] += values[BASILISK_BOBDEPOSIT] * sentflags[BASILISK_ALICECLAIM]; + } + } + else + { + if ( strcmp(alicecoin,"BTC") == 0 ) + { + BTCtotals[BASILISK_BOBPAYMENT] -= values[BASILISK_BOBPAYMENT] * sentflags[BASILISK_BOBPAYMENT]; + BTCtotals[BASILISK_BOBDEPOSIT] -= values[BASILISK_BOBDEPOSIT] * sentflags[BASILISK_BOBDEPOSIT]; + BTCtotals[BASILISK_BOBREFUND] += values[BASILISK_BOBREFUND] * sentflags[BASILISK_BOBREFUND]; + BTCtotals[BASILISK_BOBRECLAIM] += values[BASILISK_BOBRECLAIM] * sentflags[BASILISK_BOBRECLAIM]; + BTCtotals[BASILISK_MYFEE] -= values[BASILISK_MYFEE] * sentflags[BASILISK_MYFEE]; + } + else if ( strcmp(alicecoin,"KMD") == 0 ) + { + KMDtotals[BASILISK_BOBPAYMENT] -= values[BASILISK_BOBPAYMENT] * sentflags[BASILISK_BOBPAYMENT]; + KMDtotals[BASILISK_BOBDEPOSIT] -= values[BASILISK_BOBDEPOSIT] * sentflags[BASILISK_BOBDEPOSIT]; + KMDtotals[BASILISK_BOBREFUND] += values[BASILISK_BOBDEPOSIT] * sentflags[BASILISK_BOBREFUND]; + KMDtotals[BASILISK_BOBRECLAIM] += values[BASILISK_BOBPAYMENT] * sentflags[BASILISK_BOBRECLAIM]; + KMDtotals[BASILISK_MYFEE] -= values[BASILISK_MYFEE] * sentflags[BASILISK_MYFEE]; + } + if ( strcmp(bobcoin,"KMD") == 0 ) + { + KMDtotals[BASILISK_BOBSPEND] += values[BASILISK_BOBSPEND] * sentflags[BASILISK_BOBSPEND]; + } + else if ( strcmp(bobcoin,"BTC") == 0 ) + { + BTCtotals[BASILISK_BOBSPEND] += values[BASILISK_ALICEPAYMENT] * sentflags[BASILISK_BOBSPEND]; + } + } if ( bits256_nonz(paymentspent) != 0 && bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) { finishedflag = 1; @@ -3563,7 +3626,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,uint64_t *KMDtotals,uint64 char *basilisk_swaplist(struct supernet_info *myinfo) { - char fname[512]; FILE *fp; cJSON *retjson,*array,*totalsobj; uint32_t quoteid,requestid; uint64_t KMDtotals[16],BTCtotals[16]; int32_t i; + char fname[512]; FILE *fp; cJSON *retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16]; int32_t i; memset(KMDtotals,0,sizeof(KMDtotals)); memset(BTCtotals,0,sizeof(BTCtotals)); //,statebits; int32_t optionduration; struct basilisk_request R; bits256 privkey; @@ -3572,13 +3635,19 @@ char *basilisk_swaplist(struct supernet_info *myinfo) sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); if ( (fp= fopen(fname,"rb")) != 0 ) { + struct basilisk_swap *swap; int32_t flag = 0; while ( fread(&requestid,1,sizeof(requestid),fp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),fp) == sizeof(quoteid) ) { - jaddi(array,basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)); - /*if ( basilisk_swap_load(requestid,quoteid,&privkey,&R,&statebits,&optionduration) == 0 ) - { - jaddi(array,basilisk_requestjson(&R)); - }*/ + flag = 0; + for (i=0; inumswaps; i++) + if ( (swap= myinfo->swaps[i]) != 0 && swap->I.req.requestid == requestid && swap->I.req.quoteid == quoteid ) + { + jaddi(array,basilisk_swapjson(myinfo,swap)); + flag = 1; + break; + } + if ( flag == 0 ) + jaddi(array,basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)); } fclose(fp); } From b0e44aa4373507ed4f329684e6deccc6ea5cccd0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 17:54:31 +0300 Subject: [PATCH 0277/2705] Test --- basilisk/basilisk_swap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index d32bc7143..f607e9567 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3531,7 +3531,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t sentflags[BASILISK_ALICEPAYMENT] = 1; if ( sentflags[BASILISK_ALICECLAIM] != 0 || sentflags[BASILISK_BOBREFUND] != 0 ) sentflags[BASILISK_BOBDEPOSIT] = 1; - printf("Apaymentspent.(%s) alice.%d bob.%d %s %.8f\n",bits256_str(str,Apaymentspent),sentflags[BASILISK_ALICERECLAIM],sentflags[BASILISK_BOBSPEND],alicecoin,dstr(values[BASILISK_ALICEPAYMENT])); + printf("iambob.%d Apaymentspent.(%s) alice.%d bob.%d %s %.8f\n",iambob,bits256_str(str,Apaymentspent),sentflags[BASILISK_ALICERECLAIM],sentflags[BASILISK_BOBSPEND],alicecoin,dstr(values[BASILISK_ALICEPAYMENT])); printf("paymentspent.(%s) alice.%d bob.%d %s %.8f\n",bits256_str(str,paymentspent),sentflags[BASILISK_ALICESPEND],sentflags[BASILISK_BOBRECLAIM],bobcoin,dstr(values[BASILISK_BOBPAYMENT])); printf("depositspent.(%s) alice.%d bob.%d %s %.8f\n",bits256_str(str,depositspent),sentflags[BASILISK_ALICECLAIM],sentflags[BASILISK_BOBREFUND],bobcoin,dstr(values[BASILISK_BOBDEPOSIT])); values[BASILISK_OTHERFEE] = 0; @@ -3562,7 +3562,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } else { - if ( strcmp(alicecoin,"BTC") == 0 ) + if ( strcmp(bobcoin,"BTC") == 0 ) { BTCtotals[BASILISK_BOBPAYMENT] -= values[BASILISK_BOBPAYMENT] * sentflags[BASILISK_BOBPAYMENT]; BTCtotals[BASILISK_BOBDEPOSIT] -= values[BASILISK_BOBDEPOSIT] * sentflags[BASILISK_BOBDEPOSIT]; @@ -3570,7 +3570,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t BTCtotals[BASILISK_BOBRECLAIM] += values[BASILISK_BOBRECLAIM] * sentflags[BASILISK_BOBRECLAIM]; BTCtotals[BASILISK_MYFEE] -= values[BASILISK_MYFEE] * sentflags[BASILISK_MYFEE]; } - else if ( strcmp(alicecoin,"KMD") == 0 ) + else if ( strcmp(bobcoin,"KMD") == 0 ) { KMDtotals[BASILISK_BOBPAYMENT] -= values[BASILISK_BOBPAYMENT] * sentflags[BASILISK_BOBPAYMENT]; KMDtotals[BASILISK_BOBDEPOSIT] -= values[BASILISK_BOBDEPOSIT] * sentflags[BASILISK_BOBDEPOSIT]; @@ -3578,11 +3578,11 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t KMDtotals[BASILISK_BOBRECLAIM] += values[BASILISK_BOBPAYMENT] * sentflags[BASILISK_BOBRECLAIM]; KMDtotals[BASILISK_MYFEE] -= values[BASILISK_MYFEE] * sentflags[BASILISK_MYFEE]; } - if ( strcmp(bobcoin,"KMD") == 0 ) + if ( strcmp(alicecoin,"KMD") == 0 ) { KMDtotals[BASILISK_BOBSPEND] += values[BASILISK_BOBSPEND] * sentflags[BASILISK_BOBSPEND]; } - else if ( strcmp(bobcoin,"BTC") == 0 ) + else if ( strcmp(alicecoin,"BTC") == 0 ) { BTCtotals[BASILISK_BOBSPEND] += values[BASILISK_ALICEPAYMENT] * sentflags[BASILISK_BOBSPEND]; } From 496efb257a7b6b5d2b63ee27ae019a3ba46c7bba Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 18:04:54 +0300 Subject: [PATCH 0278/2705] Test --- basilisk/jumblr.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index b71e527fe..b8b202312 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -731,10 +731,10 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } if ( myinfo->numswaps == 0 && myinfo->IAMLP == 0 && kmdcoin->DEXinfo.btcprice > SMALLVAL ) { - double minbtc,btcavail; char *retstr; cJSON *vals; bits256 hash; + double minbtc,minkmd,btcavail,kmdavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( toKMD != 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) + if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { avail = (btcavail - kmdcoin->DEXinfo.DEXpending); printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); @@ -752,7 +752,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",1./(1.05 * kmdcoin->DEXinfo.btcprice)); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice); jaddnum(vals,"usejumblr",1); jaddnum(vals,"DEXselector",1); memset(hash.bytes,0,sizeof(hash)); @@ -766,16 +766,18 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - if ( toKMD == 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (100. + kmdcoin->DEXinfo.KMDpending) ) + minkmd = 100.; + kmdavail = dstr(jumblr_balance(myinfo,kmdcoin,kmdcoin->DEXinfo.jumblraddr)); + if ( toKMD != 0 && coinbtc != 0 && kmdavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) { - avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); - printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,JUMBLR_INCR,avail); - /*if ( avail > 10000. ) - vol = 10000.; - else if ( avail > 1000. ) - vol = 1000.; - else*/ if ( avail >= 100. ) - vol = 100.; + avail = (kmdavail - kmdcoin->DEXinfo.KMDpending); + printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdavail,minkmd,avail); + /*if ( avail > 100.*JUMBLR_INCR ) + vol = 100.*JUMBLR_INCR; + else if ( avail > 10.*JUMBLR_INCR ) + vol = 10.*JUMBLR_INCR; + else*/ if ( avail >= JUMBLR_INCR ) + vol = JUMBLR_INCR; else vol = 0.; if ( vol > 0. ) { @@ -784,8 +786,8 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",vol); //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice/1.05); - jaddnum(vals,"usejumblr",1); + jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"usejumblr",2); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.KMDpending += vol; jaddnum(vals,"DEXselector",2); From 33c303f65c4ff3416adb7529e34989295836702a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 18:33:30 +0300 Subject: [PATCH 0279/2705] Test --- basilisk/basilisk_swap.c | 2 +- basilisk/basilisk_tradebot.c | 16 ++++++++++------ basilisk/jumblr.c | 15 +++++++-------- iguana/m_osx | 1 + includes/iguana_funcs.h | 1 + 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f607e9567..e256b9ddf 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3610,7 +3610,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t bits256_str(str,depositspent), jaddbits256(item,"depositspent",depositspent); if ( finishedflag != 0 ) { - printf("SWAP %u-%u finished!\n",requestid,quoteid); + //printf("SWAP %u-%u finished!\n",requestid,quoteid); sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"wb")) != 0 ) { diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 706d73709..f704595e2 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -317,7 +317,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk } else noquoteflag++; } // MVP -> USD myrequest.0 pendingid.0 noquoteflag.1 havequoteflag.0 maxi.-1 0.00000000 - double retvals[4],refprice=0.,profitmargin,aveprice,destvolume; cJSON *retjson; char *retstr; + struct iguana_info *coin; char coinaddr[64]; double retvals[4],refprice=0.,profitmargin,aveprice,destvolume; destvolume = dstr(maxamount); //printf("destvolume <- %.8f\n",dstr(destvolume)); if ( fabs(destvolume) < SMALLVAL ) @@ -327,9 +327,9 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk aveprice = instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,1.3 * dstr(list[0].srcamount)); destvolume = aveprice * dstr(list[0].srcamount); printf("set destvolume %.8f\n",destvolume); - } else printf("destvolume %.8f <- minamount\n",destvolume); + } // else printf("destvolume %.8f <- minamount\n",destvolume); } - printf("%s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); + printf("%s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %.8f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); if ( myinfo->IAMLP != 0 && myrequest == 0 && pendingid == 0 && noquoteflag != 0 && ((profitmargin= tradebot_liquidity_active(myinfo,&refprice,"DEX",list[0].src,list[0].dest,destvolume)) > 0. || refprice != 0.) ) { if ( profitmargin == 0. || (aveprice= instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,.1 * dstr(list[0].srcamount))) == 0. || refprice > aveprice ) @@ -343,7 +343,12 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk if ( destamount > minamount ) destamount = minamount + ((destamount - minamount) * (1 + (rand() % 100))) / 100.; printf("%s/%s pm %f aveprice %f src %.8f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",list[0].src,list[0].dest,profitmargin,aveprice,dstr(list[0].srcamount),dstr(destamount),retvals[0],retvals[1],retvals[2],retvals[3]); - if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) + if ( (coin= iguana_coinfind(list[0].dest)) != 0 ) + { + bitcoin_address(coinaddr,coin->chain->pubtype,myinfo->persistent_pubkey33,33); + balance = dstr(jumblr_balance(myinfo,coin,coinaddr)); + } + /*if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { @@ -351,8 +356,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk free_json(retjson); } free(retstr); - } - // BTC balance 0.00500000 destamount 0.00041951 aveprice 0.00421619 minamount 0.00020000 + }*/ printf("%s balance %.8f destamount %.8f aveprice %.8f maxamount %.8f minamount %.8f\n",list[0].dest,dstr(balance),dstr(destamount),aveprice,dstr(maxamount),dstr(minamount)); if ( balance > destamount && (int64_t)destamount > 0 && destamount >= minamount ) // max? { diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index b8b202312..21d04b334 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -685,7 +685,6 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); KMDavail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->KMDjumblraddr)); - printf("%s avail %.8f KMDavail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,KMDavail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); if ( strcmp("KMD",symbol) == 0 ) { ptr->BTC2KMD = ptr->btcprice; @@ -702,6 +701,7 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char //jumblr_utxoupdate(myinfo,"KMD",ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey,estfee); } ptr->lasttime = (uint32_t)time(NULL); + printf("%s avail %.8f KMDavail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,KMDavail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); } // else printf("skip\n"); } @@ -716,7 +716,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 double vol,avail; struct iguana_info *kmdcoin,*coinbtc = 0; kmdcoin = iguana_coinfind("KMD"); coinbtc = iguana_coinfind("BTC"); - printf("jumblr_DEXcheck numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); + //printf("jumblr_DEXcheck numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 ) return; if ( kmdcoin == 0 || coinbtc == 0 ) @@ -731,7 +731,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } if ( myinfo->numswaps == 0 && myinfo->IAMLP == 0 && kmdcoin->DEXinfo.btcprice > SMALLVAL ) { - double minbtc,minkmd,btcavail,kmdavail; char *retstr; cJSON *vals; bits256 hash; + double minbtc,minkmd,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) @@ -767,11 +767,10 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); minkmd = 100.; - kmdavail = dstr(jumblr_balance(myinfo,kmdcoin,kmdcoin->DEXinfo.jumblraddr)); - if ( toKMD != 0 && coinbtc != 0 && kmdavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) + if ( toKMD != 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) { - avail = (kmdavail - kmdcoin->DEXinfo.KMDpending); - printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdavail,minkmd,avail); + avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); + printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,minkmd,avail); /*if ( avail > 100.*JUMBLR_INCR ) vol = 100.*JUMBLR_INCR; else if ( avail > 10.*JUMBLR_INCR ) @@ -798,7 +797,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } free_json(vals); } - } else printf("btcavail %.8f pending %.8f\n",btcavail,kmdcoin->DEXinfo.KMDpending); + } else printf("kmdavail %.8f pending %.8f\n",kmdcoin->DEXinfo.KMDavail,kmdcoin->DEXinfo.KMDpending); } else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); } diff --git a/iguana/m_osx b/iguana/m_osx index e752b11cc..b7a296285 100755 --- a/iguana/m_osx +++ b/iguana/m_osx @@ -3,6 +3,7 @@ rm ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. +cd ../crypto777; ./m_unix; cd ../iguana gcc -g -Wno-address-of-packed-member -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c gcc -g -Wno-address-of-packed-member -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a -lnanomsg -lcurl -lssl -lcrypto -lpthread -lz -lm diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index b8061eb61..c082dcabf 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -633,6 +633,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,uint8_t pubtype,char *KMDaddr,char *prefix); char *jumblr_importprivkey(struct supernet_info *myinfo,struct iguana_info *coin,char *wifstr); int64_t iguana_esttxfee(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx,char *signedtx,int32_t numvins); +int64_t jumblr_balance(struct supernet_info *myinfo,struct iguana_info *coin,char *addr); // ------------------------------------------------------[ Preparation ]---- // Initialise a gfshare context for producing shares From 787105c3dc92266bf7289b913ee5ed55b872ab20 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 18:41:25 +0300 Subject: [PATCH 0280/2705] Test --- basilisk/basilisk_tradebot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index f704595e2..7c2e808c0 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -347,6 +347,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk { bitcoin_address(coinaddr,coin->chain->pubtype,myinfo->persistent_pubkey33,33); balance = dstr(jumblr_balance(myinfo,coin,coinaddr)); + printf("%s %s balance %.8f destamount %.8f aveprice %.8f maxamount %.8f minamount %.8f\n",list[0].dest,coinaddr,dstr(balance),dstr(destamount),aveprice,dstr(maxamount),dstr(minamount)); } /*if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) { @@ -357,7 +358,6 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk } free(retstr); }*/ - printf("%s balance %.8f destamount %.8f aveprice %.8f maxamount %.8f minamount %.8f\n",list[0].dest,dstr(balance),dstr(destamount),aveprice,dstr(maxamount),dstr(minamount)); if ( balance > destamount && (int64_t)destamount > 0 && destamount >= minamount ) // max? { metric = 1.; From 050744ddaafef563b8904dd0e094038599c70f39 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 18:47:29 +0300 Subject: [PATCH 0281/2705] Test --- basilisk/jumblr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 21d04b334..e6d72106e 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -198,7 +198,7 @@ int64_t jumblr_balance(struct supernet_info *myinfo,struct iguana_info *coin,cha char *retstr; double val; cJSON *retjson; int32_t i,n; int64_t balance = 0; if ( jumblr_addresstype(myinfo,coin,addr) == 't' ) { - if ( coin->FULLNODE < 0 && jumblr_ismine(myinfo,coin,addr) > 0 ) + if ( coin->FULLNODE < 0 && iguana_isnotarychain(coin->symbol) < 0 ) { if ( (retstr= jumblr_listunspent(myinfo,coin,addr)) != 0 ) { From 14d170d19c6cf27054517e881aa448922c67dd74 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 19:04:16 +0300 Subject: [PATCH 0282/2705] Test --- basilisk/jumblr.c | 2 +- iguana/iguana_notary.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index e6d72106e..bafa642e4 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -752,7 +752,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"minprice",1./kmdcoin->DEXinfo.btcprice); jaddnum(vals,"usejumblr",1); jaddnum(vals,"DEXselector",1); memset(hash.bytes,0,sizeof(hash)); diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 1cc427321..fa6676dfa 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -922,7 +922,7 @@ TWO_STRINGS(dex,getbalance,symbol,address) jdelete(retjson,"unconfirmed_received"); jaddnum(retjson,"unconfirmed_received",dstr(val)); } - //printf("blocktrail.(%s) -> (%s)\n",retstr,jprint(retjson,0)); + printf("blocktrail.(%s) -> (%s)\n",retstr,jprint(retjson,0)); free(retstr); retstr = jprint(retjson,1); } From 3c0054b2d0733effb7380035540ae2286f27f13d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 19:08:15 +0300 Subject: [PATCH 0283/2705] Test --- basilisk/jumblr.c | 3 ++- iguana/iguana_notary.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index bafa642e4..a8f509b75 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -215,10 +215,11 @@ int64_t jumblr_balance(struct supernet_info *myinfo,struct iguana_info *coin,cha } else if ( (retstr= dex_getbalance(myinfo,coin,0,0,coin->symbol,addr)) != 0 ) { - //printf("DEX retstr.(%s)\n",retstr); + printf("DEX retstr.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { balance = jdouble(retjson,"balance") * SATOSHIDEN; + printf("GOT BALANCE %s %.8f\n",coin->symbol,balance); free_json(retjson); } free(retstr); diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index fa6676dfa..1cc427321 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -922,7 +922,7 @@ TWO_STRINGS(dex,getbalance,symbol,address) jdelete(retjson,"unconfirmed_received"); jaddnum(retjson,"unconfirmed_received",dstr(val)); } - printf("blocktrail.(%s) -> (%s)\n",retstr,jprint(retjson,0)); + //printf("blocktrail.(%s) -> (%s)\n",retstr,jprint(retjson,0)); free(retstr); retstr = jprint(retjson,1); } From cbafd4830b7ed2a2f1e4d8855590d41809ba16ed Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 19:11:00 +0300 Subject: [PATCH 0284/2705] Test --- basilisk/basilisk_tradebot.c | 2 +- basilisk/jumblr.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 7c2e808c0..136021efe 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -346,7 +346,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk if ( (coin= iguana_coinfind(list[0].dest)) != 0 ) { bitcoin_address(coinaddr,coin->chain->pubtype,myinfo->persistent_pubkey33,33); - balance = dstr(jumblr_balance(myinfo,coin,coinaddr)); + balance = jumblr_balance(myinfo,coin,coinaddr); printf("%s %s balance %.8f destamount %.8f aveprice %.8f maxamount %.8f minamount %.8f\n",list[0].dest,coinaddr,dstr(balance),dstr(destamount),aveprice,dstr(maxamount),dstr(minamount)); } /*if ( (retstr= InstantDEX_available(myinfo,iguana_coinfind(list[0].dest),0,0,list[0].dest)) != 0 ) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index a8f509b75..9f1315164 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -215,11 +215,11 @@ int64_t jumblr_balance(struct supernet_info *myinfo,struct iguana_info *coin,cha } else if ( (retstr= dex_getbalance(myinfo,coin,0,0,coin->symbol,addr)) != 0 ) { - printf("DEX retstr.(%s)\n",retstr); + //printf("DEX retstr.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { balance = jdouble(retjson,"balance") * SATOSHIDEN; - printf("GOT BALANCE %s %.8f\n",coin->symbol,balance); + //printf("GOT BALANCE %s %.8f\n",coin->symbol,dstr(balance)); free_json(retjson); } free(retstr); From cdafac58bea43fb318847e481a96594d9a37ca25 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 19:50:20 +0300 Subject: [PATCH 0285/2705] Test --- basilisk/basilisk.c | 6 ++++-- basilisk/basilisk_DEX.c | 8 +++++--- basilisk/basilisk_swap.c | 31 ++++++++++++++++++------------- basilisk/jumblr.c | 4 ++-- iguana/dpow/dpow_network.c | 2 +- includes/iguana_funcs.h | 2 +- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 09737092b..c37872b57 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -921,7 +921,7 @@ int32_t basilisk_issued_purge(struct supernet_info *myinfo,int32_t timepad) void basilisks_loop(void *arg) { static uint32_t counter; - struct iguana_info *relay; struct supernet_info *myinfo = arg; int32_t iter; double startmilli,endmilli; struct dpow_info *dp; + struct iguana_info *relay; struct supernet_info *myinfo = arg; int32_t i,iter; double startmilli,endmilli; struct dpow_info *dp; iter = 0; relay = iguana_coinfind("RELAY"); printf("start basilisk loop\n"); @@ -974,7 +974,9 @@ void basilisks_loop(void *arg) if ( myinfo->expiration != 0 && (myinfo->dexsock >= 0 || myinfo->IAMLP != 0 || myinfo->DEXactive > time(NULL)) ) { //fprintf(stderr,"H "); - basilisk_requests_poll(myinfo); + for (i=0; i<100; i++) + if ( basilisk_requests_poll(myinfo) <= 0 ) + break; } //printf("RELAYID.%d endmilli %f vs now %f\n",myinfo->NOTARY.RELAYID,endmilli,startmilli); while ( OS_milliseconds() < endmilli ) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index bed30428b..9ba81fccc 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -281,12 +281,12 @@ char *basilisk_start(struct supernet_info *myinfo,bits256 privkey,struct basilis } else return(clonestr("{\"error\":\"unexpected basilisk_start not mine and amrelay\"}")); } -void basilisk_requests_poll(struct supernet_info *myinfo) +int32_t basilisk_requests_poll(struct supernet_info *myinfo) { static uint32_t lastpoll; - char *retstr; uint8_t data[32768]; cJSON *outerarray,*retjson; uint32_t msgid,channel; int32_t datalen,i,n; struct basilisk_request issueR; bits256 privkey; double hwm = 0.; + char *retstr; uint8_t data[32768]; cJSON *outerarray,*retjson; uint32_t msgid,channel; int32_t datalen,i,n,retval = 0; struct basilisk_request issueR; bits256 privkey; double hwm = 0.; if ( myinfo->IAMNOTARY != 0 || time(NULL) < lastpoll+20 || (myinfo->IAMLP == 0 && myinfo->DEXactive < time(NULL)) ) - return; + return(retval); lastpoll = (uint32_t)time(NULL); memset(&issueR,0,sizeof(issueR)); memset(&myinfo->DEXaccept,0,sizeof(myinfo->DEXaccept)); @@ -298,6 +298,7 @@ void basilisk_requests_poll(struct supernet_info *myinfo) { if ( (outerarray= jarray(&n,retjson,"responses")) != 0 ) { + retval++; for (i=0; iI.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) { printf("nothing received for a while from Bob, try new sockets\n"); - if ( swap->pushsock >= 0 ) - nn_close(swap->pushsock), swap->pushsock = -1; - if ( swap->subsock >= 0 ) - nn_close(swap->subsock), swap->subsock = -1; + if ( swap->pushsock >= 0 ) //nn_close(swap->pushsock), + swap->pushsock = -1; + if ( swap->subsock >= 0 ) //nn_close(swap->subsock), + swap->subsock = -1; swap->connected = 0; basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); } @@ -1429,9 +1429,9 @@ uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *sw if ( sentbytes < 0 ) { if ( swap->pushsock >= 0 ) - nn_close(swap->pushsock), swap->pushsock = -1; - if ( swap->subsock >= 0 ) - nn_close(swap->subsock), swap->subsock = -1; + swap->pushsock = -1; //nn_close(swap->pushsock), + if ( swap->subsock >= 0 ) // nn_close(swap->subsock), + swap->subsock = -1; swap->connected = swap->I.iambob != 0 ? -1 : 0; swap->aborted = (uint32_t)time(NULL); } @@ -1451,10 +1451,10 @@ void basilisk_swap_sendabort(struct supernet_info *myinfo,struct basilisk_swap * { if ( sentbytes < 0 ) { - if ( swap->pushsock >= 0 ) - nn_close(swap->pushsock), swap->pushsock = -1; - if ( swap->subsock >= 0 ) - nn_close(swap->subsock), swap->subsock = -1; + if ( swap->pushsock >= 0 ) //nn_close(swap->pushsock), + swap->pushsock = -1; + if ( swap->subsock >= 0 ) //nn_close(swap->subsock), + swap->subsock = -1; swap->connected = 0; } } else printf("basilisk_swap_sendabort\n"); @@ -3261,6 +3261,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } free(fstr); } + if ( iambob < 0 ) + return(0); item = cJSON_CreateObject(); array = cJSON_CreateArray(); //printf("R.%u Q.%u\n",requestid,quoteid); @@ -3626,7 +3628,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t char *basilisk_swaplist(struct supernet_info *myinfo) { - char fname[512]; FILE *fp; cJSON *retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16]; int32_t i; + char fname[512]; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16]; int32_t i; memset(KMDtotals,0,sizeof(KMDtotals)); memset(BTCtotals,0,sizeof(BTCtotals)); //,statebits; int32_t optionduration; struct basilisk_request R; bits256 privkey; @@ -3647,7 +3649,10 @@ char *basilisk_swaplist(struct supernet_info *myinfo) break; } if ( flag == 0 ) - jaddi(array,basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)); + { + if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) + jaddi(array,item); + } } fclose(fp); } diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 9f1315164..7090fd33d 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -753,7 +753,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"source","BTC"); jaddstr(vals,"dest","KMD"); jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",1./kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"minprice",0.985/kmdcoin->DEXinfo.btcprice); jaddnum(vals,"usejumblr",1); jaddnum(vals,"DEXselector",1); memset(hash.bytes,0,sizeof(hash)); @@ -786,7 +786,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddstr(vals,"dest","BTC"); jaddnum(vals,"amount",vol); //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"minprice",0.985 * kmdcoin->DEXinfo.btcprice); jaddnum(vals,"usejumblr",2); memset(hash.bytes,0,sizeof(hash)); kmdcoin->DEXinfo.KMDpending += vol; diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 0b7089332..b90f7814e 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1263,7 +1263,7 @@ int32_t dex_packetcheck(struct supernet_info *myinfo,struct dex_nanomsghdr *dexp int32_t dex_subsock_poll(struct supernet_info *myinfo) { int32_t size= -1; struct dex_nanomsghdr *dexp; void *freeptr; - return(0); + //return(0); //fprintf(stderr,"subsock.%d\n",myinfo->subsock); if ( myinfo->subsock >= 0 && (size= signed_nn_recv(&freeptr,myinfo->ctx,myinfo->notaries,myinfo->numnotaries,myinfo->subsock,&dexp)) >= 0 ) { diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index c082dcabf..11072f2c9 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -604,7 +604,7 @@ int32_t iguana_scriptdata(struct iguana_info *coin,uint8_t *scriptspace,long fil void basilisk_ensurerelay(struct supernet_info *myinfo,struct iguana_info *notaries,uint32_t ipbits); void dpow_nanomsginit(struct supernet_info *myinfo,char *ipaddr); int32_t iguana_datachain_scan(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t rmd160[20]); -void basilisk_requests_poll(struct supernet_info *myinfo); +int32_t basilisk_requests_poll(struct supernet_info *myinfo); void dpow_psockloop(void *_ptr); int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *BTCaddr,char *KMDaddr); int32_t smartaddress(struct supernet_info *myinfo,bits256 *privkeyp,char *coinaddr); From b61f6d821b0de99a40649ecb9b8d68528ca5e761 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 20:04:47 +0300 Subject: [PATCH 0286/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_DEX.c | 19 ++++++++++++++----- basilisk/basilisk_swap.c | 4 ++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 0b111b91f..98ef5aaac 100755 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,5 @@ iguana/DB/SWAPS/61119357-1960547076 iguana/DB/SWAPS/26534791-3105729230 *.finished + +iguana/DB/SWAPS/2279906047-2580050792 diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index 9ba81fccc..b1e6fb579 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -484,7 +484,7 @@ char *basilisk_respond_accept(struct supernet_info *myinfo,bits256 privkey,uint3 cJSON *basilisk_unspents(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr) { - cJSON *unspents=0,*array=0; char *retstr; + cJSON *unspents=0,*array=0,*json,*ismine; char *retstr; int32_t valid = 0; if ( coin->FULLNODE > 0 ) { array = cJSON_CreateArray(); @@ -492,15 +492,24 @@ cJSON *basilisk_unspents(struct supernet_info *myinfo,struct iguana_info *coin,c unspents = iguana_listunspents(myinfo,coin,array,0,0,""); free_json(array); } - else if ( coin->FULLNODE == 0 ) + else { - if ( (retstr= dex_listunspent(myinfo,coin,0,0,coin->symbol,coinaddr)) != 0 ) + if ( coin->FULLNODE < 0 && (retstr= dpow_validateaddress(myinfo,coin,coinaddr)) != 0 ) { - unspents = cJSON_Parse(retstr); + json = cJSON_Parse(retstr); + if ( (ismine= jobj(json,"ismine")) != 0 && is_cJSON_True(ismine) != 0 ) + valid = 1; free(retstr); } + if ( coin->FULLNODE == 0 || valid == 0 ) + { + if ( (retstr= dex_listunspent(myinfo,coin,0,0,coin->symbol,coinaddr)) != 0 ) + { + unspents = cJSON_Parse(retstr); + free(retstr); + } + } else unspents = dpow_listunspent(myinfo,coin,coinaddr); } - else unspents = dpow_listunspent(myinfo,coin,coinaddr); return(unspents); } diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index f5d50a733..2bc5fa486 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -567,11 +567,11 @@ int32_t _basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swap jaddistr(addresses,coinaddr); jadd(valsobj,"addresses",addresses); rawtx->I.locktime = locktime; - //printf("%s locktime.%u\n",rawtx->name,locktime); + printf("%s locktime.%u\n",rawtx->name,locktime); V = calloc(256,sizeof(*V)); if ( (retstr= basilisk_bitcoinrawtx(myinfo,rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V)) != 0 ) { - //printf("%s %s basilisk_bitcoinrawtx.(%s)\n",rawtx->name,str,retstr); + printf("%s %s basilisk_bitcoinrawtx.(%s)\n",rawtx->name,str,retstr); flag = 0; if ( (retarray= cJSON_Parse(retstr)) != 0 ) { From fef621097cd7625e30217dc76b048f2461384a34 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 20:49:27 +0300 Subject: [PATCH 0287/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 39 ++++++++++++++++++++++++++++----------- iguana/iguana_payments.c | 1 + 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 98ef5aaac..b6bc99fa0 100755 --- a/.gitignore +++ b/.gitignore @@ -350,3 +350,5 @@ iguana/DB/SWAPS/26534791-3105729230 *.finished iguana/DB/SWAPS/2279906047-2580050792 + +iguana/DB/SWAPS/1672096208-4211948211 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2bc5fa486..a9e4fbc24 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -18,7 +18,7 @@ make sure to broadcast deposit before claiming refund, or to just skip it if neither is done */ -#define DEX_SLEEP 15 +#define DEX_SLEEP 10 #define BASILISK_DEFAULT_NUMCONFIRMS 5 // Todo: monitor blockchains, ie complete extracting scriptsig @@ -555,6 +555,8 @@ int32_t _basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swap jaddstr(valsobj,"spendscript",scriptstr); jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); jadd64bits(valsobj,"satoshis",rawtx->I.amount); + if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) + txfee = 50000; jadd64bits(valsobj,"txfee",txfee); jaddnum(valsobj,"minconf",minconf); if ( locktime == 0 ) @@ -571,7 +573,7 @@ int32_t _basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swap V = calloc(256,sizeof(*V)); if ( (retstr= basilisk_bitcoinrawtx(myinfo,rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V)) != 0 ) { - printf("%s %s basilisk_bitcoinrawtx.(%s)\n",rawtx->name,str,retstr); + printf("%s %s basilisk_bitcoinrawtx.(%s) txfee %.8f\n",rawtx->name,str,retstr,dstr(txfee)); flag = 0; if ( (retarray= cJSON_Parse(retstr)) != 0 ) { @@ -2111,7 +2113,7 @@ void basilisk_sendmostprivs(struct supernet_info *myinfo,struct basilisk_swap *s int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { - int32_t j,datalen,retval = 0; + int32_t j,datalen,retval = 0; uint32_t savestatebits=0,saveotherbits=0; if ( swap->I.iambob != 0 ) swap->I.statebits |= 0x80; while ( swap->aborted == 0 && ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) @@ -2134,7 +2136,10 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); if ( (swap->I.otherstatebits & 0x80) != 0 && (swap->I.statebits & 0x80) != 0 ) break; - sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); basilisk_sendstate(myinfo,swap,data,maxlen); if ( (swap->I.otherstatebits & 0x80) == 0 ) @@ -2321,7 +2326,10 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap } if ( (rand() % 30) == 0 ) printf("finished swapstate.%x other.%x\n",swap->I.statebits,swap->I.otherstatebits); - sleep(DEX_SLEEP + (swap->I.iambob == 0)); + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; basilisk_sendstate(myinfo,swap,data,maxlen); basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); } @@ -2466,7 +2474,7 @@ int32_t basilisk_alicetxs(struct supernet_info *myinfo,struct basilisk_swap *swa void basilisk_swaploop(void *_swap) { - uint8_t *data; uint32_t expiration; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct supernet_info *myinfo; struct basilisk_swap *swap = _swap; + uint8_t *data; uint32_t expiration,savestatebits=0,saveotherbits=0; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct supernet_info *myinfo; struct basilisk_swap *swap = _swap; myinfo = swap->myinfoptr; fprintf(stderr,"start swap\n"); maxlen = 1024*1024 + sizeof(*swap); @@ -2490,7 +2498,10 @@ void basilisk_swaploop(void *_swap) if ( (swap->I.statebits & (0x08|0x02)) == (0x08|0x02) ) break; } - sleep(DEX_SLEEP); + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; } if ( swap->connected == 0 ) { @@ -2510,7 +2521,10 @@ void basilisk_swaploop(void *_swap) swap->I.statebits |= 0x20; break; } - sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; } myinfo->DEXactive = swap->I.expiration; if ( time(NULL) >= expiration ) @@ -2603,7 +2617,10 @@ void basilisk_swaploop(void *_swap) } while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(myinfo,swap,data,maxlen) == 0 ) { - sleep(DEX_SLEEP); + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; basilisk_sendstate(myinfo,swap,data,maxlen); basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); basilisk_swap_saveupdate(myinfo,swap); @@ -2783,7 +2800,7 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t { if ( (retstr= dex_gettxout(myinfo,0,0,0,trigger,symbol,vout)) != 0 ) { - //printf("dexgettxout.(%s)\n",retstr); + printf("dexgettxout.(%s)\n",retstr); retjson = cJSON_Parse(retstr); free(retstr); } @@ -3354,7 +3371,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) { - //printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); + printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) sentflags[BASILISK_ALICEPAYMENT] = 1; else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index a6cc3b028..6fdcebffc 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -530,6 +530,7 @@ char *iguana_calcrawtx(struct supernet_info *myinfo,struct iguana_info *coin,cJS bitcoin_txoutput(txobj,opreturn,oplen,burnamount); } } + printf("total %.8f txfee %.8f change %.8f\n",dstr(total),dstr(txfee),dstr(change)); if ( vins != 0 && V == 0 ) { V = calloc(cJSON_GetArraySize(vins),sizeof(*V)), allocflag = 1; From 1156ef7e64b9a04708757f1a7542135076d85196 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 20:57:56 +0300 Subject: [PATCH 0288/2705] Test --- basilisk/basilisk_swap.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a9e4fbc24..d11f12786 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3097,7 +3097,7 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, return(signedtx); } -bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol,bits256 spendtxid,int32_t vini) +bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol,bits256 spendtxid,int32_t vini,int32_t revflag) { bits256 privkey; int32_t i,scriptlen,siglen; uint8_t script[1024]; // from Bob refund of Bob deposit memset(&privkey,0,sizeof(privkey)); @@ -3105,7 +3105,11 @@ bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol, { siglen = script[0]; for (i=0; i<32; i++) - privkey.bytes[31 - i] = script[siglen+2+i]; + { + if ( revflag != 0 ) + privkey.bytes[31 - i] = script[siglen+2+i]; + else privkey.bytes[i] = script[siglen+2+i]; + } char str[65]; printf("extracted privbob.(%s)\n",bits256_str(str,privkey)); } return(privkey); @@ -3119,7 +3123,7 @@ bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,bits256 *bobre if ( bits256_nonz(bobdeposit) != 0 ) *bobrefundp = basilisk_swap_spendtxid(myinfo,bobcoin,destaddr,bobdeposit,0); if ( bits256_nonz(*bobrefundp) != 0 ) - privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,*bobrefundp,0); + privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,*bobrefundp,0,0); } return(privBn); } @@ -3458,7 +3462,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) { txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); - if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // txcreate tested + if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // tested { sentflags[BASILISK_ALICERECLAIM] = 1; Apaymentspent = txids[BASILISK_ALICERECLAIM]; @@ -3476,7 +3480,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { if ( bits256_nonz(privAm) == 0 ) { - privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0); + privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0,1); } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { From c4521e2e2cde9105d28cfc8b69b5efb7eb278773 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 20:58:32 +0300 Subject: [PATCH 0289/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index d11f12786..2c04497f3 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2800,11 +2800,11 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t { if ( (retstr= dex_gettxout(myinfo,0,0,0,trigger,symbol,vout)) != 0 ) { - printf("dexgettxout.(%s)\n",retstr); + //printf("dexgettxout.(%s)\n",retstr); retjson = cJSON_Parse(retstr); free(retstr); } - if ( strcmp("BTC",symbol) == 0 ) + if ( 0 && strcmp("BTC",symbol) == 0 ) printf("%s gettxout.(%s)\n",symbol,jprint(retjson,0)); } else From 2afdf22044897004bd71ba4d828e466840ffe1dd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 21:09:33 +0300 Subject: [PATCH 0290/2705] Test --- basilisk/basilisk_swap.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2c04497f3..3f1cb8997 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3649,7 +3649,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t char *basilisk_swaplist(struct supernet_info *myinfo) { - char fname[512]; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16]; int32_t i; + char fname[512]; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16],Btotal,Ktotal; int32_t i; memset(KMDtotals,0,sizeof(KMDtotals)); memset(BTCtotals,0,sizeof(BTCtotals)); //,statebits; int32_t optionduration; struct basilisk_request R; bits256 privkey; @@ -3682,15 +3682,21 @@ char *basilisk_swaplist(struct supernet_info *myinfo) if ( cJSON_GetArraySize(array) > 0 ) { totalsobj = cJSON_CreateObject(); - for (i=0; i 0 && Btotal < 0 ) + jaddnum(retjson,"avebuy",(double)-Btotal/Ktotal); + else if ( Ktotal < 0 && Btotal > 0 ) + jaddnum(retjson,"avesell",(double)-Btotal/Ktotal); } array = cJSON_CreateArray(); for (i=0; ilinfos)/sizeof(*myinfo->linfos); i++) From 540ab5c6844bbb305212c25d42a43a5401df6116 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 21:14:05 +0300 Subject: [PATCH 0291/2705] Test --- basilisk/basilisk.h | 4 ++-- basilisk/jumblr.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index da79eebb4..044ff75fa 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -16,8 +16,8 @@ #ifndef H_BASILISK_H #define H_BASILISK_H -#define BASILISK_DISABLESENDTX -#define BASILISK_DISABLEWAITTX +//#define BASILISK_DISABLESENDTX +//#define BASILISK_DISABLEWAITTX #include "../iguana/iguana777.h" diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 7090fd33d..011ab3068 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -735,7 +735,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 double minbtc,minkmd,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) + if ( coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { avail = (btcavail - kmdcoin->DEXinfo.DEXpending); printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); @@ -768,7 +768,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); minkmd = 100.; - if ( toKMD != 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) + if ( coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) { avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,minkmd,avail); From 5702444a83a0f9dc99ac7d8f7570fc0d396c53ce Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 16 Apr 2017 21:53:03 +0300 Subject: [PATCH 0292/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 3 ++- crypto777/cJSON.c | 16 ++++++++++------ iguana/DB/SWAPS/3210648667-2626363704 | 1 + iguana/DB/SWAPS/415703857-2769362858 | 1 + 5 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 iguana/DB/SWAPS/3210648667-2626363704 create mode 100644 iguana/DB/SWAPS/415703857-2769362858 diff --git a/.gitignore b/.gitignore index b6bc99fa0..cea92debf 100755 --- a/.gitignore +++ b/.gitignore @@ -352,3 +352,5 @@ iguana/DB/SWAPS/26534791-3105729230 iguana/DB/SWAPS/2279906047-2580050792 iguana/DB/SWAPS/1672096208-4211948211 + +iguana/DB/SWAPS/3062665554-3128383014 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3f1cb8997..3469afc54 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2905,7 +2905,8 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * { for (i=0; ichild;int32_t i=0;while(c)i++,c=c->next;return i;} cJSON *cJSON_GetArrayItem(cJSON *array,int32_t item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} -cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) { if ( object == 0 ) return(0); cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} /* Utility for array list handling. */ static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} @@ -858,7 +858,7 @@ bits256 get_API_bits256(cJSON *obj) } return(hash); } -bits256 jbits256(cJSON *json,char *field) { if ( field == 0 ) return(get_API_bits256(json)); return(get_API_bits256(cJSON_GetObjectItem(json,field))); } +bits256 jbits256(cJSON *json,char *field) { if ( field == 0 ) return(get_API_bits256(json)); return(get_API_bits256(json != 0 ? cJSON_GetObjectItem(json,field) : 0)); } bits256 jbits256i(cJSON *json,int32_t i) { return(get_API_bits256(cJSON_GetArrayItem(json,i))); } void jaddbits256(cJSON *json,char *field,bits256 hash) { char str[65]; bits256_str(str,hash), jaddstr(json,field,str); } void jaddibits256(cJSON *json,bits256 hash) { char str[65]; bits256_str(str,hash), jaddistr(json,str); } @@ -896,10 +896,14 @@ int32_t jnum(cJSON *obj,char *field) void ensure_jsonitem(cJSON *json,char *field,char *value) { - cJSON *obj = cJSON_GetObjectItem(json,field); - if ( obj == 0 ) - cJSON_AddItemToObject(json,field,cJSON_CreateString(value)); - else cJSON_ReplaceItemInObject(json,field,cJSON_CreateString(value)); + cJSON *obj; + if ( json != 0 ) + { + obj = cJSON_GetObjectItem(json,field); + if ( obj == 0 ) + cJSON_AddItemToObject(json,field,cJSON_CreateString(value)); + else cJSON_ReplaceItemInObject(json,field,cJSON_CreateString(value)); + } } int32_t in_jsonarray(cJSON *array,char *value) diff --git a/iguana/DB/SWAPS/3210648667-2626363704 b/iguana/DB/SWAPS/3210648667-2626363704 new file mode 100644 index 000000000..890120802 --- /dev/null +++ b/iguana/DB/SWAPS/3210648667-2626363704 @@ -0,0 +1 @@ +{"src":"KMD","srcamount":99.65000000,"dest":"BTC","destamount":0.01279725,"requestid":3210648667,"quoteid":2626363704,"iambob":0,"state":63,"otherstate":191,"expiration":1492382391,"dlocktime":0,"plocktime":0,"secretAm":"41d77f89b7df4e6b4e037271af7171e5700ff78e","secretAm256":"2430481e893a8eb5dfebd803bad5e5db5dbfd7c4229e89c3412599688faaf6f4","secretBn":"58e3ed498bca71df2a09e4e083e1bfceaf37f17c","secretBn256":"4cbf23818c8ba08fc84634f2a4673f87b4ddb7b770910c83618c23478a16aed0","myprivs0":"e2f1c99ade4b40d6044db7fcc1c8440d754d984a32c29ef46fc70dc403cc5d6e","myprivs1":"7d252f9dd6ed55d4f2ac51672488c93c242bf96daab6fd9598eeced20150e8e9","privAm":"81956df0209ade7820e3642b0f1380a602670b96902f2622a4f6a454f571bbb2","pubA0":"46f8aa71581ffd70dfa22fc6fa7a1a287ba917e7eef4f28806b111fb5f2e6da3","pubB0":"2da1f98d4a628a5da9a0959db46b970dbfb41762c024123877cc7539149587ed","pubB1":"a5f17406afbcc29c0ffe103a672dd2457f833b6316439d81ee5d48afa3ae4070","myfee":"3415b8ed8853d86f986e4a932bb7d8f1b241a87b4b61e8597383f4c7dec90c2c","dest33":"025dddc7a1581b13535114dd4e6332f37420da35598b98d27ca319870abb9de7af"} diff --git a/iguana/DB/SWAPS/415703857-2769362858 b/iguana/DB/SWAPS/415703857-2769362858 new file mode 100644 index 000000000..a06d1729b --- /dev/null +++ b/iguana/DB/SWAPS/415703857-2769362858 @@ -0,0 +1 @@ +{"src":"BTC","srcamount":0.01577619,"dest":"KMD","destamount":118.45892649,"requestid":415703857,"quoteid":2769362858,"iambob":0,"state":1791,"otherstate":447,"expiration":1492383936,"dlocktime":1492383941,"plocktime":0,"secretAm":"218ec768f2df38385a08d3f3e0fd71c540243c69","secretAm256":"40cf46bc360cc79d8f29f2d3adb8cfd5d982b457a61b674dc3b3e9217c3e4496","secretBn":"86fe3a6d10f99d7396827c44767ef314d64a56d6","secretBn256":"bdf4fae7a167f185710269f3622bca4a254bf071751d2e1d7952be8a4a7c8208","myprivs0":"76605da8755998f3a8ede4920832754b6908a8ca01f3a68158a7e6b2da0711f4","myprivs1":"e4b2399987c4aff65cf73005361f182170e0de5a81e9ce6ed5cd74ad99554bf0","privAm":"baeb51e6ee3c4738482fbb352b3f097c23fb3e7e39b0836a6cbd115948e1f31d","pubA0":"7772d4a1471ada1ee192ff955c7115727ddff3383636949725c0307dfebc9eae","pubB0":"286f4c28533f12e50f328f481b73dd66fd4af3f18b6a65818ed1ff897e834e39","pubB1":"e0c4109251f7da8301e027d85b5d0dad95291362b835e003aa686dad326b5fe0","Bdeposit":"771c758300c47f6c63531e1f2cc50e57c96aaf014ef10004c0afcce64899bfdb","Apayment":"6f5ef3b1e7cd72a778abd167cc5c3a72224c1910c5d03167ee043bb003132b3e","myfee":"6f477936082053496fe46cd3a50d58a88c489e81e09db8b5781c279c4224eb6b","dest33":"0231a71ac00aed93b79f5b751d6b498cb1151314a18607328d5e79aec71deac205"} From 9720a6d5eca64900353d429014fc0ae53d60c91a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 17 Apr 2017 08:40:41 +0300 Subject: [PATCH 0293/2705] Wlc? --- .gitignore | 2 ++ iguana/m_notary | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e689f7231..b775d5e60 100755 --- a/.gitignore +++ b/.gitignore @@ -218,3 +218,5 @@ iguana/confs/5228bcea7ae2515a29c3844673de6ee2acba53bf45724744a00ff4306f192912 iguana/confs/630929d976025fafde221c7358eb5805f4359bad3c6b8bd50ad3f6e0a9b5ce78 iguana/confs/5f3283a017c31e52443d61cb43944e2157f7c03eb12d701ebf4a35a695688e1f + +iguana/3193054754-2514575257 diff --git a/iguana/m_notary b/iguana/m_notary index f6fe26d75..76d5c06a6 100755 --- a/iguana/m_notary +++ b/iguana/m_notary @@ -36,7 +36,6 @@ coins/pangea_7776 coins/mgw_7776 coins/mvp_7776 coins/wlc_7776 -#coins/wireless_7776 coins/kv_7776 coins/ceal_7776 coins/mesh_7776 From 9239977766c08882f30aab77b701381b7899198b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 17 Apr 2017 08:41:20 +0300 Subject: [PATCH 0294/2705] Test --- .gitignore | 2 ++ iguana/m_notary | 1 - iguana/tests/dexgetinfo | 3 ++- iguana/tests/getinfo | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index cea92debf..a32412cc6 100755 --- a/.gitignore +++ b/.gitignore @@ -354,3 +354,5 @@ iguana/DB/SWAPS/2279906047-2580050792 iguana/DB/SWAPS/1672096208-4211948211 iguana/DB/SWAPS/3062665554-3128383014 + +iguana/DB/SWAPS/2668150969-2698996317 diff --git a/iguana/m_notary b/iguana/m_notary index f6fe26d75..76d5c06a6 100755 --- a/iguana/m_notary +++ b/iguana/m_notary @@ -36,7 +36,6 @@ coins/pangea_7776 coins/mgw_7776 coins/mvp_7776 coins/wlc_7776 -#coins/wireless_7776 coins/kv_7776 coins/ceal_7776 coins/mesh_7776 diff --git a/iguana/tests/dexgetinfo b/iguana/tests/dexgetinfo index d31b736a6..8aa05a403 100755 --- a/iguana/tests/dexgetinfo +++ b/iguana/tests/dexgetinfo @@ -1,2 +1,3 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getinfo\",\"symbol\":\"BTC\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getinfo\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getinfo\",\"symbol\":\"WLC\"}" diff --git a/iguana/tests/getinfo b/iguana/tests/getinfo index 35e732fc9..3f0a59664 100755 --- a/iguana/tests/getinfo +++ b/iguana/tests/getinfo @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"coin\":\"SHARK\",\"method\":\"getinfo\",\"params\":[]}" +curl --url "http://127.0.0.1:7778" --data "{\"coin\":\"WLC\",\"method\":\"getinfo\",\"params\":[]}" From 64b79728a086e107543a80a52e179103aa424693 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 17 Apr 2017 08:45:38 +0300 Subject: [PATCH 0295/2705] Test --- iguana/dpow/dpow_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index b90f7814e..e7345ef1a 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -515,14 +515,14 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 printf("%d: subscribe connect (%s)\n",myinfo->numdexipbits,str); } } -#ifndef __APPLE__ +//#ifndef __APPLE__ if ( (rand() % 100) < 40 ) { nanomsg_tcpname(0,str,ipaddr,REP_SOCK); nn_connect(myinfo->reqsock,str); printf("%d: req connect (%s)\n",myinfo->numdexipbits,str); } -#endif +//#endif } } if ( freeptr != 0 ) From 53ee52d2de435bb2531a62c34ac83278d284cd14 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 17 Apr 2017 09:07:43 +0300 Subject: [PATCH 0296/2705] New mesh --- iguana/coins/basilisk/mesh | 2 +- iguana/coins/mesh_7776 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/coins/basilisk/mesh b/iguana/coins/basilisk/mesh index 81904b6d7..0ac66f536 100755 --- a/iguana/coins/basilisk/mesh +++ b/iguana/coins/basilisk/mesh @@ -1 +1 @@ -curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":11940,\"rpc\":11941,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":8399,\"rpc\":8400,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/mesh_7776 b/iguana/coins/mesh_7776 index 214335788..5e21f2c1b 100755 --- a/iguana/coins/mesh_7776 +++ b/iguana/coins/mesh_7776 @@ -1 +1 @@ -curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":11940,\"rpc\":11941,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":8399,\"rpc\":8400,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" From d1921792c1756c351b040b2dd971edd660fb71a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 17 Apr 2017 10:04:42 +0300 Subject: [PATCH 0297/2705] Test --- basilisk/basilisk_bitcoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index f91ca9ac3..3c9b8a7a7 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -594,7 +594,7 @@ char *iguana_utxoduplicates(struct supernet_info *myinfo,struct iguana_info *coi for (i=0; i duplicates/2 ) + if ( strcmp(coin->chain->symbol,"BTC") == 0 && cJSON_GetArraySize(vins) > duplicates/2 ) { free(rawtx); rawtx = 0; From 75576aa31ad5ee0c742c99290df9432b8b5c5683 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 17 Apr 2017 14:51:40 +0300 Subject: [PATCH 0298/2705] Test --- iguana/coins/basilisk/mesh | 2 +- iguana/coins/mesh_7776 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/coins/basilisk/mesh b/iguana/coins/basilisk/mesh index 0ac66f536..4f69e2095 100755 --- a/iguana/coins/basilisk/mesh +++ b/iguana/coins/basilisk/mesh @@ -1 +1 @@ -curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":8399,\"rpc\":8400,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":14402,\"rpc\":14403,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/mesh_7776 b/iguana/coins/mesh_7776 index 5e21f2c1b..92604ed7c 100755 --- a/iguana/coins/mesh_7776 +++ b/iguana/coins/mesh_7776 @@ -1 +1 @@ -curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":8399,\"rpc\":8400,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":14402,\"rpc\":14403,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" From 75ad4d445a5ba7f876e4172fed6e5f44ed95550e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 08:57:40 +0300 Subject: [PATCH 0299/2705] Newer mesh --- iguana/coins/basilisk/mesh | 2 +- iguana/coins/mesh_7776 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/coins/basilisk/mesh b/iguana/coins/basilisk/mesh index 4f69e2095..d7c51019b 100755 --- a/iguana/coins/basilisk/mesh +++ b/iguana/coins/basilisk/mesh @@ -1 +1 @@ -curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":14402,\"rpc\":14403,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"4d6bbfb6\",\"p2p\":9454,\"rpc\":9455,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/mesh_7776 b/iguana/coins/mesh_7776 index 92604ed7c..bcccf8d8d 100755 --- a/iguana/coins/mesh_7776 +++ b/iguana/coins/mesh_7776 @@ -1 +1 @@ -curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"c28227c2\",\"p2p\":14402,\"rpc\":14403,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"4d6bbfb6\",\"p2p\":9454,\"rpc\":9455,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" From 501475125d778dae5ca9526615a1892738e641e7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 15:55:50 +0300 Subject: [PATCH 0300/2705] Test --- basilisk/basilisk_swap.c | 23 ++++++++++++++++++----- basilisk/jumblr.c | 10 ++++++---- iguana/main.c | 10 +++++----- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3469afc54..b57882ed0 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2673,8 +2673,21 @@ cJSON *basilisk_swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { - int32_t i,m,n; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct basilisk_swap *swap = 0; + int32_t i,m,n; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; struct basilisk_swap *swap = 0; // statebits 1 -> client, 0 -> LP + if ( statebits == 0 && myinfo->numswaps > 0 ) + { + if ( (coin= iguana_coinfind(rp->src)) == 0 || coin->FULLNODE >= 0 ) + { + printf("dont have SRC coin.%s or not native and already swap pending\n",rp->src); + return(0); + } + if ( (coin= iguana_coinfind(rp->dest)) == 0 || coin->FULLNODE >= 0 ) + { + printf("dont have DEST coin.%s or not native and already swap pending\n",rp->dest); + return(0); + } + } portable_mutex_lock(&myinfo->DEX_swapmutex); for (i=0; inumswaps; i++) if ( myinfo->swaps[i]->I.req.requestid == rp->requestid ) @@ -2796,7 +2809,7 @@ cJSON *basilisk_nullretjson(cJSON *retjson) cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 trigger,int32_t vout) { char *retstr; cJSON *retjson=0; struct iguana_info *coin; - if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 || iguana_isnotarychain(symbol) >= 0 ) + if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) { if ( (retstr= dex_gettxout(myinfo,0,0,0,trigger,symbol,vout)) != 0 ) { @@ -2819,7 +2832,7 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid) { char *retstr; cJSON *retjson=0; struct iguana_info *coin; - if ( (coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0 || iguana_isnotarychain(symbol) >= 0 ) + if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) { if ( (retstr= dex_gettransaction(myinfo,0,0,0,txid,symbol)) != 0 ) { @@ -2886,12 +2899,12 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) { - bits256 spendtxid,txid; char *retstr,*addr; cJSON *array,*array2,*item; int32_t i,n,m; char coinaddr[64]; + bits256 spendtxid,txid; char *retstr,*addr; cJSON *array,*array2,*item; int32_t i,n,m; char coinaddr[64]; struct iguana_info *coin = iguana_coinfind(symbol); // listtransactions or listspents destaddr[0] = 0; memset(&spendtxid,0,sizeof(spendtxid)); //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); - if ( iguana_isnotarychain(symbol) >= 0 ) + if ( (coin == 0 || coin->FULLNODE >= 0) && iguana_isnotarychain(symbol) >= 0 ) { //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 011ab3068..242fd2db4 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -714,7 +714,7 @@ void jumblr_CMCname(char *CMCname,char *symbol) void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32_t toKMD) { - double vol,avail; struct iguana_info *kmdcoin,*coinbtc = 0; + double vol,avail; int32_t enabled = 0; struct iguana_info *kmdcoin,*coinbtc = 0; kmdcoin = iguana_coinfind("KMD"); coinbtc = iguana_coinfind("BTC"); //printf("jumblr_DEXcheck numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); @@ -730,12 +730,14 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 if ( coin->CMCname[0] != 0 ) jumblr_DEXupdate(myinfo,coin,coin->symbol,coin->CMCname,kmdcoin->DEXinfo.btcprice,kmdcoin->DEXinfo.avail); } - if ( myinfo->numswaps == 0 && myinfo->IAMLP == 0 && kmdcoin->DEXinfo.btcprice > SMALLVAL ) + if ( myinfo->numswaps == 0 || (kmdcoin->FULLNODE < 0 && coinbtc->FULLNODE < 0) ) + enabled = 1; + if ( enabled != 0 && myinfo->IAMLP == 0 && kmdcoin->DEXinfo.btcprice > SMALLVAL ) { double minbtc,minkmd,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - if ( coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) + if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { avail = (btcavail - kmdcoin->DEXinfo.DEXpending); printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); @@ -768,7 +770,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); minkmd = 100.; - if ( coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) + if ( toKMD != 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) { avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,minkmd,avail); diff --git a/iguana/main.c b/iguana/main.c index ceaacb6ab..610ec3106 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -751,19 +751,19 @@ void jumblr_loop(void *ptr) { struct iguana_info *coin; uint32_t t,n=0; struct supernet_info *myinfo = ptr; int32_t mult = 10; printf("JUMBLR loop\n"); - while ( 1 ) + while ( myinfo->IAMNOTARY == 0 ) { if ( (coin= iguana_coinfind("KMD")) != 0 ) { -#ifdef __APPLE__ +//#ifdef __APPLE__ if ( (n++ % 10) == 0 ) jumblr_DEXcheck(myinfo,coin,!((n/10)&1)); -#endif +//#endif if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC - if ( (n++ % 10) == 0 ) - jumblr_DEXcheck(myinfo,coin,!((n/10)&1)); + //if ( (n++ % 10) == 0 ) + // jumblr_DEXcheck(myinfo,coin,!((n/10)&1)); t = (uint32_t)time(NULL); if ( (t % (120 * mult)) < 60 ) { From d21af35b0acb0538989e25c324485088d059bdc6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 17:09:22 +0300 Subject: [PATCH 0301/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 36 +++++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index a32412cc6..3cbd517da 100755 --- a/.gitignore +++ b/.gitignore @@ -356,3 +356,5 @@ iguana/DB/SWAPS/1672096208-4211948211 iguana/DB/SWAPS/3062665554-3128383014 iguana/DB/SWAPS/2668150969-2698996317 + +iguana/DB/SWAPS/3462690702-2419919594 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b57882ed0..59ffcc783 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -335,7 +335,7 @@ int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap * bits256 basilisk_swap_broadcast(char *name,struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,uint8_t *data,int32_t datalen) { - bits256 txid; char *signedtx,*retstr; + bits256 txid; char *signedtx,*retstr; int32_t i; memset(txid.bytes,0,sizeof(txid)); if ( data != 0 && datalen != 0 ) { @@ -347,20 +347,24 @@ bits256 basilisk_swap_broadcast(char *name,struct supernet_info *myinfo,struct b #endif signedtx = malloc(datalen*2 + 1); init_hexbytes_noT(signedtx,data,datalen); - if ( (retstr= basilisk_sendrawtransaction(myinfo,coin,signedtx)) != 0 ) + for (i=0; i<3; i++) { - if ( is_hexstr(retstr,0) == 64 ) - { - decode_hex(txid.bytes,32,retstr); - free(retstr); - printf("sendrawtransaction %s.(%s)\n",name,bits256_str(str,txid)); - } - else + if ( (retstr= basilisk_sendrawtransaction(myinfo,coin,signedtx)) != 0 ) { - printf("sendrawtransaction %s error.(%s)\n",name,retstr); - free(retstr); - } - } else printf("sendrawtransaction %s got null return\n",name); + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + free(retstr); + printf("sendrawtransaction %s.(%s)\n",name,bits256_str(str,txid)); + break; + } + else + { + printf("sendrawtransaction %s error.(%s)\n",name,retstr); + free(retstr); + } + } else printf("sendrawtransaction %s got null return\n",name); + } free(signedtx); } return(txid); @@ -945,6 +949,7 @@ int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_ uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { + basilisk_swap_broadcast(swap->bobdeposit.name,myinfo,swap,swap->bobdeposit.coin,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); basilisk_dontforget_update(myinfo,swap,&swap->bobdeposit); len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_aliceclaim,userdata,len); @@ -1013,6 +1018,7 @@ int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,void *ptr,uint8_t * memset(revAm.bytes,0,sizeof(revAm)); if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { + basilisk_swap_broadcast(swap->bobpayment.name,myinfo,swap,swap->bobpayment.coin,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); basilisk_dontforget_update(myinfo,swap,&swap->bobpayment); for (i=0; i<32; i++) revAm.bytes[i] = swap->I.privAm.bytes[31-i]; @@ -1076,6 +1082,7 @@ int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->alicecoin->longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) { + basilisk_swap_broadcast(swap->alicepayment.name,myinfo,swap,swap->alicepayment.coin,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); basilisk_dontforget_update(myinfo,swap,&swap->alicepayment); return(0); } @@ -1965,7 +1972,10 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis char str[65],str2[65]; rawtx->I.actualtxid = basilisk_swap_broadcast(rawtx->name,myinfo,swap,rawtx->coin,rawtx->txbytes,rawtx->I.datalen); if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) + { printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); + rawtx->I.actualtxid = rawtx->I.signedtxid; + } if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) { sendlen = 0; From 5ed6a09d910903f02465d155ab4b6836211dbb49 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 18:03:16 +0300 Subject: [PATCH 0302/2705] Test --- .gitignore | 2 ++ basilisk/basilisk.c | 5 ++++- basilisk/basilisk_swap.c | 24 +++++++++++++++--------- iguana/iguana777.h | 2 +- iguana/iguana_payments.c | 4 ++-- iguana/main.c | 5 +++-- iguana/tests/dexlistunspent | 2 +- 7 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 3cbd517da..125465865 100755 --- a/.gitignore +++ b/.gitignore @@ -358,3 +358,5 @@ iguana/DB/SWAPS/3062665554-3128383014 iguana/DB/SWAPS/2668150969-2698996317 iguana/DB/SWAPS/3462690702-2419919594 + +iguana/DB/SWAPS/543051861-1532200070 diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index c37872b57..2743ddd0e 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1202,7 +1202,9 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) { if ( (txoutjson= dpow_gettxout(myinfo,coin,txid,vout)) != 0 ) { - if ( (coinaddr= jstr(txoutjson,"address")) != 0 && (value= SATOSHIDEN*jdouble(txoutjson,"value")) != 0 ) + if ( (value= SATOSHIDEN*jdouble(txoutjson,"value")) == 0 ) + value = SATOSHIDEN*jdouble(txoutjson,"amount"); + if ( (coinaddr= jstr(txoutjson,"address")) != 0 && value != 0 ) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); @@ -1219,6 +1221,7 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) } else { + printf("missing fields.(%s)\n",jprint(txoutjson,0)); free_json(txoutjson); return(clonestr("{\"error\":\"return from gettxout missing fields\"}")); } diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 59ffcc783..8f1288879 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -313,7 +313,7 @@ int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap * jaddstr(argjson,"coin",rawtx->coin->symbol); if ( (valstr= basilisk_value(myinfo,rawtx->coin,0,0,swap->persistent_pubkey,argjson,0)) != 0 ) { - char str[65]; printf("basilisk_numconfirms %s %s valstr.(%s)\n",rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); + char str[65]; printf("basilisk_numconfirms required.%d %s %s valstr.(%s)\n",rawtx->I.numconfirms,rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); if ( (valuearray= cJSON_Parse(valstr)) != 0 ) { if ( is_cJSON_Array(valuearray) != 0 ) @@ -949,7 +949,9 @@ int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_ uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { - basilisk_swap_broadcast(swap->bobdeposit.name,myinfo,swap,swap->bobdeposit.coin,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + swap->bobdeposit.I.actualtxid = basilisk_swap_broadcast(swap->bobdeposit.name,myinfo,swap,swap->bobdeposit.coin,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + swap->depositunconf = 1; basilisk_dontforget_update(myinfo,swap,&swap->bobdeposit); len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_aliceclaim,userdata,len); @@ -1018,7 +1020,9 @@ int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,void *ptr,uint8_t * memset(revAm.bytes,0,sizeof(revAm)); if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { - basilisk_swap_broadcast(swap->bobpayment.name,myinfo,swap,swap->bobpayment.coin,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + swap->bobpayment.I.actualtxid = basilisk_swap_broadcast(swap->bobpayment.name,myinfo,swap,swap->bobpayment.coin,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + if ( bits256_nonz(swap->bobpayment.I.actualtxid) != 0 ) + swap->paymentunconf = 1; basilisk_dontforget_update(myinfo,swap,&swap->bobpayment); for (i=0; i<32; i++) revAm.bytes[i] = swap->I.privAm.bytes[31-i]; @@ -1079,10 +1083,12 @@ int32_t basilisk_alicepayment_spend(struct supernet_info *myinfo,struct basilisk int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) { - struct basilisk_swap *swap = ptr; + bits256 txid; struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->alicecoin->longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) { - basilisk_swap_broadcast(swap->alicepayment.name,myinfo,swap,swap->alicepayment.coin,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + swap->alicepayment.I.actualtxid = basilisk_swap_broadcast(swap->alicepayment.name,myinfo,swap,swap->alicepayment.coin,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + if ( bits256_nonz(txid) != 0 ) + swap->aliceunconf = 1; basilisk_dontforget_update(myinfo,swap,&swap->alicepayment); return(0); } @@ -1770,7 +1776,7 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv if ( swap->I.aliceconfirms == 0 ) swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms; jumblrflag = (bits256_cmp(pubkey25519,myinfo->jumblr_pubkey) == 0 || bits256_cmp(pubkey25519,myinfo->jumblr_depositkey) == 0); - printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address\n",jumblrflag); + printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, bobconfs.%d aliceconfs.%d\n",jumblrflag,swap->I.bobconfirms,swap->I.aliceconfirms); if ( swap->I.iambob != 0 ) { basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_DECKSIZE,0,0,jumblrflag); @@ -2183,7 +2189,7 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap } else if ( (swap->I.statebits & 0x2000) == 0 ) { - if ( basilisk_numconfirms(myinfo,swap,&swap->alicepayment) >= swap->I.aliceconfirms ) + if ( (swap->I.aliceconfirms == 0 && swap->aliceunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->alicepayment) >= swap->I.aliceconfirms ) { swap->I.statebits |= 0x2000; printf("alicepayment confirmed\n"); @@ -2260,7 +2266,7 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap } else if ( (swap->I.statebits & 0x400) == 0 ) { - if ( basilisk_istrustedbob(myinfo,swap) != 0 || basilisk_numconfirms(myinfo,swap,&swap->bobdeposit) >= swap->I.bobconfirms ) + if ( basilisk_istrustedbob(myinfo,swap) != 0 || (swap->I.bobconfirms == 0 && swap->depositunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobdeposit) >= swap->I.bobconfirms ) { printf("bobdeposit confirmed\n"); swap->I.statebits |= 0x400; @@ -2284,7 +2290,7 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap } else if ( (swap->I.statebits & 0x10000) == 0 ) { - if ( basilisk_istrustedbob(myinfo,swap) != 0 || basilisk_numconfirms(myinfo,swap,&swap->bobpayment) >= swap->I.bobconfirms ) + if ( basilisk_istrustedbob(myinfo,swap) != 0 || (swap->I.bobconfirms == 0 && swap->paymentunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobpayment) >= swap->I.bobconfirms ) { printf("bobpayment confirmed\n"); swap->I.statebits |= 0x10000; diff --git a/iguana/iguana777.h b/iguana/iguana777.h index f83fe19c5..26ba7d77f 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -182,7 +182,7 @@ struct basilisk_swap { struct supernet_info *myinfoptr; struct iguana_info *bobcoin,*alicecoin; void (*balancingtrade)(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob); - int32_t subsock,pushsock,connected,DEXselector; uint32_t lasttime,aborted; + int32_t subsock,pushsock,connected,DEXselector,aliceunconf,depositunconf,paymentunconf; uint32_t lasttime,aborted; FILE *fp; bits256 persistent_privkey,persistent_pubkey; struct basilisk_swapinfo I; diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index 6fdcebffc..a5b2876cf 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -448,7 +448,7 @@ char *iguana_calcrawtx(struct supernet_info *myinfo,struct iguana_info *coin,cJS coinaddr = jstri(addresses,i); if ( (array= basilisk_unspents(myinfo,coin,coinaddr)) != 0 ) { - //printf("unspents.(%s) %s\n",coinaddr,jprint(array,0)); + //printf("iguana_calcrawtx unspents.(%s) %s\n",coinaddr,jprint(array,0)); if ( (m= cJSON_GetArraySize(array)) > 0 ) { for (j=0; jjumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { diff --git a/iguana/tests/dexlistunspent b/iguana/tests/dexlistunspent index dfc4bda64..2aa0e56ab 100755 --- a/iguana/tests/dexlistunspent +++ b/iguana/tests/dexlistunspent @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RSZ7dc164T9gpDLmXU7spYEScru1mGzPMB\",\"symbol\":\"KMD\"}" From 0d0f697aec43d9e5f6c781baa70e0e9b30ae3fa4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 18:16:14 +0300 Subject: [PATCH 0303/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 125465865..d537316c8 100755 --- a/.gitignore +++ b/.gitignore @@ -360,3 +360,5 @@ iguana/DB/SWAPS/2668150969-2698996317 iguana/DB/SWAPS/3462690702-2419919594 iguana/DB/SWAPS/543051861-1532200070 + +iguana/DB/SWAPS/442294237-2721246052 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 8f1288879..3ed62870d 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -949,8 +949,8 @@ int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_ uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { - swap->bobdeposit.I.actualtxid = basilisk_swap_broadcast(swap->bobdeposit.name,myinfo,swap,swap->bobdeposit.coin,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); - if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + swap->bobdeposit.I.signedtxid = basilisk_swap_broadcast(swap->bobdeposit.name,myinfo,swap,swap->bobdeposit.coin,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) swap->depositunconf = 1; basilisk_dontforget_update(myinfo,swap,&swap->bobdeposit); len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); @@ -1020,8 +1020,8 @@ int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,void *ptr,uint8_t * memset(revAm.bytes,0,sizeof(revAm)); if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { - swap->bobpayment.I.actualtxid = basilisk_swap_broadcast(swap->bobpayment.name,myinfo,swap,swap->bobpayment.coin,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); - if ( bits256_nonz(swap->bobpayment.I.actualtxid) != 0 ) + swap->bobpayment.I.signedtxid = basilisk_swap_broadcast(swap->bobpayment.name,myinfo,swap,swap->bobpayment.coin,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) swap->paymentunconf = 1; basilisk_dontforget_update(myinfo,swap,&swap->bobpayment); for (i=0; i<32; i++) @@ -1083,11 +1083,11 @@ int32_t basilisk_alicepayment_spend(struct supernet_info *myinfo,struct basilisk int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) { - bits256 txid; struct basilisk_swap *swap = ptr; + struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->alicecoin->longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) { - swap->alicepayment.I.actualtxid = basilisk_swap_broadcast(swap->alicepayment.name,myinfo,swap,swap->alicepayment.coin,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); - if ( bits256_nonz(txid) != 0 ) + swap->alicepayment.I.signedtxid = basilisk_swap_broadcast(swap->alicepayment.name,myinfo,swap,swap->alicepayment.coin,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) swap->aliceunconf = 1; basilisk_dontforget_update(myinfo,swap,&swap->alicepayment); return(0); @@ -1771,12 +1771,12 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv swap->I.bobconfirms = BASILISK_DEFAULT_NUMCONFIRMS; swap->I.aliceconfirms = BASILISK_DEFAULT_NUMCONFIRMS; } - if ( swap->I.bobconfirms == 0 ) + /*if ( swap->I.bobconfirms == 0 ) swap->I.bobconfirms = swap->bobcoin->chain->minconfirms; if ( swap->I.aliceconfirms == 0 ) - swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms; + swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms;*/ jumblrflag = (bits256_cmp(pubkey25519,myinfo->jumblr_pubkey) == 0 || bits256_cmp(pubkey25519,myinfo->jumblr_depositkey) == 0); - printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, bobconfs.%d aliceconfs.%d\n",jumblrflag,swap->I.bobconfirms,swap->I.aliceconfirms); + printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); if ( swap->I.iambob != 0 ) { basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_DECKSIZE,0,0,jumblrflag); From 120c4c05acc32bde86fddae70c7b1716afa7a453 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 18:27:21 +0300 Subject: [PATCH 0304/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index d537316c8..f5fe8bd16 100755 --- a/.gitignore +++ b/.gitignore @@ -362,3 +362,5 @@ iguana/DB/SWAPS/3462690702-2419919594 iguana/DB/SWAPS/543051861-1532200070 iguana/DB/SWAPS/442294237-2721246052 + +iguana/DB/SWAPS/1247864366-3828803132 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3ed62870d..ebef96026 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2213,13 +2213,13 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap else { tradebot_swap_balancingtrade(myinfo,swap,1); - printf("Bob spends alicepayment\n"); + printf("Bob spends alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); swap->I.statebits |= 0x40000; - while ( basilisk_numconfirms(myinfo,swap,&swap->bobspend) < swap->I.aliceconfirms ) + if ( basilisk_numconfirms(myinfo,swap,&swap->bobspend) >= swap->I.aliceconfirms ) { printf("bobspend confirmed\n"); swap->I.statebits |= 0x80000; - printf("Bob confirms spend of Alice's payment\n"); + printf("Bob confirming spend of Alice's payment\n"); sleep(DEX_SLEEP); } retval = 1; From 025595f316e33cc837ad9a73b76e7f708a2cda5d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 20:15:26 +0300 Subject: [PATCH 0305/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f5fe8bd16..d343ae204 100755 --- a/.gitignore +++ b/.gitignore @@ -364,3 +364,5 @@ iguana/DB/SWAPS/543051861-1532200070 iguana/DB/SWAPS/442294237-2721246052 iguana/DB/SWAPS/1247864366-3828803132 + +iguana/DB/SWAPS/2910626293-1439062588 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ebef96026..a0856fa2d 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -298,6 +298,7 @@ int32_t basilisk_confirmsobj(cJSON *item) numconfirms = jint(item,"numconfirms"); if ( height > 0 && numconfirms >= 0 ) return(numconfirms); + printf("basilisk_confirmsobj height.%d numconfirms.%d (%s)\n",height,numconfirms,jprint(item,0)); return(-1); } @@ -314,6 +315,8 @@ int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap * if ( (valstr= basilisk_value(myinfo,rawtx->coin,0,0,swap->persistent_pubkey,argjson,0)) != 0 ) { char str[65]; printf("basilisk_numconfirms required.%d %s %s valstr.(%s)\n",rawtx->I.numconfirms,rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); + //basilisk_numconfirms required.0 alicespend 29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85 valstr.({"result":"success","numconfirms":0,"address":"1JGvZ67oTdM7kCya4J8kj1uErbSRAoq3wH","satoshis":"1413818","value":0.01413818,"height":462440,"txid":"29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85","vout":0,"coin":"BTC"}) + if ( (valuearray= cJSON_Parse(valstr)) != 0 ) { if ( is_cJSON_Array(valuearray) != 0 ) @@ -2309,12 +2312,13 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap } else if ( (swap->I.statebits & 0x40000) == 0 ) { - if ( basilisk_numconfirms(myinfo,swap,&swap->alicespend) >= swap->I.bobconfirms ) + int32_t numconfs; + if ( (numconfs= basilisk_numconfirms(myinfo,swap,&swap->alicespend)) >= swap->I.bobconfirms ) { swap->I.statebits |= 0x40000; printf("Alice confirms spend of Bob's payment\n"); retval = 1; - } + } else printf("alicespend numconfs.%d < %d\n",numconfs,swap->I.bobconfirms); } if ( swap->bobdeposit.I.locktime != 0 && time(NULL) > swap->bobdeposit.I.locktime ) { From 8b968b57154625c4e7c043a5eafbe0505577b734 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 20:19:36 +0300 Subject: [PATCH 0306/2705] Test --- basilisk/basilisk_bitcoin.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index 3c9b8a7a7..aeb233bcc 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -741,9 +741,15 @@ char *iguana_utxorawtx(struct supernet_info *myinfo,struct iguana_info *coin,int if ( txobj != 0 ) free_json(txobj); if ( rawtx != 0 ) + { + jaddstr(retjson,"rawtx",rawtx); free(rawtx); + } if ( signedtx != 0 ) + { + jaddstr(retjson,"signedtx",signedtx); free(signedtx); + } return(jprint(retjson,1)); } From b396807c6d7a32aa968f3a97828a043af5d367dd Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 21:36:52 +0300 Subject: [PATCH 0307/2705] Test --- .gitignore | 2 ++ basilisk/basilisk.c | 1 + 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index d343ae204..1801b7773 100755 --- a/.gitignore +++ b/.gitignore @@ -366,3 +366,5 @@ iguana/DB/SWAPS/442294237-2721246052 iguana/DB/SWAPS/1247864366-3828803132 iguana/DB/SWAPS/2910626293-1439062588 + +iguana/DB/SWAPS/3893087081-2278083649 diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 2743ddd0e..f7f05e644 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1253,6 +1253,7 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); jaddnum(retjson,"numconfirms",jint(txoutjson,"confirmations")); + jaddnum(retjson,"height",jint(txoutjson,"height")); if ( (array= jarray(&n,txoutjson,"vout")) != 0 && vout < n && (txjson= jitem(array,vout)) != 0 ) { //printf("txjson.(%s)\n",jprint(txjson,0)); From 58037804cbcc4380cc0bb9f4e3c46ad35c103a11 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 18 Apr 2017 21:42:42 +0300 Subject: [PATCH 0308/2705] Test --- .gitignore | 2 ++ basilisk/basilisk.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1801b7773..179edd696 100755 --- a/.gitignore +++ b/.gitignore @@ -368,3 +368,5 @@ iguana/DB/SWAPS/1247864366-3828803132 iguana/DB/SWAPS/2910626293-1439062588 iguana/DB/SWAPS/3893087081-2278083649 + +iguana/DB/SWAPS/2990527454-48620696 diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index f7f05e644..2daa07911 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1253,7 +1253,9 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); jaddnum(retjson,"numconfirms",jint(txoutjson,"confirmations")); - jaddnum(retjson,"height",jint(txoutjson,"height")); + if ( (height= jint(txoutjson,"height")) == 0 && coin != 0 ) + height = coin->longestchain - jint(txoutjson,"confirmations"); + jaddnum(retjson,"height",height); if ( (array= jarray(&n,txoutjson,"vout")) != 0 && vout < n && (txjson= jitem(array,vout)) != 0 ) { //printf("txjson.(%s)\n",jprint(txjson,0)); From 567ea95e101e2e86ffb2c9cb778ce55185d2e30f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 19 Apr 2017 08:44:11 +0300 Subject: [PATCH 0309/2705] Test --- .gitignore | 6 ++++++ basilisk/basilisk_swap.c | 38 ++++++++++++++++++++------------------ iguana/dpow/dpow_rpc.c | 2 +- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 179edd696..1303afe77 100755 --- a/.gitignore +++ b/.gitignore @@ -370,3 +370,9 @@ iguana/DB/SWAPS/2910626293-1439062588 iguana/DB/SWAPS/3893087081-2278083649 iguana/DB/SWAPS/2990527454-48620696 + +iguana/DB/SWAPS/217534954-2300638414 + +iguana/DB/SWAPS/2780026367-3028893038 + +iguana/DB/SWAPS/467080987-1442519493 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a0856fa2d..359a49027 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -319,11 +319,12 @@ int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap * if ( (valuearray= cJSON_Parse(valstr)) != 0 ) { - if ( is_cJSON_Array(valuearray) != 0 ) + if ( valstr[0] == '[' && is_cJSON_Array(valuearray) != 0 ) { n = cJSON_GetArraySize(valuearray); for (i=0; i= 0 ) break; } @@ -333,6 +334,7 @@ int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap * free(valstr); } free_json(argjson); + printf("numconfirms.%d returned\n",retval); return(retval); } @@ -1410,10 +1412,10 @@ int32_t basilisk_swapget(struct supernet_info *myinfo,struct basilisk_swap *swap if ( swap->I.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) { printf("nothing received for a while from Bob, try new sockets\n"); - if ( swap->pushsock >= 0 ) //nn_close(swap->pushsock), - swap->pushsock = -1; - if ( swap->subsock >= 0 ) //nn_close(swap->subsock), - swap->subsock = -1; + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; swap->connected = 0; basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); } @@ -1447,9 +1449,9 @@ uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *sw if ( sentbytes < 0 ) { if ( swap->pushsock >= 0 ) - swap->pushsock = -1; //nn_close(swap->pushsock), - if ( swap->subsock >= 0 ) // nn_close(swap->subsock), - swap->subsock = -1; + nn_close(swap->pushsock), swap->pushsock = -1; //, + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; swap->connected = swap->I.iambob != 0 ? -1 : 0; swap->aborted = (uint32_t)time(NULL); } @@ -1469,10 +1471,10 @@ void basilisk_swap_sendabort(struct supernet_info *myinfo,struct basilisk_swap * { if ( sentbytes < 0 ) { - if ( swap->pushsock >= 0 ) //nn_close(swap->pushsock), - swap->pushsock = -1; - if ( swap->subsock >= 0 ) //nn_close(swap->subsock), - swap->subsock = -1; + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; swap->connected = 0; } } else printf("basilisk_swap_sendabort\n"); @@ -2302,12 +2304,9 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap else if ( (swap->I.statebits & 0x20000) == 0 ) { printf("alicespend bobpayment\n"); - if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicespend,0x20000,0) != 0 && basilisk_numconfirms(myinfo,swap,&swap->alicespend) > 0 ) + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicespend,0x20000,0) != 0 )//&& (swap->aliceunconf != 0 || basilisk_numconfirms(myinfo,swap,&swap->alicespend) > 0) ) { - for (j=datalen=0; j<32; j++) - data[datalen++] = swap->I.privAm.bytes[j]; - swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x40000,data,datalen,0x20000,swap->I.crcs_mypriv); - printf("send privAm %x\n",swap->I.statebits); + swap->I.statebits |= 0x20000; } } else if ( (swap->I.statebits & 0x40000) == 0 ) @@ -2315,7 +2314,10 @@ int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap int32_t numconfs; if ( (numconfs= basilisk_numconfirms(myinfo,swap,&swap->alicespend)) >= swap->I.bobconfirms ) { - swap->I.statebits |= 0x40000; + for (j=datalen=0; j<32; j++) + data[datalen++] = swap->I.privAm.bytes[j]; + printf("send privAm %x\n",swap->I.statebits); + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x40000,data,datalen,0x20000,swap->I.crcs_mypriv); printf("Alice confirms spend of Bob's payment\n"); retval = 1; } else printf("alicespend numconfs.%d < %d\n",numconfs,swap->I.bobconfirms); diff --git a/iguana/dpow/dpow_rpc.c b/iguana/dpow/dpow_rpc.c index f8ffded08..38e3e8f00 100755 --- a/iguana/dpow/dpow_rpc.c +++ b/iguana/dpow/dpow_rpc.c @@ -569,7 +569,7 @@ char *dpow_sendrawtransaction(struct supernet_info *myinfo,struct iguana_info *c jaddistr(array,signedtx); paramstr = jprint(array,1); retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"sendrawtransaction",paramstr); - //printf(">>>>>>>>>>> %s sendrawtransaction.(%s) -> %s\n",coin->symbol,paramstr,retstr); + printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> %s\n",coin->symbol,paramstr,retstr); free(paramstr); return(retstr); } From 5feeb3d25ba97c11e7db2ee8f1704e9f20122db5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 10:46:03 +0300 Subject: [PATCH 0310/2705] Test --- .gitignore | 4 ++++ basilisk/basilisk_swap.c | 17 ++++++++++++----- iguana/dpow/dpow_rpc.c | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 1303afe77..3c50d4146 100755 --- a/.gitignore +++ b/.gitignore @@ -376,3 +376,7 @@ iguana/DB/SWAPS/217534954-2300638414 iguana/DB/SWAPS/2780026367-3028893038 iguana/DB/SWAPS/467080987-1442519493 + +iguana/DB/SWAPS/1504818827-1454232932 + +iguana/DB/SWAPS/4093850898-2949785771 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 359a49027..7c6698d9e 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3229,11 +3229,12 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); if ( (fp= fopen(fname,"rb")) != 0 ) { - finishedflag = 1; + origfinishedflag = finishedflag = 1; + fclose(fp); } memset(values,0,sizeof(values)); memset(txids,0,sizeof(txids)); @@ -3663,11 +3664,13 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } jadd(item,"sentflags",array); jaddstr(item,"result","success"); - jaddstr(item,"status","finished"); + if ( finishedflag != 0 ) + jaddstr(item,"status","finished"); + else jaddstr(item,"status","pending"); bits256_str(str,paymentspent), jaddbits256(item,"paymentspent",paymentspent); bits256_str(str,Apaymentspent), jaddbits256(item,"Apaymentspent",Apaymentspent); bits256_str(str,depositspent), jaddbits256(item,"depositspent",depositspent); - if ( finishedflag != 0 ) + if ( origfinishedflag == 0 && finishedflag != 0 ) { //printf("SWAP %u-%u finished!\n",requestid,quoteid); sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); @@ -3685,7 +3688,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t char *basilisk_swaplist(struct supernet_info *myinfo) { - char fname[512]; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16],Btotal,Ktotal; int32_t i; + char fname[512],*status; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16],Btotal,Ktotal; int32_t i; memset(KMDtotals,0,sizeof(KMDtotals)); memset(BTCtotals,0,sizeof(BTCtotals)); //,statebits; int32_t optionduration; struct basilisk_request R; bits256 privkey; @@ -3708,7 +3711,11 @@ char *basilisk_swaplist(struct supernet_info *myinfo) if ( flag == 0 ) { if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) + { jaddi(array,item); + if ( (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + break; + } } } fclose(fp); diff --git a/iguana/dpow/dpow_rpc.c b/iguana/dpow/dpow_rpc.c index 38e3e8f00..9268e6df7 100755 --- a/iguana/dpow/dpow_rpc.c +++ b/iguana/dpow/dpow_rpc.c @@ -569,7 +569,7 @@ char *dpow_sendrawtransaction(struct supernet_info *myinfo,struct iguana_info *c jaddistr(array,signedtx); paramstr = jprint(array,1); retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"sendrawtransaction",paramstr); - printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> %s\n",coin->symbol,paramstr,retstr); + printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> (%s)\n",coin->symbol,paramstr,retstr); free(paramstr); return(retstr); } From 87bc12b18a9399fc5eab6fd347ff1195a0b1b0e3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 11:12:51 +0300 Subject: [PATCH 0311/2705] Test --- basilisk/basilisk_swap.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 7c6698d9e..12cf0be93 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2978,9 +2978,13 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * free(retstr); } } - else + else if ( coin != 0 ) { - printf("need to find spendtxid the hard way\n"); + if ( (array= dpow_listtransactions(myinfo,coin,destaddr,100,0)) != 0 ) + { + printf("list.(%s)\n",jprint(array,0)); + free_json(array); + } } return(spendtxid); } From a66a094a9a54dda22c0cdf9f6c860b122fb216c6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 11:19:32 +0300 Subject: [PATCH 0312/2705] Test --- basilisk/basilisk_swap.c | 12 +++++++++++- iguana/dpow/dpow_network.c | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 12cf0be93..66dded2cd 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2982,7 +2982,17 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * { if ( (array= dpow_listtransactions(myinfo,coin,destaddr,100,0)) != 0 ) { - printf("list.(%s)\n",jprint(array,0)); + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i Date: Thu, 20 Apr 2017 11:45:13 +0300 Subject: [PATCH 0313/2705] Test --- basilisk/basilisk_swap.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 66dded2cd..b8305e60b 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2921,7 +2921,7 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) { - bits256 spendtxid,txid; char *retstr,*addr; cJSON *array,*array2,*item; int32_t i,n,m; char coinaddr[64]; struct iguana_info *coin = iguana_coinfind(symbol); + bits256 spendtxid,txid; char *retstr,*addr,*catstr; cJSON *array,*array2,*item; int32_t i,n,m; char coinaddr[64]; struct iguana_info *coin = iguana_coinfind(symbol); // listtransactions or listspents destaddr[0] = 0; memset(&spendtxid,0,sizeof(spendtxid)); @@ -2984,14 +2984,27 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * { if ( (n= cJSON_GetArraySize(array)) > 0 ) { + coinaddr[0] = 0; for (i=0; i Date: Thu, 20 Apr 2017 11:48:37 +0300 Subject: [PATCH 0314/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b8305e60b..921c5d53e 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3000,7 +3000,7 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * if ( coinaddr[0] != 0 ) { free_json(array); - if ( (array= dpow_listtransactions(myinfo,coin,destaddr,100,0)) != 0 ) + if ( (array= dpow_listtransactions(myinfo,coin,coinaddr,100,0)) != 0 ) { printf("second array.(%s)\n",jprint(array,0)); } From e9038762adeacc4e71c5b66ff5be1d51256c48c2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 12:33:18 +0300 Subject: [PATCH 0315/2705] Test --- basilisk/basilisk_swap.c | 170 +++++++++++++++++++++++++++------------ 1 file changed, 118 insertions(+), 52 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 921c5d53e..8e96dffc1 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -781,7 +781,7 @@ void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,in void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx,int32_t locktime,bits256 triggertxid) { - char zeroes[32],fname[512],str[65],coinaddr[64],secretAmstr[41],secretAm256str[65],secretBnstr[41],secretBn256str[65]; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; + char zeroes[32],fname[512],str[65],coinaddr[64],secretAmstr[41],secretAm256str[65],secretBnstr[41],secretBn256str[65],*tmp; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); coinaddr[0] = secretAmstr[0] = secretAm256str[0] = secretBnstr[0] = secretBn256str[0] = 0; memset(zeroes,0,sizeof(zeroes)); @@ -799,6 +799,11 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap basilisk_swap_coinaddr(myinfo,swap,swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); if ( coinaddr[0] != 0 ) { + if ( swap->bobcoin != 0 && swap->bobcoin->FULLNODE < 0 ) + { + if ( (tmp= dpow_importaddress(myinfo,swap->bobcoin,coinaddr)) != 0 ) + free(tmp); + } if ( rawtx == &swap->bobdeposit ) safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); @@ -820,6 +825,11 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) { basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicecoin != 0 && swap->alicecoin->FULLNODE < 0 ) + { + if ( (tmp= dpow_importaddress(myinfo,swap->alicecoin,coinaddr)) != 0 ) + free(tmp); + } fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); } /*basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); @@ -2919,94 +2929,150 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin return(scriptlen); } -bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) +bits256 dex_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,char *coinaddr,bits256 utxotxid,int32_t vout) { - bits256 spendtxid,txid; char *retstr,*addr,*catstr; cJSON *array,*array2,*item; int32_t i,n,m; char coinaddr[64]; struct iguana_info *coin = iguana_coinfind(symbol); - // listtransactions or listspents - destaddr[0] = 0; + char *retstr,*addr; cJSON *array,*item,*array2; int32_t i,n,m; bits256 spendtxid,txid; memset(&spendtxid,0,sizeof(spendtxid)); - //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); - if ( (coin == 0 || coin->FULLNODE >= 0) && iguana_isnotarychain(symbol) >= 0 ) + if ( (retstr= dex_listtransactions(myinfo,0,0,0,symbol,coinaddr,100,0)) != 0 ) { - //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] - basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); - //printf("spendtxid %s dest.(%s)\n",symbol,coinaddr); - if ( coinaddr[0] != 0 && (retstr= dex_listtransactions(myinfo,0,0,0,symbol,coinaddr,100,0)) != 0 ) + if ( (array= cJSON_Parse(retstr)) != 0 ) { - //printf("listtransactions.(%s)\n",retstr); - if ( (array= cJSON_Parse(retstr)) != 0 ) + if ( (n= cJSON_GetArraySize(array)) > 0 ) { - if ( (n= cJSON_GetArraySize(array)) > 0 ) + for (i=0; i %s\n",bits256_str(str,spendtxid),destaddr); - break; - } + basilisk_swap_getcoinaddr(myinfo,symbol,destaddr,spendtxid,0); + //char str[65]; printf("found spendtxid.(%s) -> %s\n",bits256_str(str,spendtxid),destaddr); + break; } } } } - free(retstr); + free_json(array); } + free(retstr); + } + return(spendtxid); +} + +bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) +{ + bits256 spendtxid,txid; char *catstr,*addr; cJSON *array,*item,*item2,*txobj,*vins; int32_t i,n,m; char coinaddr[64],str[65]; struct iguana_info *coin = iguana_coinfind(symbol); + // listtransactions or listspents + destaddr[0] = 0; + coinaddr[0] = 0; + memset(&spendtxid,0,sizeof(spendtxid)); + //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); + if ( (coin == 0 || coin->FULLNODE >= 0) && iguana_isnotarychain(symbol) >= 0 ) + { + //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] + basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + if ( coinaddr[0] != 0 ) + spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); } else if ( coin != 0 ) { - if ( (array= dpow_listtransactions(myinfo,coin,destaddr,100,0)) != 0 ) + if ( (array= dpow_listtransactions(myinfo,coin,destaddr,1000,0)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { - coinaddr[0] = 0; for (i=0; i 0 ) { - free_json(array); - if ( (array= dpow_listtransactions(myinfo,coin,coinaddr,100,0)) != 0 ) + for (i=0; i jint(item,"vout") ) + { + item2 = jitem(vins,jint(item,"vout")); + if ( bits256_cmp(utxotxid,jbits256(item2,"txid")) == 0 && vout == jint(item2,"vout") ) + { + spendtxid = txid; + break; + } + } + } + } } - } + if ( i == n ) + printf("dpowlist: native couldnt find spendtxid for %s\n",bits256_str(str,utxotxid)); + } + free_json(array); } - free_json(array); + if ( bits256_nonz(spendtxid) != 0 ) + return(spendtxid); + } + if ( iguana_isnotarychain(symbol) >= 0 ) + { + basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + printf("fallback use DEX for native (%s) (%s)\n",coinaddr,bits256_str(str,utxotxid)); + if ( coinaddr[0] != 0 ) + spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); } } return(spendtxid); From 2b8b47ba8ba4390761cf32ef93ac26d0ee106628 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 12:44:32 +0300 Subject: [PATCH 0316/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- crypto777/bitcoind_RPC.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 8e96dffc1..d327b1e14 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3015,14 +3015,14 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * if (strcmp(catstr,"send") == 0 ) { strncpy(destaddr,addr,63); - printf("(%s) <- (%s) item.%d.[%s]\n",destaddr,coinaddr,i,jprint(item,0)); + //printf("(%s) <- (%s) item.%d.[%s]\n",destaddr,coinaddr,i,jprint(item,0)); if ( coinaddr[0] != 0 ) break; } if (strcmp(catstr,"receive") == 0 ) { strncpy(coinaddr,addr,63); - printf("receive dest.(%s) <- (%s)\n",destaddr,coinaddr); + //printf("receive dest.(%s) <- (%s)\n",destaddr,coinaddr); if ( destaddr[0] != 0 ) break; } diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index c7ad8be9b..a3ce6c694 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -57,7 +57,7 @@ char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char * //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) { - if ( strcmp(command,"signrawtransaction") != 0 ) + if ( strcmp(command,"signrawtransaction") != 0 && strcmp(command,"getrawtransaction") != 0 ) printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); return(rpcstr); } From 929819f4bcaa7d79b29f5cc0c06ea5da063e7f82 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 12:54:33 +0300 Subject: [PATCH 0317/2705] Test --- basilisk/basilisk_swap.c | 2 +- iguana/dpow/dpow_network.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index d327b1e14..b7fdeb78c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3654,7 +3654,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 && bits256_nonz(depositspent) == 0 ) { - if ( bits256_nonz(paymentspent) != 0 ) + if ( bits256_nonz(paymentspent) != 0 || time(NULL) > expiration ) { //if ( txbytes[BASILISK_BOBREFUND] == 0 ) { diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index ddb7ef66d..528aced8a 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -819,7 +819,7 @@ char *dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *data,int32 { if ( (retstrs[j]= _dex_reqsend(myinfo,handler,0,0,data,datalen)) != 0 ) { -printf("j.%d of max.%d M.%d (%s)\n",j,max,M,retstrs[j]); +//printf("j.%d of max.%d M.%d (%s)\n",j,max,M,retstrs[j]); if ( strncmp(retstrs[j],"{\"error\":\"null return\"}",strlen("{\"error\":\"null return\"}")) != 0 && strncmp(retstrs[j],"[]",strlen("[]")) != 0 && strcmp("0",retstrs[j]) != 0 ) { if ( ++j == M ) From d76d78254bc612233cc41a3da07ea48f3fe8ce4d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 13:03:45 +0300 Subject: [PATCH 0318/2705] Test --- basilisk/basilisk_swap.c | 21 +++++++++++++-------- crypto777/bitcoind_RPC.c | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b7fdeb78c..7337cbc1c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3319,6 +3319,17 @@ bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int3 char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; // add blocktrail presence requirement for BTC +int32_t basilisk_swap_isfinished(bits256 *txids,int32_t *sentflags,bits256 paymentspent,bits256 Apaymentspent,bits256 depositspent) +{ + if ( bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) + { + if ( bits256_nonz(paymentspent) != 0 ) + return(1); + else if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) == 0 && sentflags[BASILISK_BOBPAYMENT] == 0 ) + return(1); + } + return(0); +} cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { @@ -3517,10 +3528,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBPAYMENT,BASILISK_ALICESPEND,BASILISK_BOBRECLAIM,0,Adest,Bdest); Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,sentflags,txids,BASILISK_ALICEPAYMENT,BASILISK_ALICERECLAIM,BASILISK_BOBSPEND,0,AAdest,ABdest); depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBDEPOSIT,BASILISK_ALICECLAIM,BASILISK_BOBREFUND,0,Adest,Bdest); - if ( bits256_nonz(paymentspent) != 0 && bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) - { - finishedflag = 1; - } + finishedflag = basilisk_swap_isfinished(txids,sentflags,paymentspent,Apaymentspent,depositspent); if ( finishedflag == 0 && iambob == 0 ) { if ( sentflags[BASILISK_ALICESPEND] == 0 ) @@ -3740,10 +3748,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t BTCtotals[BASILISK_BOBSPEND] += values[BASILISK_ALICEPAYMENT] * sentflags[BASILISK_BOBSPEND]; } } - if ( bits256_nonz(paymentspent) != 0 && bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) - { - finishedflag = 1; - } + finishedflag = basilisk_swap_isfinished(txids,sentflags,paymentspent,Apaymentspent,depositspent); jaddnum(item,"requestid",requestid); jaddnum(item,"quoteid",quoteid); jadd(item,"txs",array); diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index a3ce6c694..a4a9499b1 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -85,7 +85,7 @@ char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char * } else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) { - if ( strcmp(command,"signrawtransaction") != 0 && strcmp(command,"sendrawtransaction") != 0 ) + if ( strcmp(command,"getrawtransaction") != 0 && strcmp(command,"signrawtransaction") != 0 && strcmp(command,"sendrawtransaction") != 0 ) printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr); retstr = rpcstr; rpcstr = 0; From eb3e1109934bd2e071870443013f31405049ee8d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 13:23:33 +0300 Subject: [PATCH 0319/2705] Test --- basilisk/basilisk_swap.c | 57 +++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 7337cbc1c..cbe726a32 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2855,8 +2855,8 @@ cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 t else { retjson = dpow_gettxout(myinfo,coin,trigger,vout); - printf("need to verify passthru has this info\n"); - printf("dpowgettxout.(%s)\n",jprint(retjson,0)); + //printf("need to verify passthru has this info\n"); + //printf("dpowgettxout.(%s)\n",jprint(retjson,0)); } return(basilisk_nullretjson(retjson)); } @@ -3333,13 +3333,7 @@ int32_t basilisk_swap_isfinished(bits256 *txids,int32_t *sentflags,bits256 payme cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; - sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); - if ( (fp= fopen(fname,"rb")) != 0 ) - { - origfinishedflag = finishedflag = 1; - fclose(fp); - } + FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,n,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*txname,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; memset(values,0,sizeof(values)); memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); @@ -3423,11 +3417,39 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } free(fstr); } + sprintf(fname,"%s/SWAPS/%u-%u.finished",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + if ( (fstr= OS_filestr(&fsize,fname)) != 0 ) + { + //printf("%s -> (%s)\n",fname,fstr); + if ( (txobj= cJSON_Parse(fstr)) != 0 ) + { + paymentspent = jbits256(txobj,"paymentspent"); + Apaymentspent = jbits256(txobj,"Apaymentspent"); + depositspent = jbits256(txobj,"depositspent"); + if ( (array= jarray(&n,txobj,"sentflags")) != 0 ) + { + for (i=0; i Date: Thu, 20 Apr 2017 13:33:12 +0300 Subject: [PATCH 0320/2705] Test --- basilisk/basilisk_swap.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index cbe726a32..5985fef53 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3321,6 +3321,7 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob // add blocktrail presence requirement for BTC int32_t basilisk_swap_isfinished(bits256 *txids,int32_t *sentflags,bits256 paymentspent,bits256 Apaymentspent,bits256 depositspent) { + int32_t i; if ( bits256_nonz(Apaymentspent) != 0 && bits256_nonz(depositspent) != 0 ) { if ( bits256_nonz(paymentspent) != 0 ) @@ -3328,6 +3329,14 @@ int32_t basilisk_swap_isfinished(bits256 *txids,int32_t *sentflags,bits256 payme else if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) == 0 && sentflags[BASILISK_BOBPAYMENT] == 0 ) return(1); } + else + { + for (i=0; i Date: Thu, 20 Apr 2017 13:45:01 +0300 Subject: [PATCH 0321/2705] Test --- basilisk/basilisk_swap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 5985fef53..d89d97f09 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3335,7 +3335,10 @@ int32_t basilisk_swap_isfinished(bits256 *txids,int32_t *sentflags,bits256 payme if ( i != BASILISK_OTHERFEE && i != BASILISK_MYFEE && sentflags[i] != 0 ) break; if ( i == sizeof(txnames)/sizeof(*txnames) ) + { + printf("if nothing sent, it is finished\n"); return(1); + } } return(0); } From 5c5a339bd48f8353a0473e91ae101b9b08473a7c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 13:49:32 +0300 Subject: [PATCH 0322/2705] Test --- basilisk/basilisk_swap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index d89d97f09..5ced7b069 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3698,6 +3698,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { if ( bits256_nonz(paymentspent) != 0 || time(NULL) > expiration ) { + printf("do the refund!\n"); //if ( txbytes[BASILISK_BOBREFUND] == 0 ) { revcalc_rmd160_sha256(secretBn,privBn); @@ -3716,7 +3717,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t depositspent = txids[BASILISK_BOBREFUND]; } } - } + } else printf("time %u vs expiration %u\n",(uint32_t)time(NULL),expiration); } } } From 5e436ded551f5e0cff253ce432b032e669392e4a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 13:54:30 +0300 Subject: [PATCH 0323/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 5ced7b069..70f8b0d57 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3718,7 +3718,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } } } else printf("time %u vs expiration %u\n",(uint32_t)time(NULL),expiration); - } + } else printf("REFUND %d %d %d %d\n",sentflags[BASILISK_BOBREFUND] == 0,sentflags[BASILISK_BOBDEPOSIT] != 0,bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0,bits256_nonz(depositspent) == 0); } } if ( sentflags[BASILISK_ALICESPEND] != 0 || sentflags[BASILISK_BOBRECLAIM] != 0 ) From f36dd4b49581aa491fe14e9afbafd045bb64be2a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 13:58:55 +0300 Subject: [PATCH 0324/2705] Test --- basilisk/basilisk_swap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 70f8b0d57..df33a643c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3718,9 +3718,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } } } else printf("time %u vs expiration %u\n",(uint32_t)time(NULL),expiration); - } else printf("REFUND %d %d %d %d\n",sentflags[BASILISK_BOBREFUND] == 0,sentflags[BASILISK_BOBDEPOSIT] != 0,bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0,bits256_nonz(depositspent) == 0); + } } } + printf("finish.%d iambob.%d REFUND %d %d %d %d\n",finishedflag,iambob,sentflags[BASILISK_BOBREFUND] == 0,sentflags[BASILISK_BOBDEPOSIT] != 0,bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0,bits256_nonz(depositspent) == 0); if ( sentflags[BASILISK_ALICESPEND] != 0 || sentflags[BASILISK_BOBRECLAIM] != 0 ) sentflags[BASILISK_BOBPAYMENT] = 1; if ( sentflags[BASILISK_ALICERECLAIM] != 0 || sentflags[BASILISK_BOBSPEND] != 0 ) From 09e3fc3735219d34bb677e3ff5dde6b76f99127c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 14:03:33 +0300 Subject: [PATCH 0325/2705] Test --- basilisk/basilisk_swap.c | 54 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index df33a643c..a6bf95ebc 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3514,40 +3514,40 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } } //printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); - //strcpy(bobcoin,"KMD"); - //strcpy(alicecoin,"BTC"); Adestaddr[0] = destaddr[0] = 0; Adest = Bdest = AAdest = ABdest = 0; - if ( iambob == 0 ) - { - if ( (coin= iguana_coinfind(alicecoin)) != 0 ) - { - bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); - AAdest = Adestaddr; - } - if ( (coin= iguana_coinfind(bobcoin)) != 0 ) - { - bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); - Adest = destaddr; - } - } - else + if ( bobcoin[0] == 0 || alicecoin[0] == 0 ) + return(0); + //printf("privAm.(%s) %p/%p\n",bits256_str(str,privAm),Adest,AAdest); + //printf("privBn.(%s) %p/%p\n",bits256_str(str,privBn),Bdest,ABdest); + if ( finishedflag == 0 && bobcoin[0] != 0 && alicecoin[0] != 0 ) { - if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + if ( iambob == 0 ) { - bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); - Bdest = destaddr; + if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + AAdest = Adestaddr; + } + if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + { + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + Adest = destaddr; + } } - if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + else { - bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); - ABdest = Adestaddr; + if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + { + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + Bdest = destaddr; + } + if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + ABdest = Adestaddr; + } } - } - //printf("privAm.(%s) %p/%p\n",bits256_str(str,privAm),Adest,AAdest); - //printf("privBn.(%s) %p/%p\n",bits256_str(str,privBn),Bdest,ABdest); - if ( finishedflag == 0 && bobcoin[0] != 0 && alicecoin[0] != 0 ) - { if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) { printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); From c239460c7d9ca226a6eef2acddbbc82384dc46d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 14:09:43 +0300 Subject: [PATCH 0326/2705] Test --- basilisk/basilisk_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a6bf95ebc..9ada773f5 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3646,6 +3646,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) { + printf("try to bobspend aspend.%s have privAm.%d\n",bits256_str(str,txids[BASILISK_ALICESPEND]),bits256_nonz(privAm)); if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 || bits256_nonz(privAm) != 0 ) { //if ( txbytes[BASILISK_BOBSPEND] == 0 ) From 60e0f9e1fe5f439caaf6a48b074f2bc713300851 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 14:41:16 +0300 Subject: [PATCH 0327/2705] Test --- basilisk/basilisk_swap.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 9ada773f5..2a250aef4 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -785,7 +785,7 @@ void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); coinaddr[0] = secretAmstr[0] = secretAm256str[0] = secretBnstr[0] = secretBn256str[0] = 0; memset(zeroes,0,sizeof(zeroes)); - if ( (fp= fopen(fname,"wb")) != 0 ) + if ( rawtx != 0 && (fp= fopen(fname,"wb")) != 0 ) { fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); if ( rawtx->I.datalen > 0 ) @@ -915,6 +915,11 @@ void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swa { bits256 triggertxid; memset(triggertxid.bytes,0,sizeof(triggertxid)); + if ( rawtx == 0 ) + { + basilisk_dontforget(myinfo,swap,0,0,triggertxid); + return; + } if ( rawtx == &swap->myfee ) basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); else if ( rawtx == &swap->otherfee ) @@ -1237,6 +1242,7 @@ int32_t basilisk_verify_privi(struct supernet_info *myinfo,void *ptr,uint8_t *da vcalc_sha256(0,swap->I.secretBn256,privkey.bytes,sizeof(privkey)); printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); } + basilisk_dontforget_update(myinfo,swap,0); char str[65]; printf("privi verified.(%s)\n",bits256_str(str,privkey)); return(0); } @@ -2921,7 +2927,7 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin { scriptlen >>= 1; decode_hex(script,scriptlen,hexstr); - //char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); + char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); } } free_json(retjson); @@ -3448,7 +3454,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( strcmp(txname,txnames[i]) == 0 ) { sentflags[j] = 1; - printf("finished.%s\n",txnames[j]); + //printf("finished.%s\n",txnames[j]); break; } } @@ -3505,7 +3511,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t free_json(sentobj); } values[i] = value = jdouble(txobj,"amount") * SATOSHIDEN; - //printf("%s %.8f\n",txnames[i],dstr(value)); + printf("%s %s %.8f\n",txnames[i],bits256_str(str,txid),dstr(value)); //if ( sentflags[i] == 0 || addflag != 0 ) // jaddi(array,txobj); } @@ -3722,7 +3728,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } } } - printf("finish.%d iambob.%d REFUND %d %d %d %d\n",finishedflag,iambob,sentflags[BASILISK_BOBREFUND] == 0,sentflags[BASILISK_BOBDEPOSIT] != 0,bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0,bits256_nonz(depositspent) == 0); + //printf("finish.%d iambob.%d REFUND %d %d %d %d\n",finishedflag,iambob,sentflags[BASILISK_BOBREFUND] == 0,sentflags[BASILISK_BOBDEPOSIT] != 0,bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0,bits256_nonz(depositspent) == 0); if ( sentflags[BASILISK_ALICESPEND] != 0 || sentflags[BASILISK_BOBRECLAIM] != 0 ) sentflags[BASILISK_BOBPAYMENT] = 1; if ( sentflags[BASILISK_ALICERECLAIM] != 0 || sentflags[BASILISK_BOBSPEND] != 0 ) From d14020feebc540f6ad95fd75b14f7fdbbc9df352 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 14:47:57 +0300 Subject: [PATCH 0328/2705] Test --- basilisk/basilisk_swap.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2a250aef4..efa1e6796 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2952,7 +2952,6 @@ bits256 dex_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *desta txid = jbits256(item,"txid"); if ( bits256_nonz(txid) == 0 ) { - spendtxid = jbits256(item,"hash"); if ( (array2= jarray(&m,item,"inputs")) != 0 && m == 1 ) { //printf("found inputs with %s\n",bits256_str(str,spendtxid)); @@ -2962,8 +2961,9 @@ bits256 dex_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *desta //printf("matched %s\n",bits256_str(str,txid)); if ( (array2= jarray(&m,item,"outputs")) != 0 && m == 1 && (addr= jstr(jitem(array2,0),"address")) != 0 ) { + spendtxid = jbits256(item,"hash"); strcpy(destaddr,addr); - //printf("set addr.(%s)\n",addr); + printf("set spend addr.(%s) <- %s\n",addr,jprint(item,0)); break; } } @@ -3078,7 +3078,10 @@ bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char * basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); printf("fallback use DEX for native (%s) (%s)\n",coinaddr,bits256_str(str,utxotxid)); if ( coinaddr[0] != 0 ) + { spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); + printf("spendtxid.(%s)\n",bits256_str(str,spendtxid)); + } } } return(spendtxid); From 5a274e2dec8e8c7f2be2769fc01ed8824aca36bc Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 14:57:02 +0300 Subject: [PATCH 0329/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index efa1e6796..401c6cd6f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3120,7 +3120,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); } - if ( strcmp(symbol,"KMD") != 0 ) + if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) locktime = 0; if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { From eeb153e9810d1071a5baad939ae9617d388aa0eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 15:00:32 +0300 Subject: [PATCH 0330/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 401c6cd6f..eccb9456b 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3120,8 +3120,8 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); } - if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) - locktime = 0; + //if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) + // locktime = 0; if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); From a52592adccbba4b5523bf5d5af076e54832a4a71 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 15:11:49 +0300 Subject: [PATCH 0331/2705] Test --- basilisk/basilisk_swap.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index eccb9456b..ed90f4b16 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3120,8 +3120,8 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); } - //if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) - // locktime = 0; + if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) + locktime = 0; if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); @@ -3497,21 +3497,24 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t safecopy(bobcoin,symbol,sizeof(bobcoin)); else if ( i == BASILISK_BOBSPEND || i == BASILISK_ALICEPAYMENT || i == BASILISK_ALICERECLAIM ) safecopy(alicecoin,symbol,sizeof(alicecoin)); - if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + if ( finishedflag == 0 ) { - //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); - } - else - { - checktxid = jbits256(sentobj,"txid"); - if ( bits256_nonz(checktxid) == 0 ) - checktxid = jbits256(sentobj,"hash"); - if ( bits256_cmp(checktxid,txid) == 0 ) + if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) { - //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); - sentflags[i] = 1; + //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + } + else + { + checktxid = jbits256(sentobj,"txid"); + if ( bits256_nonz(checktxid) == 0 ) + checktxid = jbits256(sentobj,"hash"); + if ( bits256_cmp(checktxid,txid) == 0 ) + { + //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); + sentflags[i] = 1; + } + free_json(sentobj); } - free_json(sentobj); } values[i] = value = jdouble(txobj,"amount") * SATOSHIDEN; printf("%s %s %.8f\n",txnames[i],bits256_str(str,txid),dstr(value)); From b185a6ad1c17ea56e302f8b4c683ddf6a1359925 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 15:20:32 +0300 Subject: [PATCH 0332/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ed90f4b16..291ae9104 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3863,7 +3863,7 @@ char *basilisk_swaplist(struct supernet_info *myinfo) if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) { jaddi(array,item); - if ( (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + if ( 0 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) break; } } From 0aa1dce81d4cb835cc3a3a71481586c0cede66ec Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 15:25:57 +0300 Subject: [PATCH 0333/2705] Test --- basilisk/basilisk_swap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 291ae9104..070aa78e0 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3120,8 +3120,9 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); } - if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) - locktime = 0; + //if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) + // locktime = 0; + sequenceid = 0xffffffff; if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); From 482ff7379e66ea11ac4ecd19a59441726063175b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 15:35:32 +0300 Subject: [PATCH 0334/2705] Test --- basilisk/basilisk_swap.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 070aa78e0..28242d3df 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3121,7 +3121,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym return(0); } //if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) - // locktime = 0; + locktime = 0; sequenceid = 0xffffffff; if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { @@ -3331,20 +3331,20 @@ char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bob // add blocktrail presence requirement for BTC int32_t basilisk_swap_isfinished(bits256 *txids,int32_t *sentflags,bits256 paymentspent,bits256 Apaymentspent,bits256 depositspent) { - int32_t i; + int32_t i,n = 0; + for (i=0; i Date: Thu, 20 Apr 2017 15:40:36 +0300 Subject: [PATCH 0335/2705] Test --- basilisk/basilisk_swap.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 28242d3df..1d0701e9b 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3499,26 +3499,24 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t safecopy(bobcoin,symbol,sizeof(bobcoin)); else if ( i == BASILISK_BOBSPEND || i == BASILISK_ALICEPAYMENT || i == BASILISK_ALICERECLAIM ) safecopy(alicecoin,symbol,sizeof(alicecoin)); - if ( finishedflag == 0 ) + if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + { + //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + } + else { - if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + checktxid = jbits256(sentobj,"txid"); + if ( bits256_nonz(checktxid) == 0 ) + checktxid = jbits256(sentobj,"hash"); + if ( bits256_cmp(checktxid,txid) == 0 ) { - //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); + sentflags[i] = 1; } - else - { - checktxid = jbits256(sentobj,"txid"); - if ( bits256_nonz(checktxid) == 0 ) - checktxid = jbits256(sentobj,"hash"); - if ( bits256_cmp(checktxid,txid) == 0 ) - { - //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); - sentflags[i] = 1; - } - free_json(sentobj); - } - printf("%s %s %.8f\n",txnames[i],bits256_str(str,txid),dstr(value)); + free_json(sentobj); } + if ( finishedflag == 0 ) + printf("%s %s %.8f\n",txnames[i],bits256_str(str,txid),dstr(value)); } } //else printf("no symbol\n"); free(fstr); From 5bb92ebf08f83e742c9627a94d7231f1ebff22af Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 15:59:31 +0300 Subject: [PATCH 0336/2705] Test --- basilisk/basilisk_swap.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 1d0701e9b..b11451444 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3120,9 +3120,6 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); } - //if ( strcmp(symbol,"KMD") != 0 && finalseqid != 0 ) - locktime = 0; - sequenceid = 0xffffffff; if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); @@ -3448,6 +3445,9 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t paymentspent = jbits256(txobj,"paymentspent"); Apaymentspent = jbits256(txobj,"Apaymentspent"); depositspent = jbits256(txobj,"depositspent"); + if ( (array= jarray(&n,txobj,"values")) != 0 ) + for (i=0; i Date: Thu, 20 Apr 2017 16:24:30 +0300 Subject: [PATCH 0337/2705] Test --- basilisk/basilisk_swap.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b11451444..ee46abcca 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3326,25 +3326,37 @@ bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int3 char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; // add blocktrail presence requirement for BTC -int32_t basilisk_swap_isfinished(bits256 *txids,int32_t *sentflags,bits256 paymentspent,bits256 Apaymentspent,bits256 depositspent) +int32_t basilisk_swap_isfinished(int32_t iambob,bits256 *txids,int32_t *sentflags,bits256 paymentspent,bits256 Apaymentspent,bits256 depositspent) { int32_t i,n = 0; for (i=0; i Date: Thu, 20 Apr 2017 16:30:50 +0300 Subject: [PATCH 0338/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ee46abcca..18ddab3ae 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = finalseqid * 0xffffffff; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xfffffffe | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 8b6f9c47d59f1efc936d19d4969a62d061047f9c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 16:34:20 +0300 Subject: [PATCH 0339/2705] Test --- basilisk/basilisk_swap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 18ddab3ae..ef471b61f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3112,6 +3112,8 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xfffffffe | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + if ( strcmp(symbol,"KMD") != 0 ) + locktime = 0; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From b5dbe2827f5032111b7efcfbc6471758d8e67e8a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 16:38:42 +0300 Subject: [PATCH 0340/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ef471b61f..039db9290 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3705,7 +3705,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0)) != 0 ) - printf("privBn.(%s) bobreclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_BOBRECLAIM]); + printf("myprivs[1].(%s) bobreclaim.(%s)\n",bits256_str(str,myprivs[1]),txbytes[BASILISK_BOBRECLAIM]); } } if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) From 7d9de6e5ff2289d3c597b9682ce76df7957f18fe Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 16:49:40 +0300 Subject: [PATCH 0341/2705] Test --- basilisk/basilisk_swap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 039db9290..e2758797e 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3387,7 +3387,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { iambob = jint(item,"iambob"); if ( (secretstr= jstr(item,"secretAm")) != 0 && strlen(secretstr) == 40 ) + { decode_hex(secretAm,20,secretstr); + printf("secretAm.(%s)\n",secretstr); + } if ( (secretstr= jstr(item,"secretAm256")) != 0 && strlen(secretstr) == 64 ) decode_hex(secretAm256,32,secretstr); if ( (secretstr= jstr(item,"secretBn")) != 0 && strlen(secretstr) == 40 ) From 2a97b767fea9a974fcaf323c0459dbe7a169ab87 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 16:53:54 +0300 Subject: [PATCH 0342/2705] Test --- basilisk/basilisk_swap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index e2758797e..12c7ff0b1 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3708,7 +3708,12 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0)) != 0 ) - printf("myprivs[1].(%s) bobreclaim.(%s)\n",bits256_str(str,myprivs[1]),txbytes[BASILISK_BOBRECLAIM]); + { + int32_t z; + for (z=0; z<20; z++) + printf("%02x",secretAm[z]); + printf(" secretAm, myprivs[1].(%s) bobreclaim.(%s)\n",bits256_str(str,myprivs[1]),txbytes[BASILISK_BOBRECLAIM]); + } } } if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) From 6823b039c6d8393a75a2adfadb80026ceb3fb558 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:04:13 +0300 Subject: [PATCH 0343/2705] Test --- basilisk/basilisk_swap.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 12c7ff0b1..530341e60 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3389,7 +3389,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( (secretstr= jstr(item,"secretAm")) != 0 && strlen(secretstr) == 40 ) { decode_hex(secretAm,20,secretstr); - printf("secretAm.(%s)\n",secretstr); + int32_t z; + for (z=0; z<20; z++) + printf("%02x",secretAm[z]); + printf(" secretAm.(%s)\n",secretstr); } if ( (secretstr= jstr(item,"secretAm256")) != 0 && strlen(secretstr) == 64 ) decode_hex(secretAm256,32,secretstr); @@ -3600,10 +3603,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) { // alicespend - for (j=0; j<32; j++) - rev.bytes[j] = privAm.bytes[31 - j]; - revcalc_rmd160_sha256(secretAm,rev);//privAm); - vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); + //for (j=0; j<32; j++) + // rev.bytes[j] = privAm.bytes[31 - j]; + //revcalc_rmd160_sha256(secretAm,rev);//privAm); + //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1)) != 0 ) @@ -3670,6 +3673,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } else if ( iambob == 1 ) { + int32_t z; + for (z=0; z<20; z++) + printf("%02x",secretAm[z]); + printf(" secretAm iambob\n"); if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) { printf("try to bobspend aspend.%s have privAm.%d\n",bits256_str(str,txids[BASILISK_ALICESPEND]),bits256_nonz(privAm)); From 5b7ab548f85a1e8e69471dc9642f50b18c8c8d3b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:08:54 +0300 Subject: [PATCH 0344/2705] Test --- basilisk/basilisk_swap.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 530341e60..89e37fd4d 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3366,7 +3366,7 @@ int32_t basilisk_swap_isfinished(int32_t iambob,bits256 *txids,int32_t *sentflag cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,n,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[512],userdata[512]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*txname,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,n,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[1024],userdata[1024]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*txname,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; memset(values,0,sizeof(values)); memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); @@ -3707,10 +3707,16 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration && bits256_nonz(paymentspent) == 0 ) { + for (z=0; z<20; z++) + printf("%02x",secretAm[z]); + printf(" secretAm inside reclaim\n"); //if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) { // bobreclaim redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + for (z=0; z<20; z++) + printf("%02x",secretAm[z]); + printf(" secretAm after redeemscript\n"); if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); From bd5d8c1d220ccbcd73e648f1f7d637c69acf6d74 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:12:30 +0300 Subject: [PATCH 0345/2705] Test --- basilisk/basilisk_swap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 89e37fd4d..53f73d084 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -181,22 +181,22 @@ bits256 basilisk_revealkey(bits256 privkey,bits256 pubkey) int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp,uint8_t *redeemscript,uint32_t locktime,bits256 pubA0,bits256 pubB0,bits256 pubB1,bits256 privAm,bits256 privBn,uint8_t *secretAm,uint8_t *secretAm256,uint8_t *secretBn,uint8_t *secretBn256) { - int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],*secret160,*secret256; + int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],secret160[20],secret256[32]; if ( depositflag != 0 ) { pubkeyA[0] = 0x02, cltvpub = pubA0; pubkeyB[0] = 0x03, destpub = pubB0; privkey = privBn; - secret160 = secretBn; - secret256 = secretBn256; + memcpy(secret160,secretBn,20); + memcpy(secret256,secretBn256,32); } else { pubkeyA[0] = 0x03, cltvpub = pubB1; pubkeyB[0] = 0x02, destpub = pubA0; privkey = privAm; - secret160 = secretAm; - secret256 = secretAm256; + memcpy(secret160,secretAm,20); + memcpy(secret256,secretAm256,32); } //for (i=0; i<32; i++) // printf("%02x",secret256[i]); From 41afba5373ac39d3a4d71e11f8b70d7da2fb9194 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:18:57 +0300 Subject: [PATCH 0346/2705] Test --- basilisk/basilisk_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 53f73d084..a97f0895c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3630,7 +3630,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { //if ( txbytes[BASILISK_ALICECLAIM] == 0 ) { - redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,zero,secretAm,secretAm256,secretBn,secretBn256); if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); @@ -3713,7 +3713,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t //if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) { // bobreclaim - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,zero,privBn,secretAm,secretAm256,secretBn,secretBn256); for (z=0; z<20; z++) printf("%02x",secretAm[z]); printf(" secretAm after redeemscript\n"); From 5fab786cf98ea7e2f03794fc8d1925f453ee3e43 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:23:12 +0300 Subject: [PATCH 0347/2705] test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a97f0895c..053f8c54b 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xfffffffe | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; if ( strcmp(symbol,"KMD") != 0 ) locktime = 0; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); From 008be966910dc90c5a46cc8928757c367c69411b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:27:35 +0300 Subject: [PATCH 0348/2705] Test --- basilisk/basilisk_swap.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 053f8c54b..69a15d1c4 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3112,8 +3112,6 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; - if ( strcmp(symbol,"KMD") != 0 ) - locktime = 0; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 0c11deb993d8d8bf855684407bbdd41ffc40d39a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:30:33 +0300 Subject: [PATCH 0349/2705] Test --- basilisk/basilisk_swap.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 69a15d1c4..164d17a77 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xfffffffe | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); @@ -3385,13 +3385,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { iambob = jint(item,"iambob"); if ( (secretstr= jstr(item,"secretAm")) != 0 && strlen(secretstr) == 40 ) - { decode_hex(secretAm,20,secretstr); - int32_t z; - for (z=0; z<20; z++) - printf("%02x",secretAm[z]); - printf(" secretAm.(%s)\n",secretstr); - } if ( (secretstr= jstr(item,"secretAm256")) != 0 && strlen(secretstr) == 64 ) decode_hex(secretAm256,32,secretstr); if ( (secretstr= jstr(item,"secretBn")) != 0 && strlen(secretstr) == 40 ) @@ -3671,10 +3665,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } else if ( iambob == 1 ) { - int32_t z; - for (z=0; z<20; z++) - printf("%02x",secretAm[z]); - printf(" secretAm iambob\n"); if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) { printf("try to bobspend aspend.%s have privAm.%d\n",bits256_str(str,txids[BASILISK_ALICESPEND]),bits256_nonz(privAm)); @@ -3705,16 +3695,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration && bits256_nonz(paymentspent) == 0 ) { - for (z=0; z<20; z++) - printf("%02x",secretAm[z]); - printf(" secretAm inside reclaim\n"); //if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) { // bobreclaim redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,zero,privBn,secretAm,secretAm256,secretBn,secretBn256); - for (z=0; z<20; z++) - printf("%02x",secretAm[z]); - printf(" secretAm after redeemscript\n"); if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); From 0e196205d0a7e57d88cd58d70c9f47a61a2ef988 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:32:49 +0300 Subject: [PATCH 0350/2705] test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 164d17a77..95bb2c21c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xfffffffe | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xffffffff | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 97f883557da99faf5edd9d81e7f90488bf8d17a2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:37:50 +0300 Subject: [PATCH 0351/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 95bb2c21c..fb4139eeb 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xffffffff | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) + 0*777,sequenceid = 0xfffffffe | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From ced2475b707a24303b7c9e5b5c6ccc326a02bf7a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:40:08 +0300 Subject: [PATCH 0352/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index fb4139eeb..50aadb5ef 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) + 0*777,sequenceid = 0xfffffffe | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) + 0*777,sequenceid = 0xffffffff | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From ab3099fce307aa503804c887c0779200386b8ad9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:47:12 +0300 Subject: [PATCH 0353/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 50aadb5ef..d90c65ddb 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) + 0*777,sequenceid = 0xffffffff | finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) + 0*777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 47a5d56d7a5bd9608a383b5af419d2365e815fa9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:51:01 +0300 Subject: [PATCH 0354/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index d90c65ddb..3cc102912 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) + 0*777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) + 777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From f683ba31991b3affa5a5044a5c6ca39131f6278c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:54:42 +0300 Subject: [PATCH 0355/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3cc102912..3f4108920 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) + 777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 14b538951ac9671321a21094d7fdfccdeb83442c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 17:59:40 +0300 Subject: [PATCH 0356/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 3f4108920..d74a74230 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3111,7 +3111,7 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 2777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); From 277eb0b77d81bf868eb440f3211cd4cf3f34ca13 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 18:05:43 +0300 Subject: [PATCH 0357/2705] Test --- basilisk/basilisk_swap.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index d74a74230..0143aa77c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3109,9 +3109,11 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna return(txid); } -char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid) +char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = (uint32_t)time(NULL) - 2777,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + if ( finalseqid == 0 ) + locktime = expiration; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) return(0); @@ -3210,7 +3212,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym return(signedtx); } -char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33]) +char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration) { char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) @@ -3228,7 +3230,7 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, rev = privBn; for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ - signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1); + signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration); } return(signedtx); } @@ -3601,7 +3603,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } @@ -3626,7 +3628,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0)) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration)) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } @@ -3648,7 +3650,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t privBn = basilisk_swap_privBn_extract(myinfo,&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) + if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration)) != 0 ) printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); } } @@ -3678,7 +3680,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33)) != 0 ) + if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration)) != 0 ) printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); } } @@ -3702,7 +3704,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0)) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration)) != 0 ) { int32_t z; for (z=0; z<20; z++) @@ -3732,7 +3734,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1)) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) From fc630009a349dcaf42da3eab16dfae9e6356e006 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 19:27:15 +0300 Subject: [PATCH 0358/2705] Test --- .gitignore | 10 ++++++++++ basilisk/basilisk_swap.c | 9 ++++++--- iguana/DB/SWAPS/3210648667-2626363704 | 1 - iguana/DB/SWAPS/415703857-2769362858 | 1 - 4 files changed, 16 insertions(+), 5 deletions(-) delete mode 100644 iguana/DB/SWAPS/3210648667-2626363704 delete mode 100644 iguana/DB/SWAPS/415703857-2769362858 diff --git a/.gitignore b/.gitignore index 3c50d4146..1295737f8 100755 --- a/.gitignore +++ b/.gitignore @@ -380,3 +380,13 @@ iguana/DB/SWAPS/467080987-1442519493 iguana/DB/SWAPS/1504818827-1454232932 iguana/DB/SWAPS/4093850898-2949785771 + +iguana/DB/SWAPS.old/1247864366-3828803132 + +iguana/DB/SWAPS.old/.tmpmarker + +iguana/DB/SWAPS/2723832060-1788071166 + +iguana/DB/SWAPS/3210648667-2626363704 + +iguana/DB/SWAPS/415703857-2769362858 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0143aa77c..71e979bec 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2927,7 +2927,7 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin { scriptlen >>= 1; decode_hex(script,scriptlen,hexstr); - char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); + //char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); } } free_json(retjson); @@ -2963,7 +2963,7 @@ bits256 dex_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *desta { spendtxid = jbits256(item,"hash"); strcpy(destaddr,addr); - printf("set spend addr.(%s) <- %s\n",addr,jprint(item,0)); + //printf("set spend addr.(%s) <- %s\n",addr,jprint(item,0)); break; } } @@ -3359,6 +3359,8 @@ int32_t basilisk_swap_isfinished(int32_t iambob,bits256 *txids,int32_t *sentflag { if ( sentflags[BASILISK_ALICERECLAIM] != 0 || sentflags[BASILISK_ALICESPEND] != 0 ) return(1); + else if ( sentflags[BASILISK_BOBSPEND] != 0 ) // without ALICECLAIM this is loss due to inactivity + return(1); } } return(0); @@ -3381,6 +3383,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t plocktime = dlocktime = 0; src[0] = dest[0] = bobcoin[0] = alicecoin[0] = 0; sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + printf("%s\n",fname); if ( (fstr= OS_filestr(&fsize,fname)) != 0 ) { if ( (item= cJSON_Parse(fstr)) != 0 ) @@ -3883,7 +3886,7 @@ char *basilisk_swaplist(struct supernet_info *myinfo) if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) { jaddi(array,item); - if ( (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + if ( 1 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) break; } } diff --git a/iguana/DB/SWAPS/3210648667-2626363704 b/iguana/DB/SWAPS/3210648667-2626363704 deleted file mode 100644 index 890120802..000000000 --- a/iguana/DB/SWAPS/3210648667-2626363704 +++ /dev/null @@ -1 +0,0 @@ -{"src":"KMD","srcamount":99.65000000,"dest":"BTC","destamount":0.01279725,"requestid":3210648667,"quoteid":2626363704,"iambob":0,"state":63,"otherstate":191,"expiration":1492382391,"dlocktime":0,"plocktime":0,"secretAm":"41d77f89b7df4e6b4e037271af7171e5700ff78e","secretAm256":"2430481e893a8eb5dfebd803bad5e5db5dbfd7c4229e89c3412599688faaf6f4","secretBn":"58e3ed498bca71df2a09e4e083e1bfceaf37f17c","secretBn256":"4cbf23818c8ba08fc84634f2a4673f87b4ddb7b770910c83618c23478a16aed0","myprivs0":"e2f1c99ade4b40d6044db7fcc1c8440d754d984a32c29ef46fc70dc403cc5d6e","myprivs1":"7d252f9dd6ed55d4f2ac51672488c93c242bf96daab6fd9598eeced20150e8e9","privAm":"81956df0209ade7820e3642b0f1380a602670b96902f2622a4f6a454f571bbb2","pubA0":"46f8aa71581ffd70dfa22fc6fa7a1a287ba917e7eef4f28806b111fb5f2e6da3","pubB0":"2da1f98d4a628a5da9a0959db46b970dbfb41762c024123877cc7539149587ed","pubB1":"a5f17406afbcc29c0ffe103a672dd2457f833b6316439d81ee5d48afa3ae4070","myfee":"3415b8ed8853d86f986e4a932bb7d8f1b241a87b4b61e8597383f4c7dec90c2c","dest33":"025dddc7a1581b13535114dd4e6332f37420da35598b98d27ca319870abb9de7af"} diff --git a/iguana/DB/SWAPS/415703857-2769362858 b/iguana/DB/SWAPS/415703857-2769362858 deleted file mode 100644 index a06d1729b..000000000 --- a/iguana/DB/SWAPS/415703857-2769362858 +++ /dev/null @@ -1 +0,0 @@ -{"src":"BTC","srcamount":0.01577619,"dest":"KMD","destamount":118.45892649,"requestid":415703857,"quoteid":2769362858,"iambob":0,"state":1791,"otherstate":447,"expiration":1492383936,"dlocktime":1492383941,"plocktime":0,"secretAm":"218ec768f2df38385a08d3f3e0fd71c540243c69","secretAm256":"40cf46bc360cc79d8f29f2d3adb8cfd5d982b457a61b674dc3b3e9217c3e4496","secretBn":"86fe3a6d10f99d7396827c44767ef314d64a56d6","secretBn256":"bdf4fae7a167f185710269f3622bca4a254bf071751d2e1d7952be8a4a7c8208","myprivs0":"76605da8755998f3a8ede4920832754b6908a8ca01f3a68158a7e6b2da0711f4","myprivs1":"e4b2399987c4aff65cf73005361f182170e0de5a81e9ce6ed5cd74ad99554bf0","privAm":"baeb51e6ee3c4738482fbb352b3f097c23fb3e7e39b0836a6cbd115948e1f31d","pubA0":"7772d4a1471ada1ee192ff955c7115727ddff3383636949725c0307dfebc9eae","pubB0":"286f4c28533f12e50f328f481b73dd66fd4af3f18b6a65818ed1ff897e834e39","pubB1":"e0c4109251f7da8301e027d85b5d0dad95291362b835e003aa686dad326b5fe0","Bdeposit":"771c758300c47f6c63531e1f2cc50e57c96aaf014ef10004c0afcce64899bfdb","Apayment":"6f5ef3b1e7cd72a778abd167cc5c3a72224c1910c5d03167ee043bb003132b3e","myfee":"6f477936082053496fe46cd3a50d58a88c489e81e09db8b5781c279c4224eb6b","dest33":"0231a71ac00aed93b79f5b751d6b498cb1151314a18607328d5e79aec71deac205"} From 5c5856cefd99c78fce1e38d3fccbee6fcb721d58 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 19:38:57 +0300 Subject: [PATCH 0359/2705] Test --- basilisk/basilisk_swap.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 71e979bec..c3bac4b66 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3109,9 +3109,10 @@ bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txna return(txid); } -char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration) +char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp) { char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + *destamountp = 0; if ( finalseqid == 0 ) locktime = expiration; //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); @@ -3128,6 +3129,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym free_json(utxoobj); return(0); } else free_json(utxoobj); + *destamountp = destamount; if ( destamount > 10000 ) destamount -= 10000; if ( strcmp(symbol,"BTC") == 0 ) @@ -3212,7 +3214,7 @@ char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *sym return(signedtx); } -char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration) +char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp) { char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) @@ -3230,7 +3232,7 @@ char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol, rev = privBn; for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ - signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration); + signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration,destamountp); } return(signedtx); } @@ -3606,7 +3608,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND])) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } @@ -3631,7 +3633,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration)) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM])) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } @@ -3653,7 +3655,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t privBn = basilisk_swap_privBn_extract(myinfo,&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration)) != 0 ) + if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM])) != 0 ) printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); } } @@ -3683,7 +3685,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration)) != 0 ) + if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND])) != 0 ) printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); } } @@ -3707,7 +3709,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration)) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM])) != 0 ) { int32_t z; for (z=0; z<20; z++) @@ -3737,7 +3739,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration)) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND])) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) From df56ecd6fd839bf320e9ec939d9adc3f73aa1d4e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 20 Apr 2017 19:49:06 +0300 Subject: [PATCH 0360/2705] Test --- basilisk/basilisk_swap.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index c3bac4b66..382c5605f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2935,6 +2935,21 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin return(scriptlen); } +int64_t basilisk_txvalue(struct supernet_info *myinfo,char *symbol,bits256 txid,int32_t vout) +{ + cJSON *txobj,*vouts,*item; int32_t n; int64_t value = 0; + if ( (txobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + { + if ( (vouts= jarray(&n,txobj,"vout")) != 0 ) + { + item = jitem(vouts,vout); + if ( (value= jdouble(item,"amount") * SATOSHIDEN) == 0 ) + value = jdouble(item,"value") * SATOSHIDEN; + } + } + return(value); +} + bits256 dex_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,char *coinaddr,bits256 utxotxid,int32_t vout) { char *retstr,*addr; cJSON *array,*item,*array2; int32_t i,n,m; bits256 spendtxid,txid; @@ -3511,7 +3526,9 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t txbytes[i] = clonestr(jstr(txobj,"tx")); //printf("[%s] TX.(%s)\n",txnames[i],txbytes[i]); } - values[i] = value = jdouble(txobj,"amount") * SATOSHIDEN; + if ( (value= jdouble(txobj,"amount") * SATOSHIDEN) == 0 ) + value = jdouble(txobj,"value") * SATOSHIDEN; + values[i] = value; if ( (symbol= jstr(txobj,"coin")) != 0 ) { if ( i == BASILISK_ALICESPEND || i == BASILISK_BOBPAYMENT || i == BASILISK_BOBDEPOSIT || i == BASILISK_BOBREFUND || i == BASILISK_BOBRECLAIM || i == BASILISK_ALICECLAIM ) @@ -3762,7 +3779,10 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t sentflags[BASILISK_ALICEPAYMENT] = 1; if ( sentflags[BASILISK_ALICECLAIM] != 0 || sentflags[BASILISK_BOBREFUND] != 0 ) sentflags[BASILISK_BOBDEPOSIT] = 1; - if ( origfinishedflag == 0 ) + for (i=0; i Date: Thu, 20 Apr 2017 20:13:15 +0300 Subject: [PATCH 0361/2705] Test --- basilisk/basilisk_swap.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 382c5605f..8b0b6c96e 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2938,14 +2938,17 @@ int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uin int64_t basilisk_txvalue(struct supernet_info *myinfo,char *symbol,bits256 txid,int32_t vout) { cJSON *txobj,*vouts,*item; int32_t n; int64_t value = 0; - if ( (txobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + //char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid)); + if ( (txobj= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) { + //printf("txobj.(%s)\n",jprint(txobj,0)); if ( (vouts= jarray(&n,txobj,"vout")) != 0 ) { item = jitem(vouts,vout); if ( (value= jdouble(item,"amount") * SATOSHIDEN) == 0 ) value = jdouble(item,"value") * SATOSHIDEN; } + free_json(txobj); } return(value); } @@ -3344,6 +3347,27 @@ bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int3 //0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0 char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; +int32_t basilisk_isbobcoin(int32_t iambob,int32_t ind) +{ + switch ( ind ) + { + case BASILISK_MYFEE: return(iambob); break; + case BASILISK_OTHERFEE: return(!iambob); break; + case BASILISK_BOBSPEND: + case BASILISK_ALICEPAYMENT: + case BASILISK_ALICERECLAIM: + case BASILISK_ALICECLAIM: return(0); + break; + case BASILISK_BOBDEPOSIT: + case BASILISK_ALICESPEND: + case BASILISK_BOBPAYMENT: + case BASILISK_BOBREFUND: + case BASILISK_BOBRECLAIM: return(1); + break; + default: return(-1); break; + } +} + // add blocktrail presence requirement for BTC int32_t basilisk_swap_isfinished(int32_t iambob,bits256 *txids,int32_t *sentflags,bits256 paymentspent,bits256 Apaymentspent,bits256 depositspent) { @@ -3780,8 +3804,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( sentflags[BASILISK_ALICECLAIM] != 0 || sentflags[BASILISK_BOBREFUND] != 0 ) sentflags[BASILISK_BOBDEPOSIT] = 1; for (i=0; i Date: Sun, 23 Apr 2017 11:34:10 +0300 Subject: [PATCH 0362/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 10 +++++----- basilisk/jumblr.c | 8 ++++---- iguana/tests/dexgetbalance | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 1295737f8..2552af19a 100755 --- a/.gitignore +++ b/.gitignore @@ -390,3 +390,5 @@ iguana/DB/SWAPS/2723832060-1788071166 iguana/DB/SWAPS/3210648667-2626363704 iguana/DB/SWAPS/415703857-2769362858 + +iguana/DB/SWAPS/3213598586-2281632307 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 8b0b6c96e..8c387928f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1800,14 +1800,14 @@ struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 priv printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); if ( swap->I.iambob != 0 ) { - basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_DECKSIZE,0,0,jumblrflag); - basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_DECKSIZE,0,0,jumblrflag); + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); bobpub33 = pubkey33; } else { - basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_DECKSIZE,0,0,jumblrflag); - basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_DECKSIZE,0,0,jumblrflag); + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); alicepub33 = pubkey33; } basilisk_rawtx_setparms("bobdeposit",swap->I.req.quoteid,&swap->bobdeposit,swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3) + swap->bobcoin->txfee,4,0,jumblrflag); @@ -2431,7 +2431,7 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, } free_json(retjson); } - printf("KVsearch.(%s) connected.%d socks.(%d %d)\n",retstr,swap->connected,swap->pushsock,swap->subsock); + printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d)\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock); free(retstr); } if ( swap->connected <= 0 && amlp != 0 ) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 242fd2db4..19835f98c 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -737,10 +737,10 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 double minbtc,minkmd,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); + avail = (btcavail - kmdcoin->DEXinfo.DEXpending); + printf("BTC.%d deposits %.8f, min %.8f avail %.8f pending %.8f\n",toKMD,btcavail,minbtc,avail,kmdcoin->DEXinfo.DEXpending); if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) { - avail = (btcavail - kmdcoin->DEXinfo.DEXpending); - printf("BTC deposits %.8f, min %.8f avail %.8f\n",btcavail,minbtc,avail); /*if ( avail >= (100. * minbtc) ) vol = (100. * minbtc); else if ( avail >= (10. * minbtc) ) @@ -770,10 +770,10 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); minkmd = 100.; + avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); + printf("KMD.%d deposits %.8f, min %.8f, avail %.8f pending %.8f\n",toKMD,kmdcoin->DEXinfo.KMDavail,minkmd,avail,kmdcoin->DEXinfo.KMDpending); if ( toKMD != 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) { - avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); - printf("KMD deposits %.8f, min %.8f, avail %.8f\n",kmdcoin->DEXinfo.KMDavail,minkmd,avail); /*if ( avail > 100.*JUMBLR_INCR ) vol = 100.*JUMBLR_INCR; else if ( avail > 10.*JUMBLR_INCR ) diff --git a/iguana/tests/dexgetbalance b/iguana/tests/dexgetbalance index 71efdf9af..25bc1f680 100755 --- a/iguana/tests/dexgetbalance +++ b/iguana/tests/dexgetbalance @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getbalance\",\"address\":\"RAGhCfNvxpL55JFV7h2HQa5dSEK86Jg3ic\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getbalance\",\"address\":\"RRvaVyKS59NJWhPp8Pn7mVPGhMuhJJXrdh\",\"symbol\":\"KMD\"}" From 30929bbee1e98a41c17eb0816cc0308f804a406e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 09:30:47 +0300 Subject: [PATCH 0363/2705] Test --- basilisk/basilisk.c | 14 ++- basilisk/basilisk_DEX.c | 6 +- basilisk/basilisk_swap.c | 19 +++- basilisk/basilisk_tradebot.c | 4 +- basilisk/jumblr.c | 40 ++----- basilisk/smartaddress.c | 190 +++++++++++++++++++++++++++++---- basilisk/tradebots_liquidity.c | 21 ++-- iguana/iguana777.h | 3 +- iguana/iguana_wallet.c | 13 ++- iguana/main.c | 2 +- includes/iguana_apideclares.h | 2 + includes/iguana_funcs.h | 8 +- 12 files changed, 245 insertions(+), 77 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 2daa07911..d93406d26 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1354,7 +1354,7 @@ HASH_ARRAY_STRING(basilisk,rawtx,hash,vals,hexstr) STRING_ARG(jumblr,setpassphrase,passphrase) { - cJSON *retjson; char KMDaddr[64],BTCaddr[64],wifstr[64]; bits256 privkey; struct iguana_info *coinbtc; + cJSON *retjson,*tmp; char KMDaddr[64],BTCaddr[64],wifstr[64],*smartaddrs; bits256 privkey; struct iguana_info *coinbtc; if ( passphrase == 0 || passphrase[0] == 0 || (coin= iguana_coinfind("KMD")) == 0 )//|| coin->FULLNODE >= 0 ) return(clonestr("{\"error\":\"no passphrase or no native komodod\"}")); else @@ -1363,7 +1363,7 @@ STRING_ARG(jumblr,setpassphrase,passphrase) retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); - smartaddress_add(myinfo,privkey,BTCaddr,KMDaddr); + smartaddress_add(myinfo,privkey,"deposit"); myinfo->jumblr_depositkey = curve25519(privkey,curve25519_basepoint9()); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); if ( coin->FULLNODE < 0 ) @@ -1378,12 +1378,18 @@ STRING_ARG(jumblr,setpassphrase,passphrase) jaddnum(retjson,"BTCdeposits",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); } privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); - smartaddress_add(myinfo,privkey,BTCaddr,KMDaddr); + smartaddress_add(myinfo,privkey,"jumblr"); myinfo->jumblr_pubkey = curve25519(privkey,curve25519_basepoint9()); jaddstr(retjson,"KMDjumblr",KMDaddr); jaddstr(retjson,"BTCjumblr",BTCaddr); if ( coinbtc != 0 ) jaddnum(retjson,"BTCjumbled",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); + if ( (smartaddrs= InstantDEX_smartaddresses(myinfo,0,0,0)) != 0 ) + { + if ( (tmp= cJSON_Parse(smartaddrs)) != 0 ) + jadd(retjson,"smartaddresses",tmp); + free(smartaddrs); + } return(jprint(retjson,1)); } } @@ -1945,6 +1951,4 @@ ZERO_ARGS(InstantDEX,getswaplist) return(basilisk_swaplist(myinfo)); } - - #include "../includes/iguana_apiundefs.h" diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index b1e6fb579..c7bc89b7c 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -245,8 +245,8 @@ char *basilisk_start(struct supernet_info *myinfo,bits256 privkey,struct basilis //printf("filter duplicate r%u\n",_rp->requestid); return(clonestr("{\"error\":\"filter duplicate requestid\"}")); } - srcmatch = smartaddress_pubkey(myinfo,&tmpprivkey,_rp->srchash) >= 0; - destmatch = smartaddress_pubkey(myinfo,&tmpprivkey,_rp->desthash) >= 0; + srcmatch = smartaddress_pubkey(myinfo,&tmpprivkey,_rp->src,_rp->srchash) >= 0; + destmatch = smartaddress_pubkey(myinfo,&tmpprivkey,_rp->dest,_rp->desthash) >= 0; if ( srcmatch != 0 || destmatch != 0 ) { for (i=0; inumswaps; i++) @@ -310,7 +310,7 @@ int32_t basilisk_requests_poll(struct supernet_info *myinfo) if ( hwm > 0. ) { myinfo->DEXaccept = issueR; - if ( smartaddress_pubkey(myinfo,&privkey,issueR.srchash) >= 0 ) + if ( smartaddress_pubkey(myinfo,&privkey,issueR.src,issueR.srchash) >= 0 ) { printf("matched dex_smartpubkey\n"); dex_channelsend(myinfo,issueR.srchash,issueR.desthash,channel,0x4000000,(void *)&issueR.requestid,sizeof(issueR.requestid)); // 60 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 8c387928f..359ebbe12 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -500,7 +500,7 @@ cJSON *basilisk_privkeyarray(struct supernet_info *myinfo,struct iguana_info *co bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype); jaddistr(privkeyarray,waddr->wifstr); } - else if ( smartaddress(myinfo,&privkey,coinaddr) >= 0 ) + else if ( smartaddress(myinfo,&privkey,coin->symbol,coinaddr) >= 0 ) { bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeyarray,wifstr); @@ -2711,9 +2711,9 @@ cJSON *basilisk_swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { - int32_t i,m,n; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; struct basilisk_swap *swap = 0; + int32_t i,m,n; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; // statebits 1 -> client, 0 -> LP - if ( statebits == 0 && myinfo->numswaps > 0 ) + if ( myinfo->numswaps > 0 ) { if ( (coin= iguana_coinfind(rp->src)) == 0 || coin->FULLNODE >= 0 ) { @@ -2818,7 +2818,18 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 } myinfo->swaps[myinfo->numswaps++] = swap; - } else printf("%u/%u offer wasnt accepted statebits.%d m.%d n.%d\n",rp->requestid,rp->quoteid,statebits,m,n); + } + else + { + if ( statebits != 0 ) + { + if ( (coin= iguana_coinfind(rp->src)) != 0 ) + { + + } + } + printf("%u/%u offer wasnt accepted statebits.%d m.%d n.%d pending %.8f\n",rp->requestid,rp->quoteid,statebits,m,n,pending); + } } } } diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 136021efe..b0156a779 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -291,7 +291,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk return(0.); pendingid = active->I.req.quoteid; } - if ( smartaddress_pubkey(myinfo,&privkey,list[0].srchash) >= 0 ) + if ( smartaddress_pubkey(myinfo,&privkey,list[0].src,list[0].srchash) >= 0 ) myrequest = 1; for (i=0; i= 0 ) + if ( smartaddress_pubkey(myinfo,&privkey,list[i].dest,list[i].desthash) >= 0 ) myrequest |= 2; havequoteflag++; if ( pendingid == 0 ) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 19835f98c..305854030 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -371,20 +371,6 @@ void jumblr_opidsupdate(struct supernet_info *myinfo,struct iguana_info *coin) } } -bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubtype,char *KMDaddr,char *prefix) -{ - bits256 privkey,pubkey; uint8_t pubkey33[33]; char passphrase[sizeof(myinfo->jumblr_passphrase) + 64]; - sprintf(passphrase,"%s%s",prefix,myinfo->jumblr_passphrase); - if ( myinfo->jumblr_passphrase[0] == 0 ) - strcpy(myinfo->jumblr_passphrase,"password"); - conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); - bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); - bitcoin_address(coinaddr,pubtype,pubkey33,33); - bitcoin_address(KMDaddr,60,pubkey33,33); - //printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); - return(privkey); -} - int64_t jumblr_DEXsplit(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *splittxidp,char *coinaddr,bits256 txid,int32_t vout,int64_t remaining,double bigprice,double middleprice,double smallprice,double fees[4],cJSON *privkeys,double esttxfee) { int64_t values[4],outputs[64],value,total,estfee; int32_t i,n,success=0,completed,sendflag,numoutputs = 0; char *retstr; cJSON *retjson,*utxo,*item; @@ -691,15 +677,11 @@ void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char ptr->BTC2KMD = ptr->btcprice; ptr->kmdprice = 1.; ptr->KMDavail = KMDavail; - /*if ( (btccoin= iguana_coinfind("BTC")) != 0 ) - jumblr_utxoupdate(myinfo,"KMD",btccoin,ptr->btcprice,ptr->depositaddr,ptr->deposit_privkey,estbtcfee); - jumblr_utxoupdate(myinfo,"BTC",kmdcoin,1.,ptr->KMDdepositaddr,ptr->deposit_privkey,estfee);*/ } else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) { ptr->kmdprice = ptr->btcprice / BTC2KMD; ptr->KMDavail = KMDavail; - //jumblr_utxoupdate(myinfo,"KMD",ptr->coin,ptr->kmdprice,ptr->depositaddr,ptr->deposit_privkey,estfee); } ptr->lasttime = (uint32_t)time(NULL); printf("%s avail %.8f KMDavail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,KMDavail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); @@ -718,12 +700,12 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 kmdcoin = iguana_coinfind("KMD"); coinbtc = iguana_coinfind("BTC"); //printf("jumblr_DEXcheck numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); - if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 ) + if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 || myinfo->secret[0] == 0 ) return; if ( kmdcoin == 0 || coinbtc == 0 ) return; jumblr_DEXupdate(myinfo,kmdcoin,"KMD","komodo",0.,0.); - if ( strcmp(coin->symbol,"KMD") != 0 && kmdcoin->DEXinfo.btcprice > 0. ) + if ( strcmp(coin->symbol,"KMD") != 0 && strcmp(coin->symbol,"BTC") != 0 && kmdcoin->DEXinfo.btcprice > 0. ) { if ( coin->CMCname[0] == 0 ) jumblr_CMCname(coin->CMCname,coin->symbol); @@ -737,9 +719,9 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 double minbtc,minkmd,btcavail; char *retstr; cJSON *vals; bits256 hash; minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - avail = (btcavail - kmdcoin->DEXinfo.DEXpending); - printf("BTC.%d deposits %.8f, min %.8f avail %.8f pending %.8f\n",toKMD,btcavail,minbtc,avail,kmdcoin->DEXinfo.DEXpending); - if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + kmdcoin->DEXinfo.DEXpending) ) + avail = (btcavail - coinbtc->DEXinfo.DEXpending); + printf("BTC.%d deposits %.8f, min %.8f avail %.8f pending %.8f\n",toKMD,btcavail,minbtc,avail,coinbtc->DEXinfo.DEXpending); + if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + coinbtc->DEXinfo.DEXpending) ) { /*if ( avail >= (100. * minbtc) ) vol = (100. * minbtc); @@ -759,7 +741,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddnum(vals,"usejumblr",1); jaddnum(vals,"DEXselector",1); memset(hash.bytes,0,sizeof(hash)); - kmdcoin->DEXinfo.DEXpending += vol; + coinbtc->DEXinfo.DEXpending += vol; if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) { printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); @@ -770,9 +752,9 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); minkmd = 100.; - avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.KMDpending); - printf("KMD.%d deposits %.8f, min %.8f, avail %.8f pending %.8f\n",toKMD,kmdcoin->DEXinfo.KMDavail,minkmd,avail,kmdcoin->DEXinfo.KMDpending); - if ( toKMD != 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.KMDpending) ) + avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.DEXpending); + printf("KMD.%d deposits %.8f, min %.8f, avail %.8f pending %.8f\n",toKMD,kmdcoin->DEXinfo.KMDavail,minkmd,avail,kmdcoin->DEXinfo.DEXpending); + if ( toKMD != 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.DEXpending) ) { /*if ( avail > 100.*JUMBLR_INCR ) vol = 100.*JUMBLR_INCR; @@ -791,7 +773,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 jaddnum(vals,"minprice",0.985 * kmdcoin->DEXinfo.btcprice); jaddnum(vals,"usejumblr",2); memset(hash.bytes,0,sizeof(hash)); - kmdcoin->DEXinfo.KMDpending += vol; + kmdcoin->DEXinfo.DEXpending += vol; jaddnum(vals,"DEXselector",2); if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) { @@ -800,7 +782,7 @@ void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32 } free_json(vals); } - } else printf("kmdavail %.8f pending %.8f\n",kmdcoin->DEXinfo.KMDavail,kmdcoin->DEXinfo.KMDpending); + } else printf("kmdavail %.8f pending %.8f\n",kmdcoin->DEXinfo.KMDavail,kmdcoin->DEXinfo.DEXpending); } else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); } diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 39fcab19a..e198bba7a 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -15,15 +15,101 @@ // included from basilisk.c -int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *BTCaddr,char *KMDaddr) +// deposit address -> corresponding KMD address, if KMD deposit starts JUMBLR +// jumblr address is the destination of JUMBLR and JUMBLR BTC (would need tracking to map back to non-BTC) +// address is DEX'ed for + +// return value convention: -1 error, 0 partial match, >= 1 exact match + +int32_t smartaddress_type(char *typestr) +{ + char upper[64]; + if ( strcmp(typestr,"deposit") != 0 && strcmp(typestr,"jumblr") != 0 ) + { + upper[sizeof(upper)-1] = 0; + strncpy(upper,typestr,sizeof(upper)-1); + touppercase(upper); + if ( iguana_coinfind(upper) != 0 ) + return(0); + } + return(-1); +} + +bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubtype,char *KMDaddr,char *prefix) +{ + bits256 privkey,pubkey; uint8_t pubkey33[33]; char passphrase[sizeof(myinfo->jumblr_passphrase) + 64]; + sprintf(passphrase,"%s%s",prefix,myinfo->jumblr_passphrase); + if ( myinfo->jumblr_passphrase[0] == 0 ) + strcpy(myinfo->jumblr_passphrase,"password"); + conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); + bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); + bitcoin_address(coinaddr,pubtype,pubkey33,33); + bitcoin_address(KMDaddr,60,pubkey33,33); + //printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); + return(privkey); +} + +cJSON *smartaddress_json(struct smartaddress *ap) +{ + char coinaddr[64],*symbol; int32_t j,n; struct iguana_info *coin; cJSON *item = cJSON_CreateObject(); + bitcoin_address(coinaddr,60,ap->pubkey33,33); + jaddstr(item,"KMD",coinaddr); + bitcoin_address(coinaddr,0,ap->pubkey33,33); + jaddstr(item,"BTC",coinaddr); + if ( ap->typejson != 0 ) + { + jadd(item,"type",ap->typejson); + if ( (n= cJSON_GetArraySize(ap->typejson)) > 1 ) + { + for (j=1; jtypejson,j)) != 0 ) + { + if ( strcmp(symbol,"KMD") != 0 && strcmp(symbol,"BTC") != 0 ) + { + if ( (coin= iguana_coinfind(symbol)) != 0 ) + { + bitcoin_address(coinaddr,coin->chain->pubtype,ap->pubkey33,33); + jaddstr(item,symbol,coinaddr); + } + } + } + } + } + } + return(item); +} + +int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol) { - char coinaddr[64]; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; int32_t i; + char coinaddr[64]; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; int32_t i,j,n; if ( myinfo->numsmartaddrs < sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs) ) { for (i=0; inumsmartaddrs; i++) if ( bits256_cmp(myinfo->smartaddrs[i].privkey,privkey) == 0 ) - return(-1); - ap = &myinfo->smartaddrs[myinfo->numsmartaddrs++]; + { + ap = &myinfo->smartaddrs[i]; + if ( ap->typejson == 0 ) + return(-1); + else + { + n = cJSON_GetArraySize(ap->typejson); + for (j=0; jtypejson,j),symbol) == 0 ) + return(0); + } + } + jaddistr(ap->typejson,symbol); + return(i+1); + } + ap = &myinfo->smartaddrs[myinfo->numsmartaddrs]; + ap->typejson = cJSON_CreateArray(); + if ( smartaddress_type(symbol) < 0 ) + return(-1); + jaddistr(ap->typejson,symbol); + jaddistr(ap->typejson,"KMD"); + jaddistr(ap->typejson,"BTC"); ap->privkey = privkey; bitcoin_pubkey33(myinfo->ctx,ap->pubkey33,privkey); calc_rmd160_sha256(ap->rmd160,ap->pubkey33,33); @@ -35,24 +121,40 @@ int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *BTCa printf(", "); for (i=0; i<20; i++) printf("%02x",rmd160[i]); - printf (" <- rmd160 for %d %s vs %s\n",myinfo->numsmartaddrs,coinaddr,BTCaddr); - return(myinfo->numsmartaddrs); + printf (" <- rmd160 for %d %s\n",myinfo->numsmartaddrs,coinaddr); + return(++myinfo->numsmartaddrs + 1); } printf("too many smartaddresses %d vs %d\n",myinfo->numsmartaddrs,(int32_t)(sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs))); return(-1); } -int32_t smartaddress(struct supernet_info *myinfo,bits256 *privkeyp,char *coinaddr) +int32_t smartaddress_symbolmatch(struct smartaddress *ap,char *symbol) { - int32_t i; uint8_t addrtype,rmd160[20]; + int32_t j,n; + if ( ap->typejson != 0 && (n= cJSON_GetArraySize(ap->typejson)) > 0 ) + { + for (j=0; jtypejson,j),symbol) == 0 ) + return(j); + } + } + return(-1); +} + +int32_t smartaddress(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,char *coinaddr) +{ + int32_t i,j; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; memset(privkeyp,0,sizeof(*privkeyp)); bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); for (i=0; inumsmartaddrs; i++) if ( memcmp(myinfo->smartaddrs[i].rmd160,rmd160,20) == 0 ) { - *privkeyp = myinfo->smartaddrs[i].privkey; - printf("MATCHED %s\n",coinaddr); - return(i); + ap = &myinfo->smartaddrs[i]; + *privkeyp = ap->privkey; + if ( (j= smartaddress_symbolmatch(ap,symbol)) >= 0 ) + return(0); + return(i+1); } for (i=0; i<20; i++) printf("%02x",rmd160[i]); @@ -60,29 +162,77 @@ int32_t smartaddress(struct supernet_info *myinfo,bits256 *privkeyp,char *coinad return(-1); } -int32_t smartaddress_pubkey(struct supernet_info *myinfo,bits256 *privkeyp,bits256 pubkey) +int32_t smartaddress_pubkey(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,bits256 pubkey) { - int32_t i; + int32_t i,j; struct smartaddress *ap; memset(privkeyp,0,sizeof(*privkeyp)); for (i=0; inumsmartaddrs; i++) if ( bits256_cmp(myinfo->smartaddrs[i].pubkey,pubkey) == 0 ) { - *privkeyp = myinfo->smartaddrs[i].privkey; - return(i); + ap = &myinfo->smartaddrs[i]; + *privkeyp = ap->privkey; + if ( (j= smartaddress_symbolmatch(ap,symbol)) >= 0 ) + return(0); + return(i+1); } return(-1); } -int32_t smartaddress_pubkey33(struct supernet_info *myinfo,bits256 *privkeyp,uint8_t *pubkey33) +int32_t smartaddress_pubkey33(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,uint8_t *pubkey33) { - int32_t i; + int32_t i,j; struct smartaddress *ap; memset(privkeyp,0,sizeof(*privkeyp)); for (i=0; inumsmartaddrs; i++) if ( memcmp(myinfo->smartaddrs[i].pubkey33,pubkey33,33) == 0 ) { - *privkeyp = myinfo->smartaddrs[i].privkey; - return(i); + ap = &myinfo->smartaddrs[i]; + *privkeyp = ap->privkey; + if ( (j= smartaddress_symbolmatch(ap,symbol)) >= 0 ) + return(0); + return(i+1); } - return(0); + return(-1); +} + +#include "../includes/iguana_apidefs.h" +#include "../includes/iguana_apideclares.h" +#include "../includes/iguana_apideclares2.h" + +ZERO_ARGS(InstantDEX,smartaddresses) +{ + int32_t i; cJSON *retjson = cJSON_CreateArray(); + for (i=0; inumsmartaddrs; i++) + jaddi(retjson,smartaddress_json(&myinfo->smartaddrs[i])); + return(jprint(retjson,1)); +} + +TWO_STRINGS(InstantDEX,smartaddress,type,symbol) +{ + char prefix[64],coinaddr[64],KMDaddr[64]; uint8_t pubkey33[33]; bits256 privkey; + if ( smartaddress_type(type) < 0 ) + return(clonestr("{\"error\":\"non-supported smartaddress type\"}")); + if ( iguana_coinfind(symbol) == 0 ) + return(clonestr("{\"error\":\"non-supported smartaddress symbol\"}")); + if ( strcmp(type,"deposit") == 0 || strcmp(type,"jumblr") == 0 ) + { + if ( smartaddress_pubkey(myinfo,&privkey,symbol,strcmp(type,"deposit") == 0 ? myinfo->jumblr_depositkey : myinfo->jumblr_pubkey) < 0 ) + return(clonestr("{\"error\":\"unexpected missing smartaddress deposit/jumblr\"}")); + } + else + { + strcpy(prefix,type); + tolowercase(prefix); + if ( strcmp(prefix,"btc") == 0 || strcmp(prefix,"kmd") == 0 ) + return(clonestr("{\"success\":\"no need add BTC or KMD to smartaddress\"}")); + strcat(prefix," "); + privkey = jumblr_privkey(myinfo,coinaddr,0,KMDaddr,prefix); + } + if ( (coin= iguana_coinfind(symbol)) == 0 ) + return(clonestr("{\"error\":\"non-supported smartaddress symbol\"}")); + bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); + bitcoin_address(coinaddr,coin->chain->pubtype,pubkey33,33); + smartaddress_add(myinfo,privkey,symbol); + return(InstantDEX_smartaddresses(myinfo,0,0,0)); } +#include "../includes/iguana_apiundefs.h" diff --git a/basilisk/tradebots_liquidity.c b/basilisk/tradebots_liquidity.c index 76cda30bc..b044accd4 100755 --- a/basilisk/tradebots_liquidity.c +++ b/basilisk/tradebots_liquidity.c @@ -1142,13 +1142,22 @@ void _default_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_s void tradebot_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob) { - struct iguana_info *kmdcoin = iguana_coinfind("KMD"); - if ( kmdcoin != 0 ) + if ( swap->bobcoin != 0 && swap->alicecoin != 0 ) { - if ( swap->DEXselector == 1 ) - kmdcoin->DEXinfo.DEXpending -= swap->I.req.srcamount; - else if ( swap->DEXselector == 2 ) - kmdcoin->DEXinfo.KMDpending -= swap->I.req.srcamount; + if ( iambob != 0 ) + { + if ( strcmp(swap->I.req.src,swap->bobcoin->symbol) == 0 ) + swap->bobcoin->DEXinfo.DEXpending -= swap->I.req.srcamount; + else if ( strcmp(swap->I.req.dest,swap->bobcoin->symbol) == 0 ) + swap->bobcoin->DEXinfo.DEXpending -= swap->I.req.destamount; + } + else + { + if ( strcmp(swap->I.req.src,swap->alicecoin->symbol) == 0 ) + swap->alicecoin->DEXinfo.DEXpending -= swap->I.req.srcamount; + else if ( strcmp(swap->I.req.dest,swap->alicecoin->symbol) == 0 ) + swap->alicecoin->DEXinfo.DEXpending -= swap->I.req.destamount; + } } printf(">>>>>>>>>>>>>>>>>> balancing trade done by marketmaker\n"); return; diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 26ba7d77f..a54d55cd6 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -98,6 +98,7 @@ struct supernet_address struct smartaddress { bits256 privkey,pubkey; + cJSON *typejson; uint8_t pubkey33[33],rmd160[20]; }; @@ -182,7 +183,7 @@ struct basilisk_swap { struct supernet_info *myinfoptr; struct iguana_info *bobcoin,*alicecoin; void (*balancingtrade)(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob); - int32_t subsock,pushsock,connected,DEXselector,aliceunconf,depositunconf,paymentunconf; uint32_t lasttime,aborted; + int32_t subsock,pushsock,connected,aliceunconf,depositunconf,paymentunconf; uint32_t lasttime,aborted; FILE *fp; bits256 persistent_privkey,persistent_pubkey; struct basilisk_swapinfo I; diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index c73259f29..1f3797e94 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -910,6 +910,9 @@ void iguana_walletlock(struct supernet_info *myinfo,struct iguana_info *coin) memset(&myinfo->persistent_priv,0,sizeof(myinfo->persistent_priv)); memset(&myinfo->persistent_pubkey33,0,sizeof(myinfo->persistent_pubkey33)); memset(myinfo->secret,0,sizeof(myinfo->secret)); + memset(myinfo->jumblr_passphrase,0,sizeof(myinfo->jumblr_passphrase)); + memset(&myinfo->jumblr_depositkey,0,sizeof(myinfo->jumblr_depositkey)); + memset(&myinfo->jumblr_pubkey,0,sizeof(myinfo->jumblr_pubkey)); memset(myinfo->permanentfile,0,sizeof(myinfo->permanentfile)); if ( myinfo->decryptstr != 0 ) scrubfree(myinfo->decryptstr), myinfo->decryptstr = 0; @@ -1369,8 +1372,14 @@ TWOSTRINGS_AND_INT(bitcoinrpc,walletpassphrase,password,permanentfile,timeout) } } if ( bits256_nonz(myinfo->persistent_priv) != 0 ) - smartaddress_add(myinfo,myinfo->persistent_priv,"",""); - + { + char *jumblrstr,jumblr_passphrase[1024]; + sprintf(jumblr_passphrase,"jumblr %s",password); + if ( (jumblrstr= jumblr_setpassphrase(myinfo,0,0,0,jumblr_passphrase)) != 0 ) + free(jumblrstr); + smartaddress_add(myinfo,myinfo->persistent_priv,"kmd"); + smartaddress_add(myinfo,myinfo->persistent_priv,"btc"); + } //basilisk_unspents_update(myinfo,coin); return(retstr); } diff --git a/iguana/main.c b/iguana/main.c index 81c1abdbd..0b082e794 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -753,7 +753,7 @@ void jumblr_loop(void *ptr) printf("JUMBLR loop\n"); while ( myinfo->IAMNOTARY == 0 ) { - if ( (coin= iguana_coinfind("KMD")) != 0 ) + if ( (coin= iguana_coinfind("KMD")) != 0 && iguana_coinfind("BTC") != 0 ) { //#ifdef __APPLE__ //if ( (n++ % 10) == 0 ) diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 77e23adf8..cfe35a6df 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -226,6 +226,8 @@ STRING_ARG(InstantDEX,allpairs,exchange); THREE_STRINGS(InstantDEX,supports,exchange,base,rel); ZERO_ARGS(InstantDEX,init); ZERO_ARGS(InstantDEX,getswaplist); +ZERO_ARGS(InstantDEX,smartaddresses); +TWO_STRINGS(InstantDEX,smartaddress,type,symbol); //THREE_STRINGS(atomic,approve,myorderid,otherid,txname); //THREE_STRINGS(atomic,claim,myorderid,otherid,txname); diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index 11072f2c9..0b18bdbe3 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -606,10 +606,10 @@ void dpow_nanomsginit(struct supernet_info *myinfo,char *ipaddr); int32_t iguana_datachain_scan(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t rmd160[20]); int32_t basilisk_requests_poll(struct supernet_info *myinfo); void dpow_psockloop(void *_ptr); -int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *BTCaddr,char *KMDaddr); -int32_t smartaddress(struct supernet_info *myinfo,bits256 *privkeyp,char *coinaddr); -int32_t smartaddress_pubkey(struct supernet_info *myinfo,bits256 *privkeyp,bits256 pubkey); -int32_t smartaddress_pubkey33(struct supernet_info *myinfo,bits256 *privkeyp,uint8_t *pubkey33); +int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *typestr); +int32_t smartaddress(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,char *coinaddr); +int32_t smartaddress_pubkey(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,bits256 pubkey); +int32_t smartaddress_pubkey33(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,uint8_t *pubkey33); void iguana_RTreset(struct iguana_info *coin); void iguana_RTpurge(struct iguana_info *coin,int32_t lastheight); From 4291a7eb7f20594c767cf79731e2eec40448a0a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 18:12:29 +0300 Subject: [PATCH 0364/2705] Test --- basilisk/basilisk.c | 5 +- basilisk/basilisk_DEX.c | 10 +-- basilisk/basilisk_swap.c | 4 +- basilisk/basilisk_tradebot.c | 6 +- basilisk/smartaddress.c | 146 +++++++++++++++++++++++----------- iguana/iguana777.h | 2 +- iguana/iguana_wallet.c | 4 +- iguana/tests/smartadd | 3 + iguana/tests/smartaddresses | 2 + includes/iguana_apideclares.h | 2 +- includes/iguana_funcs.h | 8 +- 11 files changed, 126 insertions(+), 66 deletions(-) create mode 100755 iguana/tests/smartadd create mode 100755 iguana/tests/smartaddresses diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index d93406d26..094c8e5de 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -993,6 +993,7 @@ void basilisks_init(struct supernet_info *myinfo) portable_mutex_init(&myinfo->bu_mutex); portable_mutex_init(&myinfo->allcoins_mutex); portable_mutex_init(&myinfo->basilisk_mutex); + portable_mutex_init(&myinfo->smart_mutex); portable_mutex_init(&myinfo->DEX_mutex); portable_mutex_init(&myinfo->DEX_swapmutex); portable_mutex_init(&myinfo->DEX_reqmutex); @@ -1363,7 +1364,7 @@ STRING_ARG(jumblr,setpassphrase,passphrase) retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); - smartaddress_add(myinfo,privkey,"deposit"); + smartaddress_add(myinfo,privkey,"deposit",0.,0.); myinfo->jumblr_depositkey = curve25519(privkey,curve25519_basepoint9()); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); if ( coin->FULLNODE < 0 ) @@ -1378,7 +1379,7 @@ STRING_ARG(jumblr,setpassphrase,passphrase) jaddnum(retjson,"BTCdeposits",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); } privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); - smartaddress_add(myinfo,privkey,"jumblr"); + smartaddress_add(myinfo,privkey,"jumblr",0.,0.); myinfo->jumblr_pubkey = curve25519(privkey,curve25519_basepoint9()); jaddstr(retjson,"KMDjumblr",KMDaddr); jaddstr(retjson,"BTCjumblr",BTCaddr); diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index c7bc89b7c..fd047148a 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -239,14 +239,14 @@ int32_t basilisk_request_create(struct basilisk_request *rp,cJSON *valsobj,bits2 char *basilisk_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *_rp,uint32_t statebits,int32_t optionduration) { - cJSON *retjson; bits256 tmpprivkey; struct basilisk_request *rp=0; int32_t i,srcmatch,destmatch; + cJSON *retjson; char typestr[64]; bits256 tmpprivkey; double bidasks[2]; struct basilisk_request *rp=0; int32_t i,srcmatch,destmatch; if ( _rp->requestid == myinfo->lastdexrequestid ) { //printf("filter duplicate r%u\n",_rp->requestid); return(clonestr("{\"error\":\"filter duplicate requestid\"}")); } - srcmatch = smartaddress_pubkey(myinfo,&tmpprivkey,_rp->src,_rp->srchash) >= 0; - destmatch = smartaddress_pubkey(myinfo,&tmpprivkey,_rp->dest,_rp->desthash) >= 0; + srcmatch = smartaddress_pubkey(myinfo,typestr,bidasks,&tmpprivkey,_rp->src,_rp->srchash) >= 0; + destmatch = smartaddress_pubkey(myinfo,typestr,bidasks,&tmpprivkey,_rp->dest,_rp->desthash) >= 0; if ( srcmatch != 0 || destmatch != 0 ) { for (i=0; inumswaps; i++) @@ -284,7 +284,7 @@ char *basilisk_start(struct supernet_info *myinfo,bits256 privkey,struct basilis int32_t basilisk_requests_poll(struct supernet_info *myinfo) { static uint32_t lastpoll; - char *retstr; uint8_t data[32768]; cJSON *outerarray,*retjson; uint32_t msgid,channel; int32_t datalen,i,n,retval = 0; struct basilisk_request issueR; bits256 privkey; double hwm = 0.; + char *retstr,typestr[64]; uint8_t data[32768]; cJSON *outerarray,*retjson; uint32_t msgid,channel; int32_t datalen,i,n,retval = 0; struct basilisk_request issueR; bits256 privkey; double bidasks[2],hwm = 0.; if ( myinfo->IAMNOTARY != 0 || time(NULL) < lastpoll+20 || (myinfo->IAMLP == 0 && myinfo->DEXactive < time(NULL)) ) return(retval); lastpoll = (uint32_t)time(NULL); @@ -310,7 +310,7 @@ int32_t basilisk_requests_poll(struct supernet_info *myinfo) if ( hwm > 0. ) { myinfo->DEXaccept = issueR; - if ( smartaddress_pubkey(myinfo,&privkey,issueR.src,issueR.srchash) >= 0 ) + if ( smartaddress_pubkey(myinfo,typestr,bidasks,&privkey,issueR.src,issueR.srchash) >= 0 ) { printf("matched dex_smartpubkey\n"); dex_channelsend(myinfo,issueR.srchash,issueR.desthash,channel,0x4000000,(void *)&issueR.requestid,sizeof(issueR.requestid)); // 60 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 359ebbe12..2111a910a 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -470,7 +470,7 @@ int32_t basilisk_rawtx_sign(struct supernet_info *myinfo,int32_t height,struct b cJSON *basilisk_privkeyarray(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *vins) { - cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; + cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],typestr[64],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; double bidasks[2]; privkeyarray = cJSON_CreateArray(); //printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr); if ( (n= cJSON_GetArraySize(vins)) > 0 ) @@ -500,7 +500,7 @@ cJSON *basilisk_privkeyarray(struct supernet_info *myinfo,struct iguana_info *co bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype); jaddistr(privkeyarray,waddr->wifstr); } - else if ( smartaddress(myinfo,&privkey,coin->symbol,coinaddr) >= 0 ) + else if ( smartaddress(myinfo,typestr,bidasks,&privkey,coin->symbol,coinaddr) >= 0 ) { bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeyarray,wifstr); diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index b0156a779..481640038 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -281,7 +281,7 @@ int32_t basilisk_request_cmpref(struct basilisk_request *ref,struct basilisk_req double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk_request *issueR,struct basilisk_request *list,int32_t n) { - int32_t i,noquoteflag=0,havequoteflag=0,myrequest=0,maxi=-1; int64_t balance=0,destamount,minamount = 0,maxamount = 0; bits256 privkey; uint32_t pendingid=0; struct basilisk_swap *active; double metric = 0.; + int32_t i,noquoteflag=0,havequoteflag=0,myrequest=0,maxi=-1; int64_t balance=0,destamount,minamount = 0,maxamount = 0; bits256 privkey; uint32_t pendingid=0; struct basilisk_swap *active; double metric = 0.,bidasks[2]; char typestr[64]; memset(issueR,0,sizeof(*issueR)); minamount = list[0].minamount; //printf("need to verify null quoteid is list[0] requestid.%u quoteid.%u\n",list[0].requestid,list[0].quoteid); @@ -291,7 +291,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk return(0.); pendingid = active->I.req.quoteid; } - if ( smartaddress_pubkey(myinfo,&privkey,list[0].src,list[0].srchash) >= 0 ) + if ( smartaddress_pubkey(myinfo,typestr,bidasks,&privkey,list[0].src,list[0].srchash) >= 0 ) myrequest = 1; for (i=0; i= 0 ) + if ( smartaddress_pubkey(myinfo,typestr,bidasks,&privkey,list[i].dest,list[i].desthash) >= 0 ) myrequest |= 2; havequoteflag++; if ( pendingid == 0 ) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index e198bba7a..258419a43 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -51,38 +51,44 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty cJSON *smartaddress_json(struct smartaddress *ap) { - char coinaddr[64],*symbol; int32_t j,n; struct iguana_info *coin; cJSON *item = cJSON_CreateObject(); + char coinaddr[64],*symbol; int32_t j,n; struct iguana_info *coin; cJSON *array,*ritem,*item,*retjson = cJSON_CreateObject(); bitcoin_address(coinaddr,60,ap->pubkey33,33); - jaddstr(item,"KMD",coinaddr); + jaddstr(retjson,"KMD",coinaddr); bitcoin_address(coinaddr,0,ap->pubkey33,33); - jaddstr(item,"BTC",coinaddr); + jaddstr(retjson,"BTC",coinaddr); if ( ap->typejson != 0 ) { - jadd(item,"type",ap->typejson); - if ( (n= cJSON_GetArraySize(ap->typejson)) > 1 ) + //jadd(item,"type",ap->typejson); + array = cJSON_CreateArray(); + if ( (n= cJSON_GetArraySize(ap->typejson)) > 0 ) { + jadd(retjson,"type",jitem(ap->typejson,0)); for (j=1; jtypejson,j)) != 0 ) + item = jitem(ap->typejson,j); + if ( (symbol= jstr(item,"s")) != 0 ) { - if ( strcmp(symbol,"KMD") != 0 && strcmp(symbol,"BTC") != 0 ) + if ( (coin= iguana_coinfind(symbol)) != 0 ) { - if ( (coin= iguana_coinfind(symbol)) != 0 ) - { - bitcoin_address(coinaddr,coin->chain->pubtype,ap->pubkey33,33); - jaddstr(item,symbol,coinaddr); - } + bitcoin_address(coinaddr,coin->chain->pubtype,ap->pubkey33,33); + ritem = cJSON_CreateObject(); + jaddstr(ritem,"coin",symbol); + jaddstr(ritem,"address",coinaddr); + jaddnum(ritem,"maxbid",jdouble(item,"b")); + jaddnum(ritem,"minask",jdouble(item,"a")); + jaddi(array,ritem); } } } } + jadd(retjson,"coins",array); } - return(item); + return(retjson); } -int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol) +int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol,double maxbid,double minask) { - char coinaddr[64]; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; int32_t i,j,n; + char coinaddr[64],*jsym; uint8_t addrtype,rmd160[20]; cJSON *item; struct smartaddress *ap; int32_t i,j,n; if ( myinfo->numsmartaddrs < sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs) ) { for (i=0; inumsmartaddrs; i++) @@ -96,8 +102,24 @@ int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symb n = cJSON_GetArraySize(ap->typejson); for (j=0; jtypejson,j),symbol) == 0 ) + item = jitem(ap->typejson,j); + jsym = jstr(item,"s"); + if ( jsym != 0 && strcmp(jsym,symbol) == 0 ) + { + if ( maxbid != 0. ) + { + if ( jobj(item,"b") != 0 ) + jdelete(item,"b"); + jaddnum(item,"b",maxbid); + } + if ( minask != 0. ) + { + if ( jobj(item,"a") != 0 ) + jdelete(item,"a"); + jaddnum(item,"a",minask); + } return(0); + } } } jaddistr(ap->typejson,symbol); @@ -107,9 +129,9 @@ int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symb ap->typejson = cJSON_CreateArray(); if ( smartaddress_type(symbol) < 0 ) return(-1); - jaddistr(ap->typejson,symbol); - jaddistr(ap->typejson,"KMD"); - jaddistr(ap->typejson,"BTC"); + item = cJSON_CreateObject(), jaddstr(item,"type",symbol), jaddi(ap->typejson,item); + item = cJSON_CreateObject(), jaddstr(item,"s","KMD"), jaddi(ap->typejson,item); + item = cJSON_CreateObject(), jaddstr(item,"s","BTC"), jaddi(ap->typejson,item); ap->privkey = privkey; bitcoin_pubkey33(myinfo->ctx,ap->pubkey33,privkey); calc_rmd160_sha256(ap->rmd160,ap->pubkey33,33); @@ -128,70 +150,100 @@ int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symb return(-1); } -int32_t smartaddress_symbolmatch(struct smartaddress *ap,char *symbol) +int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol,double maxbid,double minask) +{ + int32_t retval; + portable_mutex_lock(&myinfo->smart_mutex); + retval = _smartaddress_add(myinfo,privkey,symbol,maxbid,minask); + portable_mutex_unlock(&myinfo->smart_mutex); + return(retval); +} + +int32_t smartaddress_symbolmatch(char *typestr,double *bidaskp,struct smartaddress *ap,char *symbol) { - int32_t j,n; + int32_t j,n; char *str; cJSON *item; if ( ap->typejson != 0 && (n= cJSON_GetArraySize(ap->typejson)) > 0 ) { - for (j=0; jtypejson,0); + if ( (str= jstr(item,"type")) != 0 ) + strncpy(typestr,str,63); + else typestr[0] = 0; + for (j=1; jtypejson,j),symbol) == 0 ) + item = jitem(ap->typejson,j); + str = jstr(item,"s"); + if ( str != 0 && strcmp(str,symbol) == 0 ) + { + bidaskp[0] = jdouble(item,"b"); + bidaskp[1] = jdouble(item,"a"); return(j); + } } } return(-1); } -int32_t smartaddress(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,char *coinaddr) +int32_t smartaddress(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,char *coinaddr) { - int32_t i,j; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; + int32_t i,j,retval = -1; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; memset(privkeyp,0,sizeof(*privkeyp)); + memset(bidaskp,0,sizeof(*bidaskp) * 2); bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); + portable_mutex_lock(&myinfo->smart_mutex); for (i=0; inumsmartaddrs; i++) if ( memcmp(myinfo->smartaddrs[i].rmd160,rmd160,20) == 0 ) { ap = &myinfo->smartaddrs[i]; *privkeyp = ap->privkey; - if ( (j= smartaddress_symbolmatch(ap,symbol)) >= 0 ) - return(0); - return(i+1); + if ( (j= smartaddress_symbolmatch(typestr,bidaskp,ap,symbol)) >= 0 ) + retval = 0; + else retval = (i+1); + break; } + portable_mutex_unlock(&myinfo->smart_mutex); for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" <- rmd160 smartaddress cant find (%s) of %d\n",coinaddr,myinfo->numsmartaddrs); - return(-1); + return(retval); } -int32_t smartaddress_pubkey(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,bits256 pubkey) +int32_t smartaddress_pubkey(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,bits256 pubkey) { - int32_t i,j; struct smartaddress *ap; + int32_t i,j,retval = -1; struct smartaddress *ap; memset(privkeyp,0,sizeof(*privkeyp)); + memset(bidaskp,0,sizeof(*bidaskp) * 2); + portable_mutex_lock(&myinfo->smart_mutex); for (i=0; inumsmartaddrs; i++) if ( bits256_cmp(myinfo->smartaddrs[i].pubkey,pubkey) == 0 ) { ap = &myinfo->smartaddrs[i]; - *privkeyp = ap->privkey; - if ( (j= smartaddress_symbolmatch(ap,symbol)) >= 0 ) - return(0); - return(i+1); + if ( (j= smartaddress_symbolmatch(typestr,bidaskp,ap,symbol)) >= 0 ) + retval = 0; + else retval = (i+1); + break; } - return(-1); + portable_mutex_unlock(&myinfo->smart_mutex); + return(retval); } -int32_t smartaddress_pubkey33(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,uint8_t *pubkey33) +int32_t smartaddress_pubkey33(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,uint8_t *pubkey33) { - int32_t i,j; struct smartaddress *ap; + int32_t i,j,retval = -1; struct smartaddress *ap; memset(privkeyp,0,sizeof(*privkeyp)); + memset(bidaskp,0,sizeof(*bidaskp) * 2); + portable_mutex_lock(&myinfo->smart_mutex); for (i=0; inumsmartaddrs; i++) if ( memcmp(myinfo->smartaddrs[i].pubkey33,pubkey33,33) == 0 ) { ap = &myinfo->smartaddrs[i]; *privkeyp = ap->privkey; - if ( (j= smartaddress_symbolmatch(ap,symbol)) >= 0 ) - return(0); - return(i+1); + if ( (j= smartaddress_symbolmatch(typestr,bidaskp,ap,symbol)) >= 0 ) + retval = 0; + else retval = (i+1); + break; } - return(-1); + portable_mutex_unlock(&myinfo->smart_mutex); + return(retval); } #include "../includes/iguana_apidefs.h" @@ -201,21 +253,23 @@ int32_t smartaddress_pubkey33(struct supernet_info *myinfo,bits256 *privkeyp,cha ZERO_ARGS(InstantDEX,smartaddresses) { int32_t i; cJSON *retjson = cJSON_CreateArray(); + portable_mutex_lock(&myinfo->smart_mutex); for (i=0; inumsmartaddrs; i++) jaddi(retjson,smartaddress_json(&myinfo->smartaddrs[i])); + portable_mutex_unlock(&myinfo->smart_mutex); return(jprint(retjson,1)); } -TWO_STRINGS(InstantDEX,smartaddress,type,symbol) +TWO_STRINGS_AND_TWO_DOUBLES(InstantDEX,smartaddress,type,symbol,maxbid,minask) { - char prefix[64],coinaddr[64],KMDaddr[64]; uint8_t pubkey33[33]; bits256 privkey; + char prefix[64],coinaddr[64],KMDaddr[64],typestr[64]; double bidask[2]; uint8_t pubkey33[33]; bits256 privkey; if ( smartaddress_type(type) < 0 ) return(clonestr("{\"error\":\"non-supported smartaddress type\"}")); if ( iguana_coinfind(symbol) == 0 ) return(clonestr("{\"error\":\"non-supported smartaddress symbol\"}")); if ( strcmp(type,"deposit") == 0 || strcmp(type,"jumblr") == 0 ) { - if ( smartaddress_pubkey(myinfo,&privkey,symbol,strcmp(type,"deposit") == 0 ? myinfo->jumblr_depositkey : myinfo->jumblr_pubkey) < 0 ) + if ( smartaddress_pubkey(myinfo,typestr,bidask,&privkey,symbol,strcmp(type,"deposit") == 0 ? myinfo->jumblr_depositkey : myinfo->jumblr_pubkey) < 0 ) return(clonestr("{\"error\":\"unexpected missing smartaddress deposit/jumblr\"}")); } else @@ -231,7 +285,7 @@ TWO_STRINGS(InstantDEX,smartaddress,type,symbol) return(clonestr("{\"error\":\"non-supported smartaddress symbol\"}")); bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); bitcoin_address(coinaddr,coin->chain->pubtype,pubkey33,33); - smartaddress_add(myinfo,privkey,symbol); + smartaddress_add(myinfo,privkey,symbol,maxbid,minask); return(InstantDEX_smartaddresses(myinfo,0,0,0)); } diff --git a/iguana/iguana777.h b/iguana/iguana777.h index a54d55cd6..ddcac1286 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -142,7 +142,7 @@ struct supernet_info struct exchange_info *tradingexchanges[SUPERNET_MAXEXCHANGES]; int32_t numexchanges; struct iguana_waccount *wallet; struct iguana_info *allcoins; int32_t allcoins_being_added,allcoins_numvirts; - portable_mutex_t bu_mutex,allcoins_mutex,gecko_mutex,basilisk_mutex,DEX_mutex,DEX_reqmutex,DEX_swapmutex; + portable_mutex_t bu_mutex,allcoins_mutex,gecko_mutex,basilisk_mutex,DEX_mutex,DEX_reqmutex,DEX_swapmutex,smart_mutex; struct queueitem *DEX_quotes; cJSON *Cunspents,*Cspends; struct basilisk_swap *swaps[256]; int32_t numswaps; struct basilisk_message *messagetable; portable_mutex_t messagemutex; queue_t msgQ,p2pQ; diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index 1f3797e94..d6189ebb0 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -1377,8 +1377,8 @@ TWOSTRINGS_AND_INT(bitcoinrpc,walletpassphrase,password,permanentfile,timeout) sprintf(jumblr_passphrase,"jumblr %s",password); if ( (jumblrstr= jumblr_setpassphrase(myinfo,0,0,0,jumblr_passphrase)) != 0 ) free(jumblrstr); - smartaddress_add(myinfo,myinfo->persistent_priv,"kmd"); - smartaddress_add(myinfo,myinfo->persistent_priv,"btc"); + smartaddress_add(myinfo,myinfo->persistent_priv,"kmd",0.,0.); + smartaddress_add(myinfo,myinfo->persistent_priv,"btc",0.,0.); } //basilisk_unspents_update(myinfo,coin); return(retstr); diff --git a/iguana/tests/smartadd b/iguana/tests/smartadd new file mode 100755 index 000000000..d39448cde --- /dev/null +++ b/iguana/tests/smartadd @@ -0,0 +1,3 @@ +#!/bin/bash +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"coin\",\"symbol\":\"coin\"}" # first time +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"coin\",\"symbol\":\"OTHER\",\"maxbid\":0.0002,\"minask\":0.0001}" diff --git a/iguana/tests/smartaddresses b/iguana/tests/smartaddresses new file mode 100755 index 000000000..fbcccbf57 --- /dev/null +++ b/iguana/tests/smartaddresses @@ -0,0 +1,2 @@ +#!/bin/bash +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddresses\"}" diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index cfe35a6df..161173081 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -227,7 +227,7 @@ THREE_STRINGS(InstantDEX,supports,exchange,base,rel); ZERO_ARGS(InstantDEX,init); ZERO_ARGS(InstantDEX,getswaplist); ZERO_ARGS(InstantDEX,smartaddresses); -TWO_STRINGS(InstantDEX,smartaddress,type,symbol); +TWO_STRINGS_AND_TWO_DOUBLES(InstantDEX,smartaddress,type,symbol,maxbid,minask); //THREE_STRINGS(atomic,approve,myorderid,otherid,txname); //THREE_STRINGS(atomic,claim,myorderid,otherid,txname); diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index 0b18bdbe3..9a1469933 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -606,10 +606,10 @@ void dpow_nanomsginit(struct supernet_info *myinfo,char *ipaddr); int32_t iguana_datachain_scan(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t rmd160[20]); int32_t basilisk_requests_poll(struct supernet_info *myinfo); void dpow_psockloop(void *_ptr); -int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *typestr); -int32_t smartaddress(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,char *coinaddr); -int32_t smartaddress_pubkey(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,bits256 pubkey); -int32_t smartaddress_pubkey33(struct supernet_info *myinfo,bits256 *privkeyp,char *symbol,uint8_t *pubkey33); +int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *typestr,double maxbid,double minask); +int32_t smartaddress(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,char *coinaddr); +int32_t smartaddress_pubkey(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,bits256 pubkey); +int32_t smartaddress_pubkey33(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,uint8_t *pubkey33); void iguana_RTreset(struct iguana_info *coin); void iguana_RTpurge(struct iguana_info *coin,int32_t lastheight); From f93668ff3157fd59b6d774098de44211a43c5a54 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 18:18:15 +0300 Subject: [PATCH 0365/2705] Test --- basilisk/smartaddress.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 258419a43..89710c477 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -58,6 +58,7 @@ cJSON *smartaddress_json(struct smartaddress *ap) jaddstr(retjson,"BTC",coinaddr); if ( ap->typejson != 0 ) { + printf("smartjson.(%s)\n",jprint(ap->typejson,0)); //jadd(item,"type",ap->typejson); array = cJSON_CreateArray(); if ( (n= cJSON_GetArraySize(ap->typejson)) > 0 ) @@ -118,6 +119,7 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *sym jdelete(item,"a"); jaddnum(item,"a",minask); } + printf("updated.(%s)\n",jprint(ap->typejson,0)); return(0); } } @@ -132,6 +134,7 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *sym item = cJSON_CreateObject(), jaddstr(item,"type",symbol), jaddi(ap->typejson,item); item = cJSON_CreateObject(), jaddstr(item,"s","KMD"), jaddi(ap->typejson,item); item = cJSON_CreateObject(), jaddstr(item,"s","BTC"), jaddi(ap->typejson,item); + printf("created.(%s)\n",jprint(ap->typejson,0)); ap->privkey = privkey; bitcoin_pubkey33(myinfo->ctx,ap->pubkey33,privkey); calc_rmd160_sha256(ap->rmd160,ap->pubkey33,33); From 79dd18327197517c4b8fa438d5f40580a0f10557 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 18:25:05 +0300 Subject: [PATCH 0366/2705] Test --- basilisk/smartaddress.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 89710c477..af6458bff 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -61,7 +61,7 @@ cJSON *smartaddress_json(struct smartaddress *ap) printf("smartjson.(%s)\n",jprint(ap->typejson,0)); //jadd(item,"type",ap->typejson); array = cJSON_CreateArray(); - if ( (n= cJSON_GetArraySize(ap->typejson)) > 0 ) + if ( is_cJSON_Array(ap->typejson) != 0 && (n= cJSON_GetArraySize(ap->typejson)) > 0 ) { jadd(retjson,"type",jitem(ap->typejson,0)); for (j=1; jnumsmartaddrs < sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs) ) { for (i=0; inumsmartaddrs; i++) @@ -124,7 +124,13 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *sym } } } - jaddistr(ap->typejson,symbol); + item = cJSON_CreateObject(); + strcpy(tmp,symbol), touppercase(tmp), jaddstr(item,"s",tmp); + if ( maxbid != 0. ) + jaddnum(item,"b",maxbid); + if ( minask != 0. ) + jaddnum(item,"a",minask); + jaddi(ap->typejson,item); return(i+1); } ap = &myinfo->smartaddrs[myinfo->numsmartaddrs]; From 58afe44674c0cf2f246fdfbab97c7b8eff679525 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 18:29:36 +0300 Subject: [PATCH 0367/2705] Test --- basilisk/smartaddress.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index af6458bff..d9bc0c8ac 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -89,7 +89,7 @@ cJSON *smartaddress_json(struct smartaddress *ap) int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol,double maxbid,double minask) { - char coinaddr[64],*jsym,tmp[64]; uint8_t addrtype,rmd160[20]; cJSON *item; struct smartaddress *ap; int32_t i,j,n; + char coinaddr[64],*jsym,tmp[64]; uint8_t addrtype,rmd160[20]; cJSON *item,*nitem; struct smartaddress *ap; int32_t i,j,n; if ( myinfo->numsmartaddrs < sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs) ) { for (i=0; inumsmartaddrs; i++) @@ -107,18 +107,11 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *sym jsym = jstr(item,"s"); if ( jsym != 0 && strcmp(jsym,symbol) == 0 ) { - if ( maxbid != 0. ) - { - if ( jobj(item,"b") != 0 ) - jdelete(item,"b"); - jaddnum(item,"b",maxbid); - } - if ( minask != 0. ) - { - if ( jobj(item,"a") != 0 ) - jdelete(item,"a"); - jaddnum(item,"a",minask); - } + nitem = cJSON_CreateObject(); + jaddstr(nitem,"s",symbol); + jaddnum(nitem,"b",maxbid); + jaddnum(nitem,"a",minask); + cJSON_ReplaceItemInArray(ap->typejson,j,nitem); printf("updated.(%s)\n",jprint(ap->typejson,0)); return(0); } From 03e62bb9a7f96e0e93db773b88949631cce1e82f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 18:48:02 +0300 Subject: [PATCH 0368/2705] Test --- basilisk/smartaddress.c | 105 ++++++++++++++++------------------------ iguana/iguana777.h | 6 ++- 2 files changed, 47 insertions(+), 64 deletions(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index d9bc0c8ac..8380eb9ea 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -51,35 +51,27 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty cJSON *smartaddress_json(struct smartaddress *ap) { - char coinaddr[64],*symbol; int32_t j,n; struct iguana_info *coin; cJSON *array,*ritem,*item,*retjson = cJSON_CreateObject(); + char coinaddr[64]; int32_t j,n; struct iguana_info *coin; cJSON *array,*item,*retjson; + retjson = cJSON_CreateObject(); + jaddstr(retjson,"type",ap->typestr); bitcoin_address(coinaddr,60,ap->pubkey33,33); jaddstr(retjson,"KMD",coinaddr); bitcoin_address(coinaddr,0,ap->pubkey33,33); jaddstr(retjson,"BTC",coinaddr); - if ( ap->typejson != 0 ) + if ( (n= ap->numsymbols) > 0 ) { - printf("smartjson.(%s)\n",jprint(ap->typejson,0)); - //jadd(item,"type",ap->typejson); array = cJSON_CreateArray(); - if ( is_cJSON_Array(ap->typejson) != 0 && (n= cJSON_GetArraySize(ap->typejson)) > 0 ) + for (j=0; jtypejson,0)); - for (j=1; jsymbols[j].symbol)) != 0 ) { - item = jitem(ap->typejson,j); - if ( (symbol= jstr(item,"s")) != 0 ) - { - if ( (coin= iguana_coinfind(symbol)) != 0 ) - { - bitcoin_address(coinaddr,coin->chain->pubtype,ap->pubkey33,33); - ritem = cJSON_CreateObject(); - jaddstr(ritem,"coin",symbol); - jaddstr(ritem,"address",coinaddr); - jaddnum(ritem,"maxbid",jdouble(item,"b")); - jaddnum(ritem,"minask",jdouble(item,"a")); - jaddi(array,ritem); - } - } + bitcoin_address(coinaddr,coin->chain->pubtype,ap->pubkey33,33); + item = cJSON_CreateObject(); + jaddstr(item,"coin",coin->symbol); + jaddstr(item,"address",coinaddr); + jaddnum(item,"maxbid",ap->symbols[j].maxbid); + jaddnum(item,"minask",ap->symbols[j].minask); + jaddi(array,item); } } jadd(retjson,"coins",array); @@ -87,53 +79,45 @@ cJSON *smartaddress_json(struct smartaddress *ap) return(retjson); } +void smartaddress_symboladd(struct smartaddress *ap,char *symbol,double maxbid,double minask) +{ + struct smartaddress_symbol *sp; + ap->symbols = realloc(ap->symbols,(ap->numsymbols+1) * sizeof(*ap->symbols)); + sp = &ap->symbols[ap->numsymbols++]; + memset(sp,0,sizeof(*sp)); + safecopy(sp->symbol,symbol,sizeof(sp->symbol)); + sp->maxbid = maxbid; + sp->minask = minask; +} + int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol,double maxbid,double minask) { - char coinaddr[64],*jsym,tmp[64]; uint8_t addrtype,rmd160[20]; cJSON *item,*nitem; struct smartaddress *ap; int32_t i,j,n; + char coinaddr[64]; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; int32_t i,j,n; if ( myinfo->numsmartaddrs < sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs) ) { for (i=0; inumsmartaddrs; i++) if ( bits256_cmp(myinfo->smartaddrs[i].privkey,privkey) == 0 ) { ap = &myinfo->smartaddrs[i]; - if ( ap->typejson == 0 ) - return(-1); - else + n = ap->numsymbols; + for (j=0; jtypejson); - for (j=0; jsymbols[j].symbol,symbol) == 0 ) { - item = jitem(ap->typejson,j); - jsym = jstr(item,"s"); - if ( jsym != 0 && strcmp(jsym,symbol) == 0 ) - { - nitem = cJSON_CreateObject(); - jaddstr(nitem,"s",symbol); - jaddnum(nitem,"b",maxbid); - jaddnum(nitem,"a",minask); - cJSON_ReplaceItemInArray(ap->typejson,j,nitem); - printf("updated.(%s)\n",jprint(ap->typejson,0)); - return(0); - } + ap->symbols[j].maxbid = maxbid; + ap->symbols[j].minask = minask; + return(0); } } - item = cJSON_CreateObject(); - strcpy(tmp,symbol), touppercase(tmp), jaddstr(item,"s",tmp); - if ( maxbid != 0. ) - jaddnum(item,"b",maxbid); - if ( minask != 0. ) - jaddnum(item,"a",minask); - jaddi(ap->typejson,item); + smartaddress_symboladd(ap,symbol,maxbid,minask); return(i+1); } ap = &myinfo->smartaddrs[myinfo->numsmartaddrs]; - ap->typejson = cJSON_CreateArray(); + smartaddress_symboladd(ap,"KMD",0.,0.); + smartaddress_symboladd(ap,"BTC",0.,0.); if ( smartaddress_type(symbol) < 0 ) return(-1); - item = cJSON_CreateObject(), jaddstr(item,"type",symbol), jaddi(ap->typejson,item); - item = cJSON_CreateObject(), jaddstr(item,"s","KMD"), jaddi(ap->typejson,item); - item = cJSON_CreateObject(), jaddstr(item,"s","BTC"), jaddi(ap->typejson,item); - printf("created.(%s)\n",jprint(ap->typejson,0)); + strcpy(ap->typestr,symbol); ap->privkey = privkey; bitcoin_pubkey33(myinfo->ctx,ap->pubkey33,privkey); calc_rmd160_sha256(ap->rmd160,ap->pubkey33,33); @@ -163,21 +147,16 @@ int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symb int32_t smartaddress_symbolmatch(char *typestr,double *bidaskp,struct smartaddress *ap,char *symbol) { - int32_t j,n; char *str; cJSON *item; - if ( ap->typejson != 0 && (n= cJSON_GetArraySize(ap->typejson)) > 0 ) + int32_t j,n; + strcpy(typestr,ap->typestr); + if ( (n= ap->numsymbols) > 0 ) { - item = jitem(ap->typejson,0); - if ( (str= jstr(item,"type")) != 0 ) - strncpy(typestr,str,63); - else typestr[0] = 0; - for (j=1; jtypejson,j); - str = jstr(item,"s"); - if ( str != 0 && strcmp(str,symbol) == 0 ) + if ( strcmp(ap->symbols[j].symbol,symbol) == 0 ) { - bidaskp[0] = jdouble(item,"b"); - bidaskp[1] = jdouble(item,"a"); + bidaskp[0] = ap->symbols[j].maxbid; + bidaskp[1] = ap->symbols[j].minask; return(j); } } diff --git a/iguana/iguana777.h b/iguana/iguana777.h index ddcac1286..b7e0996b1 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -95,11 +95,15 @@ struct supernet_address char NXTADDR[32],BTC[64],BTCD[64]; }; +struct smartaddress_symbol { double maxbid,minask; char symbol[16]; }; + struct smartaddress { bits256 privkey,pubkey; - cJSON *typejson; + int32_t numsymbols; uint8_t pubkey33[33],rmd160[20]; + char typestr[16]; + struct smartaddress_symbol *symbols; }; struct pending_trade { UT_hash_handle hh; double basevolume,relvolume,dir; char base[32],rel[32]; }; From 809bdef00328a77173eba0452da7abdadb8f3c6d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 18:52:31 +0300 Subject: [PATCH 0369/2705] Test --- iguana/tests/smartadd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/tests/smartadd b/iguana/tests/smartadd index d39448cde..4aa80fa54 100755 --- a/iguana/tests/smartadd +++ b/iguana/tests/smartadd @@ -1,3 +1,3 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"coin\",\"symbol\":\"coin\"}" # first time -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"coin\",\"symbol\":\"OTHER\",\"maxbid\":0.0002,\"minask\":0.0001}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"usd\",\"symbol\":\"USD\"}" # first time +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"usd\",\"symbol\":\"LTC\",\"maxbid\":10,\"minask\":10}" From 4137dcd6343a04c4f3abd984491f5aad71a5f5e1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 18:57:37 +0300 Subject: [PATCH 0370/2705] Test --- basilisk/smartaddress.c | 18 +++++++++++------- iguana/tests/smartadd | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 8380eb9ea..ea34fbf50 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -81,13 +81,17 @@ cJSON *smartaddress_json(struct smartaddress *ap) void smartaddress_symboladd(struct smartaddress *ap,char *symbol,double maxbid,double minask) { - struct smartaddress_symbol *sp; - ap->symbols = realloc(ap->symbols,(ap->numsymbols+1) * sizeof(*ap->symbols)); - sp = &ap->symbols[ap->numsymbols++]; - memset(sp,0,sizeof(*sp)); - safecopy(sp->symbol,symbol,sizeof(sp->symbol)); - sp->maxbid = maxbid; - sp->minask = minask; + char tmp[64]; struct smartaddress_symbol *sp; + strcpy(tmp,ap->typestr), touppercase(tmp); + if ( strcmp(tmp,symbol) != 0 ) + { + ap->symbols = realloc(ap->symbols,(ap->numsymbols+1) * sizeof(*ap->symbols)); + sp = &ap->symbols[ap->numsymbols++]; + memset(sp,0,sizeof(*sp)); + safecopy(sp->symbol,symbol,sizeof(sp->symbol)); + sp->maxbid = maxbid; + sp->minask = minask; + } } int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol,double maxbid,double minask) diff --git a/iguana/tests/smartadd b/iguana/tests/smartadd index 4aa80fa54..41b844ecc 100755 --- a/iguana/tests/smartadd +++ b/iguana/tests/smartadd @@ -1,3 +1,3 @@ #!/bin/bash curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"usd\",\"symbol\":\"USD\"}" # first time -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"usd\",\"symbol\":\"LTC\",\"maxbid\":10,\"minask\":10}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"smartaddress\",\"type\":\"usd\",\"symbol\":\"REVS\",\"maxbid\":0.20,\"minask\":0.10}" From 6e194f180c41b385321f3d63d8152450472d854e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 19:03:51 +0300 Subject: [PATCH 0371/2705] Test --- basilisk/smartaddress.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index ea34fbf50..ebdd339eb 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -54,10 +54,6 @@ cJSON *smartaddress_json(struct smartaddress *ap) char coinaddr[64]; int32_t j,n; struct iguana_info *coin; cJSON *array,*item,*retjson; retjson = cJSON_CreateObject(); jaddstr(retjson,"type",ap->typestr); - bitcoin_address(coinaddr,60,ap->pubkey33,33); - jaddstr(retjson,"KMD",coinaddr); - bitcoin_address(coinaddr,0,ap->pubkey33,33); - jaddstr(retjson,"BTC",coinaddr); if ( (n= ap->numsymbols) > 0 ) { array = cJSON_CreateArray(); @@ -91,6 +87,7 @@ void smartaddress_symboladd(struct smartaddress *ap,char *symbol,double maxbid,d safecopy(sp->symbol,symbol,sizeof(sp->symbol)); sp->maxbid = maxbid; sp->minask = minask; + printf("symboladd (%s) <- (%s %f %f)\n",ap->typestr,symbol,maxbid,minask); } } From 13836242aab0b10c6004ea429683f617e5d3e0d7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 19:09:48 +0300 Subject: [PATCH 0372/2705] Test --- basilisk/basilisk.c | 4 ++-- basilisk/smartaddress.c | 14 +++++++------- iguana/iguana_wallet.c | 4 ++-- includes/iguana_funcs.h | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 094c8e5de..b514cbe19 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1364,7 +1364,7 @@ STRING_ARG(jumblr,setpassphrase,passphrase) retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); - smartaddress_add(myinfo,privkey,"deposit",0.,0.); + smartaddress_add(myinfo,privkey,"deposit","KMD",0.,0.); myinfo->jumblr_depositkey = curve25519(privkey,curve25519_basepoint9()); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); if ( coin->FULLNODE < 0 ) @@ -1379,7 +1379,7 @@ STRING_ARG(jumblr,setpassphrase,passphrase) jaddnum(retjson,"BTCdeposits",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); } privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); - smartaddress_add(myinfo,privkey,"jumblr",0.,0.); + smartaddress_add(myinfo,privkey,"jumblr","KMD",0.,0.); myinfo->jumblr_pubkey = curve25519(privkey,curve25519_basepoint9()); jaddstr(retjson,"KMDjumblr",KMDaddr); jaddstr(retjson,"BTCjumblr",BTCaddr); diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index ebdd339eb..57ea4684f 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -91,7 +91,7 @@ void smartaddress_symboladd(struct smartaddress *ap,char *symbol,double maxbid,d } } -int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol,double maxbid,double minask) +int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *type,char *symbol,double maxbid,double minask) { char coinaddr[64]; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; int32_t i,j,n; if ( myinfo->numsmartaddrs < sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs) ) @@ -114,11 +114,11 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *sym return(i+1); } ap = &myinfo->smartaddrs[myinfo->numsmartaddrs]; - smartaddress_symboladd(ap,"KMD",0.,0.); - smartaddress_symboladd(ap,"BTC",0.,0.); if ( smartaddress_type(symbol) < 0 ) return(-1); - strcpy(ap->typestr,symbol); + strcpy(ap->typestr,type); + smartaddress_symboladd(ap,"KMD",0.,0.); + smartaddress_symboladd(ap,"BTC",0.,0.); ap->privkey = privkey; bitcoin_pubkey33(myinfo->ctx,ap->pubkey33,privkey); calc_rmd160_sha256(ap->rmd160,ap->pubkey33,33); @@ -137,11 +137,11 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *sym return(-1); } -int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *symbol,double maxbid,double minask) +int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *type,char *symbol,double maxbid,double minask) { int32_t retval; portable_mutex_lock(&myinfo->smart_mutex); - retval = _smartaddress_add(myinfo,privkey,symbol,maxbid,minask); + retval = _smartaddress_add(myinfo,privkey,type,symbol,maxbid,minask); portable_mutex_unlock(&myinfo->smart_mutex); return(retval); } @@ -267,7 +267,7 @@ TWO_STRINGS_AND_TWO_DOUBLES(InstantDEX,smartaddress,type,symbol,maxbid,minask) return(clonestr("{\"error\":\"non-supported smartaddress symbol\"}")); bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); bitcoin_address(coinaddr,coin->chain->pubtype,pubkey33,33); - smartaddress_add(myinfo,privkey,symbol,maxbid,minask); + smartaddress_add(myinfo,privkey,type,symbol,maxbid,minask); return(InstantDEX_smartaddresses(myinfo,0,0,0)); } diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index d6189ebb0..e077f2192 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -1377,8 +1377,8 @@ TWOSTRINGS_AND_INT(bitcoinrpc,walletpassphrase,password,permanentfile,timeout) sprintf(jumblr_passphrase,"jumblr %s",password); if ( (jumblrstr= jumblr_setpassphrase(myinfo,0,0,0,jumblr_passphrase)) != 0 ) free(jumblrstr); - smartaddress_add(myinfo,myinfo->persistent_priv,"kmd",0.,0.); - smartaddress_add(myinfo,myinfo->persistent_priv,"btc",0.,0.); + smartaddress_add(myinfo,myinfo->persistent_priv,"kmd","BTC",0.,0.); + smartaddress_add(myinfo,myinfo->persistent_priv,"btc","KMD",0.,0.); } //basilisk_unspents_update(myinfo,coin); return(retstr); diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index 9a1469933..a816b319a 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -606,7 +606,7 @@ void dpow_nanomsginit(struct supernet_info *myinfo,char *ipaddr); int32_t iguana_datachain_scan(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t rmd160[20]); int32_t basilisk_requests_poll(struct supernet_info *myinfo); void dpow_psockloop(void *_ptr); -int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *typestr,double maxbid,double minask); +int32_t smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *typestr,char *symbol,double maxbid,double minask); int32_t smartaddress(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,char *coinaddr); int32_t smartaddress_pubkey(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,bits256 pubkey); int32_t smartaddress_pubkey33(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,uint8_t *pubkey33); From 39f7557f58f974ca1fa934a8ece3318b1fb0214a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 24 Apr 2017 19:15:20 +0300 Subject: [PATCH 0373/2705] Test --- basilisk/smartaddress.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 57ea4684f..e5767a0b6 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -97,9 +97,10 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *typ if ( myinfo->numsmartaddrs < sizeof(myinfo->smartaddrs)/sizeof(*myinfo->smartaddrs) ) { for (i=0; inumsmartaddrs; i++) - if ( bits256_cmp(myinfo->smartaddrs[i].privkey,privkey) == 0 ) + { + ap = &myinfo->smartaddrs[i]; + if ( strcmp(type,ap->typestr) == 0 && bits256_cmp(ap->privkey,privkey) == 0 ) { - ap = &myinfo->smartaddrs[i]; n = ap->numsymbols; for (j=0; jsmartaddrs[myinfo->numsmartaddrs]; if ( smartaddress_type(symbol) < 0 ) return(-1); From 6a4d56a00a99fab3c2233e4573f04dda0c1bd062 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 25 Apr 2017 14:41:14 +0300 Subject: [PATCH 0374/2705] Utxo test --- .gitignore | 10 ++++++++++ iguana/dpow/dpow_rpc.c | 9 +++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index b775d5e60..c45ac00b2 100755 --- a/.gitignore +++ b/.gitignore @@ -220,3 +220,13 @@ iguana/confs/630929d976025fafde221c7358eb5805f4359bad3c6b8bd50ad3f6e0a9b5ce78 iguana/confs/5f3283a017c31e52443d61cb43944e2157f7c03eb12d701ebf4a35a695688e1f iguana/3193054754-2514575257 + +iguana/DB/SWAPS/2723832060-1788071166 + +*.alicepayment + +*.finished + +*.myfee + +iguana/DB/SWAPS/3213598586-2281632307 diff --git a/iguana/dpow/dpow_rpc.c b/iguana/dpow/dpow_rpc.c index f8ffded08..2fed337f6 100755 --- a/iguana/dpow/dpow_rpc.c +++ b/iguana/dpow/dpow_rpc.c @@ -772,7 +772,7 @@ int32_t dpow_vini_ismine(struct supernet_info *myinfo,struct dpow_info *dp,cJSON int32_t dpow_haveutxo(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *txidp,int32_t *voutp,char *coinaddr) { - int32_t i,j,n,vout,haveutxo = 0; uint32_t r; bits256 txid; cJSON *unspents,*item; uint64_t satoshis; char *str,*address; uint8_t script[35]; + int32_t vout,haveutxo = 0; uint32_t i,j,n,r; bits256 txid; cJSON *unspents,*item; uint64_t satoshis; char *str,*address; uint8_t script[35]; memset(txidp,0,sizeof(*txidp)); *voutp = -1; if ( (unspents= dpow_listunspent(myinfo,coin,coinaddr)) != 0 ) @@ -788,9 +788,10 @@ int32_t dpow_haveutxo(struct supernet_info *myinfo,struct iguana_info *coin,bits "confirmations" : 4282, "spendable" : true },*/ - r = 0; - memcpy(&r,coin->symbol,3); - r = calc_crc32(0,(void *)&r,sizeof(r)); + //r = 0; + //memcpy(&r,coin->symbol,3); + //r = calc_crc32(0,(void *)&r,sizeof(r)); + OS_randombytes((uint8_t *)&r,sizeof(r)); for (j=0; j Date: Wed, 26 Apr 2017 09:17:33 +0300 Subject: [PATCH 0375/2705] Run silent --- basilisk/basilisk.c | 13 +++++++++++++ basilisk/jumblr.c | 27 +++++++++++++++------------ iguana/dpow/dpow_rpc.c | 9 +++++---- iguana/iguana777.h | 2 +- includes/iguana_apideclares.h | 2 ++ 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index b514cbe19..9c56e49f4 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1395,6 +1395,18 @@ STRING_ARG(jumblr,setpassphrase,passphrase) } } +ZERO_ARGS(jumblr,runsilent) +{ + myinfo->runsilent = 1; + return(clonestr("{\"result\":\"success\",\"mode\":\"runsilent\"}")); +} + +ZERO_ARGS(jumblr,totransparent) +{ + myinfo->runsilent = 0; + return(clonestr("{\"result\":\"success\",\"mode\":\"totransparent\"}")); +} + ZERO_ARGS(jumblr,status) { cJSON *retjson; char KMDaddr[64],BTCaddr[64]; struct jumblr_item *ptr,*tmp; struct iguana_info *coinbtc; int64_t received,deposited,jumblred,step_t2z,step_z2z,step_z2t,finished,pending,maxval,minval; @@ -1404,6 +1416,7 @@ ZERO_ARGS(jumblr,status) retjson = cJSON_CreateObject(); step_t2z = step_z2z = step_z2t = deposited = finished = pending = 0; jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); + jaddstr(retjson,"mode",myinfo->runsilent == 0 ? "totransparent" : "runsilent"); jaddstr(retjson,"KMDdeposit",KMDaddr); jaddstr(retjson,"BTCdeposit",BTCaddr); if ( (coinbtc= iguana_coinfind("BTC")) != 0 ) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 305854030..05857fa8f 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -697,11 +697,11 @@ void jumblr_CMCname(char *CMCname,char *symbol) void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32_t toKMD) { double vol,avail; int32_t enabled = 0; struct iguana_info *kmdcoin,*coinbtc = 0; - kmdcoin = iguana_coinfind("KMD"); - coinbtc = iguana_coinfind("BTC"); //printf("jumblr_DEXcheck numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 || myinfo->secret[0] == 0 ) return; + kmdcoin = iguana_coinfind("KMD"); + coinbtc = iguana_coinfind("BTC"); if ( kmdcoin == 0 || coinbtc == 0 ) return; jumblr_DEXupdate(myinfo,kmdcoin,"KMD","komodo",0.,0.); @@ -847,21 +847,24 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 } break; case 2: // z -> public - jumblr_opidsupdate(myinfo,coin); - HASH_ITER(hh,myinfo->jumblrs,ptr,tmp) + if ( myinfo->runsilent == 0 ) { - if ( jumblr_addresstype(myinfo,coin,ptr->src) == 'z' && jumblr_addresstype(myinfo,coin,ptr->dest) == 'z' ) + jumblr_opidsupdate(myinfo,coin); + HASH_ITER(hh,myinfo->jumblrs,ptr,tmp) { - if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN ) + if ( jumblr_addresstype(myinfo,coin,ptr->src) == 'z' && jumblr_addresstype(myinfo,coin,ptr->dest) == 'z' ) { - privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); - if ( (retstr= jumblr_sendz_to_t(myinfo,coin,ptr->dest,KMDaddr,dstr(total))) != 0 ) + if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN ) { - printf("sendz_to_t.(%s)\n",retstr); - free(retstr); + privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); + if ( (retstr= jumblr_sendz_to_t(myinfo,coin,ptr->dest,KMDaddr,dstr(total))) != 0 ) + { + printf("sendz_to_t.(%s)\n",retstr); + free(retstr); + } + ptr->spent = (uint32_t)time(NULL); + break; } - ptr->spent = (uint32_t)time(NULL); - break; } } } diff --git a/iguana/dpow/dpow_rpc.c b/iguana/dpow/dpow_rpc.c index 9268e6df7..0185a2f77 100755 --- a/iguana/dpow/dpow_rpc.c +++ b/iguana/dpow/dpow_rpc.c @@ -772,7 +772,7 @@ int32_t dpow_vini_ismine(struct supernet_info *myinfo,struct dpow_info *dp,cJSON int32_t dpow_haveutxo(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *txidp,int32_t *voutp,char *coinaddr) { - int32_t i,j,n,vout,haveutxo = 0; uint32_t r; bits256 txid; cJSON *unspents,*item; uint64_t satoshis; char *str,*address; uint8_t script[35]; + int32_t vout,haveutxo = 0; uint32_t i,j,n,r; bits256 txid; cJSON *unspents,*item; uint64_t satoshis; char *str,*address; uint8_t script[35]; memset(txidp,0,sizeof(*txidp)); *voutp = -1; if ( (unspents= dpow_listunspent(myinfo,coin,coinaddr)) != 0 ) @@ -788,9 +788,10 @@ int32_t dpow_haveutxo(struct supernet_info *myinfo,struct iguana_info *coin,bits "confirmations" : 4282, "spendable" : true },*/ - r = 0; - memcpy(&r,coin->symbol,3); - r = calc_crc32(0,(void *)&r,sizeof(r)); + //r = 0; + //memcpy(&r,coin->symbol,3); + //r = calc_crc32(0,(void *)&r,sizeof(r)); + OS_randombytes((uint8_t *)&r,sizeof(r)); for (j=0; j Date: Wed, 26 Apr 2017 16:46:21 +0300 Subject: [PATCH 0376/2705] Test --- basilisk/basilisk.h | 4 + basilisk/jumblr.c | 147 ----------------- basilisk/smartaddress.c | 336 +++++++++++++++++++++++++++++++++++++- iguana/main.c | 9 +- includes/iguana_funcs.h | 2 +- includes/iguana_structs.h | 4 +- 6 files changed, 343 insertions(+), 159 deletions(-) diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index 044ff75fa..8d0c3da9d 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -42,6 +42,10 @@ #define INSTANTDEX_BTC "1KRhTPvoxyJmVALwHFXZdeeWFbcJSbkFPu" #define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" +#define JUMBLR_INCR 99.65 +#define JUMBLR_FEE 0.001 +#define JUMBLR_TXFEE 0.01 + struct basilisk_swap; struct basilisk_rawtxinfo diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 05857fa8f..e7144fb57 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -27,11 +27,8 @@ z_sendmany "fromaddress" [{"address":... ,"amount":..., "memo":""},...] ( minconf ) ( fee ) */ -#define JUMBLR_INCR 99.65 -#define JUMBLR_TXFEE 0.01 #define JUMBLR_ADDR "RGhxXpXSSBTBm9EvNsXnTQczthMCxHX91t" #define JUMBLR_BTCADDR "18RmTJe9qMech8siuhYfMtHo8RtcN1obC6" -#define JUMBLR_FEE 0.001 int32_t jumblr_addresstype(struct supernet_info *myinfo,struct iguana_info *coin,char *addr) { @@ -642,150 +639,6 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_inf } } -void jumblr_DEXupdate(struct supernet_info *myinfo,struct iguana_info *coin,char *symbol,char *CMCname,double BTC2KMD,double KMDavail) -{ - double avebid,aveask,highbid,lowask,CMC_average,changes[3],estfee,estbtcfee; struct iguana_info *kmdcoin; struct DEXcoin_info *ptr = &coin->DEXinfo; - // wait for one confirmation to clear most in mempool (ha, ha) - // deal with changing addresses, ie all pendings? - estfee = 0.0001; - estbtcfee = 0.0015; - if ( coin != 0 && (kmdcoin= iguana_coinfind("KMD")) != 0 && time(NULL) > ptr->lasttime+60 ) - { - ptr->coin = coin; - if ( strcmp(symbol,ptr->symbol) != 0 ) - { - safecopy(ptr->symbol,symbol,sizeof(ptr->symbol)); - safecopy(ptr->CMCname,CMCname,sizeof(ptr->CMCname)); - } - //if ( ptr->depositaddr[0] == 0 ) - { - if ( strcmp("KMD",symbol) == 0 ) - ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,0,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); - else ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,ptr->coin->chain->pubtype,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); - } - //if ( ptr->jumblraddr[0] == 0 ) - { - if ( strcmp("KMD",symbol) == 0 ) - ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,0,ptr->KMDjumblraddr,""); - else ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,ptr->coin->chain->pubtype,ptr->KMDjumblraddr,""); - } - ptr->avail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->depositaddr)); - ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,CMCname,symbol,"BTC",&ptr->USD_average); - KMDavail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->KMDjumblraddr)); - if ( strcmp("KMD",symbol) == 0 ) - { - ptr->BTC2KMD = ptr->btcprice; - ptr->kmdprice = 1.; - ptr->KMDavail = KMDavail; - } - else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) - { - ptr->kmdprice = ptr->btcprice / BTC2KMD; - ptr->KMDavail = KMDavail; - } - ptr->lasttime = (uint32_t)time(NULL); - printf("%s avail %.8f KMDavail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,KMDavail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); - } // else printf("skip\n"); -} - -void jumblr_CMCname(char *CMCname,char *symbol) -{ - if ( strcmp(symbol,"KMD") == 0 ) - strcpy(CMCname,"komodo"); -} - -void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32_t toKMD) -{ - double vol,avail; int32_t enabled = 0; struct iguana_info *kmdcoin,*coinbtc = 0; - //printf("jumblr_DEXcheck numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); - if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 || myinfo->secret[0] == 0 ) - return; - kmdcoin = iguana_coinfind("KMD"); - coinbtc = iguana_coinfind("BTC"); - if ( kmdcoin == 0 || coinbtc == 0 ) - return; - jumblr_DEXupdate(myinfo,kmdcoin,"KMD","komodo",0.,0.); - if ( strcmp(coin->symbol,"KMD") != 0 && strcmp(coin->symbol,"BTC") != 0 && kmdcoin->DEXinfo.btcprice > 0. ) - { - if ( coin->CMCname[0] == 0 ) - jumblr_CMCname(coin->CMCname,coin->symbol); - if ( coin->CMCname[0] != 0 ) - jumblr_DEXupdate(myinfo,coin,coin->symbol,coin->CMCname,kmdcoin->DEXinfo.btcprice,kmdcoin->DEXinfo.avail); - } - if ( myinfo->numswaps == 0 || (kmdcoin->FULLNODE < 0 && coinbtc->FULLNODE < 0) ) - enabled = 1; - if ( enabled != 0 && myinfo->IAMLP == 0 && kmdcoin->DEXinfo.btcprice > SMALLVAL ) - { - double minbtc,minkmd,btcavail; char *retstr; cJSON *vals; bits256 hash; - minbtc = (kmdcoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); - btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); - avail = (btcavail - coinbtc->DEXinfo.DEXpending); - printf("BTC.%d deposits %.8f, min %.8f avail %.8f pending %.8f\n",toKMD,btcavail,minbtc,avail,coinbtc->DEXinfo.DEXpending); - if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + coinbtc->DEXinfo.DEXpending) ) - { - /*if ( avail >= (100. * minbtc) ) - vol = (100. * minbtc); - else if ( avail >= (10. * minbtc) ) - vol = (10. * minbtc); - else*/ - if ( avail >= minbtc ) - vol = minbtc; - else vol = 0.; - if ( vol > 0. ) - { - vals = cJSON_CreateObject(); - jaddstr(vals,"source","BTC"); - jaddstr(vals,"dest","KMD"); - jaddnum(vals,"amount",vol); - jaddnum(vals,"minprice",0.985/kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"usejumblr",1); - jaddnum(vals,"DEXselector",1); - memset(hash.bytes,0,sizeof(hash)); - coinbtc->DEXinfo.DEXpending += vol; - if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) - { - printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); - free(retstr); - } - free_json(vals); - // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" - } - } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); - minkmd = 100.; - avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.DEXpending); - printf("KMD.%d deposits %.8f, min %.8f, avail %.8f pending %.8f\n",toKMD,kmdcoin->DEXinfo.KMDavail,minkmd,avail,kmdcoin->DEXinfo.DEXpending); - if ( toKMD != 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.DEXpending) ) - { - /*if ( avail > 100.*JUMBLR_INCR ) - vol = 100.*JUMBLR_INCR; - else if ( avail > 10.*JUMBLR_INCR ) - vol = 10.*JUMBLR_INCR; - else*/ if ( avail >= JUMBLR_INCR ) - vol = JUMBLR_INCR; - else vol = 0.; - if ( vol > 0. ) - { - vals = cJSON_CreateObject(); - jaddstr(vals,"source","KMD"); - jaddstr(vals,"dest","BTC"); - jaddnum(vals,"amount",vol); - //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"minprice",0.985 * kmdcoin->DEXinfo.btcprice); - jaddnum(vals,"usejumblr",2); - memset(hash.bytes,0,sizeof(hash)); - kmdcoin->DEXinfo.DEXpending += vol; - jaddnum(vals,"DEXselector",2); - if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) - { - printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); - free(retstr); - } - free_json(vals); - } - } else printf("kmdavail %.8f pending %.8f\n",kmdcoin->DEXinfo.KMDavail,kmdcoin->DEXinfo.DEXpending); - } else printf("notlp.%d kmdprice %.8f\n",myinfo->IAMLP,kmdcoin->DEXinfo.btcprice); -} - void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval) { //static uint32_t lasttime; diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index e5767a0b6..dae45ecbb 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -24,15 +24,16 @@ int32_t smartaddress_type(char *typestr) { char upper[64]; - if ( strcmp(typestr,"deposit") != 0 && strcmp(typestr,"jumblr") != 0 ) + if ( strcmp(typestr,"deposit") != 0 && strcmp(typestr,"jumblr") != 0 && strcmp(typestr,"dividend") != 0 && strcmp(typestr,"pangea") != 0 ) { upper[sizeof(upper)-1] = 0; strncpy(upper,typestr,sizeof(upper)-1); touppercase(upper); if ( iguana_coinfind(upper) != 0 ) return(0); + else return(-1); } - return(-1); + return(1); } bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubtype,char *KMDaddr,char *prefix) @@ -49,6 +50,16 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty return(privkey); } +cJSON *smartaddress_extrajson(struct smartaddress *ap) +{ + cJSON *retjson = cJSON_CreateObject(); + if ( strcmp(ap->typestr,"dividend") == 0 ) + { + + } + return(retjson); +} + cJSON *smartaddress_json(struct smartaddress *ap) { char coinaddr[64]; int32_t j,n; struct iguana_info *coin; cJSON *array,*item,*retjson; @@ -67,6 +78,7 @@ cJSON *smartaddress_json(struct smartaddress *ap) jaddstr(item,"address",coinaddr); jaddnum(item,"maxbid",ap->symbols[j].maxbid); jaddnum(item,"minask",ap->symbols[j].minask); + jadd(item,"extra",smartaddress_extrajson(ap)); jaddi(array,item); } } @@ -91,6 +103,29 @@ void smartaddress_symboladd(struct smartaddress *ap,char *symbol,double maxbid,d } } +void smartaddress_minmaxupdate(struct supernet_info *myinfo,char *_type,char *_symbol,double maxbid,double minask) +{ + char type[64],symbol[64]; int32_t i,j,n; struct smartaddress *ap; + strcpy(type,_type), tolowercase(type); + strcpy(symbol,_symbol), touppercase(symbol); + for (i=0; inumsmartaddrs; i++) + { + ap = &myinfo->smartaddrs[i]; + if ( strcmp(type,ap->typestr) == 0 ) + { + n = ap->numsymbols; + for (j=0; jsymbols[j].symbol,symbol) == 0 ) + { + dxblend(&ap->symbols[j].maxbid,maxbid,0.5); + dxblend(&ap->symbols[j].minask,minask,0.5); + } + } + } + } +} + int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *type,char *symbol,double maxbid,double minask) { char coinaddr[64]; uint8_t addrtype,rmd160[20]; struct smartaddress *ap; int32_t i,j,n; @@ -108,6 +143,8 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *typ { ap->symbols[j].maxbid = maxbid; ap->symbols[j].minask = minask; + if ( maxbid > SMALLVAL && minask > SMALLVAL && smartaddress_type(type) == 0 ) + smartaddress_minmaxupdate(myinfo,symbol,type,1./minask,1./maxbid); return(0); } } @@ -230,6 +267,301 @@ int32_t smartaddress_pubkey33(struct supernet_info *myinfo,char *typestr,double return(retval); } +void smartaddress_CMCname(char *CMCname,char *symbol) +{ + if ( strcmp(symbol,"KMD") == 0 ) + strcpy(CMCname,"komodo"); + else if ( strcmp(symbol,"BTC") == 0 ) + strcpy(CMCname,"bitcoin"); +} + +void smartaddress_coinupdate(struct supernet_info *myinfo,char *symbol,double BTC2KMD,double KMDavail,double KMD2USD) +{ + int32_t r; double avebid,aveask,highbid,lowask,CMC_average,changes[3]; struct iguana_info *coin; struct DEXcoin_info *ptr; + if ( (coin= iguana_coinfind(symbol)) != 0 ) + { + ptr = &coin->DEXinfo; + ptr->coin = coin; + if ( coin->CMCname[0] == 0 ) + smartaddress_CMCname(coin->CMCname,symbol); + r = (((symbol[0]^symbol[1]^symbol[2])&0x7f) % 15) - 7; // 53 to 67 seconds + if ( time(NULL) > (ptr->lasttime + 60 + r) ) + { + if ( strcmp(symbol,ptr->symbol) != 0 ) + { + safecopy(ptr->symbol,symbol,sizeof(ptr->symbol)); + safecopy(ptr->CMCname,coin->CMCname,sizeof(ptr->CMCname)); + } + ptr->deposit_privkey = jumblr_privkey(myinfo,ptr->depositaddr,coin->chain->pubtype,ptr->KMDdepositaddr,JUMBLR_DEPOSITPREFIX); + ptr->jumblr_privkey = jumblr_privkey(myinfo,ptr->jumblraddr,coin->chain->pubtype,ptr->KMDjumblraddr,""); + ptr->avail = dstr(jumblr_balance(myinfo,coin,ptr->depositaddr)); + ptr->jumblravail = dstr(jumblr_balance(myinfo,ptr->coin,ptr->jumblraddr)); + if ( strcmp(symbol,"USD") == 0 ) + { + if ( KMD2USD > SMALLVAL ) + { + ptr->kmdprice = 1./ KMD2USD; + if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) + ptr->btcprice = ptr->kmdprice * BTC2KMD; + } + printf("USD btcprice %.8f kmdprice %.8f\n",ptr->btcprice,ptr->kmdprice); + } + else + { + if ( strcmp(symbol,"BTC") == 0 ) + ptr->btcprice = 1.; + else if ( coin->CMCname[0] != 0 && (ptr->btcprice == 0. || (ptr->counter++ % 10) == 0) ) + ptr->btcprice = get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,coin->CMCname,symbol,"BTC",&ptr->USD_average); + if ( strcmp("KMD",symbol) == 0 ) + ptr->kmdprice = 1.; + else if ( (ptr->BTC2KMD= BTC2KMD) > SMALLVAL ) + ptr->kmdprice = ptr->btcprice / BTC2KMD; + } + ptr->lasttime = (uint32_t)time(NULL); + printf("%s avail %.8f KMDavail %.8f btcprice %.8f deposit.(%s %s) -> jumblr.(%s %s)\n",symbol,ptr->avail,KMDavail,ptr->btcprice,ptr->depositaddr,ptr->KMDdepositaddr,ptr->jumblraddr,ptr->KMDjumblraddr); + } + } // else printf("skip\n"); +} + +void smartaddress_dex(struct supernet_info *myinfo,int32_t selector,struct iguana_info *basecoin,char *coinaddr,double maxavail,struct iguana_info *relcoin,double maxbid,double minask,cJSON *extraobj,double maxvol) +{ + double minamount,minbtc,price,avail,vol,btc2kmd,basebtc,relbtc,baseusd,relusd; char *retstr; cJSON *vals; bits256 hash; + basebtc = basecoin->DEXinfo.btcprice; + relbtc = relcoin->DEXinfo.btcprice; + baseusd = basecoin->DEXinfo.USD_average; + relusd = relcoin->DEXinfo.USD_average; + if ( (btc2kmd= basecoin->DEXinfo.BTC2KMD) < SMALLVAL && (btc2kmd= relcoin->DEXinfo.BTC2KMD) < SMALLVAL ) + return; + minamount = price = 0.; + if ( basebtc < SMALLVAL && relbtc < SMALLVAL ) + return; + if ( basebtc < SMALLVAL || relbtc < SMALLVAL ) + { + if ( (price= maxbid) > SMALLVAL ) + { + if ( basebtc < SMALLVAL ) + basebtc = price * relbtc, printf("calculated basebtc %.8f from (%.8f * %.8f)\n",basebtc,price,relbtc); + else if ( relbtc < SMALLVAL ) + relbtc = basebtc / price, printf("calculated relbtc %.8f from (%.8f / %.8f)\n",relbtc,basebtc,price); // price * relbtc == basebtc + } + } else price = 0.985 * (basebtc / relbtc); + minbtc = btc2kmd * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); + if ( minamount == 0. && basebtc > SMALLVAL ) + minamount = (minbtc / basebtc); + printf("%s/%s minbtc %.8f btcprice %.8f -> minamount %.8f price %.8f vs maxbid %.8f\n",basecoin->symbol,relcoin->symbol,minbtc,basecoin->DEXinfo.btcprice,minamount,price,maxbid); + if ( minamount > SMALLVAL && maxavail > minamount + basecoin->DEXinfo.DEXpending && (maxbid == 0. || price <= maxbid) ) + { + avail = (maxavail - (minamount + basecoin->DEXinfo.DEXpending)); + if ( avail >= (100. * minamount) ) + vol = (100. * minamount); + else if ( avail >= (10. * minamount) ) + vol = (10. * minamount); + else if ( avail >= minamount ) + vol = minamount; + else vol = 0.; + if ( vol > 0. ) + { + vals = cJSON_CreateObject(); + jaddstr(vals,"source",basecoin->symbol); + jaddstr(vals,"dest",relcoin->symbol); + jaddnum(vals,"amount",vol); + jaddnum(vals,"minprice",price); + if ( selector != 0 ) + { + jaddnum(vals,"usejumblr",selector); + jaddnum(vals,"DEXselector",selector); + } + memset(hash.bytes,0,sizeof(hash)); + basecoin->DEXinfo.DEXpending += vol; + if ( (retstr= InstantDEX_request(myinfo,basecoin,0,0,hash,vals,"")) != 0 ) + { + printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); + free(retstr); + } + free_json(vals); + } + } + /* + minbtc = (basecoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); + btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); + avail = (btcavail - coinbtc->DEXinfo.DEXpending); + printf("BTC.%d deposits %.8f, min %.8f avail %.8f pending %.8f\n",toKMD,btcavail,minbtc,avail,coinbtc->DEXinfo.DEXpending); + if ( toKMD == 0 && coinbtc != 0 && btcavail > (minbtc + coinbtc->DEXinfo.DEXpending) ) + { + if ( vol > 0. ) + { + vals = cJSON_CreateObject(); + jaddstr(vals,"source","BTC"); + jaddstr(vals,"dest","KMD"); + jaddnum(vals,"amount",vol); + jaddnum(vals,"minprice",0.985/kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"usejumblr",1); + jaddnum(vals,"DEXselector",1); + memset(hash.bytes,0,sizeof(hash)); + coinbtc->DEXinfo.DEXpending += vol; + if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) + { + printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); + free(retstr); + } + free_json(vals); + // curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"InstantDEX\",\"method\":\"request\",\"vals\":{\"source\":\"KMD\",\"amount\":20,\"dest\":\"USD\",\"minprice\":0.08}}" + } + } //else printf("btcavail %.8f pending %.8f\n",btcavail,pending); + minkmd = 100.; + avail = (kmdcoin->DEXinfo.KMDavail - kmdcoin->DEXinfo.DEXpending); + printf("KMD.%d deposits %.8f, min %.8f, avail %.8f pending %.8f\n",toKMD,kmdcoin->DEXinfo.KMDavail,minkmd,avail,kmdcoin->DEXinfo.DEXpending); + if ( toKMD != 0 && coinbtc != 0 && kmdcoin->DEXinfo.KMDavail > (minkmd + kmdcoin->DEXinfo.DEXpending) ) + { + if ( avail > 100.*JUMBLR_INCR ) + vol = 100.*JUMBLR_INCR; + else if ( avail > 10.*JUMBLR_INCR ) + vol = 10.*JUMBLR_INCR; + else if ( avail >= JUMBLR_INCR ) + vol = JUMBLR_INCR; + else vol = 0.; + if ( vol > 0. ) + { + vals = cJSON_CreateObject(); + jaddstr(vals,"source","KMD"); + jaddstr(vals,"dest","BTC"); + jaddnum(vals,"amount",vol); + //jaddnum(vals,"destamount",JUMBLR_INCR*kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"minprice",0.985 * kmdcoin->DEXinfo.btcprice); + jaddnum(vals,"usejumblr",2); + memset(hash.bytes,0,sizeof(hash)); + kmdcoin->DEXinfo.DEXpending += vol; + jaddnum(vals,"DEXselector",2); + if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 ) + { + printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr); + free(retstr); + } + free_json(vals); + } + } else printf("kmdavail %.8f pending %.8f\n",kmdcoin->DEXinfo.avail,kmdcoin->DEXinfo.DEXpending);*/ +} + +void smartaddress_depositjumblr(struct supernet_info *myinfo,char *symbol,char *coinaddr,double maxbid,double minask,cJSON *extraobj) +{ + struct iguana_info *basecoin,*relcoin; + if ( (basecoin= iguana_coinfind(symbol)) != 0 && (relcoin= iguana_coinfind("KMD")) != 0 ) + { + if ( strcmp(coinaddr,basecoin->DEXinfo.depositaddr) == 0 ) + smartaddress_dex(myinfo,1,basecoin,coinaddr,basecoin->DEXinfo.avail,relcoin,maxbid,minask,extraobj,0.); + else printf("smartaddress_jumblr: mismatch deposit address (%s) vs (%s)\n",coinaddr,basecoin->DEXinfo.depositaddr); + } +} + +double smartaddress_jumblrcredit(struct supernet_info *myinfo,char *symbol) +{ + return(0.); // default to BTC conversion for now +} + +void smartaddress_jumblr(struct supernet_info *myinfo,char *symbol,char *coinaddr,double maxbid,double minask,cJSON *extraobj) +{ + struct iguana_info *basecoin,*relcoin; double credits = 0.; + if ( strcmp("BTC",symbol) != 0 ) + { + if ( (credits= smartaddress_jumblrcredit(myinfo,symbol)) <= 0. ) + return; + } + if ( (basecoin= iguana_coinfind("KMD")) != 0 && (relcoin= iguana_coinfind(symbol)) != 0 ) + { + if ( strcmp(coinaddr,basecoin->DEXinfo.jumblraddr) == 0 ) + smartaddress_dex(myinfo,2,basecoin,coinaddr,basecoin->DEXinfo.jumblravail,relcoin,maxbid,minask,extraobj,credits); + else printf("smartaddress_jumblr: mismatch jumblr address (%s) vs (%s)\n",coinaddr,basecoin->DEXinfo.jumblraddr); + } +} + +void smartaddress_dividend(struct supernet_info *myinfo,char *symbol,char *coinaddr,double maxbid,double minask,cJSON *extraobj) +{ + // support list of weighted addresses, including snapshots +} + +void smartaddress_pangea(struct supernet_info *myinfo,char *symbol,char *coinaddr,double maxbid,double minask,cJSON *extraobj) +{ + // table deposit +} + +void smartaddress_action(struct supernet_info *myinfo,int32_t selector,char *typestr,char *symbol,char *coinaddr,double maxbid,double minask,cJSON *extraobj) +{ + char rel[64]; struct iguana_info *basecoin,*relcoin; double avail; + if ( strcmp(typestr,"deposit") == 0 && selector == 0 ) + smartaddress_depositjumblr(myinfo,symbol,coinaddr,maxbid,minask,extraobj); + else if ( strcmp(typestr,"jumblr") == 0 && selector == 0 ) + smartaddress_jumblr(myinfo,symbol,coinaddr,maxbid,minask,extraobj); + else if ( strcmp(typestr,"dividend") == 0 && selector == 0 ) + smartaddress_dividend(myinfo,symbol,coinaddr,maxbid,minask,extraobj); + else if ( strcmp(typestr,"pangea") == 0 && selector == 0 ) + smartaddress_pangea(myinfo,symbol,coinaddr,maxbid,minask,extraobj); + else + { + safecopy(rel,typestr,sizeof(rel)); + touppercase(rel); + if ( (relcoin= iguana_coinfind(rel)) != 0 && (basecoin= iguana_coinfind(symbol)) != 0 ) + { + if ( myinfo->numswaps == 0 || (basecoin->FULLNODE < 0 && relcoin->FULLNODE < 0) ) + { + if ( (avail= dstr(jumblr_balance(myinfo,basecoin,coinaddr))) > SMALLVAL ) + smartaddress_dex(myinfo,0,basecoin,coinaddr,avail,relcoin,maxbid,minask,extraobj,0.); + } + } + } +} + +void smartaddress_update(struct supernet_info *myinfo,int32_t selector) +{ + double maxbid,minask; char *smartstr,*typestr,*symbol,*address; cJSON *smartarray,*extraobj,*item,*array,*coinitem; int32_t iter,i,n,j,m; struct iguana_info *kmdcoin,*coinbtc = 0; + //printf("smartaddress_update numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); + if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 || myinfo->secret[0] == 0 ) + return; + kmdcoin = iguana_coinfind("KMD"); + coinbtc = iguana_coinfind("BTC"); + if ( kmdcoin == 0 || coinbtc == 0 ) + return; + smartaddress_coinupdate(myinfo,"KMD",0.,0.,0.); // must be first + if ( kmdcoin->DEXinfo.btcprice > SMALLVAL ) + { + if ( (smartstr= InstantDEX_smartaddresses(myinfo,0,0,0)) != 0 ) + { + if ( (smartarray= cJSON_Parse(smartstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(smartarray)) > 0 ) + { + for (iter=0; iter<2; iter++) + { + for (i=0; iDEXinfo.btcprice,kmdcoin->DEXinfo.avail,kmdcoin->DEXinfo.USD_average); + else + { + address = jstr(coinitem,"address"); + maxbid = jdouble(coinitem,"maxbid"); + minask = jdouble(coinitem,"minask"); + extraobj = jobj(coinitem,"extra"); + smartaddress_action(myinfo,selector,typestr,symbol,address,maxbid,minask,extraobj); + } + } + } + } + } + } + free_json(smartarray); + } + free(smartstr); + } + } +} + #include "../includes/iguana_apidefs.h" #include "../includes/iguana_apideclares.h" #include "../includes/iguana_apideclares2.h" diff --git a/iguana/main.c b/iguana/main.c index 0b082e794..5cf2e4bc1 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -753,18 +753,13 @@ void jumblr_loop(void *ptr) printf("JUMBLR loop\n"); while ( myinfo->IAMNOTARY == 0 ) { - if ( (coin= iguana_coinfind("KMD")) != 0 && iguana_coinfind("BTC") != 0 ) + if ( (coin= iguana_coinfind("KMD")) != 0 ) { -//#ifdef __APPLE__ - //if ( (n++ % 10) == 0 ) n++; - jumblr_DEXcheck(myinfo,coin,n & 1);//!((n/10)&1)); -//#endif + smartaddress_update(myinfo,n & 1); if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC - //if ( (n++ % 10) == 0 ) - // jumblr_DEXcheck(myinfo,coin,!((n/10)&1)); t = (uint32_t)time(NULL); if ( (t % (120 * mult)) < 60 ) { diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index a816b319a..8ca911a49 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -629,7 +629,7 @@ int32_t iguana_staker_sort(struct iguana_info *coin,bits256 *hash2p,uint8_t *ref bits256 mpz_div64(bits256 hash,uint64_t divval); void iguana_walletinitcheck(struct supernet_info *myinfo,struct iguana_info *coin); void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval); -void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coin,int32_t toKMD); +void smartaddress_update(struct supernet_info *myinfo,int32_t selector); bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,uint8_t pubtype,char *KMDaddr,char *prefix); char *jumblr_importprivkey(struct supernet_info *myinfo,struct iguana_info *coin,char *wifstr); int64_t iguana_esttxfee(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx,char *signedtx,int32_t numvins); diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index 463faf0f5..3becc3b26 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -472,8 +472,8 @@ struct DEXcoin_info { bits256 deposit_privkey,jumblr_privkey; struct iguana_info *coin; - double btcprice,BTC2KMD,kmdprice,USD_average,DEXpending,KMDpending,maxbid,minask,avail,KMDavail; - uint32_t lasttime; int32_t numpending; + double btcprice,BTC2KMD,kmdprice,USD_average,DEXpending,maxbid,minask,avail,jumblravail; + uint32_t lasttime,counter; int32_t numpending; char CMCname[32],symbol[16],depositaddr[64],KMDdepositaddr[64],KMDjumblraddr[64],jumblraddr[64]; struct jumblr_pending *pending; }; From ddb096b7e0faa5653496ac4c969ef958862b7f1e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 26 Apr 2017 17:03:30 +0300 Subject: [PATCH 0377/2705] Test --- basilisk/smartaddress.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index dae45ecbb..be127b3a5 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -352,11 +352,11 @@ void smartaddress_dex(struct supernet_info *myinfo,int32_t selector,struct iguan if ( minamount > SMALLVAL && maxavail > minamount + basecoin->DEXinfo.DEXpending && (maxbid == 0. || price <= maxbid) ) { avail = (maxavail - (minamount + basecoin->DEXinfo.DEXpending)); - if ( avail >= (100. * minamount) ) + /*if ( avail >= (100. * minamount) ) vol = (100. * minamount); else if ( avail >= (10. * minamount) ) vol = (10. * minamount); - else if ( avail >= minamount ) + else*/ if ( avail >= minamount ) vol = minamount; else vol = 0.; if ( vol > 0. ) From a76b356f5f6a0c4c5f1385b67cbc9e1660cc2974 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 26 Apr 2017 17:18:03 +0300 Subject: [PATCH 0378/2705] Test --- basilisk/smartaddress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index be127b3a5..41b615f96 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -238,6 +238,7 @@ int32_t smartaddress_pubkey(struct supernet_info *myinfo,char *typestr,double *b if ( bits256_cmp(myinfo->smartaddrs[i].pubkey,pubkey) == 0 ) { ap = &myinfo->smartaddrs[i]; + *privkeyp = ap->privkey; if ( (j= smartaddress_symbolmatch(typestr,bidaskp,ap,symbol)) >= 0 ) retval = 0; else retval = (i+1); From 10fb6cb9466f2c58f0e1f2cb616704832433e1ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 26 Apr 2017 17:48:40 +0300 Subject: [PATCH 0379/2705] Test --- basilisk/basilisk_swap.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2111a910a..15fd46543 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1892,7 +1892,22 @@ int32_t basilisk_verify_otherstatebits(struct supernet_info *myinfo,void *ptr,ui return(retval); } else return(-1); } - + +int32_t basilisk_verify_statebits(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t retval = -1; uint32_t statebits; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(swap->I.statebits) ) + { + retval = iguana_rwnum(0,data,sizeof(swap->I.statebits),&statebits); + if ( statebits != swap->I.statebits ) + { + printf("statebits.%x != %x\n",statebits,swap->I.statebits); + return(-1); + } + } + return(retval); +} + int32_t basilisk_verify_choosei(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) { int32_t otherchoosei=-1,i,len = 0; struct basilisk_swap *swap = ptr; @@ -2711,7 +2726,7 @@ cJSON *basilisk_swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { - int32_t i,m,n; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; + int32_t i,m,n,iter; uint8_t pubkey33[33],data[64]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; // statebits 1 -> client, 0 -> LP if ( myinfo->numswaps > 0 ) { @@ -2749,7 +2764,16 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 m = n = 0; if ( bitcoin_swapinit(myinfo,privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) { - basilisk_psockinit(myinfo,swap,statebits == 0); + for (iter=0; iter<3; iter++) + { + basilisk_psockinit(myinfo,swap,statebits == 0); + basilisk_sendstate(myinfo,swap,data,sizeof(data)); + basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); + if ( swap->connected > 0 ) + break; + printf("loopback didntwork with %d %d\n",swap->pushsock,swap->subsock); + sleep(3); + } if ( reinit != 0 ) { if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) From f02b46d696b708bbe0629dbe80bdf69912e4455f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 26 Apr 2017 18:00:40 +0300 Subject: [PATCH 0380/2705] Test --- basilisk/basilisk_swap.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 15fd46543..343b7287d 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2446,10 +2446,10 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, } free_json(retjson); } - printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d)\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock); + printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d) amlp.%d\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock,amlp); free(retstr); } - if ( swap->connected <= 0 && amlp != 0 ) + if ( swap->connected <= 0 && amlp != 0 && subsock >= 0 && pushsock >= 0 ) { if ( (retstr= _dex_psock(myinfo,"{}")) != 0 ) { @@ -2460,25 +2460,30 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, subaddr = jstr(retjson,"subaddr"); if ( pushaddr != 0 && subaddr != 0 ) { - if ( nn_connect(pushsock,pushaddr) >= 0 && nn_connect(subsock,subaddr) >= 0 ) + if ( nn_connect(pushsock,pushaddr) >= 0 ) { - swap->connected = 1; - sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f]}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); - datalen = (int32_t)strlen((char *)data) + 1; - printf("datalen.%d (%s)\n",datalen,(char *)data); - init_hexbytes_noT(databuf,data,datalen); - printf("%s -> %s\n",keystr,databuf); - if ( (retstr2= _dex_kvupdate(myinfo,"KV",keystr,databuf,1)) != 0 ) + printf("connected to %d pushaddr.(%s)\n",pushsock,pushaddr); + if ( nn_connect(subsock,subaddr) >= 0 ) { - printf("KVupdate.(%s)\n",retstr2); - free(retstr2); - } - } + swap->connected = 1; + sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f]}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); + datalen = (int32_t)strlen((char *)data) + 1; + printf("datalen.%d (%s)\n",datalen,(char *)data); + init_hexbytes_noT(databuf,data,datalen); + printf("%s -> %s\n",keystr,databuf); + if ( (retstr2= _dex_kvupdate(myinfo,"KV",keystr,databuf,1)) != 0 ) + { + printf("KVupdate.(%s)\n",retstr2); + free(retstr2); + } + } else printf("nn_connect error to %d subaddr.(%s)\n",subsock,subaddr); + } else printf("nn_connect error to %d pushaddr.(%s)\n",pushsock,pushaddr); } + else printf("missing addr (%p) (%p) (%s)\n",pushaddr,subaddr,jprint(retjson,0)); free_json(retjson); - } + } else printf("Error parsing psock.(%s)\n",retstr); free(retstr); - } + } else printf("error issuing _dex_psock\n"); } } @@ -2767,12 +2772,12 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 for (iter=0; iter<3; iter++) { basilisk_psockinit(myinfo,swap,statebits == 0); + sleep(13); basilisk_sendstate(myinfo,swap,data,sizeof(data)); basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); if ( swap->connected > 0 ) break; printf("loopback didntwork with %d %d\n",swap->pushsock,swap->subsock); - sleep(3); } if ( reinit != 0 ) { From 4b7922f8b2eebafd7ff6079083d4235334e6ac7c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 26 Apr 2017 18:02:18 +0300 Subject: [PATCH 0381/2705] Test --- basilisk/basilisk_swap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 343b7287d..09e439131 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2772,6 +2772,9 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 for (iter=0; iter<3; iter++) { basilisk_psockinit(myinfo,swap,statebits == 0); + sleep(3); + if ( swap->connected <= 0 ) + continue; sleep(13); basilisk_sendstate(myinfo,swap,data,sizeof(data)); basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); From 0111021e79f4f62d0aed934c3e2639575c2766c6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 27 Apr 2017 11:02:38 +0300 Subject: [PATCH 0382/2705] Test --- iguana/coins/basilisk/mesh | 2 +- iguana/coins/mesh_7776 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/coins/basilisk/mesh b/iguana/coins/basilisk/mesh index d7c51019b..a8cf1b219 100755 --- a/iguana/coins/basilisk/mesh +++ b/iguana/coins/basilisk/mesh @@ -1 +1 @@ -curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"4d6bbfb6\",\"p2p\":9454,\"rpc\":9455,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"4d6bbfb6\",\"p2p\":8399,\"rpc\":8400,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/mesh_7776 b/iguana/coins/mesh_7776 index bcccf8d8d..01d8dd737 100755 --- a/iguana/coins/mesh_7776 +++ b/iguana/coins/mesh_7776 @@ -1 +1 @@ -curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"4d6bbfb6\",\"p2p\":9454,\"rpc\":9455,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"4d6bbfb6\",\"p2p\":8399,\"rpc\":8400,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" From 95e7db506e131094f8a132958ba9bc37e1971e60 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 27 Apr 2017 17:19:25 +0300 Subject: [PATCH 0383/2705] Test --- basilisk/basilisk.c | 4 +++- basilisk/smartaddress.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 9c56e49f4..55e1eff02 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1205,7 +1205,9 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) { if ( (value= SATOSHIDEN*jdouble(txoutjson,"value")) == 0 ) value = SATOSHIDEN*jdouble(txoutjson,"amount"); - if ( (coinaddr= jstr(txoutjson,"address")) != 0 && value != 0 ) + if ( (coinaddr= jstr(txoutjson,"address")) == 0 && (addrs= jarray(&n,txoutjson,"addresses")) != 0 && n > 0 ) + coinaddr = jstri(addrs,0); + if ( coinaddr != 0 && value != 0 ) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 41b615f96..198884053 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -471,7 +471,7 @@ void smartaddress_jumblr(struct supernet_info *myinfo,char *symbol,char *coinadd { if ( strcmp(coinaddr,basecoin->DEXinfo.jumblraddr) == 0 ) smartaddress_dex(myinfo,2,basecoin,coinaddr,basecoin->DEXinfo.jumblravail,relcoin,maxbid,minask,extraobj,credits); - else printf("smartaddress_jumblr: mismatch jumblr address (%s) vs (%s)\n",coinaddr,basecoin->DEXinfo.jumblraddr); + else printf("smartaddress_jumblr.%s: mismatch jumblr address (%s) vs (%s)\n",symbol,coinaddr,basecoin->DEXinfo.jumblraddr); } } @@ -540,11 +540,13 @@ void smartaddress_update(struct supernet_info *myinfo,int32_t selector) for (j=0; jDEXinfo.btcprice,kmdcoin->DEXinfo.avail,kmdcoin->DEXinfo.USD_average); else { + printf("Action.(%s)\n",jprint(coinitem,0)); address = jstr(coinitem,"address"); maxbid = jdouble(coinitem,"maxbid"); minask = jdouble(coinitem,"minask"); From 0d08846495285d5a69c1122a0b06f24e2f935655 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 28 Apr 2017 11:29:58 +0300 Subject: [PATCH 0384/2705] Test --- basilisk/basilisk.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 55e1eff02..5326d5134 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1205,8 +1205,12 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) { if ( (value= SATOSHIDEN*jdouble(txoutjson,"value")) == 0 ) value = SATOSHIDEN*jdouble(txoutjson,"amount"); - if ( (coinaddr= jstr(txoutjson,"address")) == 0 && (addrs= jarray(&n,txoutjson,"addresses")) != 0 && n > 0 ) - coinaddr = jstri(addrs,0); + if ( (coinaddr= jstr(txoutjson,"address")) == 0 ) + { + if ( (addrs= jarray(&n,txoutjson,"addresses")) != 0 && n > 0 ) + coinaddr = jstri(addrs,0); + printf("no address, check addrs.[%d] %p coinaddr.%p\n",n,addrs,coinaddr); + } if ( coinaddr != 0 && value != 0 ) { retjson = cJSON_CreateObject(); From b88e8e4d50b43549dc0912f3722bb2d1ca5663e5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 28 Apr 2017 14:38:07 +0300 Subject: [PATCH 0385/2705] Test --- basilisk/smartaddress.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 198884053..ffaf96467 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -450,7 +450,7 @@ void smartaddress_depositjumblr(struct supernet_info *myinfo,char *symbol,char * { if ( strcmp(coinaddr,basecoin->DEXinfo.depositaddr) == 0 ) smartaddress_dex(myinfo,1,basecoin,coinaddr,basecoin->DEXinfo.avail,relcoin,maxbid,minask,extraobj,0.); - else printf("smartaddress_jumblr: mismatch deposit address (%s) vs (%s)\n",coinaddr,basecoin->DEXinfo.depositaddr); + else printf("smartaddress_jumblr.%s: mismatch deposit address (%s) vs (%s)\n",symbol,coinaddr,basecoin->DEXinfo.depositaddr); } } @@ -513,7 +513,7 @@ void smartaddress_action(struct supernet_info *myinfo,int32_t selector,char *typ void smartaddress_update(struct supernet_info *myinfo,int32_t selector) { - double maxbid,minask; char *smartstr,*typestr,*symbol,*address; cJSON *smartarray,*extraobj,*item,*array,*coinitem; int32_t iter,i,n,j,m; struct iguana_info *kmdcoin,*coinbtc = 0; + double maxbid,minask; uint8_t addrtype,rmd160[20]; char *smartstr,*typestr,*symbol,*address,coinaddr[64]; cJSON *smartarray,*extraobj,*item,*array,*coinitem; int32_t iter,i,n,j,m; struct iguana_info *kmdcoin,*coinbtc = 0; //printf("smartaddress_update numswaps.%d notary.%d IAMLP.%d %p %p %f\n",myinfo->numswaps,myinfo->IAMNOTARY,myinfo->IAMLP,kmdcoin,coinbtc,kmdcoin->DEXinfo.btcprice); if ( myinfo->IAMNOTARY != 0 || myinfo->IAMLP != 0 || myinfo->secret[0] == 0 ) return; @@ -547,11 +547,15 @@ void smartaddress_update(struct supernet_info *myinfo,int32_t selector) else { printf("Action.(%s)\n",jprint(coinitem,0)); - address = jstr(coinitem,"address"); - maxbid = jdouble(coinitem,"maxbid"); - minask = jdouble(coinitem,"minask"); - extraobj = jobj(coinitem,"extra"); - smartaddress_action(myinfo,selector,typestr,symbol,address,maxbid,minask,extraobj); + if ( (address= jstr(coinitem,"address")) != 0 ) + { + bitcoin_addr2rmd160(&addrtype,rmd160,address); + bitcoin_address(coinaddr,kmdcoin->chain->pubtype,rmd160,20); + maxbid = jdouble(coinitem,"maxbid"); + minask = jdouble(coinitem,"minask"); + extraobj = jobj(coinitem,"extra"); + smartaddress_action(myinfo,selector,typestr,symbol,coinaddr,maxbid,minask,extraobj); + } } } } From 7c6537fd3b2c021c86f2c325dd692a2f911f172b Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 28 Apr 2017 14:52:37 +0300 Subject: [PATCH 0386/2705] Test --- .gitignore | 2 ++ basilisk/basilisk.c | 1 + basilisk/basilisk_DEX.c | 13 ++++++++----- iguana/iguana777.h | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index e47bf922a..0235dd6e5 100755 --- a/.gitignore +++ b/.gitignore @@ -399,3 +399,5 @@ iguana/DB/SWAPS/2723832060-1788071166 iguana/DB/SWAPS/3213598586-2281632307 + +iguana/DB/SWAPS/2686675855-3655454671 diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 5326d5134..ff5a89a4c 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1857,6 +1857,7 @@ HASH_ARRAY_STRING(InstantDEX,request,hash,vals,hexstr) memset(hash.bytes,0,sizeof(hash)); msgid = (uint32_t)time(NULL); DEX_channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); + myinfo->DEXtrades++; // not exact but allows a one side initiated self-trade basilisk_channelsend(myinfo,hash,hash,DEX_channel,msgid,serialized,datalen,60); sleep(3); /*while ( numiters < 10 && (crc= basilisk_crcsend(myinfo,0,buf,sizeof(buf),hash,myinfo->myaddr.persistent,DEX_channel,msgid,serialized,datalen,crcs)) == 0 ) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index fd047148a..63064c6d9 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -313,11 +313,14 @@ int32_t basilisk_requests_poll(struct supernet_info *myinfo) if ( smartaddress_pubkey(myinfo,typestr,bidasks,&privkey,issueR.src,issueR.srchash) >= 0 ) { printf("matched dex_smartpubkey\n"); - dex_channelsend(myinfo,issueR.srchash,issueR.desthash,channel,0x4000000,(void *)&issueR.requestid,sizeof(issueR.requestid)); // 60 - dpow_nanomsg_update(myinfo); - dex_updateclient(myinfo); - if ( (retstr= basilisk_start(myinfo,privkey,&issueR,1,issueR.optionhours * 3600)) != 0 ) - free(retstr); + if ( myinfo->DEXtrades > 0 ) + { + dex_channelsend(myinfo,issueR.srchash,issueR.desthash,channel,0x4000000,(void *)&issueR.requestid,sizeof(issueR.requestid)); // 60 + dpow_nanomsg_update(myinfo); + dex_updateclient(myinfo); + if ( (retstr= basilisk_start(myinfo,privkey,&issueR,1,issueR.optionhours * 3600)) != 0 ) + free(retstr); + } } else if ( issueR.requestid != myinfo->lastdexrequestid )//if ( issueR.quoteid == 0 ) { diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 7ef130d08..de8def6f4 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -173,7 +173,7 @@ struct supernet_info uint16_t psockport,numpsocks; struct psock *PSOCKS; portable_mutex_t psockmutex; uint8_t notaries[64][33]; int32_t numnotaries,DEXEXPLORER; FILE *swapsfp; - struct smartaddress smartaddrs[64]; int32_t numsmartaddrs,cancelrefresh,runsilent; + struct smartaddress smartaddrs[64]; int32_t numsmartaddrs,cancelrefresh,runsilent,DEXtrades; }; struct basilisk_swapmessage From 45004e40dd60fd0efcbeb5cd2d366b2865608bc6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 28 Apr 2017 15:58:14 +0300 Subject: [PATCH 0387/2705] Test --- .gitignore | 2 ++ basilisk/basilisk.c | 4 ++-- basilisk/basilisk_swap.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 0235dd6e5..a0469beac 100755 --- a/.gitignore +++ b/.gitignore @@ -401,3 +401,5 @@ iguana/DB/SWAPS/2723832060-1788071166 iguana/DB/SWAPS/3213598586-2281632307 iguana/DB/SWAPS/2686675855-3655454671 + +iguana/DB/SWAPS/1878868608-154367763 diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index ff5a89a4c..a4b82664e 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1207,9 +1207,9 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) value = SATOSHIDEN*jdouble(txoutjson,"amount"); if ( (coinaddr= jstr(txoutjson,"address")) == 0 ) { - if ( (addrs= jarray(&n,txoutjson,"addresses")) != 0 && n > 0 ) + if ( (sobj= jobj(txoutjson,"scriptPubKey")) != 0 && (addrs= jarray(&n,sobj,"addresses")) != 0 && n > 0 ) coinaddr = jstri(addrs,0); - printf("no address, check addrs.[%d] %p coinaddr.%p\n",n,addrs,coinaddr); + printf("no address, check addrs %p coinaddr.%p\n",sobj,coinaddr); } if ( coinaddr != 0 && value != 0 ) { diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 09e439131..ee9af7593 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2537,7 +2537,7 @@ void basilisk_swaploop(void *_swap) fprintf(stderr,"start swap\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); - expiration = (uint32_t)time(NULL) + 600; + expiration = (uint32_t)time(NULL) + 120; myinfo->DEXactive = expiration; channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) @@ -3975,7 +3975,7 @@ char *basilisk_swaplist(struct supernet_info *myinfo) if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) { jaddi(array,item); - if ( 1 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + if ( 0 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) break; } } From be27eecbe559b4b1031c18de2bd26ea2e312c8c6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 28 Apr 2017 16:11:02 +0300 Subject: [PATCH 0388/2705] Test --- basilisk/basilisk.c | 2 +- basilisk/smartaddress.c | 9 ++++++--- iguana/main.c | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index a4b82664e..274f687ed 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1921,7 +1921,7 @@ INT_ARG(InstantDEX,incoming,requestid) else { jaddstr(retjson,"error","cant do InstantDEX channelget"); - printf("error channelget\n"); + char str[65]; printf("error channelget %s %x\n",bits256_str(str,myinfo->myaddr.persistent),msgid); } return(jprint(retjson,1)); } diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index ffaf96467..725b712a4 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -546,11 +546,14 @@ void smartaddress_update(struct supernet_info *myinfo,int32_t selector) smartaddress_coinupdate(myinfo,symbol,kmdcoin->DEXinfo.btcprice,kmdcoin->DEXinfo.avail,kmdcoin->DEXinfo.USD_average); else { - printf("Action.(%s)\n",jprint(coinitem,0)); + printf("Action.%s (%s)\n",typestr,jprint(coinitem,0)); if ( (address= jstr(coinitem,"address")) != 0 ) { - bitcoin_addr2rmd160(&addrtype,rmd160,address); - bitcoin_address(coinaddr,kmdcoin->chain->pubtype,rmd160,20); + if ( strcmp(typestr,"jumblr") == 0 ) + { + bitcoin_addr2rmd160(&addrtype,rmd160,address); + bitcoin_address(coinaddr,kmdcoin->chain->pubtype,rmd160,20); + } else strcpy(coinaddr,address); maxbid = jdouble(coinitem,"maxbid"); minask = jdouble(coinitem,"minask"); extraobj = jobj(coinitem,"extra"); diff --git a/iguana/main.c b/iguana/main.c index 5cf2e4bc1..afbeecd80 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -756,7 +756,8 @@ void jumblr_loop(void *ptr) if ( (coin= iguana_coinfind("KMD")) != 0 ) { n++; - smartaddress_update(myinfo,n & 1); + if ( (n % 3) == 0 ) + smartaddress_update(myinfo,(n/3) & 1); if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC From cc2a65e46e3cb2095b963229d2550c69333dfe10 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 28 Apr 2017 16:32:31 +0300 Subject: [PATCH 0389/2705] Test --- basilisk/basilisk.c | 7 +++++++ basilisk/basilisk_swap.c | 8 ++++---- basilisk/smartaddress.c | 6 ++++-- iguana/iguana777.h | 1 + includes/iguana_apideclares.h | 1 + 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 274f687ed..f08ed1857 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1972,4 +1972,11 @@ ZERO_ARGS(InstantDEX,getswaplist) return(basilisk_swaplist(myinfo)); } +DOUBLE_ARG(InstantDEX,DEXratio,ratio) +{ + if ( ratio < 0.95 || ratio > 1.01 ) + return(clonestr("{\"result\":\"error\",\"description\":\"DEXratio must be between 0.95 and 1.01\"}")); + myinfo->DEXratio = ratio; + return(clonestr("{\"result\":\"success\"}")); +} #include "../includes/iguana_apiundefs.h" diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index ee9af7593..d31394425 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2769,18 +2769,18 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 m = n = 0; if ( bitcoin_swapinit(myinfo,privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) { - for (iter=0; iter<3; iter++) + for (iter=0; iter<1; iter++) { basilisk_psockinit(myinfo,swap,statebits == 0); sleep(3); if ( swap->connected <= 0 ) continue; - sleep(13); - basilisk_sendstate(myinfo,swap,data,sizeof(data)); + sleep(30); + /*basilisk_sendstate(myinfo,swap,data,sizeof(data)); basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); if ( swap->connected > 0 ) break; - printf("loopback didntwork with %d %d\n",swap->pushsock,swap->subsock); + printf("loopback didntwork with %d %d\n",swap->pushsock,swap->subsock);*/ } if ( reinit != 0 ) { diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 725b712a4..ea1ab2e6f 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -336,6 +336,8 @@ void smartaddress_dex(struct supernet_info *myinfo,int32_t selector,struct iguan minamount = price = 0.; if ( basebtc < SMALLVAL && relbtc < SMALLVAL ) return; + if ( myinfo->DEXratio < .95 || myinfo->DEXratio > 1.01 ) + myinfo->DEXratio = 0.995; if ( basebtc < SMALLVAL || relbtc < SMALLVAL ) { if ( (price= maxbid) > SMALLVAL ) @@ -345,11 +347,11 @@ void smartaddress_dex(struct supernet_info *myinfo,int32_t selector,struct iguan else if ( relbtc < SMALLVAL ) relbtc = basebtc / price, printf("calculated relbtc %.8f from (%.8f / %.8f)\n",relbtc,basebtc,price); // price * relbtc == basebtc } - } else price = 0.985 * (basebtc / relbtc); + } else price = myinfo->DEXratio * (basebtc / relbtc); minbtc = btc2kmd * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); if ( minamount == 0. && basebtc > SMALLVAL ) minamount = (minbtc / basebtc); - printf("%s/%s minbtc %.8f btcprice %.8f -> minamount %.8f price %.8f vs maxbid %.8f\n",basecoin->symbol,relcoin->symbol,minbtc,basecoin->DEXinfo.btcprice,minamount,price,maxbid); + printf("%s/%s minbtc %.8f btcprice %.8f -> minamount %.8f price %.8f vs maxbid %.8f DEXratio %.5f\n",basecoin->symbol,relcoin->symbol,minbtc,basecoin->DEXinfo.btcprice,minamount,price,maxbid,myinfo->DEXratio); if ( minamount > SMALLVAL && maxavail > minamount + basecoin->DEXinfo.DEXpending && (maxbid == 0. || price <= maxbid) ) { avail = (maxavail - (minamount + basecoin->DEXinfo.DEXpending)); diff --git a/iguana/iguana777.h b/iguana/iguana777.h index de8def6f4..2e1cc17a9 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -173,6 +173,7 @@ struct supernet_info uint16_t psockport,numpsocks; struct psock *PSOCKS; portable_mutex_t psockmutex; uint8_t notaries[64][33]; int32_t numnotaries,DEXEXPLORER; FILE *swapsfp; + double DEXratio; struct smartaddress smartaddrs[64]; int32_t numsmartaddrs,cancelrefresh,runsilent,DEXtrades; }; diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 81785bb26..9ec461b91 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -230,6 +230,7 @@ ZERO_ARGS(InstantDEX,init); ZERO_ARGS(InstantDEX,getswaplist); ZERO_ARGS(InstantDEX,smartaddresses); TWO_STRINGS_AND_TWO_DOUBLES(InstantDEX,smartaddress,type,symbol,maxbid,minask); +DOUBLE_ARG(InstantDEX,DEXratio,ratio); //THREE_STRINGS(atomic,approve,myorderid,otherid,txname); //THREE_STRINGS(atomic,claim,myorderid,otherid,txname); From 166c94cc7693e99463edb47b823fe5e0c13d307c Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 28 Apr 2017 17:45:20 +0300 Subject: [PATCH 0390/2705] Test --- .gitignore | 4 ++++ basilisk/basilisk_swap.c | 2 +- basilisk/smartaddress.c | 14 ++++++++++++-- iguana/iguana_wallet.c | 8 +++++--- iguana/tests/DEXratio | 2 ++ 5 files changed, 24 insertions(+), 6 deletions(-) create mode 100755 iguana/tests/DEXratio diff --git a/.gitignore b/.gitignore index a0469beac..9814a7d00 100755 --- a/.gitignore +++ b/.gitignore @@ -403,3 +403,7 @@ iguana/DB/SWAPS/3213598586-2281632307 iguana/DB/SWAPS/2686675855-3655454671 iguana/DB/SWAPS/1878868608-154367763 + +iguana/DB/SWAPS/1306454711-1938980379 + +iguana/DB/SWAPS/912783809-2523701920 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index d31394425..b36395556 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2731,7 +2731,7 @@ cJSON *basilisk_swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { - int32_t i,m,n,iter; uint8_t pubkey33[33],data[64]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; + int32_t i,m,n,iter; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; // statebits 1 -> client, 0 -> LP if ( myinfo->numswaps > 0 ) { diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index ea1ab2e6f..76de3948d 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -62,9 +62,13 @@ cJSON *smartaddress_extrajson(struct smartaddress *ap) cJSON *smartaddress_json(struct smartaddress *ap) { - char coinaddr[64]; int32_t j,n; struct iguana_info *coin; cJSON *array,*item,*retjson; + char coinaddr[64],symbol[64]; uint8_t desttype,tmp,rmd160[20]; int32_t j,n; struct iguana_info *coin,*dest; cJSON *array,*item,*retjson; retjson = cJSON_CreateObject(); jaddstr(retjson,"type",ap->typestr); + strcpy(symbol,ap->typestr), touppercase(symbol); + if ( (dest= iguana_coinfind(symbol)) != 0 ) + desttype = dest->chain->pubtype; + else desttype = 60; if ( (n= ap->numsymbols) > 0 ) { array = cJSON_CreateArray(); @@ -76,6 +80,12 @@ cJSON *smartaddress_json(struct smartaddress *ap) item = cJSON_CreateObject(); jaddstr(item,"coin",coin->symbol); jaddstr(item,"address",coinaddr); + if ( dest != 0 ) + { + bitcoin_addr2rmd160(&tmp,rmd160,coinaddr); + bitcoin_address(coinaddr,desttype,rmd160,20); + jaddstr(item,"dest",coinaddr); + } jaddnum(item,"maxbid",ap->symbols[j].maxbid); jaddnum(item,"minask",ap->symbols[j].minask); jadd(item,"extra",smartaddress_extrajson(ap)); @@ -99,7 +109,7 @@ void smartaddress_symboladd(struct smartaddress *ap,char *symbol,double maxbid,d safecopy(sp->symbol,symbol,sizeof(sp->symbol)); sp->maxbid = maxbid; sp->minask = minask; - printf("symboladd (%s) <- (%s %f %f)\n",ap->typestr,symbol,maxbid,minask); + printf("symboladd.%d (%s) <- (%s %f %f)\n",ap->numsymbols,ap->typestr,symbol,maxbid,minask); } } diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index e077f2192..21aa5b703 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -1373,12 +1373,14 @@ TWOSTRINGS_AND_INT(bitcoinrpc,walletpassphrase,password,permanentfile,timeout) } if ( bits256_nonz(myinfo->persistent_priv) != 0 ) { - char *jumblrstr,jumblr_passphrase[1024]; + char *jumblrstr,jumblr_passphrase[1024],coinaddr[64],KMDaddr[64]; bits256 privkey; sprintf(jumblr_passphrase,"jumblr %s",password); if ( (jumblrstr= jumblr_setpassphrase(myinfo,0,0,0,jumblr_passphrase)) != 0 ) free(jumblrstr); - smartaddress_add(myinfo,myinfo->persistent_priv,"kmd","BTC",0.,0.); - smartaddress_add(myinfo,myinfo->persistent_priv,"btc","KMD",0.,0.); + privkey = jumblr_privkey(myinfo,coinaddr,0,KMDaddr,"kmd "); + smartaddress_add(myinfo,privkey,"kmd","BTC",0.,0.); + privkey = jumblr_privkey(myinfo,coinaddr,0,KMDaddr,"btc "); + smartaddress_add(myinfo,privkey,"btc","KMD",0.,0.); } //basilisk_unspents_update(myinfo,coin); return(retstr); diff --git a/iguana/tests/DEXratio b/iguana/tests/DEXratio new file mode 100755 index 000000000..09365cc85 --- /dev/null +++ b/iguana/tests/DEXratio @@ -0,0 +1,2 @@ +#!/bin/bash +curl --url "http://127.0.0.1:7778" --data "{\"ratio\":0.97,\"agent\":\"InstantDEX\",\"method\":\"DEXratio\"}" From b74faeb73eb150860bb6df3fc12cbb29c02f48f4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 28 Apr 2017 17:59:56 +0300 Subject: [PATCH 0391/2705] Test --- .gitignore | 2 ++ basilisk/basilisk.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9814a7d00..22b82b68f 100755 --- a/.gitignore +++ b/.gitignore @@ -407,3 +407,5 @@ iguana/DB/SWAPS/1878868608-154367763 iguana/DB/SWAPS/1306454711-1938980379 iguana/DB/SWAPS/912783809-2523701920 + +iguana/DB/SWAPS/1238069553-2363573428 diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index f08ed1857..8c65f62bc 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1183,7 +1183,7 @@ HASH_ARRAY_STRING(basilisk,sendmessage,hash,vals,hexstr) HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) { - char *retstr=0,*symbol,*coinaddr,*infostr; cJSON *retjson,*sobj,*info,*addrs,*txoutjson,*txjson,*array; uint32_t basilisktag,blocktime; bits256 txid,blockhash; struct basilisk_item *ptr,Lptr; uint64_t value; int32_t timeoutmillis,vout,height,n,m; + char *retstr=0,*symbol,*coinaddr,*infostr; cJSON *retjson,*sobj,*info,*addrs,*txoutjson,*txjson,*array; uint32_t basilisktag,blocktime,numtx=0; bits256 txid,blockhash; struct basilisk_item *ptr,Lptr; uint64_t value; int32_t timeoutmillis,vout,height,n,m; if ( vals == 0 ) return(clonestr("{\"error\":\"null valsobj\"}")); //if ( myinfo->IAMNOTARY != 0 || myinfo->NOTARY.RELAYID >= 0 ) @@ -1219,7 +1219,7 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) jadd64bits(retjson,"satoshis",value); jaddnum(retjson,"value",dstr(value)); jaddnum(retjson,"amount",dstr(value)); - height = dpow_getchaintip(myinfo,&blockhash,&blocktime,0,0,coin); + height = dpow_getchaintip(myinfo,&blockhash,&blocktime,0,&numtx,coin); jaddnum(retjson,"height",height); jaddnum(retjson,"numconfirms",jint(txoutjson,"confirmations")); jaddbits256(retjson,"txid",txid); From 5aacd82b8ac3c582a6ceb4f869a88043f1fd3aed Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 29 Apr 2017 11:11:30 +0300 Subject: [PATCH 0392/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 32 +++++++++++++++++--------------- basilisk/smartaddress.c | 16 ++++++++++++++-- iguana/dpow/dpow_network.c | 27 +++++++++++++++++++-------- 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 22b82b68f..b3674ef11 100755 --- a/.gitignore +++ b/.gitignore @@ -409,3 +409,5 @@ iguana/DB/SWAPS/1306454711-1938980379 iguana/DB/SWAPS/912783809-2523701920 iguana/DB/SWAPS/1238069553-2363573428 + +iguana/DB/SWAPS/2895470622-2170247626 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b36395556..0b66d301f 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3568,7 +3568,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } origfinishedflag = finishedflag = 1; free(fstr); - } + } else printf("%s not finished\n",fname); if ( iambob < 0 ) return(0); item = cJSON_CreateObject(); @@ -3602,24 +3602,26 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t safecopy(bobcoin,symbol,sizeof(bobcoin)); else if ( i == BASILISK_BOBSPEND || i == BASILISK_ALICEPAYMENT || i == BASILISK_ALICERECLAIM ) safecopy(alicecoin,symbol,sizeof(alicecoin)); - if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) - { - //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); - } - else + if ( finishedflag == 0 ) { - checktxid = jbits256(sentobj,"txid"); - if ( bits256_nonz(checktxid) == 0 ) - checktxid = jbits256(sentobj,"hash"); - if ( bits256_cmp(checktxid,txid) == 0 ) + if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) { - //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); - sentflags[i] = 1; + //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + } + else + { + checktxid = jbits256(sentobj,"txid"); + if ( bits256_nonz(checktxid) == 0 ) + checktxid = jbits256(sentobj,"hash"); + if ( bits256_cmp(checktxid,txid) == 0 ) + { + //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); + sentflags[i] = 1; + } + free_json(sentobj); } - free_json(sentobj); - } - if ( finishedflag == 0 ) printf("%s %s %.8f\n",txnames[i],bits256_str(str,txid),dstr(value)); + } } } //else printf("no symbol\n"); free(fstr); diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index 76de3948d..15a3c9ac2 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -85,9 +85,21 @@ cJSON *smartaddress_json(struct smartaddress *ap) bitcoin_addr2rmd160(&tmp,rmd160,coinaddr); bitcoin_address(coinaddr,desttype,rmd160,20); jaddstr(item,"dest",coinaddr); + if ( coin->DEXinfo.depositaddr[0] != 0 ) + { + jaddstr(item,"jumblr_deposit",coin->DEXinfo.depositaddr); + jaddnum(item,"deposit_avail",coin->DEXinfo.avail); + } + if ( coin->DEXinfo.jumblraddr[0] != 0 ) + { + jaddstr(item,"jumblr",coin->DEXinfo.jumblraddr); + jaddnum(item,"jumblr_avail",coin->DEXinfo.jumblravail); + } + if ( ap->symbols[j].maxbid != 0. ) + jaddnum(item,"maxbid",ap->symbols[j].maxbid); + if ( ap->symbols[j].minask != 0. ) + jaddnum(item,"minask",ap->symbols[j].minask); } - jaddnum(item,"maxbid",ap->symbols[j].maxbid); - jaddnum(item,"minask",ap->symbols[j].minask); jadd(item,"extra",smartaddress_extrajson(ap)); jaddi(array,item); } diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 528aced8a..201024a9d 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -140,12 +140,23 @@ int32_t signed_nn_send(struct supernet_info *myinfo,void *ctx,bits256 privkey,in return(-1); } -int32_t signed_nn_recv(void **freeptrp,void *ctx,uint8_t notaries[64][33],int32_t n,int32_t sock,void *packetp) +int32_t signed_nn_recv(void **freeptrp,struct supernet_info *myinfo,uint8_t notaries[64][33],int32_t n,int32_t sock,void *packetp) { int32_t i,recvbytes; uint8_t pubkey33[33],pubkey0[33]; bits256 packethash; struct signed_nnpacket *sigpacket=0; *(void **)packetp = 0; *freeptrp = 0; - if ( (recvbytes= nn_recv(sock,&sigpacket,NN_MSG,0)) > 0 ) + for (i=0; i<100; i++) + { + struct nn_pollfd pfd; + pfd.fd = myinfo->reqsock; + pfd.events = NN_POLLIN; + if ( nn_poll(&pfd,1,100) > 0 ) + break; + usleep(1000); + } + if ( i == 100 ) + recvbytes = 0; + else if ( (recvbytes= nn_recv(sock,&sigpacket,NN_MSG,0)) > 0 ) { //for (i=0; inonce,(int32_t)(sigpacket->packetlen+sizeof(sigpacket->nonce)+sizeof(sigpacket->packetlen))); if ( bits256_cmp(packethash,sigpacket->packethash) == 0 && sigpacket->packethash.bytes[0] == 0 ) { - if ( bitcoin_recoververify(ctx,"nnrecv",sigpacket->sig64,sigpacket->packethash,pubkey33,33) == 0 ) + if ( bitcoin_recoververify(myinfo->ctx,"nnrecv",sigpacket->sig64,sigpacket->packethash,pubkey33,33) == 0 ) { char *notary0 = "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828"; // expand to official notaries @@ -474,7 +485,7 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 } //for (i=0; ictx,myinfo->notaries,myinfo->numnotaries,myinfo->reqsock,&retptr)) >= 0 ) + if ( (recvbytes= signed_nn_recv(&freeptr,myinfo,myinfo->notaries,myinfo->numnotaries,myinfo->reqsock,&retptr)) >= 0 ) { //printf("req returned.[%d]\n",recvbytes); portable_mutex_lock(&myinfo->dexmutex); @@ -819,7 +830,7 @@ char *dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *data,int32 { if ( (retstrs[j]= _dex_reqsend(myinfo,handler,0,0,data,datalen)) != 0 ) { -//printf("j.%d of max.%d M.%d (%s)\n",j,max,M,retstrs[j]); +printf("j.%d of max.%d M.%d (%s)\n",j,max,M,retstrs[j]); if ( strncmp(retstrs[j],"{\"error\":\"null return\"}",strlen("{\"error\":\"null return\"}")) != 0 && strncmp(retstrs[j],"[]",strlen("[]")) != 0 && strcmp("0",retstrs[j]) != 0 ) { if ( ++j == M ) @@ -1265,7 +1276,7 @@ int32_t dex_subsock_poll(struct supernet_info *myinfo) int32_t size= -1; struct dex_nanomsghdr *dexp; void *freeptr; //return(0); //fprintf(stderr,"subsock.%d\n",myinfo->subsock); - if ( myinfo->subsock >= 0 && (size= signed_nn_recv(&freeptr,myinfo->ctx,myinfo->notaries,myinfo->numnotaries,myinfo->subsock,&dexp)) >= 0 ) + if ( myinfo->subsock >= 0 && (size= signed_nn_recv(&freeptr,myinfo,myinfo->notaries,myinfo->numnotaries,myinfo->subsock,&dexp)) >= 0 ) { if ( dexp != 0 ) { @@ -2071,7 +2082,7 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo) for (iter=0; iter<100; iter++) { freeptr = 0; - if ( (flags & 1) == 0 && (size= signed_nn_recv(&freeptr,myinfo->ctx,myinfo->notaries,myinfo->numnotaries,myinfo->dpowsock,&np)) > 0 ) + if ( (flags & 1) == 0 && (size= signed_nn_recv(&freeptr,myinfo,myinfo->notaries,myinfo->numnotaries,myinfo->dpowsock,&np)) > 0 ) { num++; if ( size > 0 ) @@ -2125,7 +2136,7 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo) if ( myinfo->dexsock >= 0 ) // from servers { freeptr = 0; - if ( (flags & 2) == 0 && (size= signed_nn_recv(&freeptr,myinfo->ctx,myinfo->notaries,myinfo->numnotaries,myinfo->dexsock,&dexp)) > 0 ) + if ( (flags & 2) == 0 && (size= signed_nn_recv(&freeptr,myinfo,myinfo->notaries,myinfo->numnotaries,myinfo->dexsock,&dexp)) > 0 ) { //fprintf(stderr,"%d ",size); n++; From 64731758c20428a45235463e18e8f658dc0c0175 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 29 Apr 2017 11:16:26 +0300 Subject: [PATCH 0393/2705] Test --- basilisk/basilisk_swap.c | 5 +++-- iguana/dpow/dpow_network.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0b66d301f..4d34e40fa 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3568,7 +3568,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } origfinishedflag = finishedflag = 1; free(fstr); - } else printf("%s not finished\n",fname); + } if ( iambob < 0 ) return(0); item = cJSON_CreateObject(); @@ -3625,7 +3625,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } } //else printf("no symbol\n"); free(fstr); - } + } else if ( finishedflag == 0 ) + printf("%s not finished\n",fname); } //printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); Adestaddr[0] = destaddr[0] = 0; diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 201024a9d..5d9f4c233 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -830,7 +830,7 @@ char *dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *data,int32 { if ( (retstrs[j]= _dex_reqsend(myinfo,handler,0,0,data,datalen)) != 0 ) { -printf("j.%d of max.%d M.%d (%s)\n",j,max,M,retstrs[j]); +//printf("j.%d of max.%d M.%d (%s)\n",j,max,M,retstrs[j]); if ( strncmp(retstrs[j],"{\"error\":\"null return\"}",strlen("{\"error\":\"null return\"}")) != 0 && strncmp(retstrs[j],"[]",strlen("[]")) != 0 && strcmp("0",retstrs[j]) != 0 ) { if ( ++j == M ) From 2da8cd21f35307e721d955ad0e37cda9fadfd4ac Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 29 Apr 2017 11:18:36 +0300 Subject: [PATCH 0394/2705] Test --- basilisk/basilisk_swap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 4d34e40fa..8e46db831 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -3467,7 +3467,6 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t plocktime = dlocktime = 0; src[0] = dest[0] = bobcoin[0] = alicecoin[0] = 0; sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); - printf("%s\n",fname); if ( (fstr= OS_filestr(&fsize,fname)) != 0 ) { if ( (item= cJSON_Parse(fstr)) != 0 ) @@ -3579,6 +3578,8 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,requestid,quoteid,txnames[i]), OS_compatible_path(fname); if ( (fstr= OS_filestr(&fsize,fname)) != 0 ) { + if ( finishedflag == 0 ) + printf("%s\n",fname); //printf("%s -> (%s)\n",fname,fstr); if ( (txobj= cJSON_Parse(fstr)) != 0 ) { From 21814135c1a1a61d788af85310895c5785fae032 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 2 May 2017 20:45:59 +0300 Subject: [PATCH 0395/2705] Stats --- basilisk/basilisk_swap.c | 16 +- iguana/exchanges/stats.c | 327 +++++++++++++++++++++++++++++++++++++++ iguana/m_stats | 1 + iguana/stats | Bin 0 -> 346064 bytes 4 files changed, 337 insertions(+), 7 deletions(-) create mode 100644 iguana/exchanges/stats.c create mode 100755 iguana/m_stats create mode 100755 iguana/stats diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 8e46db831..2777b4f13 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2404,7 +2404,7 @@ cJSON *swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap) void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t amlp) { - char keystr[64],databuf[1024],*retstr,*retstr2,*datastr,*pushaddr=0,*subaddr=0; cJSON *retjson,*addrjson; uint8_t data[512]; int32_t datalen,timeout,pushsock = -1,subsock = -1; + char keystr[64],databuf[1024],pubkeystr[128],*retstr,*retstr2,*datastr,*pushaddr=0,*subaddr=0; cJSON *retjson,*addrjson; uint8_t data[512]; int32_t datalen,timeout,pushsock = -1,subsock = -1; if ( swap->connected == 1 ) return; if ( swap->pushsock < 0 && swap->subsock < 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) @@ -2466,7 +2466,8 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, if ( nn_connect(subsock,subaddr) >= 0 ) { swap->connected = 1; - sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f]}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); + init_hexbytes_noT(pubkeystr,myinfo->persistent_pubkey33,33); + sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f],\"pub\":\"%s\"}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),pubkeystr); datalen = (int32_t)strlen((char *)data) + 1; printf("datalen.%d (%s)\n",datalen,(char *)data); init_hexbytes_noT(databuf,data,datalen); @@ -3690,12 +3691,13 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) { // alicespend - //for (j=0; j<32; j++) - // rev.bytes[j] = privAm.bytes[31 - j]; - //revcalc_rmd160_sha256(secretAm,rev);//privAm); - //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); + for (j=0; j<32; j++) + rev.bytes[j] = privAm.bytes[31 - j]; + revcalc_rmd160_sha256(secretAm,rev);//privAm); + vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + printf("alicespend len.%d redeemlen.%d\n",len,redeemlen); if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND])) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } @@ -3979,7 +3981,7 @@ char *basilisk_swaplist(struct supernet_info *myinfo) if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) { jaddi(array,item); - if ( 0 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + if ( 1 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) break; } } diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c new file mode 100644 index 000000000..e31fd12ab --- /dev/null +++ b/iguana/exchanges/stats.c @@ -0,0 +1,327 @@ +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// main.c +// stats +// +// Copyright © 2017 SuperNET. All rights reserved. +// + +#include +#include +#include "OS_portable.h" +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + + +#define IGUANA_URL "http://127.0.0.1:7778" +#define STATS_DESTDIR "/var/www/html" +#define STATS_DEST "/var/www/html/DEXstats.json" + +char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies + "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", // end of currencies +}; + +char ASSETCHAINS_SYMBOL[16] = { "KV" }; + +struct komodo_state +{ + bits256 NOTARIZED_HASH,NOTARIZED_DESTTXID; + int32_t SAVEDHEIGHT,CURRENT_HEIGHT,NOTARIZED_HEIGHT; + uint32_t SAVEDTIMESTAMP; + uint64_t deposited,issued,withdrawn,approved,redeemed,shorted; + struct notarized_checkpoint *NPOINTS; int32_t NUM_NPOINTS; + struct komodo_event **Komodo_events; int32_t Komodo_numevents; + uint32_t RTbufs[64][3]; uint64_t RTmask; +}; + +struct komodo_state KOMODO_STATE; +void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) +{ + static bits256 zeroes; + uint32_t flags; bits256 pubkey,refpubkey,sig; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; + iguana_rwnum(0,&opretbuf[1],sizeof(keylen),&keylen); + iguana_rwnum(0,&opretbuf[3],sizeof(valuesize),&valuesize); + iguana_rwnum(0,&opretbuf[5],sizeof(height),&height); + iguana_rwnum(0,&opretbuf[9],sizeof(flags),&flags); + key = &opretbuf[13]; + if ( keylen+13 > opretlen ) + { + printf("komodo_kvupdate: keylen.%d + 13 > opretlen.%d\n",keylen,opretlen); + return; + } + valueptr = &key[keylen]; + coresize = (int32_t)(sizeof(flags)+sizeof(height)+sizeof(keylen)+sizeof(valuesize)+keylen+valuesize+1); + if ( opretlen == coresize || opretlen == coresize+sizeof(bits256) || opretlen == coresize+2*sizeof(bits256) ) + { + memset(&pubkey,0,sizeof(pubkey)); + memset(&sig,0,sizeof(sig)); + if ( (haspubkey= (opretlen >= coresize+sizeof(bits256))) != 0 ) + { + for (i=0; i<32; i++) + ((uint8_t *)&pubkey)[i] = opretbuf[coresize+i]; + } + if ( (hassig= (opretlen == coresize+sizeof(bits256)*2)) != 0 ) + { + for (i=0; i<32; i++) + ((uint8_t *)&sig)[i] = opretbuf[coresize+sizeof(bits256)+i]; + } + /*if ( (refvaluesize= komodo_kvsearch((bits256 *)&refpubkey,height,&flags,&kvheight,&keyvalue[keylen],key,keylen)) >= 0 ) + { + if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 ) + { + if ( komodo_kvsigverify(keyvalue,keylen+refvaluesize,refpubkey,sig) < 0 ) + { + //printf("komodo_kvsigverify error [%d]\n",coresize-13); + return; + } + } + }*/ + for (i=0; i "); + for (i=0; i sp->SAVEDHEIGHT ) + { + sp->SAVEDHEIGHT = kmdheight; + sp->SAVEDTIMESTAMP = timestamp; + } + if ( kmdheight > sp->CURRENT_HEIGHT ) + sp->CURRENT_HEIGHT = kmdheight; + } +} + +void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t height,int32_t kmdheight,uint32_t timestamp) +{ + uint32_t buf[2]; + if ( kmdheight > 0 ) + { + buf[0] = (uint32_t)kmdheight; + buf[1] = timestamp; + //komodo_eventadd(sp,height,symbol,KOMODO_EVENT_KMDHEIGHT,(uint8_t *)buf,sizeof(buf)); + if ( sp != 0 ) + komodo_setkmdheight(sp,kmdheight,timestamp); + } + else + { + kmdheight = -kmdheight; + //komodo_eventadd(sp,height,symbol,KOMODO_EVENT_REWIND,(uint8_t *)&height,sizeof(height)); + //if ( sp != 0 ) + // komodo_event_rewind(sp,symbol,height); + } +} + +int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char *dest) +{ + static int32_t errs; + int32_t func,ht,notarized_height,num,matched=0; bits256 notarized_hash,notarized_desttxid; uint8_t pubkeys[64][33]; + if ( (func= fgetc(fp)) != EOF ) + { + if ( ASSETCHAINS_SYMBOL[0] == 0 && strcmp(symbol,"KMD") == 0 ) + matched = 1; + else matched = (strcmp(symbol,ASSETCHAINS_SYMBOL) == 0); + if ( fread(&ht,1,sizeof(ht),fp) != sizeof(ht) ) + errs++; + //printf("fpos.%ld func.(%d %c) ht.%d ",ftell(fp),func,func,ht); + if ( func == 'P' ) + { + if ( (num= fgetc(fp)) <= 64 ) + { + if ( fread(pubkeys,33,num,fp) != num ) + errs++; + else + { + //printf("updated %d pubkeys at %s ht.%d\n",num,symbol,ht); + //if ( (KOMODO_EXTERNAL_NOTARIES != 0 && matched != 0) || (strcmp(symbol,"KMD") == 0 && KOMODO_EXTERNAL_NOTARIES == 0) ) + // komodo_eventadd_pubkeys(sp,symbol,ht,num,pubkeys); + } + } else printf("illegal num.%d\n",num); + } + else if ( func == 'N' ) + { + if ( fread(¬arized_height,1,sizeof(notarized_height),fp) != sizeof(notarized_height) ) + errs++; + if ( fread(¬arized_hash,1,sizeof(notarized_hash),fp) != sizeof(notarized_hash) ) + errs++; + if ( fread(¬arized_desttxid,1,sizeof(notarized_desttxid),fp) != sizeof(notarized_desttxid) ) + errs++; + //if ( matched != 0 ) global independent states -> inside *sp + //komodo_eventadd_notarized(sp,symbol,ht,dest,notarized_hash,notarized_desttxid,notarized_height); + } + else if ( func == 'U' ) // deprecated + { + uint8_t n,nid; bits256 hash; uint64_t mask; + n = fgetc(fp); + nid = fgetc(fp); + //printf("U %d %d\n",n,nid); + if ( fread(&mask,1,sizeof(mask),fp) != sizeof(mask) ) + errs++; + if ( fread(&hash,1,sizeof(hash),fp) != sizeof(hash) ) + errs++; + //if ( matched != 0 ) + // komodo_eventadd_utxo(sp,symbol,ht,nid,hash,mask,n); + } + else if ( func == 'K' ) + { + int32_t kheight; + if ( fread(&kheight,1,sizeof(kheight),fp) != sizeof(kheight) ) + errs++; + //if ( matched != 0 ) global independent states -> inside *sp + //printf("%s.%d load[%s] ht.%d\n",ASSETCHAINS_SYMBOL,ht,symbol,kheight); + komodo_eventadd_kmdheight(sp,symbol,ht,kheight,0); + } + else if ( func == 'T' ) + { + int32_t kheight,ktimestamp; + if ( fread(&kheight,1,sizeof(kheight),fp) != sizeof(kheight) ) + errs++; + if ( fread(&ktimestamp,1,sizeof(ktimestamp),fp) != sizeof(ktimestamp) ) + errs++; + //if ( matched != 0 ) global independent states -> inside *sp + //printf("%s.%d load[%s] ht.%d t.%u\n",ASSETCHAINS_SYMBOL,ht,symbol,kheight,ktimestamp); + komodo_eventadd_kmdheight(sp,symbol,ht,kheight,ktimestamp); + } + else if ( func == 'R' ) + { + uint16_t olen,v; uint64_t ovalue; bits256 txid; uint8_t opret[16384]; + if ( fread(&txid,1,sizeof(txid),fp) != sizeof(txid) ) + errs++; + if ( fread(&v,1,sizeof(v),fp) != sizeof(v) ) + errs++; + if ( fread(&ovalue,1,sizeof(ovalue),fp) != sizeof(ovalue) ) + errs++; + if ( fread(&olen,1,sizeof(olen),fp) != sizeof(olen) ) + errs++; + if ( olen < sizeof(opret) ) + { + if ( fread(opret,1,olen,fp) != olen ) + errs++; + if ( 0 && matched != 0 ) + { + int32_t i; for (i=0; i global PAX + } else + { + int32_t i; + for (i=0; i global PVALS + //printf("%s load[%s] prices %d\n",ASSETCHAINS_SYMBOL,symbol,ht); + //komodo_eventadd_pricefeed(sp,symbol,ht,pvals,numpvals); + //printf("load pvals ht.%d numpvals.%d\n",ht,numpvals); + } else printf("error loading pvals[%d]\n",numpvals); + } + else printf("[%s] %s illegal func.(%d %c)\n",ASSETCHAINS_SYMBOL,symbol,func,func); + return(func); + } else return(-1); +} + +void stats_stateupdate(char *destdir,char *statefname,int32_t maxseconds) +{ + static long lastpos; + char fname[512],symbol[64],base[64],dest[64]; int32_t n; FILE *fp; uint32_t starttime; struct komodo_state *sp; + starttime = (uint32_t)time(NULL); + strcpy(base,"KV"); + strcpy(symbol,"KV"); + strcpy(dest,"KMD"); + sp = &KOMODO_STATE; + n = 0; + if ( (fp= fopen(fname,"rb")) != 0 && sp != 0 ) + { + fseek(fp,0,SEEK_END); + if ( ftell(fp) > lastpos ) + { + fseek(fp,lastpos,SEEK_SET); + while ( komodo_parsestatefile(sp,fp,symbol,dest) >= 0 && n < 1000 ) + { + if ( n == 999 ) + { + if ( time(NULL) < starttime+maxseconds ) + n = 0; + else break; + } + n++; + } + lastpos = ftell(fp); + } + fclose(fp); + } +} + +char *stats_update(char *destdir,char *statefname) +{ + cJSON *retjson = cJSON_CreateArray(); + stats_stateupdate(destdir,statefname,10); + return(jprint(retjson,1)); +} + +int main(int argc, const char * argv[]) +{ + FILE *fp; char *filestr,*statefname; + if ( argc < 2 ) + statefname = "/root/.komodo/KV/komodostate"; + else statefname = (char *)argv[1]; + printf("DEX stats running\n"); + while ( 1 ) + { + if ( (filestr= stats_update(STATS_DEST,statefname)) != 0 ) + { + printf("%u: %s\n",(uint32_t)time(NULL),filestr); + if ( (fp= fopen(STATS_DEST,"wb")) != 0 ) + { + fwrite(filestr,1,strlen(filestr)+1,fp); + fclose(fp); + } + free(filestr); + } + sleep(60); + } + return 0; +} diff --git a/iguana/m_stats b/iguana/m_stats new file mode 100755 index 000000000..b3a26cf18 --- /dev/null +++ b/iguana/m_stats @@ -0,0 +1 @@ +gcc -o stats -I../crypto777 exchanges/stats.c ../crypto777/cJSON.c ../agents/libcrypto777.a -lcurl -lpthread -lm diff --git a/iguana/stats b/iguana/stats new file mode 100755 index 0000000000000000000000000000000000000000..4979b85e020e35d211b74fbcdc05f200f3fbcab3 GIT binary patch literal 346064 zcmeFa3wTu3xi>zOWFS!DjutAXibMq^Dw?!lL7>g(jPB8ipc3yEHHytag(~qx$^PT)XU`xy9$tUx&945I({Zi zn&7>{f3yGE@hr{!=g!Rbm?NBF7+}(*iT)cWW;T)jvvM*E?L2UEdGG_2oew69y2AVU{%nD_-=3tCcRJ+S z@KX2@-lQMheeblpA3&q7@Ma!V@UB+qxtJ&2lmEKmSN`Di2P*Er$8OLSUfW>>Z}~vg zfcf_(qTtopK$!1}QxX^wcsq4uj^fROur*FKv()r z_^pChV^5g*uZDN$gQ;ECeLdP1D|ok`o`RA}sXd*-M)C1|_f5UuDeH<~$;MpamxB}@ z_P?)!my&bAz|~jzeE~;CwJA8RSvHV*1*Q2JmFGIxqCpDIa=EI7r_in%CDnL3UD+T% zn&X-aoL+6ran+selD)vK`|9U8uFY8M=0T`D&*l0C$|kS_{yk^^v}2$r(dI@e?fKWh z(>$&}^-y&Z$_nt)4?h=GKKQ^z_g36_(Or+;dl&NjcN%_($5|^c`f|aABlo>=(z==7 zIpejvhM+7TKdyd#!Vl{d3+E!$J2f`OFRy&y-U~-u z2rMe@M5X-e-ft5K?#}3U-J=gqzx%!mFHP@x4tf*MqR(<%w_~Fe+WA?aD{=VOzkgBS zUljNk1^z{We^KCH6!;ef{--EVrW>E=HG2zS2Nl=9MN21WhA(YRB!ZE=SF3YerI9{C zqqIXembRkMSk!{wx-q8-kIAv{_wj ht*QJ=EYfV!E-(SRFK?RzqI4t2psCLF%Si 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 literal 0 HcmV?d00001 From 049f17f15f94a5f8e7510f379cf392a21de3ab04 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 2 May 2017 20:47:39 +0300 Subject: [PATCH 0396/2705] Test --- iguana/stats | Bin 346064 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 iguana/stats diff --git a/iguana/stats b/iguana/stats deleted file mode 100755 index 4979b85e020e35d211b74fbcdc05f200f3fbcab3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 346064 zcmeFa3wTu3xi>zOWFS!DjutAXibMq^Dw?!lL7>g(jPB8ipc3yEHHytag(~qx$^PT)XU`xy9$tUx&945I({Zi zn&7>{f3yGE@hr{!=g!Rbm?NBF7+}(*iT)cWW;T)jvvM*E?L2UEdGG_2oew69y2AVU{%nD_-=3tCcRJ+S z@KX2@-lQMheeblpA3&q7@Ma!V@UB+qxtJ&2lmEKmSN`Di2P*Er$8OLSUfW>>Z}~vg zfcf_(qTtopK$!1}QxX^wcsq4uj^fROur*FKv()r z_^pChV^5g*uZDN$gQ;ECeLdP1D|ok`o`RA}sXd*-M)C1|_f5UuDeH<~$;MpamxB}@ z_P?)!my&bAz|~jzeE~;CwJA8RSvHV*1*Q2JmFGIxqCpDIa=EI7r_in%CDnL3UD+T% zn&X-aoL+6ran+selD)vK`|9U8uFY8M=0T`D&*l0C$|kS_{yk^^v}2$r(dI@e?fKWh z(>$&}^-y&Z$_nt)4?h=GKKQ^z_g36_(Or+;dl&NjcN%_($5|^c`f|aABlo>=(z==7 zIpejvhM+7TKdyd#!Vl{d3+E!$J2f`OFRy&y-U~-u z2rMe@M5X-e-ft5K?#}3U-J=gqzx%!mFHP@x4tf*MqR(<%w_~Fe+WA?aD{=VOzkgBS zUljNk1^z{We^KCH6!;ef{--EVrW>E=HG2zS2Nl=9MN21WhA(YRB!ZE=SF3YerI9{C zqqIXembRkMSk!{wx-q8-kIAv{_wj ht*QJ=EYfV!E-(SRFK?RzqI4t2psCLF%Si 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 From 4976f3ddf56880d8408454bc9c60486c9ef4ea8d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 2 May 2017 20:49:55 +0300 Subject: [PATCH 0397/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index e31fd12ab..6f937159e 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -266,14 +266,14 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char void stats_stateupdate(char *destdir,char *statefname,int32_t maxseconds) { static long lastpos; - char fname[512],symbol[64],base[64],dest[64]; int32_t n; FILE *fp; uint32_t starttime; struct komodo_state *sp; + char symbol[64],base[64],dest[64]; int32_t n; FILE *fp; uint32_t starttime; struct komodo_state *sp; starttime = (uint32_t)time(NULL); strcpy(base,"KV"); strcpy(symbol,"KV"); strcpy(dest,"KMD"); sp = &KOMODO_STATE; n = 0; - if ( (fp= fopen(fname,"rb")) != 0 && sp != 0 ) + if ( (fp= fopen(statefname,"rb")) != 0 && sp != 0 ) { fseek(fp,0,SEEK_END); if ( ftell(fp) > lastpos ) From fa95f8f3d67d6a6ca81cc424d95e201ad02647cb Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 2 May 2017 20:53:47 +0300 Subject: [PATCH 0398/2705] Test --- iguana/exchanges/stats.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 6f937159e..8c6e11805 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -47,7 +47,8 @@ struct komodo_state }; struct komodo_state KOMODO_STATE; -void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) + +void komodo_kvupdate(int32_t height,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) { static bits256 zeroes; uint32_t flags; bits256 pubkey,refpubkey,sig; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; @@ -93,7 +94,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) printf(" -> "); for (i=0; i Date: Tue, 2 May 2017 20:54:41 +0300 Subject: [PATCH 0399/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 8c6e11805..83a404a35 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -48,7 +48,7 @@ struct komodo_state struct komodo_state KOMODO_STATE; -void komodo_kvupdate(int32_t height,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) +void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) { static bits256 zeroes; uint32_t flags; bits256 pubkey,refpubkey,sig; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; @@ -94,7 +94,7 @@ void komodo_kvupdate(int32_t height,bits256 txid,int32_t vout,uint8_t *opretbuf, printf(" -> "); for (i=0; i Date: Tue, 2 May 2017 20:55:46 +0300 Subject: [PATCH 0400/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 83a404a35..8f650a35a 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -92,7 +92,7 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 for (i=0; i "); - for (i=0; i Date: Tue, 2 May 2017 20:57:04 +0300 Subject: [PATCH 0401/2705] Test --- iguana/exchanges/stats.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 8f650a35a..2e8246b88 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -92,9 +92,9 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 for (i=0; i "); - for (i=0; i Date: Tue, 2 May 2017 20:58:38 +0300 Subject: [PATCH 0402/2705] Test --- iguana/exchanges/stats.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 2e8246b88..a8c2165e4 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -51,7 +51,7 @@ struct komodo_state KOMODO_STATE; void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) { static bits256 zeroes; - uint32_t flags; bits256 pubkey,refpubkey,sig; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; + uint32_t flags; bits256 pubkey,refpubkey,sig; char decodestr[10000]; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; iguana_rwnum(0,&opretbuf[1],sizeof(keylen),&keylen); iguana_rwnum(0,&opretbuf[3],sizeof(valuesize),&valuesize); iguana_rwnum(0,&opretbuf[5],sizeof(height),&height); @@ -94,7 +94,8 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 printf(" -> "); //for (i=0; i Date: Tue, 2 May 2017 21:00:08 +0300 Subject: [PATCH 0403/2705] Test --- iguana/exchanges/stats.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index a8c2165e4..63d875a9e 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -92,10 +92,10 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 for (i=0; i "); - //for (i=0; i Date: Tue, 2 May 2017 21:01:34 +0300 Subject: [PATCH 0404/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 63d875a9e..0946e2b15 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -93,8 +93,8 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 putchar((char)key[i]); printf(" -> "); for (i=0; i Date: Tue, 2 May 2017 21:02:54 +0300 Subject: [PATCH 0405/2705] Test --- iguana/exchanges/stats.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 0946e2b15..71502b718 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -92,9 +92,9 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 for (i=0; i "); - for (i=0; i Date: Tue, 2 May 2017 21:03:33 +0300 Subject: [PATCH 0406/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 71502b718..cc5d01b77 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -95,7 +95,7 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 //for (i=0; i Date: Tue, 2 May 2017 21:04:47 +0300 Subject: [PATCH 0407/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index cc5d01b77..68f4b9293 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -94,7 +94,7 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 printf(" -> "); //for (i=0; i Date: Tue, 2 May 2017 21:07:56 +0300 Subject: [PATCH 0408/2705] Test --- iguana/exchanges/stats.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 68f4b9293..27e524ff3 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -92,9 +92,9 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 for (i=0; i "); - //for (i=0; i Date: Tue, 2 May 2017 21:09:23 +0300 Subject: [PATCH 0409/2705] Test --- iguana/exchanges/stats.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 27e524ff3..7371fd9c4 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -51,7 +51,7 @@ struct komodo_state KOMODO_STATE; void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) { static bits256 zeroes; - uint32_t flags; bits256 pubkey,refpubkey,sig; char decodestr[10000]; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; + uint32_t flags; bits256 pubkey,refpubkey,sig; cJSON *kvjson; char decodestr[10000]; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; iguana_rwnum(0,&opretbuf[1],sizeof(keylen),&keylen); iguana_rwnum(0,&opretbuf[3],sizeof(valuesize),&valuesize); iguana_rwnum(0,&opretbuf[5],sizeof(height),&height); @@ -89,13 +89,18 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 } } }*/ - for (i=0; i "); - for (i=0; i "); + printf(" (%s) [%d] %s/v%d ht.%d height.%d\n",decodestr,valuesize,bits256_str(str,txid),vout,ht,height); + free_json(kvjson); + } } } From 1de13581a4b31e31033496a0c8ce3142157ef0de Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:15:33 +0300 Subject: [PATCH 0410/2705] Test --- iguana/exchanges/stats.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 7371fd9c4..4f20c0f97 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -48,6 +48,11 @@ struct komodo_state struct komodo_state KOMODO_STATE; +void stats_kvjson(char *key,cJSON *kvjson) +{ + printf("(%s) -> (%s)\n",key,jprint(kvjson,0)); +} + void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) { static bits256 zeroes; @@ -94,11 +99,13 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 decode_hex(decodestr,coresize/2,valueptr); if ( (kvjson= cJSON_Parse(decodestr)) != 0 ) { - char str[65]; - for (i=0; i "); - printf(" (%s) [%d] %s/v%d ht.%d height.%d\n",decodestr,valuesize,bits256_str(str,txid),vout,ht,height); + //char str[65]; + //for (i=0; i "); + //printf(" (%s) [%d] %s/v%d ht.%d height.%d\n",decodestr,valuesize,bits256_str(str,txid),vout,ht,height); + if ( key[keylen-1] == 0 ) + stats_kvjson((char *)key,kvjson); free_json(kvjson); } } From 86fc96d7fa9435083de30b34bc2691bc7e68ae7a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:18:29 +0300 Subject: [PATCH 0411/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 4f20c0f97..2764d420b 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -48,7 +48,7 @@ struct komodo_state struct komodo_state KOMODO_STATE; -void stats_kvjson(char *key,cJSON *kvjson) +void stats_kvjson(char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) { printf("(%s) -> (%s)\n",key,jprint(kvjson,0)); } @@ -105,7 +105,7 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 //printf(" -> "); //printf(" (%s) [%d] %s/v%d ht.%d height.%d\n",decodestr,valuesize,bits256_str(str,txid),vout,ht,height); if ( key[keylen-1] == 0 ) - stats_kvjson((char *)key,kvjson); + stats_kvjson((char *)key,kvjson,pubkey,sig); free_json(kvjson); } } From 2b94336d33ab306e82fdde96aa9c3b0858e20900 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:19:18 +0300 Subject: [PATCH 0412/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 2764d420b..9873ed980 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -104,8 +104,8 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 // putchar((char)key[i]); //printf(" -> "); //printf(" (%s) [%d] %s/v%d ht.%d height.%d\n",decodestr,valuesize,bits256_str(str,txid),vout,ht,height); - if ( key[keylen-1] == 0 ) - stats_kvjson((char *)key,kvjson,pubkey,sig); + key[keylen] = 0; + stats_kvjson((char *)key,kvjson,pubkey,sig); free_json(kvjson); } } From b8c5be3765595a00dec0386bc85a7492a4888f7c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:21:04 +0300 Subject: [PATCH 0413/2705] Test --- iguana/exchanges/stats.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 9873ed980..2a3e33a5e 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -130,6 +130,7 @@ void komodo_setkmdheight(struct komodo_state *sp,int32_t kmdheight,uint32_t time { sp->SAVEDHEIGHT = kmdheight; sp->SAVEDTIMESTAMP = timestamp; + printf("ht.%d t.%u\n",kmdheight,timestamp); } if ( kmdheight > sp->CURRENT_HEIGHT ) sp->CURRENT_HEIGHT = kmdheight; From b3ba181b7d8480df3b09fb016408e0824cb27369 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:23:25 +0300 Subject: [PATCH 0414/2705] Test --- iguana/exchanges/stats.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 2a3e33a5e..e8cc7767b 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -48,12 +48,12 @@ struct komodo_state struct komodo_state KOMODO_STATE; -void stats_kvjson(char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) +void stats_kvjson(int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) { - printf("(%s) -> (%s)\n",key,jprint(kvjson,0)); + printf("(%d/%d).%u (%s) -> (%s)\n",height,savedheight,timestamp,key,jprint(kvjson,0)); } -void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) +void komodo_kvupdate(struct komodo_state *sp,int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) { static bits256 zeroes; uint32_t flags; bits256 pubkey,refpubkey,sig; cJSON *kvjson; char decodestr[10000]; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; @@ -105,7 +105,7 @@ void komodo_kvupdate(int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int3 //printf(" -> "); //printf(" (%s) [%d] %s/v%d ht.%d height.%d\n",decodestr,valuesize,bits256_str(str,txid),vout,ht,height); key[keylen] = 0; - stats_kvjson((char *)key,kvjson,pubkey,sig); + stats_kvjson(ht,sp->SAVEDHEIGHT,sp->SAVEDTIMESTAMP,(char *)key,kvjson,pubkey,sig); free_json(kvjson); } } @@ -117,7 +117,7 @@ void komodo_eventadd_opreturn(struct komodo_state *sp,char *symbol,int32_t heigh { if ( opretbuf[0] == 'K' && opretlen != 40 ) { - komodo_kvupdate(height,txid,vout,opretbuf,opretlen,value); + komodo_kvupdate(sp,height,txid,vout,opretbuf,opretlen,value); } } } From 3aa611b2f979d805cb58473beee07218cc2b35b4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:29:36 +0300 Subject: [PATCH 0415/2705] Test --- iguana/exchanges/stats.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index e8cc7767b..b6a88cb74 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -50,7 +50,9 @@ struct komodo_state KOMODO_STATE; void stats_kvjson(int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) { - printf("(%d/%d).%u (%s) -> (%s)\n",height,savedheight,timestamp,key,jprint(kvjson,0)); + struct tai T; int32_t seconds; + datenum = OS_conv_unixtime(&T,&seconds,timestamp); + printf("%d.%u (%s) -> (%s)\n",datenum,seconds,timestamp,key,jprint(kvjson,0)); } void komodo_kvupdate(struct komodo_state *sp,int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) From 66a252d37f226b690a3d8ffe9369046f6870349c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:30:06 +0300 Subject: [PATCH 0416/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index b6a88cb74..e98111144 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -50,7 +50,7 @@ struct komodo_state KOMODO_STATE; void stats_kvjson(int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) { - struct tai T; int32_t seconds; + struct tai T; int32_t seconds,datenum; datenum = OS_conv_unixtime(&T,&seconds,timestamp); printf("%d.%u (%s) -> (%s)\n",datenum,seconds,timestamp,key,jprint(kvjson,0)); } From 4815d69eb74a62b684adc73c9dad1ef1f9fac53b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:30:41 +0300 Subject: [PATCH 0417/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index e98111144..d150b39ca 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -52,7 +52,7 @@ void stats_kvjson(int32_t height,int32_t savedheight,uint32_t timestamp,char *ke { struct tai T; int32_t seconds,datenum; datenum = OS_conv_unixtime(&T,&seconds,timestamp); - printf("%d.%u (%s) -> (%s)\n",datenum,seconds,timestamp,key,jprint(kvjson,0)); + printf("%d.%d %u (%s) -> (%s)\n",datenum,seconds,timestamp,key,jprint(kvjson,0)); } void komodo_kvupdate(struct komodo_state *sp,int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) From bc2821ff82e1e6c354f2f7ed46e608199519adfd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:37:43 +0300 Subject: [PATCH 0418/2705] Test --- iguana/exchanges/stats.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index d150b39ca..5c9e80450 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -48,11 +48,16 @@ struct komodo_state struct komodo_state KOMODO_STATE; -void stats_kvjson(int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) +void stats_kvjson(FILE *fp,int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) { struct tai T; int32_t seconds,datenum; datenum = OS_conv_unixtime(&T,&seconds,timestamp); - printf("%d.%d %u (%s) -> (%s)\n",datenum,seconds,timestamp,key,jprint(kvjson,0)); + jaddnum(kvjson,"key",key); + jaddnum(kvjson,"datenum",datenum); + jaddnum(kvjson,"hour",seconds/3600); + jaddnum(kvjson,"seconds",seconds % 3600); + jaddnum(kvjson,"height",height); + printf("(%s)\n",jprint(kvjson,0)); } void komodo_kvupdate(struct komodo_state *sp,int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) From 36ce41ebe3e7d7a91ae976b19bf1f079d27b61fa Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:40:38 +0300 Subject: [PATCH 0419/2705] Test --- iguana/exchanges/stats.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 5c9e80450..2833c92ec 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -60,7 +60,7 @@ void stats_kvjson(FILE *fp,int32_t height,int32_t savedheight,uint32_t timestamp printf("(%s)\n",jprint(kvjson,0)); } -void komodo_kvupdate(struct komodo_state *sp,int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) +void komodo_kvupdate(FILE *logfp,struct komodo_state *sp,int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) { static bits256 zeroes; uint32_t flags; bits256 pubkey,refpubkey,sig; cJSON *kvjson; char decodestr[10000]; int32_t i,refvaluesize,hassig,coresize,haspubkey,height,kvheight; uint16_t keylen,valuesize,newflag = 0; uint8_t *key,*valueptr,keyvalue[10000]; @@ -112,19 +112,19 @@ void komodo_kvupdate(struct komodo_state *sp,int32_t ht,bits256 txid,int32_t vou //printf(" -> "); //printf(" (%s) [%d] %s/v%d ht.%d height.%d\n",decodestr,valuesize,bits256_str(str,txid),vout,ht,height); key[keylen] = 0; - stats_kvjson(ht,sp->SAVEDHEIGHT,sp->SAVEDTIMESTAMP,(char *)key,kvjson,pubkey,sig); + stats_kvjson(logfp,ht,sp->SAVEDHEIGHT,sp->SAVEDTIMESTAMP,(char *)key,kvjson,pubkey,sig); free_json(kvjson); } } } -void komodo_eventadd_opreturn(struct komodo_state *sp,char *symbol,int32_t height,bits256 txid,uint64_t value,uint16_t vout,uint8_t *opretbuf,uint16_t opretlen) +void komodo_eventadd_opreturn(FILE *logfp,struct komodo_state *sp,char *symbol,int32_t height,bits256 txid,uint64_t value,uint16_t vout,uint8_t *opretbuf,uint16_t opretlen) { if ( sp != 0 ) { if ( opretbuf[0] == 'K' && opretlen != 40 ) { - komodo_kvupdate(sp,height,txid,vout,opretbuf,opretlen,value); + komodo_kvupdate(logfp,sp,height,txid,vout,opretbuf,opretlen,value); } } } @@ -164,7 +164,7 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig } } -int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char *dest) +int32_t komodo_parsestatefile(FILE *logfp,struct komodo_state *sp,FILE *fp,char *symbol,char *dest) { static int32_t errs; int32_t func,ht,notarized_height,num,matched=0; bits256 notarized_hash,notarized_desttxid; uint8_t pubkeys[64][33]; @@ -255,7 +255,7 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char printf("%02x",opret[i]); printf(" %s.%d load[%s] opret[%c] len.%d %.8f\n",ASSETCHAINS_SYMBOL,ht,symbol,opret[0],olen,(double)ovalue/SATOSHIDEN); } - komodo_eventadd_opreturn(sp,symbol,ht,txid,ovalue,v,opret,olen); // global shared state -> global PAX + komodo_eventadd_opreturn(logfp,sp,symbol,ht,txid,ovalue,v,opret,olen); // global shared state -> global PAX } else { int32_t i; @@ -285,7 +285,7 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char } else return(-1); } -void stats_stateupdate(char *destdir,char *statefname,int32_t maxseconds) +void stats_stateupdate(FILE *logfp,char *destdir,char *statefname,int32_t maxseconds) { static long lastpos; char symbol[64],base[64],dest[64]; int32_t n; FILE *fp; uint32_t starttime; struct komodo_state *sp; @@ -301,7 +301,7 @@ void stats_stateupdate(char *destdir,char *statefname,int32_t maxseconds) if ( ftell(fp) > lastpos ) { fseek(fp,lastpos,SEEK_SET); - while ( komodo_parsestatefile(sp,fp,symbol,dest) >= 0 && n < 1000 ) + while ( komodo_parsestatefile(logfp,sp,fp,symbol,dest) >= 0 && n < 1000 ) { if ( n == 999 ) { @@ -317,23 +317,25 @@ void stats_stateupdate(char *destdir,char *statefname,int32_t maxseconds) } } -char *stats_update(char *destdir,char *statefname) +char *stats_update(FILE *logfp,char *destdir,char *statefname) { cJSON *retjson = cJSON_CreateArray(); - stats_stateupdate(destdir,statefname,10); + stats_stateupdate(logfp,destdir,statefname,10); return(jprint(retjson,1)); } int main(int argc, const char * argv[]) { - FILE *fp; char *filestr,*statefname; + FILE *fp,*logfp; char *filestr,*statefname,logfname[512]; if ( argc < 2 ) statefname = "/root/.komodo/KV/komodostate"; else statefname = (char *)argv[1]; + sprintf(logfname,"%s/logfile",DEST_DIR); + logfp = fopen(logfname,"wb"); printf("DEX stats running\n"); while ( 1 ) { - if ( (filestr= stats_update(STATS_DEST,statefname)) != 0 ) + if ( (filestr= stats_update(logfp,STATS_DEST,statefname)) != 0 ) { printf("%u: %s\n",(uint32_t)time(NULL),filestr); if ( (fp= fopen(STATS_DEST,"wb")) != 0 ) From 8e2cb38601b7ecd59d1c9ea537a860e18e8e91c8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:42:07 +0300 Subject: [PATCH 0420/2705] Test --- iguana/exchanges/stats.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 2833c92ec..7b4a473f9 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -52,12 +52,17 @@ void stats_kvjson(FILE *fp,int32_t height,int32_t savedheight,uint32_t timestamp { struct tai T; int32_t seconds,datenum; datenum = OS_conv_unixtime(&T,&seconds,timestamp); - jaddnum(kvjson,"key",key); + jaddstr(kvjson,"key",key); jaddnum(kvjson,"datenum",datenum); jaddnum(kvjson,"hour",seconds/3600); jaddnum(kvjson,"seconds",seconds % 3600); jaddnum(kvjson,"height",height); printf("(%s)\n",jprint(kvjson,0)); + if ( logfp != 0 ) + { + fprintf(logfp,"%s\n",jprint(kvjson,0)); + fflush(logfp); + } } void komodo_kvupdate(FILE *logfp,struct komodo_state *sp,int32_t ht,bits256 txid,int32_t vout,uint8_t *opretbuf,int32_t opretlen,uint64_t value) @@ -330,7 +335,7 @@ int main(int argc, const char * argv[]) if ( argc < 2 ) statefname = "/root/.komodo/KV/komodostate"; else statefname = (char *)argv[1]; - sprintf(logfname,"%s/logfile",DEST_DIR); + sprintf(logfname,"%s/logfile",STATS_DESTDIR); logfp = fopen(logfname,"wb"); printf("DEX stats running\n"); while ( 1 ) From 2198d1e9db9fa275e67554c4dfa11ca69428b269 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:42:39 +0300 Subject: [PATCH 0421/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 7b4a473f9..d4d42599e 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -48,7 +48,7 @@ struct komodo_state struct komodo_state KOMODO_STATE; -void stats_kvjson(FILE *fp,int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) +void stats_kvjson(FILE *logfp,int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) { struct tai T; int32_t seconds,datenum; datenum = OS_conv_unixtime(&T,&seconds,timestamp); From 72a32ace0aedddf8ada1347e93260d4d26a6d867 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:49:37 +0300 Subject: [PATCH 0422/2705] Test --- iguana/exchanges/stats.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index d4d42599e..0a2e50b25 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -48,18 +48,34 @@ struct komodo_state struct komodo_state KOMODO_STATE; +void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t timestamp,int32_t height,char *key,char *LPpubkey,cJSON *tradejson) +{ + uint64_t srcamount,destamount; char *source,*dest; + if ( LPpubkey != 0 ) + stats_LPpubkeyupdate(LPpubkey,timestamp); + if ( tradejson != 0 ) + { + source = jstr(jitem(array,0),0); + srcamount = SATOSHIDEN * jdouble(jitem(array,1),0); + dest = jstr(jitem(array,2),0); + destamount = SATOSHIDEN * jdouble(jitem(array,3),0); + printf("%s (%s %.8f) -> (%s %.8f)\n",key,source,dstr(srcamount),dest,dstr(destamount)); + } +} + void stats_kvjson(FILE *logfp,int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) { - struct tai T; int32_t seconds,datenum; + struct tai T; int32_t seconds,datenum,n; datenum = OS_conv_unixtime(&T,&seconds,timestamp); jaddstr(kvjson,"key",key); jaddnum(kvjson,"datenum",datenum); jaddnum(kvjson,"hour",seconds/3600); jaddnum(kvjson,"seconds",seconds % 3600); jaddnum(kvjson,"height",height); - printf("(%s)\n",jprint(kvjson,0)); + //printf("(%s)\n",jprint(kvjson,0)); if ( logfp != 0 ) { + stats_datenumupdate(datenum,seconds/3600,seconds % 3600,height,key,jstr(kvjson,"pubkey"),jarray(&n,kvjson,"trade")); fprintf(logfp,"%s\n",jprint(kvjson,0)); fflush(logfp); } @@ -142,7 +158,7 @@ void komodo_setkmdheight(struct komodo_state *sp,int32_t kmdheight,uint32_t time { sp->SAVEDHEIGHT = kmdheight; sp->SAVEDTIMESTAMP = timestamp; - printf("ht.%d t.%u\n",kmdheight,timestamp); + //printf("ht.%d t.%u\n",kmdheight,timestamp); } if ( kmdheight > sp->CURRENT_HEIGHT ) sp->CURRENT_HEIGHT = kmdheight; From 6d7b4bc3565d5cdbb50e66eb41808a1e5462c257 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:51:27 +0300 Subject: [PATCH 0423/2705] Test --- iguana/exchanges/stats.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 0a2e50b25..2dab460bb 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -55,11 +55,11 @@ void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t t stats_LPpubkeyupdate(LPpubkey,timestamp); if ( tradejson != 0 ) { - source = jstr(jitem(array,0),0); - srcamount = SATOSHIDEN * jdouble(jitem(array,1),0); - dest = jstr(jitem(array,2),0); - destamount = SATOSHIDEN * jdouble(jitem(array,3),0); - printf("%s (%s %.8f) -> (%s %.8f)\n",key,source,dstr(srcamount),dest,dstr(destamount)); + source = jstr(jitem(tradejson,0),0); + srcamount = SATOSHIDEN * jdouble(jitem(tradejson,1),0); + dest = jstr(jitem(tradejson,2),0); + destamount = SATOSHIDEN * jdouble(jitem(tradejson,3),0); + printf("%d.%d.%d ht.%d %s (%s %.8f) -> (%s %.8f)\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount)); } } @@ -75,7 +75,7 @@ void stats_kvjson(FILE *logfp,int32_t height,int32_t savedheight,uint32_t timest //printf("(%s)\n",jprint(kvjson,0)); if ( logfp != 0 ) { - stats_datenumupdate(datenum,seconds/3600,seconds % 3600,height,key,jstr(kvjson,"pubkey"),jarray(&n,kvjson,"trade")); + stats_datenumupdate(datenum,seconds/3600,seconds % 3600,timestamp,height,key,jstr(kvjson,"pubkey"),jarray(&n,kvjson,"trade")); fprintf(logfp,"%s\n",jprint(kvjson,0)); fflush(logfp); } From 8050201c32e0a90bc8d9d081790bada36cdc925c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:52:15 +0300 Subject: [PATCH 0424/2705] Test --- iguana/exchanges/stats.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 2dab460bb..30bc6d687 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -48,6 +48,11 @@ struct komodo_state struct komodo_state KOMODO_STATE; +void stats_LPpubkeyupdate(char *LPpubkey,uint32_t timestamp) +{ + printf("LP.(%s) t.%u\n",LPpubkey,timestamp); +} + void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t timestamp,int32_t height,char *key,char *LPpubkey,cJSON *tradejson) { uint64_t srcamount,destamount; char *source,*dest; From 0463307b45f3e852a0cd3c53dc0abe1b382470b2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 15:53:47 +0300 Subject: [PATCH 0425/2705] Test --- iguana/exchanges/stats.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 30bc6d687..c21a5c37d 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -55,7 +55,7 @@ void stats_LPpubkeyupdate(char *LPpubkey,uint32_t timestamp) void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t timestamp,int32_t height,char *key,char *LPpubkey,cJSON *tradejson) { - uint64_t srcamount,destamount; char *source,*dest; + uint64_t srcamount,destamount; char *source,*dest; double price; if ( LPpubkey != 0 ) stats_LPpubkeyupdate(LPpubkey,timestamp); if ( tradejson != 0 ) @@ -64,7 +64,10 @@ void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t t srcamount = SATOSHIDEN * jdouble(jitem(tradejson,1),0); dest = jstr(jitem(tradejson,2),0); destamount = SATOSHIDEN * jdouble(jitem(tradejson,3),0); - printf("%d.%d.%d ht.%d %s (%s %.8f) -> (%s %.8f)\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount)); + if ( srcamount != 0 && destamount != 0 ) + price = (double)destamount / srcamount; + else price = 0.; + printf("%d.%02d.%04d ht.%-4d %s (%s %.8f) -> (%s %.8f) %.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price); } } From 4a335309e558a07372663ef933aa5d2ee4dad46e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 16:00:44 +0300 Subject: [PATCH 0426/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index c21a5c37d..76314f5e9 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -67,7 +67,7 @@ void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t t if ( srcamount != 0 && destamount != 0 ) price = (double)destamount / srcamount; else price = 0.; - printf("%d.%02d.%04d ht.%-4d %s (%s %.8f) -> (%s %.8f) %.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price); + printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %12.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price); } } From b5d97f24a2c1f431ff17e3022c4573267aa57537 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 16:01:20 +0300 Subject: [PATCH 0427/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 76314f5e9..ae3d7fe3c 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -67,7 +67,7 @@ void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t t if ( srcamount != 0 && destamount != 0 ) price = (double)destamount / srcamount; else price = 0.; - printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %12.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price); + printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price); } } From 3bad3ad52fec9d117b59fb4fef3cc43ad4fd58ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 May 2017 16:04:13 +0300 Subject: [PATCH 0428/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index ae3d7fe3c..636c8aa6b 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -67,7 +67,7 @@ void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t t if ( srcamount != 0 && destamount != 0 ) price = (double)destamount / srcamount; else price = 0.; - printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price); + printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price,1/price); } } From 31a4a7e67f10deaeac6e6ef450d354a32531f6ff Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 5 May 2017 14:18:45 +0300 Subject: [PATCH 0429/2705] batch16 --- iguana/dpow/dpow_rpc.c | 3 +- iguana/main.c | 4 +- iguana/tests/KMD.batch16 | 464 +++++++++++++++++++++++++++ iguana/tests/KMD.batch16.listunspent | 370 +++++++++++++++++++++ iguana/tests/REVS.batch16 | 19 ++ 5 files changed, 857 insertions(+), 3 deletions(-) create mode 100644 iguana/tests/KMD.batch16 create mode 100644 iguana/tests/KMD.batch16.listunspent create mode 100644 iguana/tests/REVS.batch16 diff --git a/iguana/dpow/dpow_rpc.c b/iguana/dpow/dpow_rpc.c index 0185a2f77..3a7c83aea 100755 --- a/iguana/dpow/dpow_rpc.c +++ b/iguana/dpow/dpow_rpc.c @@ -795,7 +795,8 @@ int32_t dpow_haveutxo(struct supernet_info *myinfo,struct iguana_info *coin,bits for (j=0; j 0 ) { totalKMD = totalREVS = 0; - for (iter=0; iter<1; iter++) + for (iter=3; iter<4; iter++) for (i=0; i Date: Fri, 5 May 2017 14:35:37 +0300 Subject: [PATCH 0430/2705] chmod --- iguana/tests/KMD.batch16 | 0 iguana/tests/KMD.batch16.listunspent | 0 iguana/tests/REVS.batch16 | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 iguana/tests/KMD.batch16 mode change 100644 => 100755 iguana/tests/KMD.batch16.listunspent mode change 100644 => 100755 iguana/tests/REVS.batch16 diff --git a/iguana/tests/KMD.batch16 b/iguana/tests/KMD.batch16 old mode 100644 new mode 100755 diff --git a/iguana/tests/KMD.batch16.listunspent b/iguana/tests/KMD.batch16.listunspent old mode 100644 new mode 100755 diff --git a/iguana/tests/REVS.batch16 b/iguana/tests/REVS.batch16 old mode 100644 new mode 100755 From dfd4e08807cb925de411ae9720fa8a5683b04b62 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 09:14:45 +0300 Subject: [PATCH 0431/2705] Fix spurious address in getaddressesbyaccount --- .gitignore | 10 + iguana/exchanges/DEXstats.h | 822 ++++++++++++++++++++++++++++++++++++ iguana/exchanges/stats.c | 679 ++++++++++++++++++++++++++++- iguana/iguana_wallet.c | 3 +- iguana/stats | Bin 0 -> 387304 bytes iguana/tests/statstest | 2 + 6 files changed, 1495 insertions(+), 21 deletions(-) create mode 100644 iguana/exchanges/DEXstats.h create mode 100755 iguana/stats create mode 100755 iguana/tests/statstest diff --git a/.gitignore b/.gitignore index b3674ef11..251e614b3 100755 --- a/.gitignore +++ b/.gitignore @@ -411,3 +411,13 @@ iguana/DB/SWAPS/912783809-2523701920 iguana/DB/SWAPS/1238069553-2363573428 iguana/DB/SWAPS/2895470622-2170247626 + +iguana/confs/ed476386688e486f359ce67e44ce4268a875125527e122ea9126ebc54f473d31 + +iguana/confs/f6e8e8ab82ed33b2de063d6820dcaefb99b95cf1aef6527b8f27e1e5b1fe882d + +iguana/e + +iguana/a + +iguana/t diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h new file mode 100644 index 000000000..4c426981f --- /dev/null +++ b/iguana/exchanges/DEXstats.h @@ -0,0 +1,822 @@ +// +// DEXstats.h +// marketmaker +// +// Created by Mac on 5/7/17. +// Copyright © 2017 SuperNET. All rights reserved. +// + +#ifndef DEXstats_h +#define DEXstats_h + +#define LEFTMARGIN 40 +#define MAX_SPLINES 1024 +#define MAX_LOOKAHEAD 60 + +struct stats_spline { char name[64]; int32_t splineid,lasti,basenum,num,firstx,dispincr,spline32[MAX_SPLINES][4]; uint32_t utc32[MAX_SPLINES]; int64_t spline64[MAX_SPLINES][4]; double dSplines[MAX_SPLINES][4],pricevals[MAX_SPLINES+MAX_LOOKAHEAD],lastutc,lastval,aveslopeabs; }; + +#define _extrapolate_Spline(Splines,gap) ((double)(Splines)[0] + ((gap) * ((double)(Splines)[1] + ((gap) * ((double)(Splines)[2] + ((gap) * (double)(Splines)[3])))))) +#define _extrapolate_Slope(Splines,gap) ((double)(Splines)[1] + ((gap) * ((double)(Splines)[2] + ((gap) * (double)(Splines)[3])))) + +#define dto64(x) ((int64_t)((x) * (double)SATOSHIDEN * SATOSHIDEN)) +#define dto32(x) ((int32_t)((x) * (double)SATOSHIDEN)) +#define i64tod(x) ((double)(x) / ((double)SATOSHIDEN * SATOSHIDEN)) +#define i32tod(x) ((double)(x) / (double)SATOSHIDEN) +#define _extrapolate_spline64(spline64,gap) ((double)i64tod((spline64)[0]) + ((gap) * ((double)i64tod(.001*.001*(spline64)[1]) + ((gap) * ((double)i64tod(.001*.001*.001*.001*(spline64)[2]) + ((gap) * (double)i64tod(.001*.001*.001*.001*.001*.001*(spline64)[3]))))))) +#define _extrapolate_spline32(spline32,gap) ((double)i32tod((spline32)[0]) + ((gap) * ((double)i32tod(.001*.001*(spline32)[1]) + ((gap) * ((double)i32tod(.001*.001*.001*.001*(spline32)[2]) + ((gap) * (double)i32tod(.001*.001*.001*.001*.001*.001*(spline32)[3]))))))) + +uint32_t forex_colors[16]; +double Display_scale = 1.; + +struct DEXstats_disp { double pricesum,volumesum; }; + +struct DEXstats_pricepoint +{ + double price,volume; + uint32_t height:27,hour:5; + uint16_t seconds; +}; + +struct DEXstats_pairinfo +{ + char dest[16]; + int32_t numprices; + struct DEXstats_pricepoint *prices; +}; + +struct DEXstats_datenuminfo +{ + int32_t numpairs,datenum; + struct DEXstats_pairinfo *pairs; +}; + +struct DEXstats_priceinfo +{ + char symbol[16]; + int32_t firstdatenum,numdates; + struct DEXstats_datenuminfo *dates; +} Prices[1024]; +int32_t Num_priceinfos; + +void stats_pricepoint(struct DEXstats_pricepoint *ptr,uint8_t hour,uint16_t seconds,int32_t height,double volume,double price) +{ + ptr->price = price; + ptr->volume = volume; + ptr->height = height; + ptr->hour = hour; + ptr->seconds = seconds; + printf("h.%d s.%-4d %.8f %.6f\n",hour,seconds,price,volume); +} + +void stats_pairupdate(struct DEXstats_datenuminfo *date,char *dest,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,double price) +{ + int32_t i; struct DEXstats_pairinfo *pair = 0; + if ( date->datenum != datenum || seconds < 0 || seconds >= 3600 || hour < 0 || hour >= 24 ) + { + printf("date->datenum %d != %d? hour.%d seconds.%d\n",date->datenum,datenum,hour,seconds); + return; + } + for (i=0; inumpairs; i++) + if ( strcmp(dest,date->pairs[i].dest) == 0 ) + { + pair = &date->pairs[i]; + break; + } + if ( i == date->numpairs ) + { + date->pairs = realloc(date->pairs,sizeof(*date->pairs) * (date->numpairs + 1)); + pair = &date->pairs[date->numpairs++]; + memset(pair,0,sizeof(*pair)); + strcpy(pair->dest,dest); + } + pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); + stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); +} + +void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,char *dest,double price) +{ + int32_t offset,i,n; struct DEXstats_datenuminfo *date; + if ( (offset= datenum - pp->firstdatenum) < 0 ) + { + printf("illegal datenum.%d for %s when 1st.%d\n",datenum,pp->symbol,pp->firstdatenum); + return; + } + if ( offset > pp->numdates ) + { + pp->dates = realloc(pp->dates,sizeof(*pp->dates) * (offset+1)); + n = (offset - pp->numdates); + for (i=0; i<=n; i++) + { + date = &pp->dates[pp->numdates + i]; + memset(date,0,sizeof(*date)); + date->datenum = pp->firstdatenum + pp->numdates + i; + } + } + stats_pairupdate(&pp->dates[offset],dest,datenum,hour,seconds,height,volume,price); +} + +struct DEXstats_priceinfo *stats_priceinfo(char *symbol,int32_t datenum) +{ + int32_t i; struct DEXstats_priceinfo *pp = 0; + if ( Num_priceinfos >= sizeof(Prices)/sizeof(*Prices) ) + return(0); + for (i=0; isymbol,symbol); + pp->firstdatenum = datenum; + } + return(pp); +} + +void stats_LPpubkeyupdate(char *LPpubkey,uint32_t timestamp) +{ + printf("LP.(%s) t.%u\n",LPpubkey,timestamp); +} + +void stats_priceupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t timestamp,int32_t height,char *key,char *LPpubkey,cJSON *tradejson) +{ + uint64_t srcamount,destamount; char *source,*dest; double price; struct DEXstats_priceinfo *pp; + if ( LPpubkey != 0 ) + stats_LPpubkeyupdate(LPpubkey,timestamp); + if ( tradejson != 0 ) + { + source = jstr(jitem(tradejson,0),0); + srcamount = SATOSHIDEN * jdouble(jitem(tradejson,1),0); + dest = jstr(jitem(tradejson,2),0); + destamount = SATOSHIDEN * jdouble(jitem(tradejson,3),0); + if ( srcamount != 0 && destamount != 0 ) + { + price = (double)destamount / srcamount; + if ( (pp= stats_priceinfo(source,datenum)) != 0 ) + stats_datenumupdate(pp,datenum,hour,seconds,height,dstr(srcamount),dest,price); + if ( (pp= stats_priceinfo(dest,datenum)) != 0 ) + stats_datenumupdate(pp,datenum,hour,seconds,height,dstr(destamount),source,1. / price); + } else price = 0.; + printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price,1./price); + } +} + +double _pairaved(double valA,double valB) +{ + if ( valA != 0. && valB != 0. ) + return((valA + valB) / 2.); + else if ( valA != 0. ) return(valA); + else return(valB); +} + +double calc_loganswer(double pastlogprice,double futurelogprice) +{ + if ( fabs(pastlogprice) < .0000001 || fabs(futurelogprice) < .0000001 ) + return(0); + return(10000. * (exp(futurelogprice - pastlogprice)-1.)); +} + +double _pairdiff(register double valA,register double valB) +{ + if ( valA != 0. && valB != 0. ) + return((valA - valB)); + else return(0.); +} + +double balanced_ave(double buf[],int32_t i,int32_t width) +{ + register int32_t nonz,j; register double sum,price; + nonz = 0; + sum = 0.0; + for (j=-width; j<=width; j++) + { + price = buf[i + j]; + if ( price != 0.0 ) + { + sum += price; + nonz++; + } + } + if ( nonz != 0 ) + sum /= nonz; + return(sum); +} + +void buf_trioave(double dest[],double src[],int32_t n) +{ + register int32_t i,j,width = 3; + for (i=0; i<128; i++) + src[i] = 0; + //for (i=n-width-1; i>width; i--) + // dest[i] = balanced_ave(src,i,width); + //for (i=width; i>0; i--) + // dest[i] = balanced_ave(src,i,i); + for (i=1; i>16)&0x0ff) + (float)((color>>8)&0x0ff) + (float)((color>>0)&0x0ff))/0x300); +} + +int32_t pixel_ratios(uint32_t red,uint32_t green,uint32_t blue) +{ + float max; + /*if ( red > green ) + max = red; + else + max = green; + if ( blue > max ) + max = blue;*/ + max = (red + green + blue); + if ( max == 0. ) + return(0); + if ( max > 0xff ) + { + red = (uint32_t)(((float)red / max) * 0xff); + green = (uint32_t)(((float)green / max) * 0xff); + blue = (uint32_t)(((float)blue / max) * 0xff); + } + + if ( red > 0xff ) + red = 0xff; + if ( green > 0xff ) + green = 0xff; + if ( blue > 0xff ) + blue = 0xff; + return((red << 16) | (green << 8) | blue); +} + +int32_t conv_yval_to_y(register float yval,register int32_t height) +{ + register int32_t y; + height = (height>>1) - 2; + y = (int32_t)-yval; + if ( y > height ) + y = height; + else if ( y < -height ) + y = -height; + + y += height; + if ( y < 0 ) + y = 0; + height <<= 1; + if ( y >= height-1 ) + y = height-1; + return(y); +} + +uint32_t scale_color(uint32_t color,float strength) +{ + int32_t red,green,blue; + if ( strength < 0. ) + strength = -strength; + red = (color>>16) & 0xff; + green = (color>>8) & 0xff; + blue = color & 0xff; + + red = (int32_t)((float)red * (strength/100.f)); + green = (int32_t)((float)green * (strength/100.f)); + blue = (int32_t)((float)blue * (strength/100.f)); + if ( red > 0xff ) + red = 0xff; + if ( green > 0xff ) + green = 0xff; + if ( blue > 0xff ) + blue = 0xff; + return((red<<16) | (green<<8) | blue); +} + +uint32_t pixel_blend(uint32_t pixel,uint32_t color)//,int32_t groupsize) +{ + int32_t red,green,blue,sum,n,n2,groupsize = 1; + float red2,green2,blue2,sum2; + if ( color == 0 ) + return(pixel); + if ( pixel == 0 ) + { + return((1<<24) | scale_color(color,100.f/(float)groupsize)); + } + n = (pixel>>24) & 0xff; + if ( n == 0 ) + n = 1; + pixel &= 0xffffff; + red = (pixel>>16) & 0xff; + green = (pixel>>8) & 0xff; + blue = pixel & 0xff; + sum = red + green + blue; + + n2 = (color>>24) & 0xff; + if ( n2 == 0 ) + n2 = 1; + red2 = ((float)((color>>16) & 0xff)) / groupsize; + green2 = ((float)((color>>8) & 0xff)) / groupsize; + blue2 = ((float)(color & 0xff)) / groupsize; + sum2 = (red2 + green2 + blue2); + + //printf("gs %d (%d x %d,%d,%d: %d) + (%d x %.1f,%.1f,%.1f: %.1f) = ",groupsize,n,red,green,blue,sum,n2,red2,green2,blue2,sum2); + red = (uint32_t)(((((((float)red / (float) sum) * n) + (((float)red2 / (float) sum2) * n2)) / (n+n2)) * ((sum+sum2)/2))); + green = (uint32_t)(((((((float)green / (float) sum) * n) + (((float)green2 / (float) sum2) * n2)) / (n+n2)) * ((sum+sum2)/2))); + blue = (uint32_t)(((((((float)blue / (float) sum) * n) + (((float)blue2 / (float) sum2) * n2)) / (n+n2)) * ((sum+sum2)/2))); + + n += n2; + if ( n > 0xff ) + n = 0xff; + ///printf("%x (%d,%d,%d) ",color,red,green,blue); + color = (n<<24) | pixel_ratios(red,green,blue);//pixel_overflow(&red,&green,&blue); + + //printf("%x (%d,%d,%d)\n",color,(color>>16)&0xff,(color>>8)&0xff,color&0xff); + return(color); +} + +void init_forex_colors(uint32_t *forex_colors) +{ + int32_t i; + forex_colors[0] = 0x00ff00; + forex_colors[1] = 0x0033ff; + forex_colors[2] = 0xff0000; + forex_colors[3] = 0x00ffff; + forex_colors[4] = 0xffff00; + forex_colors[5] = 0xff00ff; + forex_colors[6] = 0xffffff; + forex_colors[7] = 0xff8800; + forex_colors[8] = 0xff88ff; + for (i=9; i<16; i++) + forex_colors[i] = pixel_blend(forex_colors[i-8],0xffffff); +} + +int32_t is_primary_color(register uint32_t color) +{ + static uint32_t forex_colors[16]; + register int32_t i; + if ( forex_colors[0] == 0 ) + init_forex_colors(forex_colors); + for (i=0; i<8; i++) + if ( color == forex_colors[i] ) + return(1); + return(0); +} + +void disp_yval(register int32_t color,register float yval,register uint32_t *bitmap,register int32_t x,register int32_t rowwidth,register int32_t height) +{ + register int32_t y; + if ( forex_colors[0] == 0 ) + init_forex_colors(forex_colors); + x += LEFTMARGIN; + if ( x < 0 || x >= rowwidth ) + return; + //y = conv_yval_to_y(yval,height/Display_scale) * Display_scale; + y = conv_yval_to_y(yval * Display_scale,height); + if ( 1 && is_primary_color(color) != 0 ) + { + bitmap[y*rowwidth + x] = color; + return; + } + //if ( pixelwt(color) > pixelwt(bitmap[y*rowwidth + x]) ) + bitmap[y*rowwidth + x] = pixel_blend(bitmap[y*rowwidth + x],color); + return; + //if ( is_primary_color(color) != 0 || (is_primary_color(bitmap[y*rowwidth+x]) == 0 && pixelwt(color) > pixelwt(bitmap[y*rowwidth + x])) ) + // bitmap[y*rowwidth + x] = color; +} + +void disp_yvalsum(register int32_t color,register float yval,register uint32_t *bitmap,register int32_t x,register int32_t rowwidth,register int32_t height) +{ + int32_t y,red,green,blue,dispcolor; + x += LEFTMARGIN; + if ( x < 0 || x >= rowwidth ) + return; + y = conv_yval_to_y(yval * Display_scale,height); + red = (color>>16) & 0xff; + green = (color>>8) & 0xff; + blue = color & 0xff; + dispcolor = bitmap[y*rowwidth + x]; + red += (dispcolor>>16) & 0xff; + green += (dispcolor>>8) & 0xff; + blue += dispcolor & 0xff; + bitmap[y*rowwidth + x] = pixel_ratios(red,green,blue); +} + +void disp_dot(register float radius,register int32_t color,register float yval,register uint32_t *bitmap,register int32_t x,register int32_t rowwidth,register int32_t height) +{ + register float i,j,sq,val; + if ( radius > 1 ) + { + sq = radius * radius; + for (i=-radius; i<=radius; i++) + { + for (j=-radius; j<=radius; j++) + { + val = ((j*j + i*i) / sq); + if ( val <= 1. ) + { + val = 1. - val; + disp_yval(scale_color(color,(100 * val * val * val * val)),yval+j,bitmap,x+i,rowwidth,height); + } + } + } + } + else disp_yval(color,yval,bitmap,x,rowwidth,height); +} + +void horizline(int32_t calclogflag,int32_t rowwidth,int32_t height,uint32_t *bitmap,double rawprice,double ave) +{ + int32_t x; + double yval; + if ( calclogflag != 0 ) + yval = _calc_pricey(log(rawprice),log(ave)); + else yval = _calc_pricey(rawprice,ave); + for (x=0; x .0000000001 ) + { + aveabs += fabs(yval); + nonz++; + if ( color != 0 ) + disp_yval(color,yval,bitmap,x,rowwidth,height); + } + } else yval = 0.; + output[x] = yval; + } + if ( nonz != 0 ) + aveabs /= nonz; + return(aveabs); + // + //printf("ave %f rowwidth.%d\n",ave,rowwidth); +} + +double stats_splineval(struct stats_spline *spline,uint32_t timestamp,int32_t lookahead) +{ + int32_t i,gap,ind = (spline->num - 1); + if ( timestamp >= spline->utc32[ind] ) + { + gap = (timestamp - spline->utc32[ind]); + if ( gap < lookahead ) + return(_extrapolate_spline64(spline->spline64[ind],gap)); + else return(0.); + } + else if ( timestamp <= spline->utc32[0] ) + { + gap = (spline->utc32[0] - timestamp); + if ( gap < lookahead ) + return(_extrapolate_spline64(spline->spline64[0],gap)); + else return(0.); + } + for (i=0; inum-1; i++) + { + ind = (i + spline->lasti) % (spline->num - 1); + if ( timestamp >= spline->utc32[ind] && timestamp < spline->utc32[ind+1] ) + { + spline->lasti = ind; + return(_extrapolate_spline64(spline->spline64[ind],timestamp - spline->utc32[ind])); + } + } + return(0.); +} + +double stats_calcspline(struct stats_spline *spline,double *outputs,double *slopes,int32_t dispwidth,uint32_t *utc32,double *splinevals,int32_t num) +{ + static double errsums[3]; static int errcount; + double c[MAX_SPLINES],f[MAX_SPLINES],dd[MAX_SPLINES],dl[MAX_SPLINES],du[MAX_SPLINES],gaps[MAX_SPLINES]; + int32_t n,i,lasti,x,numsplines,nonz; double vx,vy,vw,vz,gap,sum,xval,yval,abssum,lastval,lastxval,yval64,yval32,yval3; uint32_t gap32; + sum = lastxval = n = lasti = nonz = 0; + for (i=0; i 0 ) + { + if ( (gaps[n-1]= utc32[i] - lastxval) < 0 ) + { + printf("illegal gap %f to t%d\n",lastxval,utc32[i]); + return(0); + } + } + spline->utc32[n] = lastxval = utc32[i]; + n++; + } + } + if ( (numsplines= n) < 4 ) + return(0); + for (i=0; i=0; i--) + c[i] -= c[i+1] * du[i]; + //tridiagonal(n-2, dl, dd, du, c); + + for (i=n-3; i>=0; i--) + c[i+1] = c[i]; + c[0] = (1.0 + (double)gaps[0] / gaps[1]) * c[1] - ((double)gaps[0] / gaps[1] * c[2]); + c[n-1] = (1.0 + (double)gaps[n-2] / gaps[n-3] ) * c[n-2] - ((double)gaps[n-2] / gaps[n-3] * c[n-3]); + //printf("c[n-1] %f, n-2 %f, n-3 %f\n",c[n-1],c[n-2],c[n-3]); + abssum = nonz = lastval = 0; + outputs[spline->firstx] = f[0]; + spline->num = numsplines; + for (i=0; iutc32[i],(vx),vy*1000*1000,vz*1000*1000*1000*1000,vw*1000*1000*1000*1000*1000*1000,gap,conv_unixtime(&tmp,spline->utc32[i])); + spline->dSplines[i][0] = vx, spline->dSplines[i][1] = vy, spline->dSplines[i][2] = vz, spline->dSplines[i][3] = vw; + spline->spline64[i][0] = dto64(vx), spline->spline64[i][1] = dto64(vy*1000*1000), spline->spline64[i][2] = dto64(vz*1000*1000*1000*1000), spline->spline64[i][3] = dto64(vw*1000*1000*1000*1000*1000*1000); + spline->spline32[i][0] = dto32(vx), spline->spline32[i][1] = dto32(vy*1000*1000), spline->spline32[i][2] = dto32(vz*1000*1000*1000*1000), spline->spline32[i][3] = dto32(vw*1000*1000*1000*1000*1000*1000); + gap32 = gap = spline->dispincr; + xval = spline->utc32[i] + gap; + lastval = vx; + while ( i < n-1 ) + { + x = spline->firstx + ((xval - spline->utc32[0]) / spline->dispincr); + if ( x > dispwidth-1 ) x = dispwidth-1; + if ( x < 0 ) x = 0; + if ( (i < n-2 && gap > gaps[i] + spline->dispincr) ) + break; + if ( i == n-2 && xval > spline->utc32[n-1] + MAX_LOOKAHEAD*spline->dispincr ) + { + //printf("x.%d dispwidth.%d xval %f > utc[n-1] %f + %f\n",x,dispwidth,xval,utc[n-1],MAX_LOOKAHEAD*incr); + break; + } + if ( x >= 0 ) + { + yval = _extrapolate_Spline(spline->dSplines[i],gap); + yval64 = _extrapolate_spline64(spline->spline64[i],gap32); + if ( (yval3 = stats_splineval(spline,gap32 + spline->utc32[i],MAX_LOOKAHEAD*spline->dispincr)) != 0 ) + { + yval32 = _extrapolate_spline32(spline->spline32[i],gap32); + errsums[0] += fabs(yval - yval64), errsums[1] += fabs(yval - yval32), errsums[2] += fabs(yval - yval3), errcount++; + if ( fabs(yval - yval3) > SMALLVAL ) + printf("(%.10f vs %.10f %.10f %.10f [%.16f %.16f %.16f]) ",yval,yval64,yval32,yval3, errsums[0]/errcount,errsums[1]/errcount,errsums[2]/errcount); + } + if ( yval > 5000. ) yval = 5000.; + else if ( yval < -5000. ) yval = -5000.; + if ( isnan(yval) == 0 ) + { + outputs[x] = yval; + spline->lastval = outputs[x], spline->lastutc = xval; + if ( 1 && fabs(lastval) > SMALLVAL ) + { + if ( lastval != 0 && outputs[x] != 0 ) + { + if ( slopes != 0 ) + slopes[x] = (outputs[x] - lastval), abssum += fabs(slopes[x]); + nonz++; + } + } + } + //else outputs[x] = 0.; + //printf("x.%-4d %d %f %f %f i%-4d: gap %9.6f %9.6f last %9.6f slope %9.6f | %9.1f [%9.1f %9.6f %9.6f %9.6f %9.6f]\n",x,firstx,xval,utc[0],incr,i,gap,yval,lastval,slopes[x],xval,utc[i+1],dSplines[i][0],dSplines[i][1]*1000*1000,dSplines[i][2]*1000*1000*1000*1000,dSplines[i][3]*1000*1000*1000*1000*1000*1000); + } + gap32 += spline->dispincr, gap += spline->dispincr, xval += spline->dispincr; + } + //double pred = (i>0) ? _extrapolate_Spline(dSplines[i-1],gaps[i-1]) : 0.; + //printf("%2d: w%8.1f [gap %f -> %9.6f | %9.6f %9.6f %9.6f %9.6f %9.6f]\n",i,weekinds[i],gap,pred,f[i],dSplines[i].x,1000000*dSplines[i].y,1000000*1000000*dSplines[i].z,1000000*1000000*1000*dSplines[i].w); + } + if ( nonz != 0 ) + abssum /= nonz; + spline->aveslopeabs = abssum; + return(lastval); +} + +int32_t stats_genspline(double output[2048],double slopes[2048],struct stats_spline *spline,int32_t splineid,char *name,uint32_t *utc32,double *splinevals,int32_t numsplines,double *refvals) +{ + int32_t i; double origvals[MAX_SPLINES]; + if ( numsplines > MAX_SPLINES ) + { + printf("numsplines.%d > MAX_SPLINES.%d\n",numsplines,MAX_SPLINES); + return(-1); + } + memset(spline,0,sizeof(*spline)), memset(output,0,sizeof(*output)*2048), memset(slopes,0,sizeof(*slopes)*2048); + spline->dispincr = 3600, spline->basenum = splineid, strcpy(spline->name,name); + memcpy(origvals,splinevals,sizeof(*splinevals) * MAX_SPLINES); + spline->lastval = stats_calcspline(spline,output,slopes,2048,utc32,splinevals,numsplines); + if ( refvals != 0 ) + { + for (i=0; inum; i++) + { + if ( i < spline->num ) + { + if ( 0 && refvals[i] != 0 && output[i * 24] != refvals[i] ) + printf("{%.8f != %.8f}.%d ",output[i * 24],refvals[i],i); + spline->pricevals[i] = output[i * 24]; + } + } + } + //printf("spline.%s num.%d\n",name,spline->num); + return(spline->num); +} + +void output_line(int32_t calclogflag,double ave,double *buf,int32_t n,int32_t color,uint32_t *bitmap,int32_t rowwidth,int32_t height) +{ + double src[1024],dest[1024]; int32_t i; + memset(src,0,sizeof(src)); + memset(dest,0,sizeof(dest)); + if ( (1) ) + { + for (i=0; i<1024; i++) + src[1023-i] = dest[1023-i] = buf[i]; + smooth1024(dest,src,3); + for (i=0; i<1024; i++) + src[1023-i] = dest[i]; + } + else + { + for (i=0; i<1024; i++) + src[i] = buf[i]; + } + _output_line(calclogflag,ave,buf,src,1024,color,bitmap,rowwidth,height); +} + +void stats_updatedisp(struct DEXstats_disp *disp,int32_t seconds,double price,double volume) +{ + if ( price > SMALLVAL && volume > SMALLVAL ) + { + disp->pricesum += (price * volume); + disp->volumesum += volume; + } +} + +void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates,struct DEXstats_datenuminfo *date,char *dest,int32_t current_daysecond) +{ + int32_t i,j,seconds,hour,offset,delta,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp; + if ( datenum >= leftdatenum-1 && datenum <= leftdatenum+numdates ) + { + offset = datenum - leftdatenum; + for (i=0; inumpairs; i++) + if ( strcmp(dest,date->pairs[i].dest) == 0 ) + { + pair = &date->pairs[i]; + for (j=0; jnumprices; j++) + { + ptr = &pair->prices[j]; + seconds = 3600*ptr->hour + ptr->seconds + (24*3600 - current_daysecond); + if ( seconds >= 24*3600 ) + delta = 1; + else delta = 0; + seconds -= delta*24*3600; + if ( offset+delta >= leftdatenum && offset+delta < leftdatenum+numdates ) + stats_updatedisp(&prices[offset+delta],seconds,ptr->price,ptr->volume); + } + break; + } + + } +} + +struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) +{ + int32_t i,j,datenum,n; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp; double *splinevals; + timestamp = (uint32_t)time(NULL); + if ( Num_priceinfos >= sizeof(Prices)/sizeof(*Prices) ) + return(0); + for (i=0; i= pp->firstdatenum && datenum < pp->firstdatenum+pp->numdates ) + { + for (j=0; jnumdates; j++) + { + datenum = pp->firstdatenum+j; + if ( datenum < leftdatenum ) // can speed up by calculating offset 0 + continue; + if ( datenum >= leftdatenum+numdates ) + break; + stats_dispprices(prices,leftdatenum,numdates,&pp->dates[j],dest,timestamp % (3600*24)); + } + } + break; + } + tmp = OS_conv_datenum(leftdatenum,0,0,0); + utc32 = calloc(sizeof(*utc32),numdates); + splinevals = calloc(sizeof(*splinevals),numdates); + for (i=n=0; i 3 ) + { + double output[2048],slopes[2048]; struct stats_spline spline; int32_t splineid = 0; + memset(&spline,0,sizeof(spline)); + stats_genspline(output,slopes,&spline,splineid,"spline",utc32,splinevals,n,0); + + } + free(utc32); + free(splinevals); + return(0); +} + +char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) +{ + char *method,*agent; + if ( (method= jstr(argjson,"method")) == 0 ) + return(clonestr("{\"error\":\"need method in request\"}")); + if ( (agent= jstr(argjson,"agent")) == 0 ) + agent = "stats"; + + return(clonestr(jprint(argjson,0))); +} + +#endif /* DEXstats_h */ diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 636c8aa6b..959f98c37 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -23,11 +23,19 @@ #include #include "OS_portable.h" #define MAX(a,b) ((a) > (b) ? (a) : (b)) +#include "DEXstats.h" +#ifndef WIN32 +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0x4000 // Do not generate SIGPIPE +#endif +#else +#define MSG_NOSIGNAL 0 +#endif -#define IGUANA_URL "http://127.0.0.1:7778" #define STATS_DESTDIR "/var/www/html" #define STATS_DEST "/var/www/html/DEXstats.json" +#define GLOBAL_HELPDIR "/root/SuperNET/iguana/help" char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", // end of currencies @@ -48,26 +56,648 @@ struct komodo_state struct komodo_state KOMODO_STATE; -void stats_LPpubkeyupdate(char *LPpubkey,uint32_t timestamp) +int32_t iguana_socket(int32_t bindflag,char *hostname,uint16_t port) { - printf("LP.(%s) t.%u\n",LPpubkey,timestamp); + int32_t opt,sock,result; char ipaddr[64],checkipaddr[64]; struct timeval timeout; + struct sockaddr_in saddr; socklen_t addrlen,slen; + addrlen = sizeof(saddr); + struct hostent *hostent; + + /** + * gethostbyname() is deprecated and cause crash on x64 windows + * the solution is to implement similar functionality by using getaddrinfo() + * it is standard posix function and is correctly supported in win32/win64/linux + * @author - fadedreamz@gmail.com + */ +#if defined(_M_X64) + struct addrinfo *addrresult = NULL; + struct addrinfo *returnptr = NULL; + struct addrinfo hints; + struct sockaddr_in * sockaddr_ipv4; + int retVal; + int found = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; +#endif + + if ( parse_ipaddr(ipaddr,hostname) != 0 ) + port = parse_ipaddr(ipaddr,hostname); + +#if defined(_M_X64) + retVal = getaddrinfo(ipaddr, NULL, &hints, &addrresult); + for (returnptr = addrresult; returnptr != NULL && found == 0; returnptr = returnptr->ai_next) { + switch (returnptr->ai_family) { + case AF_INET: + sockaddr_ipv4 = (struct sockaddr_in *) returnptr->ai_addr; + // we want to break from the loop after founding the first ipv4 address + found = 1; + break; + } + } + + // if we iterate through the loop and didn't find anything, + // that means we failed in the dns lookup + if (found == 0) { + printf("getaddrinfo(%s) returned error\n", hostname); + freeaddrinfo(addrresult); + return(-1); + } +#else + hostent = gethostbyname(ipaddr); + if ( hostent == NULL ) + { + printf("gethostbyname(%s) returned error: %d port.%d ipaddr.(%s)\n",hostname,errno,port,ipaddr); + return(-1); + } +#endif + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + //#ifdef WIN32 + // saddr.sin_addr.s_addr = (uint32_t)calc_ipbits("127.0.0.1"); + //#else + +#if defined(_M_X64) + saddr.sin_addr.s_addr = sockaddr_ipv4->sin_addr.s_addr; + // graceful cleanup + sockaddr_ipv4 = NULL; + freeaddrinfo(addrresult); +#else + memcpy(&saddr.sin_addr.s_addr,hostent->h_addr_list[0],hostent->h_length); +#endif + expand_ipbits(checkipaddr,saddr.sin_addr.s_addr); + if ( strcmp(ipaddr,checkipaddr) != 0 ) + printf("bindflag.%d iguana_socket mismatch (%s) -> (%s)?\n",bindflag,checkipaddr,ipaddr); + //#endif + if ( (sock= socket(AF_INET,SOCK_STREAM,0)) < 0 ) + { + if ( errno != ETIMEDOUT ) + printf("socket() failed: %s errno.%d", strerror(errno),errno); + return(-1); + } + opt = 1; + slen = sizeof(opt); + //printf("set keepalive.%d\n",setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(void *)&opt,slen)); +#ifndef WIN32 + if ( 1 )//&& bindflag != 0 ) + { + opt = 0; + getsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(void *)&opt,&slen); + opt = 1; + //printf("keepalive.%d\n",opt); + } + setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void *)&opt,sizeof(opt)); +#ifdef __APPLE__ + setsockopt(sock,SOL_SOCKET,SO_NOSIGPIPE,&opt,sizeof(opt)); +#endif +#endif + if ( bindflag == 0 ) + { + timeout.tv_sec = 10; + timeout.tv_usec = 0; + setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(void *)&timeout,sizeof(timeout)); + result = connect(sock,(struct sockaddr *)&saddr,addrlen); + if ( result != 0 ) + { + if ( errno != ECONNRESET && errno != ENOTCONN && errno != ECONNREFUSED && errno != ETIMEDOUT && errno != EHOSTUNREACH ) + { + //printf("%s(%s) port.%d failed: %s sock.%d. errno.%d\n",bindflag!=0?"bind":"connect",hostname,port,strerror(errno),sock,errno); + } + if ( sock >= 0 ) + closesocket(sock); + return(-1); + } + timeout.tv_sec = 10000000; + timeout.tv_usec = 0; + setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(void *)&timeout,sizeof(timeout)); + } + else + { + while ( (result= bind(sock,(struct sockaddr*)&saddr,addrlen)) != 0 ) + { + if ( errno == EADDRINUSE ) + { + sleep(1); + printf("ERROR BINDING PORT.%d. this is normal tcp timeout, unless another process is using port\n",port); + sleep(3); + printf("%s(%s) port.%d try again: %s sock.%d. errno.%d\n",bindflag!=0?"bind":"connect",hostname,port,strerror(errno),sock,errno); + if ( bindflag == 1 ) + { + closesocket(sock); + return(-1); + } + sleep(13); + //continue; + } + if ( errno != ECONNRESET && errno != ENOTCONN && errno != ECONNREFUSED && errno != ETIMEDOUT && errno != EHOSTUNREACH ) + { + printf("%s(%s) port.%d failed: %s sock.%d. errno.%d\n",bindflag!=0?"bind":"connect",hostname,port,strerror(errno),sock,errno); + closesocket(sock); + return(-1); + } + } + if ( listen(sock,64) != 0 ) + { + printf("listen(%s) port.%d failed: %s sock.%d. errno.%d\n",hostname,port,strerror(errno),sock,errno); + if ( sock >= 0 ) + closesocket(sock); + return(-1); + } + } +#ifdef __APPLE__ + //timeout.tv_sec = 0; + //timeout.tv_usec = 30000; + //setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(void *)&timeout,sizeof(timeout)); + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(void *)&timeout,sizeof(timeout)); +#endif + return(sock); } -void stats_datenumupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t timestamp,int32_t height,char *key,char *LPpubkey,cJSON *tradejson) +int32_t Supernet_lineparse(char *key,int32_t keymax,char *value,int32_t valuemax,char *src) { - uint64_t srcamount,destamount; char *source,*dest; double price; - if ( LPpubkey != 0 ) - stats_LPpubkeyupdate(LPpubkey,timestamp); - if ( tradejson != 0 ) + int32_t a,b,c,n = 0; //char *origkey=key,*origvalue=value; + key[0] = value[0] = 0; + while ( (c= src[n]) == ' ' || c == '\t' || c == '\n' || c == '\t' ) + n++; + while ( (c= src[n]) != ':' && c != 0 ) + { + *key++ = c; + //printf("(%c) ",c); + if ( ++n >= keymax-1 ) + { + *key = 0; + printf("lineparse overflow key.(%s)\n",src); + return(-1); + } + } + *key = 0; + //printf("-> key.(%s)\n",origkey); + if ( src[n] != ':' ) + return(n); + n++; + while ( (c= src[n]) == ' ' || c == '\t' ) + n++; + while ( (c= src[n]) != 0 && c != '\r' && c != '\n' ) { - source = jstr(jitem(tradejson,0),0); - srcamount = SATOSHIDEN * jdouble(jitem(tradejson,1),0); - dest = jstr(jitem(tradejson,2),0); - destamount = SATOSHIDEN * jdouble(jitem(tradejson,3),0); - if ( srcamount != 0 && destamount != 0 ) - price = (double)destamount / srcamount; - else price = 0.; - printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price,1/price); + if ( c == '%' && (a= src[n+1]) != 0 && (b= src[n+2]) != 0 ) + c = ((unhex(a) << 4) | unhex(b)), n += 2; + *value++ = c; + n++; + if ( n >= valuemax-1 ) + { + *value = 0; + printf("lineparse overflow.(%s)\n",src); + return(-1); + } + } + *value = 0; + if ( src[n] != 0 ) + { + n++; + while ( (c= src[n]) == '\r' || c == '\n' ) + n++; + } + //printf("key.(%s) value.(%s)\n",origkey,origvalue); + return(n); +} + +cJSON *SuperNET_urlconv(char *value,int32_t bufsize,char *urlstr) +{ + int32_t i,n,totallen,datalen,len = 0; cJSON *json,*array; char key[8192],*data; + json = cJSON_CreateObject(); + array = cJSON_CreateArray(); + totallen = (int32_t)strlen(urlstr); + while ( 1 ) + { + for (i=len; urlstr[i]!=0; i++) + if ( urlstr[i] == '\r' || urlstr[i] == '\n' ) + break; + if ( i == len && (urlstr[len] == '\r' || urlstr[len] == '\n') ) + { + len++; + continue; + } + urlstr[i] = 0; + //printf("URLSTR[%d]=%s\n",i,&urlstr[len]); + if ( (n= Supernet_lineparse(key,sizeof(key),value,bufsize,&urlstr[len])) > 0 ) + { + if ( value[0] != 0 ) + jaddstr(json,key,value); + else jaddistr(array,key); + len += (n + 1); + if ( strcmp(key,"Content-Length") == 0 && (datalen= atoi(value)) > 0 ) + { + data = &urlstr[totallen - datalen]; + data[-1] = 0; + //printf("post.(%s) (%c)\n",data,data[0]); + jaddstr(json,"POST",data); + } + } else break; + } + jadd(json,"lines",array); + //printf("urlconv.(%s)\n",jprint(json,0)); + return(json); +} + +char *stats_rpcparse(char *retbuf,int32_t bufsize,int32_t *jsonflagp,int32_t *postflagp,char *urlstr,char *remoteaddr,char *filetype,uint16_t port) +{ + cJSON *tokens,*argjson,*origargjson,*tmpjson=0,*json = 0; long filesize; + char symbol[64],buf[4096],*originstr,*fieldstr,*userpass=0,urlmethod[16],*data,url[8192],furl[8192],*retstr,*filestr,*token = 0; int32_t i,j,n,iter,num=0; + //printf("rpcparse.(%s)\n",urlstr); + for (i=0; i0; i--) + if ( url[i] == '.' || url[i] == '/' ) + break; + if ( url[i] == '.' ) + strcpy(filetype,url+i+1); + //printf("return filetype.(%s) size.%ld\n",filetype,filesize); + return(filestr); + } + if ( strncmp(&url[i],"/api",strlen("/api")) == 0 ) + { + *jsonflagp = 1; + i += strlen("/api"); + } else *jsonflagp = 0; + if ( strcmp(url,"/favicon.ico") == 0 ) + { + *jsonflagp = 1; + return(0); + } + if ( url[i] != '/' ) + token = &url[i]; + n = i; + tokens = cJSON_CreateArray(); + for (; url[i]!=0; i++) + { + //printf("i.%d (%c)\n",i,url[i]); + if ( url[i] == '/' ) + { + url[i] = 0; + if ( token != 0 ) + { + //printf("TOKEN.(%s) i.%d\n",token,i); + jaddistr(tokens,token); + num++; + } + token = &url[i+1]; + i++; + //printf("new token.(%s) i.%d\n",token,i+1); + continue; + } + } + if ( token != 0 ) + { + //printf("add token.(%s)\n",token); + jaddistr(tokens,token); + num++; + } + argjson = cJSON_CreateObject(); + if ( num > 0 ) + jaddstr(argjson,"agent",jstri(tokens,0)); + if ( num > 1 ) + jaddstr(argjson,"method",jstri(tokens,1)); + if ( (json= SuperNET_urlconv(retbuf,bufsize,urlstr+n)) != 0 ) + { + jadd(json,"tokens",tokens); + jaddstr(json,"urlmethod",urlmethod); + if ( (data= jstr(json,"POST")) == 0 || (argjson= cJSON_Parse(data)) == 0 ) + { + userpass = jstr(argjson,"userpass"); + //printf("userpass.(%s)\n",userpass); + if ( (n= cJSON_GetArraySize(tokens)) > 0 ) + { + if ( n > 1 ) + { + if ( jstri(tokens,1) != 0 ) + { + char *key,*value; + strcpy(buf,jstri(tokens,1)); + key = value = 0; + i = 0; + for (; buf[i]!=0; i++) + { + if ( buf[i] == '?' ) + { + buf[i] = 0; + jdelete(argjson,"method"); + jaddstr(argjson,"method",buf); + i++; + key = &buf[i]; + break; + } + } + while ( buf[i] != 0 ) + { + //printf("iter.[%s]\n",&buf[i]); + if ( buf[i] != 0 && key != 0 ) + { + for (; buf[i]!=0; i++) + { + if ( buf[i] == '=' ) + { + buf[i] = 0; + i++; + //printf("got key.(%s)\n",key); + value = &buf[i]; + break; + } + } + if ( buf[i] != 0 && value != 0 ) + { + for (; buf[i]!=0; i++) + { + if ( buf[i] == '&' ) + { + buf[i] = 0; + jaddstr(argjson,key,value); + i++; + //printf("got value.(%s)\n",value); + value = 0; + key = &buf[i]; + break; + } + else if ( buf[i] == '+' ) + buf[i] = ' '; + } + } + } + } + if ( key != 0 && value != 0 ) + jaddstr(argjson,key,value); + } + else + { + //jdelete(argjson,"method"); + //jaddstr(argjson,"method",buf); + } + } + for (i=2; i 0 ) + { + cJSON *retitem,*retarray = cJSON_CreateArray(); + origargjson = argjson; + symbol[0] = 0; + for (i=0; i (%s) postflag.%d (%s)\n",urlstr,jprint(argjson,0),cJSON_Print(json),*postflagp,retstr); + } + free_json(origargjson); + retstr = jprint(retarray,1); + } + else + { + cJSON *arg; + if ( jstr(argjson,"agent") != 0 && strcmp(jstr(argjson,"agent"),"bitcoinrpc") != 0 && jobj(argjson,"params") != 0 ) + { + arg = jobj(argjson,"params"); + if ( is_cJSON_Array(arg) != 0 && cJSON_GetArraySize(arg) == 1 ) + arg = jitem(arg,0); + } else arg = argjson; + //printf("ARGJSON.(%s)\n",jprint(arg,0)); + if ( userpass != 0 && jstr(arg,"userpass") == 0 ) + jaddstr(arg,"userpass",userpass); + retstr = stats_JSON(arg,remoteaddr,port); + } + free_json(argjson); + free_json(json); + if ( tmpjson != 0 ) + free(tmpjson); + return(retstr); + } + free_json(argjson); + if ( tmpjson != 0 ) + free(tmpjson); + *jsonflagp = 1; + return(clonestr("{\"error\":\"couldnt process packet\"}")); +} + +int32_t iguana_getcontentlen(char *buf,int32_t recvlen) +{ + char *str,*clenstr = "Content-Length: "; int32_t len = -1; + if ( (str= strstr(buf,clenstr)) != 0 ) + { + //printf("strstr.(%s)\n",str); + str += strlen(clenstr); + len = atoi(str); + //printf("len.%d\n",len); + } + return(len); +} + +int32_t iguana_getheadersize(char *buf,int32_t recvlen) +{ + char *str,*delim = "\r\n\r\n"; + if ( (str= strstr(buf,delim)) != 0 ) + return((int32_t)(((long)str - (long)buf) + strlen(delim))); + return(recvlen); +} + +void stats_rpcloop(void *args) +{ + static char *jsonbuf; + uint16_t port; char filetype[128],content_type[128]; + int32_t recvlen,flag,bindsock,postflag=0,contentlen,sock,remains,numsent,jsonflag=0,hdrsize,len; + socklen_t clilen; char helpname[512],remoteaddr[64],*buf,*retstr,*space; + struct sockaddr_in cli_addr; uint32_t ipbits,i,size = IGUANA_MAXPACKETSIZE + 512; + if ( (port= *(uint16_t *)args) == 0 ) + port = 7779; + if ( jsonbuf == 0 ) + jsonbuf = calloc(1,IGUANA_MAXPACKETSIZE); + while ( (bindsock= iguana_socket(1,"127.0.0.1",port)) < 0 ) + { + //if ( coin->MAXPEERS == 1 ) + // break; + //exit(-1); + sleep(3); + } + printf(">>>>>>>>>> DEX stats 127.0.0.1:%d bind sock.%d DEX stats API enabled <<<<<<<<<\n",port,bindsock); + space = calloc(1,size); + while ( bindsock >= 0 ) + { + clilen = sizeof(cli_addr); + sock = accept(bindsock,(struct sockaddr *)&cli_addr,&clilen); + if ( sock < 0 ) + { + //printf("iguana_rpcloop ERROR on accept usock.%d errno %d %s\n",sock,errno,strerror(errno)); + continue; + } + memcpy(&ipbits,&cli_addr.sin_addr.s_addr,sizeof(ipbits)); + expand_ipbits(remoteaddr,ipbits); + printf("remote RPC request from (%s) %x\n",remoteaddr,ipbits); + + memset(jsonbuf,0,IGUANA_MAXPACKETSIZE); + remains = (int32_t)(IGUANA_MAXPACKETSIZE - 1); + buf = jsonbuf; + recvlen = flag = 0; + retstr = 0; + while ( remains > 0 ) + { + //printf("flag.%d remains.%d recvlen.%d\n",flag,remains,recvlen); + if ( (len= (int32_t)recv(sock,buf,remains,0)) < 0 ) + { + if ( errno == EAGAIN ) + { + printf("EAGAIN for len %d, remains.%d\n",len,remains); + usleep(10000); + } + break; + } + else + { + if ( len > 0 ) + { + buf[len] = 0; + if ( recvlen == 0 ) + { + if ( (contentlen= iguana_getcontentlen(buf,recvlen)) > 0 ) + { + hdrsize = iguana_getheadersize(buf,recvlen); + if ( hdrsize > 0 ) + { + if ( len < (hdrsize + contentlen) ) + { + remains = (hdrsize + contentlen) - len; + buf = &buf[len]; + flag = 1; + //printf("got.(%s) %d remains.%d of len.%d contentlen.%d hdrsize.%d remains.%d\n",buf,recvlen,remains,len,contentlen,hdrsize,(hdrsize+contentlen)-len); + continue; + } + } + } + } + recvlen += len; + remains -= len; + buf = &buf[len]; + if ( flag == 0 || remains <= 0 ) + break; + } + else + { + usleep(10000); + //printf("got.(%s) %d remains.%d of total.%d\n",jsonbuf,recvlen,remains,len); + //retstr = iguana_rpcparse(space,size,&postflag,jsonbuf); + if ( flag == 0 ) + break; + } + } + } + content_type[0] = 0; + if ( recvlen > 0 ) + { + retstr = stats_rpcparse(space,size,&jsonflag,&postflag,jsonbuf,remoteaddr,filetype,port); + if ( filetype[0] != 0 ) + { + static cJSON *mimejson; char *tmp,*typestr=0; long tmpsize; + sprintf(helpname,"%s/mime.json",GLOBAL_HELPDIR); + if ( (tmp= OS_filestr(&tmpsize,helpname)) != 0 ) + { + mimejson = cJSON_Parse(tmp); + free(tmp); + } + if ( mimejson != 0 ) + { + if ( (typestr= jstr(mimejson,filetype)) != 0 ) + sprintf(content_type,"Content-Type: %s\r\n",typestr); + } else printf("parse error.(%s)\n",tmp); + //printf("filetype.(%s) json.%p type.%p tmp.%p [%s]\n",filetype,mimejson,typestr,tmp,content_type); + } + } + if ( retstr != 0 ) + { + char *response,hdrs[1024]; + //printf("RETURN.(%s)\n",retstr); + if ( jsonflag != 0 || postflag != 0 ) + { + response = malloc(strlen(retstr)+1024+1+1); + sprintf(hdrs,"HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Credentials: true\r\nAccess-Control-Allow-Methods: GET, POST\r\nCache-Control : no-cache, no-store, must-revalidate\r\n%sContent-Length : %8d\r\n\r\n",content_type,(int32_t)strlen(retstr)); + response[0] = '\0'; + strcat(response,hdrs); + strcat(response,retstr); + strcat(response,"\n"); + if ( retstr != space ) + free(retstr); + retstr = response; + } + remains = (int32_t)strlen(retstr); + i = 0; + while ( remains > 0 ) + { + if ( (numsent= (int32_t)send(sock,&retstr[i],remains,MSG_NOSIGNAL)) < 0 ) + { + if ( errno != EAGAIN && errno != EWOULDBLOCK ) + { + //printf("%s: %s numsent.%d vs remains.%d len.%d errno.%d (%s) usock.%d\n",retstr,ipaddr,numsent,remains,recvlen,errno,strerror(errno),sock); + break; + } + } + else if ( remains > 0 ) + { + remains -= numsent; + i += numsent; + if ( remains > 0 ) + printf("iguana sent.%d remains.%d of len.%d\n",numsent,remains,recvlen); + } + } + if ( retstr != space) + free(retstr); + } + closesocket(sock); } } @@ -83,7 +713,7 @@ void stats_kvjson(FILE *logfp,int32_t height,int32_t savedheight,uint32_t timest //printf("(%s)\n",jprint(kvjson,0)); if ( logfp != 0 ) { - stats_datenumupdate(datenum,seconds/3600,seconds % 3600,timestamp,height,key,jstr(kvjson,"pubkey"),jarray(&n,kvjson,"trade")); + stats_priceupdate(datenum,seconds/3600,seconds % 3600,timestamp,height,key,jstr(kvjson,"pubkey"),jarray(&n,kvjson,"trade")); fprintf(logfp,"%s\n",jprint(kvjson,0)); fflush(logfp); } @@ -132,7 +762,7 @@ void komodo_kvupdate(FILE *logfp,struct komodo_state *sp,int32_t ht,bits256 txid }*/ //for (i=0; ipassword,password); if ( permanentfile != 0 ) strcpy(myinfo->permanentfile,permanentfile); + if ( (retstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,myinfo->password)) != 0 ) + free(retstr); retstr = SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,myinfo->password); myinfo->expiration = (uint32_t)time(NULL) + timeout; iguana_walletinitcheck(myinfo,coin); @@ -1382,7 +1384,6 @@ TWOSTRINGS_AND_INT(bitcoinrpc,walletpassphrase,password,permanentfile,timeout) privkey = jumblr_privkey(myinfo,coinaddr,0,KMDaddr,"btc "); smartaddress_add(myinfo,privkey,"btc","KMD",0.,0.); } - //basilisk_unspents_update(myinfo,coin); return(retstr); } diff --git a/iguana/stats b/iguana/stats new file mode 100755 index 0000000000000000000000000000000000000000..d9ac40ee0b2cc9db9f1a77f04f46a4aae8c5563b GIT binary patch literal 387304 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
y?ST{%cQS^sW+gA`H!R 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 g$ Date: Mon, 8 May 2017 09:43:08 +0300 Subject: [PATCH 0432/2705] Test --- .gitignore | 2 ++ iguana/stats | Bin 387304 -> 0 bytes iguana/tests/dexgetbalance | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) delete mode 100755 iguana/stats diff --git a/.gitignore b/.gitignore index 251e614b3..8d846866a 100755 --- a/.gitignore +++ b/.gitignore @@ -421,3 +421,5 @@ iguana/e iguana/a iguana/t + +iguana/stats diff --git a/iguana/stats b/iguana/stats deleted file mode 100755 index d9ac40ee0b2cc9db9f1a77f04f46a4aae8c5563b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 387304 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 g$ Date: Mon, 8 May 2017 09:50:00 +0300 Subject: [PATCH 0433/2705] Test --- iguana/m_stats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/m_stats b/iguana/m_stats index b3a26cf18..9fface988 100755 --- a/iguana/m_stats +++ b/iguana/m_stats @@ -1 +1 @@ -gcc -o stats -I../crypto777 exchanges/stats.c ../crypto777/cJSON.c ../agents/libcrypto777.a -lcurl -lpthread -lm +gcc -g -o DEXstats -I../crypto777 exchanges/stats.c ../crypto777/cJSON.c ../agents/libcrypto777.a -lcurl -lpthread -lm From 8fe14dae45c452fdcb60a58be228ba0bbf40a31e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 09:53:51 +0300 Subject: [PATCH 0434/2705] Test --- .gitignore | 6 ++++++ iguana/exchanges/DEXstats.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8d846866a..d61e17ebd 100755 --- a/.gitignore +++ b/.gitignore @@ -423,3 +423,9 @@ iguana/a iguana/t iguana/stats + +iguana/DEXstats + +iguana/DEXstats.dSYM/Contents/Info.plist + +iguana/DEXstats.dSYM/Contents/Resources/DWARF/DEXstats diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 4c426981f..110566846 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -101,7 +101,7 @@ void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t h printf("illegal datenum.%d for %s when 1st.%d\n",datenum,pp->symbol,pp->firstdatenum); return; } - if ( offset > pp->numdates ) + if ( offset >= pp->numdates ) { pp->dates = realloc(pp->dates,sizeof(*pp->dates) * (offset+1)); n = (offset - pp->numdates); From 2772f7906789d04c6902c625e3d2e0f9eb5990c7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 09:57:33 +0300 Subject: [PATCH 0435/2705] Test --- iguana/exchanges/DEXstats.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 110566846..cf6f52918 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -770,6 +770,7 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ if ( strcmp(Prices[i].symbol,symbol) == 0 ) { pp = &Prices[i]; + printf("found (%s) datenums %d %d %d\n",datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); if ( datenum >= pp->firstdatenum && datenum < pp->firstdatenum+pp->numdates ) { for (j=0; jnumdates; j++) From fccd10145bb708462a2408f2406185a00f2cde18 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 09:57:56 +0300 Subject: [PATCH 0436/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index cf6f52918..340c13107 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -770,7 +770,7 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ if ( strcmp(Prices[i].symbol,symbol) == 0 ) { pp = &Prices[i]; - printf("found (%s) datenums %d %d %d\n",datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); + printf("found (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); if ( datenum >= pp->firstdatenum && datenum < pp->firstdatenum+pp->numdates ) { for (j=0; jnumdates; j++) From b7d7f8f32c74082868d5f8497b01d33e639199d1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 09:59:42 +0300 Subject: [PATCH 0437/2705] Test --- iguana/exchanges/DEXstats.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 340c13107..26e27b56f 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -111,6 +111,7 @@ void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t h memset(date,0,sizeof(*date)); date->datenum = pp->firstdatenum + pp->numdates + i; } + pp->numdates = offset; } stats_pairupdate(&pp->dates[offset],dest,datenum,hour,seconds,height,volume,price); } From 19b487c53b7df013fabdf43625338b4b7a225dbf Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:13:02 +0300 Subject: [PATCH 0438/2705] Test --- iguana/exchanges/DEXstats.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 26e27b56f..12ff55269 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -65,7 +65,7 @@ void stats_pricepoint(struct DEXstats_pricepoint *ptr,uint8_t hour,uint16_t seco ptr->height = height; ptr->hour = hour; ptr->seconds = seconds; - printf("h.%d s.%-4d %.8f %.6f\n",hour,seconds,price,volume); + //printf("h.%d s.%-4d %.8f %.6f\n",hour,seconds,price,volume); } void stats_pairupdate(struct DEXstats_datenuminfo *date,char *dest,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,double price) @@ -771,7 +771,6 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ if ( strcmp(Prices[i].symbol,symbol) == 0 ) { pp = &Prices[i]; - printf("found (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); if ( datenum >= pp->firstdatenum && datenum < pp->firstdatenum+pp->numdates ) { for (j=0; jnumdates; j++) @@ -781,6 +780,7 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ continue; if ( datenum >= leftdatenum+numdates ) break; + printf("found (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); stats_dispprices(prices,leftdatenum,numdates,&pp->dates[j],dest,timestamp % (3600*24)); } } From e4a98d0af27eec8a73cd489f2e302215b15e4b60 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:14:04 +0300 Subject: [PATCH 0439/2705] Test --- iguana/exchanges/DEXstats.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 12ff55269..b61d66321 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -777,10 +777,16 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ { datenum = pp->firstdatenum+j; if ( datenum < leftdatenum ) // can speed up by calculating offset 0 + { + printf("skip (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); continue; + } if ( datenum >= leftdatenum+numdates ) + { + printf("break (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); break; - printf("found (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); + } + printf("add (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); stats_dispprices(prices,leftdatenum,numdates,&pp->dates[j],dest,timestamp % (3600*24)); } } From 924d73ae023e7c52d86b8a5f148dad0d4d109a43 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:15:35 +0300 Subject: [PATCH 0440/2705] Test --- iguana/exchanges/DEXstats.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index b61d66321..d98025333 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -771,8 +771,9 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ if ( strcmp(Prices[i].symbol,symbol) == 0 ) { pp = &Prices[i]; - if ( datenum >= pp->firstdatenum && datenum < pp->firstdatenum+pp->numdates ) + if ( leftdatenum >= pp->firstdatenum && leftdatenum < pp->firstdatenum+pp->numdates ) { + printf(" (%s) numdates %d 1st %d left %d\n",symbol,pp->numdates,pp->firstdatenum,leftdatenum); for (j=0; jnumdates; j++) { datenum = pp->firstdatenum+j; From 1befacf084d863289715796513d352b16247fa7f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:16:40 +0300 Subject: [PATCH 0441/2705] Test --- iguana/exchanges/DEXstats.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index d98025333..169b31302 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -771,9 +771,9 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ if ( strcmp(Prices[i].symbol,symbol) == 0 ) { pp = &Prices[i]; - if ( leftdatenum >= pp->firstdatenum && leftdatenum < pp->firstdatenum+pp->numdates ) + if ( leftdatenum+numdates >= pp->firstdatenum && leftdatenum <= pp->firstdatenum+pp->numdates ) { - printf(" (%s) numdates %d 1st %d left %d\n",symbol,pp->numdates,pp->firstdatenum,leftdatenum); + printf(" (%s) numdates %d 1st %d left %d+%d\n",symbol,pp->numdates,pp->firstdatenum,leftdatenum,numdates); for (j=0; jnumdates; j++) { datenum = pp->firstdatenum+j; From 81246a0cb59f72e754617a00e9fef3a440db3908 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:18:02 +0300 Subject: [PATCH 0442/2705] Test --- iguana/exchanges/DEXstats.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 169b31302..b4639d670 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -737,9 +737,11 @@ void stats_updatedisp(struct DEXstats_disp *disp,int32_t seconds,double price,do void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates,struct DEXstats_datenuminfo *date,char *dest,int32_t current_daysecond) { int32_t i,j,seconds,hour,offset,delta,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp; + printf("add datenum.%d vs leftdatenum.%d numdates.%d\n",datenum,leftdatenum,numdates); if ( datenum >= leftdatenum-1 && datenum <= leftdatenum+numdates ) { offset = datenum - leftdatenum; + printf("offset.%d\n",offset); for (i=0; inumpairs; i++) if ( strcmp(dest,date->pairs[i].dest) == 0 ) { @@ -787,7 +789,6 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ printf("break (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); break; } - printf("add (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); stats_dispprices(prices,leftdatenum,numdates,&pp->dates[j],dest,timestamp % (3600*24)); } } From c6594240ab1e1183951c1b6e3cf582a35f85f7a5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:21:14 +0300 Subject: [PATCH 0443/2705] Test --- iguana/exchanges/DEXstats.h | 4 ++-- iguana/exchanges/stats.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index b4639d670..3e8c8dba6 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -737,15 +737,15 @@ void stats_updatedisp(struct DEXstats_disp *disp,int32_t seconds,double price,do void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates,struct DEXstats_datenuminfo *date,char *dest,int32_t current_daysecond) { int32_t i,j,seconds,hour,offset,delta,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp; - printf("add datenum.%d vs leftdatenum.%d numdates.%d\n",datenum,leftdatenum,numdates); if ( datenum >= leftdatenum-1 && datenum <= leftdatenum+numdates ) { offset = datenum - leftdatenum; - printf("offset.%d\n",offset); + printf("add datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",datenum,leftdatenum,numdates,offset,date->numpairs); for (i=0; inumpairs; i++) if ( strcmp(dest,date->pairs[i].dest) == 0 ) { pair = &date->pairs[i]; + printf("found dest.(%s) numprices.%d\n",dest,pair->numprices); for (j=0; jnumprices; j++) { ptr = &pair->prices[j]; diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 959f98c37..85996d091 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -1005,7 +1005,7 @@ int main(int argc, const char * argv[]) leftdatenum = OS_conv_unixtime(&T,&seconds,timestamp - 1024*3600); printf("%u: leftdatenum.%d %s\n",timestamp,leftdatenum,filestr); memset(prices,0,sizeof(prices)); - stats_prices("KMD","BTC",prices,leftdatenum,(int32_t)(sizeof(prices)/sizeof(*prices))); + stats_prices("KMD","BTC",prices,leftdatenum,1024/24+1); if ( (fp= fopen(STATS_DEST,"wb")) != 0 ) { fwrite(filestr,1,strlen(filestr)+1,fp); From 58d5deeaeb562d95669d830da470ff677b1bc1d8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:21:55 +0300 Subject: [PATCH 0444/2705] Test --- iguana/exchanges/DEXstats.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 3e8c8dba6..ff99d37fc 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -737,9 +737,10 @@ void stats_updatedisp(struct DEXstats_disp *disp,int32_t seconds,double price,do void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates,struct DEXstats_datenuminfo *date,char *dest,int32_t current_daysecond) { int32_t i,j,seconds,hour,offset,delta,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp; + offset = datenum - leftdatenum; + printf("add datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",datenum,leftdatenum,numdates,offset,date->numpairs); if ( datenum >= leftdatenum-1 && datenum <= leftdatenum+numdates ) { - offset = datenum - leftdatenum; printf("add datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",datenum,leftdatenum,numdates,offset,date->numpairs); for (i=0; inumpairs; i++) if ( strcmp(dest,date->pairs[i].dest) == 0 ) From f310b294605477bf2451efc4e61432b84635bbb9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:22:34 +0300 Subject: [PATCH 0445/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index ff99d37fc..c15180731 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -774,9 +774,9 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ if ( strcmp(Prices[i].symbol,symbol) == 0 ) { pp = &Prices[i]; + printf(" (%s) numdates %d 1st %d left %d+%d\n",symbol,pp->numdates,pp->firstdatenum,leftdatenum,numdates); if ( leftdatenum+numdates >= pp->firstdatenum && leftdatenum <= pp->firstdatenum+pp->numdates ) { - printf(" (%s) numdates %d 1st %d left %d+%d\n",symbol,pp->numdates,pp->firstdatenum,leftdatenum,numdates); for (j=0; jnumdates; j++) { datenum = pp->firstdatenum+j; From 978b7c51550dc4e53507599222dd55b37f3a01e8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:27:04 +0300 Subject: [PATCH 0446/2705] Test --- iguana/exchanges/DEXstats.h | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index c15180731..4b4736f7a 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -766,7 +766,7 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) { - int32_t i,j,datenum,n; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp; double *splinevals; + int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp; double *splinevals; struct tai T; timestamp = (uint32_t)time(NULL); if ( Num_priceinfos >= sizeof(Prices)/sizeof(*Prices) ) return(0); @@ -774,24 +774,21 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ if ( strcmp(Prices[i].symbol,symbol) == 0 ) { pp = &Prices[i]; - printf(" (%s) numdates %d 1st %d left %d+%d\n",symbol,pp->numdates,pp->firstdatenum,leftdatenum,numdates); - if ( leftdatenum+numdates >= pp->firstdatenum && leftdatenum <= pp->firstdatenum+pp->numdates ) + for (j=0; jnumdates; j++) { - for (j=0; jnumdates; j++) + timestamp = OS_conv_datenum(pp->firstdatenum+j,0,0,0); + datenum = OS_conv_unixtime(&T,&seconds,timestamp); + if ( datenum < leftdatenum ) // can speed up by calculating offset 0 { - datenum = pp->firstdatenum+j; - if ( datenum < leftdatenum ) // can speed up by calculating offset 0 - { - printf("skip (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); - continue; - } - if ( datenum >= leftdatenum+numdates ) - { - printf("break (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); - break; - } - stats_dispprices(prices,leftdatenum,numdates,&pp->dates[j],dest,timestamp % (3600*24)); + printf("skip (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); + continue; + } + if ( datenum >= leftdatenum+numdates ) + { + printf("break (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); + break; } + stats_dispprices(prices,leftdatenum,numdates,&pp->dates[j],dest,timestamp % (3600*24)); } break; } From ab0d1182fc2070fda6c51ee0f885dc64f9951f7a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:29:22 +0300 Subject: [PATCH 0447/2705] Test --- iguana/exchanges/DEXstats.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 4b4736f7a..fc768f142 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -766,10 +766,12 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) { - int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp; double *splinevals; struct tai T; + int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals; struct tai T; timestamp = (uint32_t)time(NULL); if ( Num_priceinfos >= sizeof(Prices)/sizeof(*Prices) ) return(0); + lefttimestamp = OS_conv_datenum(leftdatenum-1,0,0,0); + righttimestamp = OS_conv_datenum(leftdatenum+numdates,0,0,0); for (i=0; inumdates; j++) { timestamp = OS_conv_datenum(pp->firstdatenum+j,0,0,0); - datenum = OS_conv_unixtime(&T,&seconds,timestamp); - if ( datenum < leftdatenum ) // can speed up by calculating offset 0 + if ( timestamp < lefttimestamp ) // can speed up by calculating offset 0 { printf("skip (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); continue; } - if ( datenum >= leftdatenum+numdates ) - { - printf("break (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); - break; - } stats_dispprices(prices,leftdatenum,numdates,&pp->dates[j],dest,timestamp % (3600*24)); } break; From 4bb4a21a1fa01133a32bf5fcdadb56a5e960b1ca Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:30:13 +0300 Subject: [PATCH 0448/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index fc768f142..3372a0a87 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -776,7 +776,7 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ if ( strcmp(Prices[i].symbol,symbol) == 0 ) { pp = &Prices[i]; - for (j=0; jnumdates; j++) + for (j=0; j<=pp->numdates; j++) { timestamp = OS_conv_datenum(pp->firstdatenum+j,0,0,0); if ( timestamp < lefttimestamp ) // can speed up by calculating offset 0 From e66d9710a749a20553f0e93b935c68d8649a0912 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:32:33 +0300 Subject: [PATCH 0449/2705] Test --- iguana/exchanges/DEXstats.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 3372a0a87..760e3af52 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -88,6 +88,7 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *dest,int32_t daten pair = &date->pairs[date->numpairs++]; memset(pair,0,sizeof(*pair)); strcpy(pair->dest,dest); + printf("new pair.%d (%s -> %s)\n",date->numpairs,date->symbol,date->dest); } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); From 4ebc4b82a813638867cc4ac8b5b1956dfffcbb1f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:33:13 +0300 Subject: [PATCH 0450/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 760e3af52..818e9c20b 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -88,7 +88,7 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *dest,int32_t daten pair = &date->pairs[date->numpairs++]; memset(pair,0,sizeof(*pair)); strcpy(pair->dest,dest); - printf("new pair.%d (%s -> %s)\n",date->numpairs,date->symbol,date->dest); + printf("new pair.%d (%s -> %s)\n",date->numpairs,date->symbol,dest); } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); From bc0fb856c84cedec176e3601117d114d3f2b3a2a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:33:50 +0300 Subject: [PATCH 0451/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 818e9c20b..702e771c3 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -88,7 +88,7 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *dest,int32_t daten pair = &date->pairs[date->numpairs++]; memset(pair,0,sizeof(*pair)); strcpy(pair->dest,dest); - printf("new pair.%d (%s -> %s)\n",date->numpairs,date->symbol,dest); + printf("new pair.%d dest.(%s)\n",date->numpairs,dest); } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); From 772c23df5e0058c5de329bbc039c9a64c940e0cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:35:40 +0300 Subject: [PATCH 0452/2705] Test --- iguana/exchanges/DEXstats.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 702e771c3..efcff5da0 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -65,10 +65,9 @@ void stats_pricepoint(struct DEXstats_pricepoint *ptr,uint8_t hour,uint16_t seco ptr->height = height; ptr->hour = hour; ptr->seconds = seconds; - //printf("h.%d s.%-4d %.8f %.6f\n",hour,seconds,price,volume); } -void stats_pairupdate(struct DEXstats_datenuminfo *date,char *dest,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,double price) +void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,double price) { int32_t i; struct DEXstats_pairinfo *pair = 0; if ( date->datenum != datenum || seconds < 0 || seconds >= 3600 || hour < 0 || hour >= 24 ) @@ -88,10 +87,11 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *dest,int32_t daten pair = &date->pairs[date->numpairs++]; memset(pair,0,sizeof(*pair)); strcpy(pair->dest,dest); - printf("new pair.%d dest.(%s)\n",date->numpairs,dest); + printf("new pair.%d (%s) -> dest.(%s)\n",date->numpairs,symbol,dest); } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); + printf("(%s/%s) numprices.%d h.%d s.%-4d %.8f %.6f\n",symbol,dest,hour,seconds,price,volume); } void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,char *dest,double price) @@ -114,7 +114,7 @@ void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t h } pp->numdates = offset; } - stats_pairupdate(&pp->dates[offset],dest,datenum,hour,seconds,height,volume,price); + stats_pairupdate(&pp->dates[offset],pp->symbol,dest,datenum,hour,seconds,height,volume,price); } struct DEXstats_priceinfo *stats_priceinfo(char *symbol,int32_t datenum) From 6dc261c4a81672a5b805d763a62d9f7e8c510a1f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:37:17 +0300 Subject: [PATCH 0453/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index efcff5da0..3d3adcd6a 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -91,7 +91,7 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest, } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); - printf("(%s/%s) numprices.%d h.%d s.%-4d %.8f %.6f\n",symbol,dest,hour,seconds,price,volume); + printf("(%s/%s) numprices.%d h.%d s.%-4d %.8f %.6f\n",symbol,dest,pair->numprices,hour,seconds,price,volume); } void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,char *dest,double price) From 8ebf78627c362272deb017b6203be7bf099ccfdd Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:39:30 +0300 Subject: [PATCH 0454/2705] Test --- iguana/exchanges/DEXstats.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 3d3adcd6a..91f4d49a8 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -87,11 +87,11 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest, pair = &date->pairs[date->numpairs++]; memset(pair,0,sizeof(*pair)); strcpy(pair->dest,dest); - printf("new pair.%d (%s) -> dest.(%s)\n",date->numpairs,symbol,dest); + printf("%d new pair.%d (%s) -> dest.(%s)\n",date->datenum,date->numpairs,symbol,dest); } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); - printf("(%s/%s) numprices.%d h.%d s.%-4d %.8f %.6f\n",symbol,dest,pair->numprices,hour,seconds,price,volume); + printf("(%s/%s).%d numprices.%d h.%d s.%-4d %.8f %.6f\n",symbol,dest,date->datenum,pair->numprices,hour,seconds,price,volume); } void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,char *dest,double price) From 858fd481c05cdd659d053966fe98bd3b1e379f3f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:43:13 +0300 Subject: [PATCH 0455/2705] Test --- iguana/exchanges/DEXstats.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 91f4d49a8..905e0dc4b 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -75,6 +75,7 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest, printf("date->datenum %d != %d? hour.%d seconds.%d\n",date->datenum,datenum,hour,seconds); return; } + printf("%d numpairs.%d %p %p\n",date->datenum,date->numpairs,date,date->pairs); for (i=0; inumpairs; i++) if ( strcmp(dest,date->pairs[i].dest) == 0 ) { @@ -106,6 +107,7 @@ void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t h { pp->dates = realloc(pp->dates,sizeof(*pp->dates) * (offset+1)); n = (offset - pp->numdates); + printf("allocate %s.[%d to %d]\n",pp->symbol,pp->numdates,pp->numdates+n); for (i=0; i<=n; i++) { date = &pp->dates[pp->numdates + i]; From 412b3e42441e46ad9c741d9f4644aae3fe1024a3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:48:35 +0300 Subject: [PATCH 0456/2705] Test --- iguana/exchanges/DEXstats.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 905e0dc4b..7a7edf268 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -86,9 +86,12 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest, { date->pairs = realloc(date->pairs,sizeof(*date->pairs) * (date->numpairs + 1)); pair = &date->pairs[date->numpairs++]; - memset(pair,0,sizeof(*pair)); - strcpy(pair->dest,dest); - printf("%d new pair.%d (%s) -> dest.(%s)\n",date->datenum,date->numpairs,symbol,dest); + if ( pair->dest[0] == 0 ) + { + memset(pair,0,sizeof(*pair)); + strcpy(pair->dest,dest); + printf("%d new pair.%d (%s) -> dest.(%s)\n",date->datenum,date->numpairs,symbol,dest); + } } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); @@ -103,7 +106,7 @@ void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t h printf("illegal datenum.%d for %s when 1st.%d\n",datenum,pp->symbol,pp->firstdatenum); return; } - if ( offset >= pp->numdates ) + if ( offset == 0 || offset > pp->numdates ) { pp->dates = realloc(pp->dates,sizeof(*pp->dates) * (offset+1)); n = (offset - pp->numdates); @@ -111,8 +114,11 @@ void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t h for (i=0; i<=n; i++) { date = &pp->dates[pp->numdates + i]; - memset(date,0,sizeof(*date)); - date->datenum = pp->firstdatenum + pp->numdates + i; + if ( date->datenum != pp->firstdatenum + pp->numdates + i ) + { + memset(date,0,sizeof(*date)); + date->datenum = pp->firstdatenum + pp->numdates + i; + } } pp->numdates = offset; } From 5a87220c81aa2bceff03f0e0b91e09e67b3a3b65 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 10:51:59 +0300 Subject: [PATCH 0457/2705] Test --- iguana/exchanges/DEXstats.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 7a7edf268..c21199494 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -82,16 +82,13 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest, pair = &date->pairs[i]; break; } - if ( i == date->numpairs ) + if ( date->pairs == 0 || i == date->numpairs ) { date->pairs = realloc(date->pairs,sizeof(*date->pairs) * (date->numpairs + 1)); pair = &date->pairs[date->numpairs++]; - if ( pair->dest[0] == 0 ) - { - memset(pair,0,sizeof(*pair)); - strcpy(pair->dest,dest); - printf("%d new pair.%d (%s) -> dest.(%s)\n",date->datenum,date->numpairs,symbol,dest); - } + memset(pair,0,sizeof(*pair)); + strcpy(pair->dest,dest); + printf("%d new pair.%d (%s) -> dest.(%s)\n",date->datenum,date->numpairs,symbol,dest); } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); From a61404ff171899026fdcbb3989574b43941c6807 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:00:57 +0300 Subject: [PATCH 0458/2705] Test --- iguana/exchanges/DEXstats.h | 39 +++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index c21199494..e7d5de5d0 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -75,7 +75,7 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest, printf("date->datenum %d != %d? hour.%d seconds.%d\n",date->datenum,datenum,hour,seconds); return; } - printf("%d numpairs.%d %p %p\n",date->datenum,date->numpairs,date,date->pairs); + //printf("%d numpairs.%d %p %p\n",date->datenum,date->numpairs,date,date->pairs); for (i=0; inumpairs; i++) if ( strcmp(dest,date->pairs[i].dest) == 0 ) { @@ -744,29 +744,26 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n { int32_t i,j,seconds,hour,offset,delta,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp; offset = datenum - leftdatenum; - printf("add datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",datenum,leftdatenum,numdates,offset,date->numpairs); - if ( datenum >= leftdatenum-1 && datenum <= leftdatenum+numdates ) + printf("search dest.%s datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",dest,datenum,leftdatenum,numdates,offset,date->numpairs); + for (i=0; inumpairs; i++) { - printf("add datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",datenum,leftdatenum,numdates,offset,date->numpairs); - for (i=0; inumpairs; i++) - if ( strcmp(dest,date->pairs[i].dest) == 0 ) + if ( strcmp(dest,date->pairs[i].dest) == 0 ) + { + pair = &date->pairs[i]; + printf("found dest.(%s) numprices.%d\n",dest,pair->numprices); + for (j=0; jnumprices; j++) { - pair = &date->pairs[i]; - printf("found dest.(%s) numprices.%d\n",dest,pair->numprices); - for (j=0; jnumprices; j++) - { - ptr = &pair->prices[j]; - seconds = 3600*ptr->hour + ptr->seconds + (24*3600 - current_daysecond); - if ( seconds >= 24*3600 ) - delta = 1; - else delta = 0; - seconds -= delta*24*3600; - if ( offset+delta >= leftdatenum && offset+delta < leftdatenum+numdates ) - stats_updatedisp(&prices[offset+delta],seconds,ptr->price,ptr->volume); - } - break; + ptr = &pair->prices[j]; + seconds = 3600*ptr->hour + ptr->seconds + (24*3600 - current_daysecond); + if ( seconds >= 24*3600 ) + delta = 1; + else delta = 0; + seconds -= delta*24*3600; + if ( offset+delta >= leftdatenum && offset+delta < leftdatenum+numdates ) + stats_updatedisp(&prices[offset+delta],seconds,ptr->price,ptr->volume); } - + break; + } } } From 1c0da119180196c5c77c88ed3c9281635bc629e0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:10:18 +0300 Subject: [PATCH 0459/2705] Test --- iguana/exchanges/DEXstats.h | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index e7d5de5d0..b1f273614 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -731,7 +731,7 @@ void output_line(int32_t calclogflag,double ave,double *buf,int32_t n,int32_t co _output_line(calclogflag,ave,buf,src,1024,color,bitmap,rowwidth,height); } -void stats_updatedisp(struct DEXstats_disp *disp,int32_t seconds,double price,double volume) +void stats_updatedisp(struct DEXstats_disp *disp,double price,double volume) { if ( price > SMALLVAL && volume > SMALLVAL ) { @@ -742,8 +742,10 @@ void stats_updatedisp(struct DEXstats_disp *disp,int32_t seconds,double price,do void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates,struct DEXstats_datenuminfo *date,char *dest,int32_t current_daysecond) { - int32_t i,j,seconds,hour,offset,delta,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp; + int32_t i,j,seconds,hour,offset,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp,lefttimestamp,righttimestamp; offset = datenum - leftdatenum; + lefttimestamp = OS_conv_datenum(leftdatenum,0,0,0); + righttimestamp = OS_conv_datenum(leftdatenum+numdates,0,0,0); printf("search dest.%s datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",dest,datenum,leftdatenum,numdates,offset,date->numpairs); for (i=0; inumpairs; i++) { @@ -754,13 +756,14 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n for (j=0; jnumprices; j++) { ptr = &pair->prices[j]; - seconds = 3600*ptr->hour + ptr->seconds + (24*3600 - current_daysecond); - if ( seconds >= 24*3600 ) - delta = 1; - else delta = 0; - seconds -= delta*24*3600; - if ( offset+delta >= leftdatenum && offset+delta < leftdatenum+numdates ) - stats_updatedisp(&prices[offset+delta],seconds,ptr->price,ptr->volume); + timestamp = OS_conv_datenum(date->datenum,ptr->hour,ptr->seconds/60,ptr->seconds%60); + timestamp += (24*3600 - current_daysecond); + offset = (timestamp - lefttimestamp) / (24*3600); + if ( offset >= 0 && offset < numdates ) + { + printf("found dest.(%s) numprices.%d %d (%.8f %.6f)\n",dest,pair->numprices,ptr->price,ptr->volume); + stats_updatedisp(&prices[offset],ptr->price,ptr->volume); + } } break; } From 20ad56a841612743e88673d23160dde8e9c0ba9c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:11:45 +0300 Subject: [PATCH 0460/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index b1f273614..1510bfa50 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -761,7 +761,7 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n offset = (timestamp - lefttimestamp) / (24*3600); if ( offset >= 0 && offset < numdates ) { - printf("found dest.(%s) numprices.%d %d (%.8f %.6f)\n",dest,pair->numprices,ptr->price,ptr->volume); + printf("found dest.(%s) numprices.%d offset.%d (%.8f %.6f)\n",dest,pair->numprices,offset,ptr->price,ptr->volume); stats_updatedisp(&prices[offset],ptr->price,ptr->volume); } } From d273e5aab436a119bcc295f9d0e415539e200db7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:13:42 +0300 Subject: [PATCH 0461/2705] Test --- iguana/exchanges/DEXstats.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 1510bfa50..ec16484f3 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -746,13 +746,13 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n offset = datenum - leftdatenum; lefttimestamp = OS_conv_datenum(leftdatenum,0,0,0); righttimestamp = OS_conv_datenum(leftdatenum+numdates,0,0,0); - printf("search dest.%s datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",dest,datenum,leftdatenum,numdates,offset,date->numpairs); + //printf("search dest.%s datenum.%d vs leftdatenum.%d numdates.%d offset.%d numpairs.%d\n",dest,datenum,leftdatenum,numdates,offset,date->numpairs); for (i=0; inumpairs; i++) { if ( strcmp(dest,date->pairs[i].dest) == 0 ) { pair = &date->pairs[i]; - printf("found dest.(%s) numprices.%d\n",dest,pair->numprices); + //printf("found dest.(%s) numprices.%d\n",dest,pair->numprices); for (j=0; jnumprices; j++) { ptr = &pair->prices[j]; @@ -803,8 +803,9 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ { splinevals[n] = (prices[i].pricesum / prices[i].volumesum); utc32[n] = tmp; + printf("offset.%d splineval %.8f t%u n.%d\n",i,splinevals[n],tmp,n); n++; - } else memset(&prices[i],0,sizeof(prices[i])); + } } if ( n > 3 ) { From 4dd0b0c41363682f23d60df4fa4f75b70cbbace6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:16:24 +0300 Subject: [PATCH 0462/2705] Test --- iguana/exchanges/DEXstats.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index ec16484f3..0b4c9ea2c 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -812,7 +812,9 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ double output[2048],slopes[2048]; struct stats_spline spline; int32_t splineid = 0; memset(&spline,0,sizeof(spline)); stats_genspline(output,slopes,&spline,splineid,"spline",utc32,splinevals,n,0); - + for (i=0; i<2048; i++) + printf("%.8f ",output[i]); + printf(" output\n"); } free(utc32); free(splinevals); From da90c93042f642408f13bf42ccbbebae355c3a4b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:17:16 +0300 Subject: [PATCH 0463/2705] Test --- iguana/exchanges/DEXstats.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 0b4c9ea2c..4feee35f9 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -813,7 +813,8 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ memset(&spline,0,sizeof(spline)); stats_genspline(output,slopes,&spline,splineid,"spline",utc32,splinevals,n,0); for (i=0; i<2048; i++) - printf("%.8f ",output[i]); + if ( output[i] != 0. ) + printf("(%d %.8f) ",i,output[i]); printf(" output\n"); } free(utc32); From 860770ac1da9c4614111b58b73db5923a5173b99 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:25:06 +0300 Subject: [PATCH 0464/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 4feee35f9..c23e76032 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -11,7 +11,7 @@ #define LEFTMARGIN 40 #define MAX_SPLINES 1024 -#define MAX_LOOKAHEAD 60 +#define MAX_LOOKAHEAD 7 struct stats_spline { char name[64]; int32_t splineid,lasti,basenum,num,firstx,dispincr,spline32[MAX_SPLINES][4]; uint32_t utc32[MAX_SPLINES]; int64_t spline64[MAX_SPLINES][4]; double dSplines[MAX_SPLINES][4],pricevals[MAX_SPLINES+MAX_LOOKAHEAD],lastutc,lastval,aveslopeabs; }; From f74d7438d99a68a84da2568b71cd193b5be2806e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:27:49 +0300 Subject: [PATCH 0465/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index c23e76032..814a135ef 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -814,7 +814,7 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ stats_genspline(output,slopes,&spline,splineid,"spline",utc32,splinevals,n,0); for (i=0; i<2048; i++) if ( output[i] != 0. ) - printf("(%d %.8f) ",i,output[i]); + printf("(%d %.8f).t%u ",i,output[i],utc32[0]+i*3600); printf(" output\n"); } free(utc32); From b9f9ddba4c51802c17071d81c79fb35eedce047e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 11:36:31 +0300 Subject: [PATCH 0466/2705] Test --- iguana/exchanges/DEXstats.h | 41 +++++++++++++++++++++++++++++-------- iguana/exchanges/stats.c | 8 ++++++-- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 814a135ef..371837cba 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -92,7 +92,7 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest, } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); - printf("(%s/%s).%d numprices.%d h.%d s.%-4d %.8f %.6f\n",symbol,dest,date->datenum,pair->numprices,hour,seconds,price,volume); + //printf("(%s/%s).%d numprices.%d h.%d s.%-4d %.8f %.6f\n",symbol,dest,date->datenum,pair->numprices,hour,seconds,price,volume); } void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,char *dest,double price) @@ -761,7 +761,7 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n offset = (timestamp - lefttimestamp) / (24*3600); if ( offset >= 0 && offset < numdates ) { - printf("found dest.(%s) numprices.%d offset.%d (%.8f %.6f)\n",dest,pair->numprices,offset,ptr->price,ptr->volume); + //printf("found dest.(%s) numprices.%d offset.%d (%.8f %.6f)\n",dest,pair->numprices,offset,ptr->price,ptr->volume); stats_updatedisp(&prices[offset],ptr->price,ptr->volume); } } @@ -770,9 +770,9 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n } } -struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) +char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) { - int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals; struct tai T; + int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals; struct tai T; cJSON *retjson,*array,*item; timestamp = (uint32_t)time(NULL); if ( Num_priceinfos >= sizeof(Prices)/sizeof(*Prices) ) return(0); @@ -807,19 +807,42 @@ struct DEXstats_priceinfo *stats_prices(char *symbol,char *dest,struct DEXstats_ n++; } } + retjson = cJSON_CreateObject(); + jaddstr(retjson,"source",symbol); + jaddstr(retjson,"dest",dest); + jaddnum(retjson,"start",leftdatenum); + jaddnum(retjson,"numdates",numdates); if ( n > 3 ) { - double output[2048],slopes[2048]; struct stats_spline spline; int32_t splineid = 0; + double output[2048],slopes[2048],sum = 0.; struct stats_spline spline; int32_t splineid = 0; memset(&spline,0,sizeof(spline)); stats_genspline(output,slopes,&spline,splineid,"spline",utc32,splinevals,n,0); + array = cJSON_CreateArray(); + for (i=0; i Date: Mon, 8 May 2017 12:00:41 +0300 Subject: [PATCH 0467/2705] Test --- iguana/exchanges/DEXstats.h | 41 ++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 371837cba..ce7333695 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -770,9 +770,42 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n } } +void gen_jpegfile(char *fname,int32_t quality,uint8_t *bitmap,int32_t width,int32_t height) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + if ( (outfile= fopen(fname,"wb")) == NULL) + { + fprintf(stderr, "can't open %s\n", fname); + iguana_exit(0,0); + } + jpeg_stdio_dest(&cinfo, outfile); + cinfo.image_width = width; /* image width and height, in pixels */ + cinfo.image_height = height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + jpeg_start_compress(&cinfo, TRUE); + row_stride = width * 3; /* JSAMPLEs per row in image_buffer */ + while (cinfo.next_scanline < cinfo.image_height) + { + row_pointer[0] = &bitmap[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + jpeg_finish_compress(&cinfo); + fclose(outfile); + jpeg_destroy_compress(&cinfo); +} + char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) { - int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals; struct tai T; cJSON *retjson,*array,*item; + int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals; char fname[1024]; struct tai T; cJSON *retjson,*array,*item; timestamp = (uint32_t)time(NULL); if ( Num_priceinfos >= sizeof(Prices)/sizeof(*Prices) ) return(0); @@ -837,6 +870,12 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t if ( i != 2048 ) i++; sum /= i; + uint32_t height = 400,*bitmap = calloc(sizeof(*bitmap),3 * height * numdates*24); + output_line(0,sum,output,i,0xff00ff,bitmap,numdates*24,height) + sprintf(fname,"%s/bitmaps/%s_%s.jpg",STATS_DEST,symbol,dest), OS_portable_path(fname); + gen_jpegfile(fname,1,bitmap,numdates*24,height); + free(bitmap); + jaddstr(retjson,"bitmap",fname); jadd(retjson,"hourly",array); jaddnum(retjson,"average",sum); } From d1708d994e568f29a736fc53d5e13630fb8e552b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:05:05 +0300 Subject: [PATCH 0468/2705] Test --- iguana/exchanges/DEXstats.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index ce7333695..f1f48f501 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -770,6 +770,9 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n } } +#include "../crypto777/jpeg/jinclude.h" +#include "../crypto777/jpeg/jpeglib.h" + void gen_jpegfile(char *fname,int32_t quality,uint8_t *bitmap,int32_t width,int32_t height) { struct jpeg_compress_struct cinfo; From f5afc164f19b1a8f21de56cd979d56de60a25a98 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:11:33 +0300 Subject: [PATCH 0469/2705] Test --- iguana/exchanges/DEXstats.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index f1f48f501..09d57c291 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -772,6 +772,7 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n #include "../crypto777/jpeg/jinclude.h" #include "../crypto777/jpeg/jpeglib.h" +#include "../crypto777/jpeg/jerror.h" void gen_jpegfile(char *fname,int32_t quality,uint8_t *bitmap,int32_t width,int32_t height) { From 359e13f22e0a4d716bffa07b4217d5491a05aa2f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:14:45 +0300 Subject: [PATCH 0470/2705] Test --- iguana/exchanges/DEXstats.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 09d57c291..c72a5e172 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -786,7 +786,7 @@ void gen_jpegfile(char *fname,int32_t quality,uint8_t *bitmap,int32_t width,int3 if ( (outfile= fopen(fname,"wb")) == NULL) { fprintf(stderr, "can't open %s\n", fname); - iguana_exit(0,0); + return; } jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = width; /* image width and height, in pixels */ @@ -874,8 +874,8 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t if ( i != 2048 ) i++; sum /= i; - uint32_t height = 400,*bitmap = calloc(sizeof(*bitmap),3 * height * numdates*24); - output_line(0,sum,output,i,0xff00ff,bitmap,numdates*24,height) + uint32_t height = 400; uint8_t *bitmap = calloc(sizeof(*bitmap),3 * height * numdates*24); + output_line(0,sum,output,i,0xff00ff,bitmap,numdates*24,height); sprintf(fname,"%s/bitmaps/%s_%s.jpg",STATS_DEST,symbol,dest), OS_portable_path(fname); gen_jpegfile(fname,1,bitmap,numdates*24,height); free(bitmap); From 566f112f531e3c5ce0d6a3a83e55d647f872e52d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:19:03 +0300 Subject: [PATCH 0471/2705] Test --- iguana/exchanges/DEXstats.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index c72a5e172..39bfb569c 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -874,11 +874,23 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t if ( i != 2048 ) i++; sum /= i; - uint32_t height = 400; uint8_t *bitmap = calloc(sizeof(*bitmap),3 * height * numdates*24); + uint32_t height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); + uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); output_line(0,sum,output,i,0xff00ff,bitmap,numdates*24,height); + tmpptr = bytemap; + for (j=0; j> 8) & 0xff; + blue = (val >> 16) & 0xff; + *tmpptr++ = red; + *tmpptr++ = green; + *tmpptr++ = blue; + } sprintf(fname,"%s/bitmaps/%s_%s.jpg",STATS_DEST,symbol,dest), OS_portable_path(fname); - gen_jpegfile(fname,1,bitmap,numdates*24,height); - free(bitmap); + gen_jpegfile(fname,1,bytemap,numdates*24,height); + free(bitmap), free(bytemap); jaddstr(retjson,"bitmap",fname); jadd(retjson,"hourly",array); jaddnum(retjson,"average",sum); From 477dc883ab63ca13fd5110de7331c4569a2a7f8d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:19:29 +0300 Subject: [PATCH 0472/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 39bfb569c..9bf114ece 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -874,7 +874,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t if ( i != 2048 ) i++; sum /= i; - uint32_t height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); + uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); output_line(0,sum,output,i,0xff00ff,bitmap,numdates*24,height); tmpptr = bytemap; From 801456dfd9eaa12bc0879be08a1577c7161cff9b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:19:56 +0300 Subject: [PATCH 0473/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 9bf114ece..fd1f80701 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -888,7 +888,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t *tmpptr++ = green; *tmpptr++ = blue; } - sprintf(fname,"%s/bitmaps/%s_%s.jpg",STATS_DEST,symbol,dest), OS_portable_path(fname); + sprintf(fname,"%s/bitmaps/%s_%s.jpg",STATS_DESTDIR,symbol,dest), OS_portable_path(fname); gen_jpegfile(fname,1,bytemap,numdates*24,height); free(bitmap), free(bytemap); jaddstr(retjson,"bitmap",fname); From b9d3444d41b0f7020d0723318d7628b4968f67e7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:20:36 +0300 Subject: [PATCH 0474/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 921702730..5ac808123 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -23,6 +23,8 @@ #include #include "OS_portable.h" #define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define STATS_DESTDIR "/var/www/html" +#define STATS_DEST "/var/www/html/DEXstats.json" #include "DEXstats.h" #ifndef WIN32 @@ -33,8 +35,6 @@ #define MSG_NOSIGNAL 0 #endif -#define STATS_DESTDIR "/var/www/html" -#define STATS_DEST "/var/www/html/DEXstats.json" #define GLOBAL_HELPDIR "/root/SuperNET/iguana/help" char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies From 2fb70e2af7b9366d41b3c297646a7c0ed931a120 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:25:49 +0300 Subject: [PATCH 0475/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index fd1f80701..1859079a7 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -498,7 +498,7 @@ double _output_line(int32_t calclogflag,double ave,double *output,double *buf,in if ( ave != 1. ) yval = _calc_pricey(val,ave); else yval = val; - printf("%f ",yval); + //printf("%f ",yval); if ( fabs(yval) > .0000000001 ) { aveabs += fabs(yval); From 70ccddc37652e105168e83430de63fa2bf0a4900 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:39:33 +0300 Subject: [PATCH 0476/2705] Test --- iguana/exchanges/DEXstats.h | 15 +++++++++++++-- iguana/exchanges/stats.c | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 1859079a7..a6368f31c 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -840,7 +840,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t { splinevals[n] = (prices[i].pricesum / prices[i].volumesum); utc32[n] = tmp; - printf("offset.%d splineval %.8f t%u n.%d\n",i,splinevals[n],tmp,n); + //printf("offset.%d splineval %.8f t%u n.%d\n",i,splinevals[n],tmp,n); n++; } } @@ -907,7 +907,18 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) return(clonestr("{\"error\":\"need method in request\"}")); if ( (agent= jstr(argjson,"agent")) == 0 ) agent = "stats"; - + /*timestamp = (uint32_t)time(NULL); + leftdatenum = OS_conv_unixtime(&T,&seconds,timestamp - 1024*3600); + printf("%u: leftdatenum.%d %s\n",timestamp,leftdatenum,filestr); + memset(prices,0,sizeof(prices)); + if ( (retstr= stats_prices("KMD","BTC",prices,leftdatenum,1024/24+1)) != 0 ) + { + printf("%s\n",retstr); + free(retstr); + } + + char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) +*/ return(clonestr(jprint(argjson,0))); } diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 5ac808123..b17facbaf 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -1003,11 +1003,11 @@ int main(int argc, const char * argv[]) { timestamp = (uint32_t)time(NULL); leftdatenum = OS_conv_unixtime(&T,&seconds,timestamp - 1024*3600); - printf("%u: leftdatenum.%d %s\n",timestamp,leftdatenum,filestr); + //printf("%u: leftdatenum.%d %s\n",timestamp,leftdatenum,filestr); memset(prices,0,sizeof(prices)); if ( (retstr= stats_prices("KMD","BTC",prices,leftdatenum,1024/24+1)) != 0 ) { - printf("%s\n",retstr); + //printf("%s\n",retstr); free(retstr); } if ( (fp= fopen(STATS_DEST,"wb")) != 0 ) From 61e0b12227a99d380ed899d596b7037995bceb67 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:46:50 +0300 Subject: [PATCH 0477/2705] Test --- iguana/exchanges/DEXstats.h | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index a6368f31c..1bdc9d6ae 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -902,23 +902,25 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { - char *method,*agent; + char *method,*agent,*retstr,*source,*dest; struct tai T; uint32_t endtimestamp; struct DEXstats_disp prices[365]; int32_t leftdatenum,seconds,width = 1024; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); if ( (agent= jstr(argjson,"agent")) == 0 ) agent = "stats"; - /*timestamp = (uint32_t)time(NULL); - leftdatenum = OS_conv_unixtime(&T,&seconds,timestamp - 1024*3600); - printf("%u: leftdatenum.%d %s\n",timestamp,leftdatenum,filestr); - memset(prices,0,sizeof(prices)); - if ( (retstr= stats_prices("KMD","BTC",prices,leftdatenum,1024/24+1)) != 0 ) + if ( strcmp(method,"bitmap") == 0 ) { - printf("%s\n",retstr); - free(retstr); + if ( (timestamp= juint(argjson,"endtimestamp")) == 0 ) + endtimestamp = (uint32_t)time(NULL); + if ( (source= jstr(argjson,"source")) == 0 ) + source = "KMD"; + if ( (dest= jstr(argjson,"dest")) == 0 ) + dest = "USD"; + leftdatenum = OS_conv_unixtime(&T,&seconds,endtimestamp - width*3600); + printf("(%s/%s) endtimestamp.%u: leftdatenum.%d\n",source,dest,endtimestamp,leftdatenum); + memset(prices,0,sizeof(prices)); + if ( (retstr= stats_prices(source,dest,prices,leftdatenum,width/24+1)) != 0 ) + return(retstr); } - - char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) -*/ return(clonestr(jprint(argjson,0))); } From 6baf0a979d0cc8c9f5397680addae74d434e3a50 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:47:08 +0300 Subject: [PATCH 0478/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 1bdc9d6ae..09f0a639f 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -909,7 +909,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) agent = "stats"; if ( strcmp(method,"bitmap") == 0 ) { - if ( (timestamp= juint(argjson,"endtimestamp")) == 0 ) + if ( (endtimestamp= juint(argjson,"endtimestamp")) == 0 ) endtimestamp = (uint32_t)time(NULL); if ( (source= jstr(argjson,"source")) == 0 ) source = "KMD"; From cfe6e0a1e68da25e39e49061bd731050a204dc5a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 12:59:55 +0300 Subject: [PATCH 0479/2705] Test --- iguana/exchanges/DEXstats.h | 8 +++++--- iguana/tests/dexlisttransactions | 2 +- iguana/tests/statstest | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 09f0a639f..df145ae15 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -902,7 +902,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { - char *method,*agent,*retstr,*source,*dest; struct tai T; uint32_t endtimestamp; struct DEXstats_disp prices[365]; int32_t leftdatenum,seconds,width = 1024; + char *method,*agent,*retstr,*source,*dest; struct tai T; uint32_t endtimestamp; struct DEXstats_disp prices[365]; int32_t leftdatenum,seconds,numdates; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); if ( (agent= jstr(argjson,"agent")) == 0 ) @@ -915,10 +915,12 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) source = "KMD"; if ( (dest= jstr(argjson,"dest")) == 0 ) dest = "USD"; - leftdatenum = OS_conv_unixtime(&T,&seconds,endtimestamp - width*3600); + if ( (numdates= jstr(argjson,"numdates")) == 0 ) + numdates = 1024/24; + leftdatenum = OS_conv_unixtime(&T,&seconds,endtimestamp - numdates*24*3600); printf("(%s/%s) endtimestamp.%u: leftdatenum.%d\n",source,dest,endtimestamp,leftdatenum); memset(prices,0,sizeof(prices)); - if ( (retstr= stats_prices(source,dest,prices,leftdatenum,width/24+1)) != 0 ) + if ( (retstr= stats_prices(source,dest,prices,leftdatenum,numdates+1)) != 0 ) return(retstr); } return(clonestr(jprint(argjson,0))); diff --git a/iguana/tests/dexlisttransactions b/iguana/tests/dexlisttransactions index c12c56d96..09a94f406 100755 --- a/iguana/tests/dexlisttransactions +++ b/iguana/tests/dexlisttransactions @@ -1,5 +1,5 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"bZY6LMGHXbpLkyw14uW5XbRsH8LB5MhnLe\",\"count\":100,\"skip\":0,\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"RWE3NWHT6Fb1zW4mY9LU859MPoWGYvtLfj\",\"count\":100,\"skip\":0,\"symbol\":\"KMD\"}" #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"RRyBxbrAPRUBCUpiJgJZYrkxqrh8x5ta9Z\",\"count\":100,\"skip\":0,\"symbol\":\"MVP\"}" #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"RMGpGoX82M1ZUUbHxZ3JKHacxY9NYVakqr\",\"count\":100,\"skip\":0,\"symbol\":\"USD\"}" #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listtransactions\",\"address\":\"RMGpGoX82M1ZUUbHxZ3JKHacxY9NYVakqr\",\"count\":100,\"skip\":0,\"symbol\":\"MVP\"}" diff --git a/iguana/tests/statstest b/iguana/tests/statstest index f9eec7e0b..9d95e23cc 100755 --- a/iguana/tests/statstest +++ b/iguana/tests/statstest @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7779" --data "{\"method\":\"start\"}" +curl --url "http://127.0.0.1:7779" --data "{\"method\":\"bitmap\",\"endtimestamp\":0,\"source\":\"KMD\",\"dest\":\"BTC\",\"numdates\":30}" From ca49a3018e5c0d3c37d0e9ce702a78e196796ef0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 13:00:47 +0300 Subject: [PATCH 0480/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index df145ae15..c2b82eec4 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -915,7 +915,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) source = "KMD"; if ( (dest= jstr(argjson,"dest")) == 0 ) dest = "USD"; - if ( (numdates= jstr(argjson,"numdates")) == 0 ) + if ( (numdates= jint(argjson,"numdates")) <= 0 || numdates > 1024/24 ) numdates = 1024/24; leftdatenum = OS_conv_unixtime(&T,&seconds,endtimestamp - numdates*24*3600); printf("(%s/%s) endtimestamp.%u: leftdatenum.%d\n",source,dest,endtimestamp,leftdatenum); From 63288fa4c3969ed84c1d32d185da97c87826c022 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 14:33:13 +0300 Subject: [PATCH 0481/2705] Test --- iguana/exchanges/stats.c | 78 ++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index b17facbaf..b45754eac 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -823,7 +823,15 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig } } -int32_t komodo_parsestatefile(FILE *logfp,struct komodo_state *sp,FILE *fp,char *symbol,char *dest) +void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t pvals,int32_t numpvals) +{ + int32_t i; + for (i=0; i global PVALS - //printf("%s load[%s] prices %d\n",ASSETCHAINS_SYMBOL,symbol,ht); - //komodo_eventadd_pricefeed(sp,symbol,ht,pvals,numpvals); - //printf("load pvals ht.%d numpvals.%d\n",ht,numpvals); + //printf("load pvals ht.%d numpvals.%d\n",ht,numpvals); } else printf("error loading pvals[%d]\n",numpvals); } else printf("[%s] %s illegal func.(%d %c)\n",ASSETCHAINS_SYMBOL,symbol,func,func); @@ -944,52 +955,67 @@ int32_t komodo_parsestatefile(FILE *logfp,struct komodo_state *sp,FILE *fp,char } else return(-1); } -void stats_stateupdate(FILE *logfp,char *destdir,char *statefname,int32_t maxseconds) +void stats_stateupdate(FILE *logfp,char *destdir,char *statefname,int32_t maxseconds,char *komodofile) { - static long lastpos; - char symbol[64],base[64],dest[64]; int32_t n; FILE *fp; uint32_t starttime; struct komodo_state *sp; + static long lastpos[2]; + char symbol[64],base[64]; int32_t iter,n; FILE *fp; uint32_t starttime; struct komodo_state *sp; starttime = (uint32_t)time(NULL); strcpy(base,"KV"); strcpy(symbol,"KV"); - strcpy(dest,"KMD"); sp = &KOMODO_STATE; n = 0; - if ( (fp= fopen(statefname,"rb")) != 0 && sp != 0 ) + for (iter=0; iter<2; iter++) { - fseek(fp,0,SEEK_END); - if ( ftell(fp) > lastpos ) + if ( (fp= fopen(iter == 0 ? statefname : komodofile,"rb")) != 0 ) { - fseek(fp,lastpos,SEEK_SET); - while ( komodo_parsestatefile(logfp,sp,fp,symbol,dest) >= 0 && n < 1000 ) + fseek(fp,0,SEEK_END); + if ( ftell(fp) > lastpos[iter] ) { - if ( n == 999 ) + fseek(fp,lastpos,SEEK_SET); + while ( komodo_parsestatefile(logfp,sp,fp,symbol,iter) >= 0 && n < 1000 ) { - if ( time(NULL) < starttime+maxseconds ) - n = 0; - else break; + if ( n == 999 ) + { + if ( time(NULL) < starttime+maxseconds ) + n = 0; + else break; + } + n++; } - n++; + lastpos[iter] = ftell(fp); } - lastpos = ftell(fp); + fclose(fp); } - fclose(fp); + strcpy(base,"KMD"); + strcpy(symbol,"KMD"); } } -char *stats_update(FILE *logfp,char *destdir,char *statefname) +char *stats_update(FILE *logfp,char *destdir,char *statefname,char *komodofname) { cJSON *retjson = cJSON_CreateArray(); - stats_stateupdate(logfp,destdir,statefname,10); + stats_stateupdate(logfp,destdir,statefname,10,komodofname); return(jprint(retjson,1)); } int main(int argc, const char * argv[]) { - struct tai T; uint32_t timestamp; struct DEXstats_disp prices[365]; int32_t seconds,leftdatenum; FILE *fp,*logfp; char *filestr,*retstr,*statefname,logfname[512]; uint16_t port = 7779; + struct tai T; uint32_t timestamp; struct DEXstats_disp prices[365]; int32_t i,n,seconds,leftdatenum; FILE *fp,*logfp; char *filestr,*retstr,*statefname,logfname[512],komodofile[512]; uint16_t port = 7779; if ( argc < 2 ) + { statefname = "/root/.komodo/KV/komodostate"; - else statefname = (char *)argv[1]; - sprintf(logfname,"%s/logfile",STATS_DESTDIR); + strcpy(komodofile,"/root/.komodo/komodostate"); + } + else + { + statefname = (char *)argv[1]; + strcpy(komodofile,statefname); + n = (int32_t)strlen(komodofile); + for (i=0; i<=strlen("komodostate"); i++) + komodofile[n-14+i] = komodofile[n-11+i]; + printf("komodofile.(%s)\n",komodofile); + } + sprintf(logfname,"%s/logfile",STATS_DESTDIR), OS_portable_path(logfname); logfp = fopen(logfname,"wb"); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&port) != 0 ) { @@ -999,7 +1025,7 @@ int main(int argc, const char * argv[]) printf("DEX stats running\n"); while ( 1 ) { - if ( (filestr= stats_update(logfp,STATS_DEST,statefname)) != 0 ) + if ( (filestr= stats_update(logfp,STATS_DEST,statefname,komodofname)) != 0 ) { timestamp = (uint32_t)time(NULL); leftdatenum = OS_conv_unixtime(&T,&seconds,timestamp - 1024*3600); From 2c5a23479502f9c65d4926ca3e037c0d0e637e5b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 14:34:07 +0300 Subject: [PATCH 0482/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index b45754eac..2d8bc1500 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -823,7 +823,7 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig } } -void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t pvals,int32_t numpvals) +void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *pvals,int32_t numpvals) { int32_t i; for (i=0; i lastpos[iter] ) { - fseek(fp,lastpos,SEEK_SET); + fseek(fp,lastpos[iter],SEEK_SET); while ( komodo_parsestatefile(logfp,sp,fp,symbol,iter) >= 0 && n < 1000 ) { if ( n == 999 ) From 3886ffc5eeb8d78f09023c6a77243111b08e2821 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 14:34:31 +0300 Subject: [PATCH 0483/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 2d8bc1500..a16c9b4d6 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -1025,7 +1025,7 @@ int main(int argc, const char * argv[]) printf("DEX stats running\n"); while ( 1 ) { - if ( (filestr= stats_update(logfp,STATS_DEST,statefname,komodofname)) != 0 ) + if ( (filestr= stats_update(logfp,STATS_DEST,statefname,komodofile)) != 0 ) { timestamp = (uint32_t)time(NULL); leftdatenum = OS_conv_unixtime(&T,&seconds,timestamp - 1024*3600); From 0c0041cba5162476990c3867015e8107094407c4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 14:36:41 +0300 Subject: [PATCH 0484/2705] Test --- iguana/exchanges/stats.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index a16c9b4d6..90615740b 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -955,7 +955,7 @@ int32_t komodo_parsestatefile(FILE *logfp,struct komodo_state *sp,FILE *fp,char } else return(-1); } -void stats_stateupdate(FILE *logfp,char *destdir,char *statefname,int32_t maxseconds,char *komodofile) +int32_t stats_stateupdate(FILE *logfp,char *destdir,char *statefname,int32_t maxseconds,char *komodofile) { static long lastpos[2]; char symbol[64],base[64]; int32_t iter,n; FILE *fp; uint32_t starttime; struct komodo_state *sp; @@ -993,8 +993,11 @@ void stats_stateupdate(FILE *logfp,char *destdir,char *statefname,int32_t maxsec char *stats_update(FILE *logfp,char *destdir,char *statefname,char *komodofname) { + int32_t i; cJSON *retjson = cJSON_CreateArray(); - stats_stateupdate(logfp,destdir,statefname,10,komodofname); + for (i=0; i<100; i++) + if ( stats_stateupdate(logfp,destdir,statefname,10,komodofname) <= 0 ) + break; return(jprint(retjson,1)); } From eac92104c422d106c64a007944a0cec1cefcac0f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 14:37:28 +0300 Subject: [PATCH 0485/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 90615740b..83ca2e231 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -972,9 +972,9 @@ int32_t stats_stateupdate(FILE *logfp,char *destdir,char *statefname,int32_t max if ( ftell(fp) > lastpos[iter] ) { fseek(fp,lastpos[iter],SEEK_SET); - while ( komodo_parsestatefile(logfp,sp,fp,symbol,iter) >= 0 && n < 1000 ) + while ( komodo_parsestatefile(logfp,sp,fp,symbol,iter) >= 0 && n < 100000 ) { - if ( n == 999 ) + if ( n == 99999 ) { if ( time(NULL) < starttime+maxseconds ) n = 0; From 7d703ec7c47464a373538885c3958aad0c5cff17 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 14:38:36 +0300 Subject: [PATCH 0486/2705] Test --- iguana/exchanges/stats.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 83ca2e231..6102dbd5d 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -825,10 +825,11 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *pvals,int32_t numpvals) { - int32_t i; + /*int32_t i; for (i=0; i Date: Mon, 8 May 2017 14:42:09 +0300 Subject: [PATCH 0487/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 6102dbd5d..869fa3a76 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -829,7 +829,7 @@ void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *p for (i=0; i Date: Mon, 8 May 2017 14:44:09 +0300 Subject: [PATCH 0488/2705] Test --- iguana/exchanges/stats.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 869fa3a76..dbdb5ab29 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -825,11 +825,14 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *pvals,int32_t numpvals) { - /*int32_t i; - for (i=0; i 300000 ) + { + for (i=0; i global PVALS From 81c08e05a379328467f2d947c584fa505e809e20 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 14:47:35 +0300 Subject: [PATCH 0489/2705] Test --- iguana/exchanges/stats.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index dbdb5ab29..9f4cb6b4d 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -825,13 +825,13 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *pvals,int32_t numpvals) { - int32_t i; + //int32_t i; if ( ht > 300000 ) { - for (i=0; i Date: Mon, 8 May 2017 14:53:18 +0300 Subject: [PATCH 0490/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 9f4cb6b4d..dcdd0ac67 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -831,7 +831,7 @@ void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *p //for (i=0; i Date: Mon, 8 May 2017 14:55:28 +0300 Subject: [PATCH 0491/2705] Test --- iguana/exchanges/stats.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index dcdd0ac67..355d50977 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -54,7 +54,7 @@ struct komodo_state uint32_t RTbufs[64][3]; uint64_t RTmask; }; -struct komodo_state KOMODO_STATE; +struct komodo_state KOMODO_STATE[2]; int32_t iguana_socket(int32_t bindflag,char *hostname,uint16_t port) { @@ -831,7 +831,7 @@ void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *p //for (i=0; iSAVEDTIMESTAMP,dstr(pvals[32]) / 1000.); } } @@ -966,10 +966,10 @@ int32_t stats_stateupdate(FILE *logfp,char *destdir,char *statefname,int32_t max starttime = (uint32_t)time(NULL); strcpy(base,"KV"); strcpy(symbol,"KV"); - sp = &KOMODO_STATE; n = 0; for (iter=0; iter<2; iter++) { + sp = &KOMODO_STATE[iter]; if ( (fp= fopen(iter == 0 ? statefname : komodofile,"rb")) != 0 ) { fseek(fp,0,SEEK_END); From 71e8b4cd56cb7529c44ab5f03da02acf5cf9caa6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 15:05:10 +0300 Subject: [PATCH 0492/2705] Test --- iguana/exchanges/DEXstats.h | 29 ++++++++++++++++++----------- iguana/exchanges/stats.c | 17 +++++++++++------ 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index c2b82eec4..f399d8f6e 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -33,8 +33,9 @@ struct DEXstats_disp { double pricesum,volumesum; }; struct DEXstats_pricepoint { double price,volume; - uint32_t height:27,hour:5; + uint32_t height; uint16_t seconds; + int8_t hour,dir; }; struct DEXstats_pairinfo @@ -58,16 +59,17 @@ struct DEXstats_priceinfo } Prices[1024]; int32_t Num_priceinfos; -void stats_pricepoint(struct DEXstats_pricepoint *ptr,uint8_t hour,uint16_t seconds,int32_t height,double volume,double price) +void stats_pricepoint(int32_t dir,struct DEXstats_pricepoint *ptr,uint8_t hour,uint16_t seconds,int32_t height,double volume,double price) { ptr->price = price; ptr->volume = volume; ptr->height = height; ptr->hour = hour; + ptr->dir = dir; ptr->seconds = seconds; } -void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,double price) +void stats_pairupdate(int32_t dir,struct DEXstats_datenuminfo *date,char *symbol,char *dest,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,double price) { int32_t i; struct DEXstats_pairinfo *pair = 0; if ( date->datenum != datenum || seconds < 0 || seconds >= 3600 || hour < 0 || hour >= 24 ) @@ -91,11 +93,11 @@ void stats_pairupdate(struct DEXstats_datenuminfo *date,char *symbol,char *dest, printf("%d new pair.%d (%s) -> dest.(%s)\n",date->datenum,date->numpairs,symbol,dest); } pair->prices = realloc(pair->prices,sizeof(*pair->prices) * (pair->numprices+1)); - stats_pricepoint(&pair->prices[pair->numprices++],hour,seconds,height,volume,price); + stats_pricepoint(dir,&pair->prices[pair->numprices++],hour,seconds,height,volume,price); //printf("(%s/%s).%d numprices.%d h.%d s.%-4d %.8f %.6f\n",symbol,dest,date->datenum,pair->numprices,hour,seconds,price,volume); } -void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,char *dest,double price) +void stats_datenumupdate(int32_t dir,struct DEXstats_priceinfo *pp,int32_t datenum,int32_t hour,int32_t seconds,int32_t height,double volume,char *dest,double price) { int32_t offset,i,n; struct DEXstats_datenuminfo *date; if ( (offset= datenum - pp->firstdatenum) < 0 ) @@ -119,7 +121,7 @@ void stats_datenumupdate(struct DEXstats_priceinfo *pp,int32_t datenum,int32_t h } pp->numdates = offset; } - stats_pairupdate(&pp->dates[offset],pp->symbol,dest,datenum,hour,seconds,height,volume,price); + stats_pairupdate(dir,&pp->dates[offset],pp->symbol,dest,datenum,hour,seconds,height,volume,price); } struct DEXstats_priceinfo *stats_priceinfo(char *symbol,int32_t datenum) @@ -161,12 +163,17 @@ void stats_priceupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t tim if ( srcamount != 0 && destamount != 0 ) { price = (double)destamount / srcamount; - if ( (pp= stats_priceinfo(source,datenum)) != 0 ) - stats_datenumupdate(pp,datenum,hour,seconds,height,dstr(srcamount),dest,price); - if ( (pp= stats_priceinfo(dest,datenum)) != 0 ) - stats_datenumupdate(pp,datenum,hour,seconds,height,dstr(destamount),source,1. / price); + if ( key != 0 ) + { + if ( (pp= stats_priceinfo(source,datenum)) != 0 ) + stats_datenumupdate(-1,pp,datenum,hour,seconds,height,dstr(srcamount),dest,price); + if ( (pp= stats_priceinfo(dest,datenum)) != 0 ) + stats_datenumupdate(1,pp,datenum,hour,seconds,height,dstr(destamount),source,1. / price); + } + else if ( (pp= stats_priceinfo(source,datenum)) != 0 ) + stats_datenumupdate(0,pp,datenum,hour,seconds,height,dstr(srcamount),dest,price); } else price = 0.; - printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",datenum,hour,seconds,height,key,source,dstr(srcamount),dest,dstr(destamount),price,1./price); + printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",datenum,hour,seconds,height,key!=0?key:"",source,dstr(srcamount),dest,dstr(destamount),price,1./price); } } diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 355d50977..f451e5ce9 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -825,13 +825,18 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *pvals,int32_t numpvals) { - //int32_t i; - if ( ht > 300000 ) + struct tai T; int32_t seconds,datenum,n; cJSON *argjson; + if ( ht > 300000 && pvals[32] != 0 ) { - //for (i=0; iSAVEDTIMESTAMP,dstr(pvals[32]) / 1000.); + datenum = OS_conv_unixtime(&T,&seconds,sp->SAVEDTIMESTAMP); + //printf("(%s)\n",jprint(kvjson,0)); + argjson = cJSON_CreateArray(); + jaddistr(argjson,"KMD"); + jaddnum(argjson,1); + jaddistr(argjson,"BTC"); + jaddnum(argjson,dstr(pvals[32]) / 1000.); + stats_priceupdate(datenum,seconds/3600,seconds % 3600,sp->SAVEDTIMESTAMP,sp->SAVEDHEIGHT,0,0,argjson); + free_json(argjson); } } From 102ad0b0ca59220b0044a921b5a329b9347fa4a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 15:06:11 +0300 Subject: [PATCH 0493/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index f399d8f6e..1ea2416a9 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -173,7 +173,7 @@ void stats_priceupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t tim else if ( (pp= stats_priceinfo(source,datenum)) != 0 ) stats_datenumupdate(0,pp,datenum,hour,seconds,height,dstr(srcamount),dest,price); } else price = 0.; - printf("%d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",datenum,hour,seconds,height,key!=0?key:"",source,dstr(srcamount),dest,dstr(destamount),price,1./price); + printf("dir.%-2d %d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",dir,datenum,hour,seconds,height,key!=0?key:"",source,dstr(srcamount),dest,dstr(destamount),price,1./price); } } From 8d07874da47720f14a91d55348191e4c5ab28893 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 15:07:39 +0300 Subject: [PATCH 0494/2705] Test --- iguana/exchanges/DEXstats.h | 3 ++- iguana/exchanges/stats.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 1ea2416a9..97316cf41 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -151,7 +151,7 @@ void stats_LPpubkeyupdate(char *LPpubkey,uint32_t timestamp) void stats_priceupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t timestamp,int32_t height,char *key,char *LPpubkey,cJSON *tradejson) { - uint64_t srcamount,destamount; char *source,*dest; double price; struct DEXstats_priceinfo *pp; + int32_t dir = 0; uint64_t srcamount,destamount; char *source,*dest; double price; struct DEXstats_priceinfo *pp; if ( LPpubkey != 0 ) stats_LPpubkeyupdate(LPpubkey,timestamp); if ( tradejson != 0 ) @@ -165,6 +165,7 @@ void stats_priceupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t tim price = (double)destamount / srcamount; if ( key != 0 ) { + dir = 1; if ( (pp= stats_priceinfo(source,datenum)) != 0 ) stats_datenumupdate(-1,pp,datenum,hour,seconds,height,dstr(srcamount),dest,price); if ( (pp= stats_priceinfo(dest,datenum)) != 0 ) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index f451e5ce9..66a067b81 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -832,9 +832,9 @@ void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *p //printf("(%s)\n",jprint(kvjson,0)); argjson = cJSON_CreateArray(); jaddistr(argjson,"KMD"); - jaddnum(argjson,1); + jaddinum(argjson,1); jaddistr(argjson,"BTC"); - jaddnum(argjson,dstr(pvals[32]) / 1000.); + jaddinum(argjson,dstr(pvals[32]) / 1000.); stats_priceupdate(datenum,seconds/3600,seconds % 3600,sp->SAVEDTIMESTAMP,sp->SAVEDHEIGHT,0,0,argjson); free_json(argjson); } From b3af4fff65b1a9b8d836d1be08457e19d1828016 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 15:09:54 +0300 Subject: [PATCH 0495/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- iguana/exchanges/stats.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 97316cf41..1c9dae455 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -832,7 +832,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t timestamp = OS_conv_datenum(pp->firstdatenum+j,0,0,0); if ( timestamp < lefttimestamp ) // can speed up by calculating offset 0 { - printf("skip (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); + //printf("skip (%s) datenums %d %d %d\n",symbol,datenum,pp->firstdatenum,pp->firstdatenum+pp->numdates); continue; } stats_dispprices(prices,leftdatenum,numdates,&pp->dates[j],dest,timestamp % (3600*24)); diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 66a067b81..a26ce4c22 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -834,7 +834,7 @@ void stats_pricefeed(struct komodo_state *sp,char *symbol,int32_t ht,uint32_t *p jaddistr(argjson,"KMD"); jaddinum(argjson,1); jaddistr(argjson,"BTC"); - jaddinum(argjson,dstr(pvals[32]) / 1000.); + jaddinum(argjson,dstr(pvals[32]) / 10000.); stats_priceupdate(datenum,seconds/3600,seconds % 3600,sp->SAVEDTIMESTAMP,sp->SAVEDHEIGHT,0,0,argjson); free_json(argjson); } From dde768f16439860a309b9d32b8edb7fecfc07915 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 15:22:25 +0300 Subject: [PATCH 0496/2705] Test --- iguana/exchanges/DEXstats.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 1c9dae455..6962d2f6c 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -817,7 +817,7 @@ void gen_jpegfile(char *fname,int32_t quality,uint8_t *bitmap,int32_t width,int3 char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) { - int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals; char fname[1024]; struct tai T; cJSON *retjson,*array,*item; + int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals,total; char fname[1024]; struct tai T; cJSON *retjson,*array,*item; timestamp = (uint32_t)time(NULL); if ( Num_priceinfos >= sizeof(Prices)/sizeof(*Prices) ) return(0); @@ -842,10 +842,11 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t tmp = OS_conv_datenum(leftdatenum,0,0,0); utc32 = calloc(sizeof(*utc32),numdates); splinevals = calloc(sizeof(*splinevals),numdates); - for (i=n=0; i 3 ) From 8708231cbeed979600c8bc45b127dce9924faa7c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:02:41 +0300 Subject: [PATCH 0497/2705] Test --- iguana/exchanges/DEXstats.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 6962d2f6c..d32beea7a 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -256,7 +256,7 @@ void smooth1024(double dest[],double src[],int32_t smoothiters) float _calc_pricey(register double price,register double weekave) { if ( price != 0. && weekave != 0. ) - return(.2 * calc_loganswer(weekave,price)); + return(calc_loganswer(weekave,price)); else return(0.f); } @@ -506,7 +506,7 @@ double _output_line(int32_t calclogflag,double ave,double *output,double *buf,in if ( ave != 1. ) yval = _calc_pricey(val,ave); else yval = val; - //printf("%f ",yval); + printf("(%f -> %f) ",val,yval); if ( fabs(yval) > .0000000001 ) { aveabs += fabs(yval); @@ -886,7 +886,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); - output_line(0,sum,output,i,0xff00ff,bitmap,numdates*24,height); + output_line(1,sum,output,i,0xff00ff,bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:03:43 +0300 Subject: [PATCH 0498/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index d32beea7a..35ad7b36b 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -256,7 +256,7 @@ void smooth1024(double dest[],double src[],int32_t smoothiters) float _calc_pricey(register double price,register double weekave) { if ( price != 0. && weekave != 0. ) - return(calc_loganswer(weekave,price)); + return(0.2 * calc_loganswer(weekave,price)); else return(0.f); } From a3b8db5bd72bab76bb95389cd8d7e3176476c466 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:04:45 +0300 Subject: [PATCH 0499/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 35ad7b36b..669bdc5ea 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -256,7 +256,7 @@ void smooth1024(double dest[],double src[],int32_t smoothiters) float _calc_pricey(register double price,register double weekave) { if ( price != 0. && weekave != 0. ) - return(0.2 * calc_loganswer(weekave,price)); + return(0.1 * calc_loganswer(weekave,price)); else return(0.f); } From 2ce5720c8473ed2a9d3e2963ebd61a8b05f8dd1f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:07:37 +0300 Subject: [PATCH 0500/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 669bdc5ea..fc9a7d0de 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -886,7 +886,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); - output_line(1,sum,output,i,0xff00ff,bitmap,numdates*24,height); + output_line(0,sum,output,i,0xff00ff,bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:10:01 +0300 Subject: [PATCH 0501/2705] Test --- iguana/exchanges/DEXstats.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index fc9a7d0de..3219f6d8c 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -499,13 +499,15 @@ double _output_line(int32_t calclogflag,double ave,double *output,double *buf,in ave = log(ave); for (x=0; x %f) ",val,yval); if ( fabs(yval) > .0000000001 ) { From 2286ee93075de575c654005d5ed52cd2af0709b4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:12:54 +0300 Subject: [PATCH 0502/2705] Test --- iguana/exchanges/DEXstats.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 3219f6d8c..5f42ecc67 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -501,13 +501,13 @@ double _output_line(int32_t calclogflag,double ave,double *output,double *buf,in { if ( (val= buf[x]) != 0. ) { - if ( calclogflag != 0 ) + //if ( calclogflag != 0 ) { val = log(buf[x]); if ( ave != 1. ) yval = _calc_pricey(val,ave); else yval = val; - } else yval = (val / ave) * height / 3; + } //else yval = (val / ave) * height / 3; printf("(%f -> %f) ",val,yval); if ( fabs(yval) > .0000000001 ) { @@ -888,7 +888,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); - output_line(0,sum,output,i,0xff00ff,bitmap,numdates*24,height); + output_line(1,sum,output,i,0xff00ff,bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:14:53 +0300 Subject: [PATCH 0503/2705] Test --- iguana/exchanges/DEXstats.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 5f42ecc67..42205c342 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -26,7 +26,7 @@ struct stats_spline { char name[64]; int32_t splineid,lasti,basenum,num,firstx,d #define _extrapolate_spline32(spline32,gap) ((double)i32tod((spline32)[0]) + ((gap) * ((double)i32tod(.001*.001*(spline32)[1]) + ((gap) * ((double)i32tod(.001*.001*.001*.001*(spline32)[2]) + ((gap) * (double)i32tod(.001*.001*.001*.001*.001*.001*(spline32)[3]))))))) uint32_t forex_colors[16]; -double Display_scale = 1.; +double Display_scale = 0.1; struct DEXstats_disp { double pricesum,volumesum; }; @@ -413,9 +413,10 @@ void disp_yval(register int32_t color,register float yval,register uint32_t *bit return; //y = conv_yval_to_y(yval,height/Display_scale) * Display_scale; y = conv_yval_to_y(yval * Display_scale,height); - if ( 1 && is_primary_color(color) != 0 ) + //if ( 1 && is_primary_color(color) != 0 ) { bitmap[y*rowwidth + x] = color; + printf("(%d, %d) <- %x, ",x,y,color); return; } //if ( pixelwt(color) > pixelwt(bitmap[y*rowwidth + x]) ) From 2a3799242b07d3c977b34355e7e6d3a1cf2642ba Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:16:46 +0300 Subject: [PATCH 0504/2705] Test --- iguana/exchanges/DEXstats.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 42205c342..cc0c7b12f 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -26,7 +26,7 @@ struct stats_spline { char name[64]; int32_t splineid,lasti,basenum,num,firstx,d #define _extrapolate_spline32(spline32,gap) ((double)i32tod((spline32)[0]) + ((gap) * ((double)i32tod(.001*.001*(spline32)[1]) + ((gap) * ((double)i32tod(.001*.001*.001*.001*(spline32)[2]) + ((gap) * (double)i32tod(.001*.001*.001*.001*.001*.001*(spline32)[3]))))))) uint32_t forex_colors[16]; -double Display_scale = 0.1; +double Display_scale = 0.25; struct DEXstats_disp { double pricesum,volumesum; }; @@ -413,7 +413,7 @@ void disp_yval(register int32_t color,register float yval,register uint32_t *bit return; //y = conv_yval_to_y(yval,height/Display_scale) * Display_scale; y = conv_yval_to_y(yval * Display_scale,height); - //if ( 1 && is_primary_color(color) != 0 ) + if ( 1 && is_primary_color(color) != 0 ) { bitmap[y*rowwidth + x] = color; printf("(%d, %d) <- %x, ",x,y,color); @@ -902,7 +902,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t *tmpptr++ = blue; } sprintf(fname,"%s/bitmaps/%s_%s.jpg",STATS_DESTDIR,symbol,dest), OS_portable_path(fname); - gen_jpegfile(fname,1,bytemap,numdates*24,height); + gen_jpegfile(fname,100,bytemap,numdates*24,height); free(bitmap), free(bytemap); jaddstr(retjson,"bitmap",fname); jadd(retjson,"hourly",array); From 8e35615d2b4379bc6809173bbaa0401fee421b3c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:17:40 +0300 Subject: [PATCH 0505/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index cc0c7b12f..0cc2d133e 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -889,7 +889,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); - output_line(1,sum,output,i,0xff00ff,bitmap,numdates*24,height); + output_line(1,sum,output,i,0xffff00,bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:18:22 +0300 Subject: [PATCH 0506/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 0cc2d133e..2e5b1dcbc 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -889,7 +889,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); - output_line(1,sum,output,i,0xffff00,bitmap,numdates*24,height); + output_line(1,sum,output,i,0x00ffff,bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:19:42 +0300 Subject: [PATCH 0507/2705] Test --- iguana/exchanges/DEXstats.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 2e5b1dcbc..91b9a91ec 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -416,7 +416,7 @@ void disp_yval(register int32_t color,register float yval,register uint32_t *bit if ( 1 && is_primary_color(color) != 0 ) { bitmap[y*rowwidth + x] = color; - printf("(%d, %d) <- %x, ",x,y,color); + //printf("(%d, %d) <- %x, ",x,y,color); return; } //if ( pixelwt(color) > pixelwt(bitmap[y*rowwidth + x]) ) @@ -509,7 +509,7 @@ double _output_line(int32_t calclogflag,double ave,double *output,double *buf,in yval = _calc_pricey(val,ave); else yval = val; } //else yval = (val / ave) * height / 3; - printf("(%f -> %f) ",val,yval); + //printf("(%f -> %f) ",val,yval); if ( fabs(yval) > .0000000001 ) { aveabs += fabs(yval); @@ -889,7 +889,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); - output_line(1,sum,output,i,0x00ffff,bitmap,numdates*24,height); + output_line(1,sum,output,i,0xffffff,bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:20:08 +0300 Subject: [PATCH 0508/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 91b9a91ec..155cb4311 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -889,7 +889,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); - output_line(1,sum,output,i,0xffffff,bitmap,numdates*24,height); + output_line(1,sum,output,i,forex_colors[0],bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:21:05 +0300 Subject: [PATCH 0509/2705] Test --- iguana/exchanges/DEXstats.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 155cb4311..238549c90 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -889,6 +889,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); + init_forex_colors(forex_colors); output_line(1,sum,output,i,forex_colors[0],bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:21:53 +0300 Subject: [PATCH 0510/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 238549c90..7b38f953d 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -890,7 +890,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); init_forex_colors(forex_colors); - output_line(1,sum,output,i,forex_colors[0],bitmap,numdates*24,height); + output_line(1,sum,output,i,0x00ff00,bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:24:05 +0300 Subject: [PATCH 0511/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 7b38f953d..ae93a7c70 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -889,7 +889,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t sum /= i; uint32_t val,height = 400,*bitmap = calloc(sizeof(*bitmap),height * numdates*24); uint8_t red,green,blue,*tmpptr,*bytemap = calloc(sizeof(*bytemap),3 * height * numdates*24); - init_forex_colors(forex_colors); + horizline(1,numdates*24,height,bitmap,sum,sum); output_line(1,sum,output,i,0x00ff00,bitmap,numdates*24,height); tmpptr = bytemap; for (j=0; j Date: Mon, 8 May 2017 20:28:00 +0300 Subject: [PATCH 0512/2705] Test --- iguana/exchanges/stats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index a26ce4c22..9b5914b2c 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -1040,10 +1040,10 @@ int main(int argc, const char * argv[]) if ( (filestr= stats_update(logfp,STATS_DEST,statefname,komodofile)) != 0 ) { timestamp = (uint32_t)time(NULL); - leftdatenum = OS_conv_unixtime(&T,&seconds,timestamp - 1024*3600); + leftdatenum = OS_conv_unixtime(&T,&seconds,timestamp - 30*24*3600); //printf("%u: leftdatenum.%d %s\n",timestamp,leftdatenum,filestr); memset(prices,0,sizeof(prices)); - if ( (retstr= stats_prices("KMD","BTC",prices,leftdatenum,1024/24+1)) != 0 ) + if ( (retstr= stats_prices("KMD","BTC",prices,leftdatenum,30+1)) != 0 ) { //printf("%s\n",retstr); free(retstr); From d6cb3bc8c11805f5745f8e53892ce92c78601a85 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:29:17 +0300 Subject: [PATCH 0513/2705] Test --- iguana/tests/statstest | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/tests/statstest b/iguana/tests/statstest index 9d95e23cc..70e63b43a 100755 --- a/iguana/tests/statstest +++ b/iguana/tests/statstest @@ -1,2 +1,3 @@ #!/bin/bash curl --url "http://127.0.0.1:7779" --data "{\"method\":\"bitmap\",\"endtimestamp\":0,\"source\":\"KMD\",\"dest\":\"BTC\",\"numdates\":30}" +curl --url "http://78.46.193.199:7779" --data "{\"method\":\"bitmap\",\"endtimestamp\":0,\"source\":\"KMD\",\"dest\":\"BTC\",\"numdates\":30}" From 34bc5f89a46b362119bf8079dcf942f716974923 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:30:54 +0300 Subject: [PATCH 0514/2705] Test --- iguana/exchanges/DEXstats.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index ae93a7c70..38c2d1fa3 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -174,7 +174,8 @@ void stats_priceupdate(int32_t datenum,int32_t hour,int32_t seconds,uint32_t tim else if ( (pp= stats_priceinfo(source,datenum)) != 0 ) stats_datenumupdate(0,pp,datenum,hour,seconds,height,dstr(srcamount),dest,price); } else price = 0.; - printf("dir.%-2d %d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",dir,datenum,hour,seconds,height,key!=0?key:"",source,dstr(srcamount),dest,dstr(destamount),price,1./price); + if ( dir != 0 ) + printf("dir.%-2d %d.%02d.%04d ht.%-4d %s (%s %12.8f) -> (%s %12.8f) %16.8f %16.8f\n",dir,datenum,hour,seconds,height,key!=0?key:"",source,dstr(srcamount),dest,dstr(destamount),price,1./price); } } From ce6bfff1bbb9dbe430abc8f57c974a7b1e90cfa3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 8 May 2017 20:33:00 +0300 Subject: [PATCH 0515/2705] Test --- iguana/exchanges/stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 9b5914b2c..d69e369c1 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -559,7 +559,7 @@ void stats_rpcloop(void *args) port = 7779; if ( jsonbuf == 0 ) jsonbuf = calloc(1,IGUANA_MAXPACKETSIZE); - while ( (bindsock= iguana_socket(1,"127.0.0.1",port)) < 0 ) + while ( (bindsock= iguana_socket(1,"0.0.0.0",port)) < 0 ) { //if ( coin->MAXPEERS == 1 ) // break; From 03e8a5a185cdbefe99792060958b26336d873338 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 12 May 2017 08:21:23 +0300 Subject: [PATCH 0516/2705] LTCwif to encrypt wallet output --- iguana/iguana_wallet.c | 5 +++++ iguana/kmd_lookup.h | 3 +++ iguana/tests/statstest | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index adf28c5a8..e17538201 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -1431,6 +1431,11 @@ THREE_STRINGS(bitcoinrpc,encryptwallet,passphrase,password,permanentfile) bitcoin_priv2wif(wifstr,waddr.privkey,coin->chain->wiftype); jaddstr(retjson,"KMDwif",wifstr); } + if ( (coin= iguana_coinfind("LTC")) != 0 ) + { + bitcoin_priv2wif(wifstr,waddr.privkey,coin->chain->wiftype); + jaddstr(retjson,"LTCwif",wifstr); + } if ( need_BTC != 0 ) { bitcoin_priv2wif(wifstr,waddr.privkey,128); diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index a09c83ee2..b54fd4415 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -704,6 +704,7 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) { ptr->fpos = ftell(coin->kmd_txidfp); fwrite(tx,1,sizeof(*tx) + tx->numvouts*sizeof(*tx->vouts),coin->kmd_txidfp); + fflush(coin->kmd_txidfp); } } else @@ -712,6 +713,7 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) { fwrite(&txid,1,sizeof(txid),coin->kmd_spendfp); fwrite(&numvins,1,sizeof(numvins),coin->kmd_spendfp); + fflush(coin->kmd_spendfp); } for (j=0; jkmd_spendfp); fwrite(&spentvout,1,sizeof(spentvout),coin->kmd_spendfp); + fflush(coin->kmd_spendfp); } } } diff --git a/iguana/tests/statstest b/iguana/tests/statstest index 70e63b43a..a91ae778e 100755 --- a/iguana/tests/statstest +++ b/iguana/tests/statstest @@ -1,3 +1,3 @@ #!/bin/bash -curl --url "http://127.0.0.1:7779" --data "{\"method\":\"bitmap\",\"endtimestamp\":0,\"source\":\"KMD\",\"dest\":\"BTC\",\"numdates\":30}" +#curl --url "http://127.0.0.1:7779" --data "{\"method\":\"bitmap\",\"endtimestamp\":0,\"source\":\"KMD\",\"dest\":\"BTC\",\"numdates\":30}" curl --url "http://78.46.193.199:7779" --data "{\"method\":\"bitmap\",\"endtimestamp\":0,\"source\":\"KMD\",\"dest\":\"BTC\",\"numdates\":30}" From 6489a56a101b2a63c4ee30b92bf6ae8d5c98d0fe Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 14 May 2017 18:48:33 +0300 Subject: [PATCH 0517/2705] Test --- .gitignore | 2 ++ iguana/m_notary | 2 +- iguana/tests/dexgetbalance | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d61e17ebd..27b6205c6 100755 --- a/.gitignore +++ b/.gitignore @@ -429,3 +429,5 @@ iguana/DEXstats iguana/DEXstats.dSYM/Contents/Info.plist iguana/DEXstats.dSYM/Contents/Resources/DWARF/DEXstats + +iguana/confs/dc54d862abd6809d9fd200759538014248f18a5a69e7bc22c0a1f2111a896157 diff --git a/iguana/m_notary b/iguana/m_notary index 76d5c06a6..4bba148a4 100755 --- a/iguana/m_notary +++ b/iguana/m_notary @@ -1,5 +1,5 @@ #!/bin/bash -pkill iguana +pkill -15 iguana rm -f ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. diff --git a/iguana/tests/dexgetbalance b/iguana/tests/dexgetbalance index fc53edd53..77d8982af 100755 --- a/iguana/tests/dexgetbalance +++ b/iguana/tests/dexgetbalance @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getbalance\",\"address\":\"RWE3NWHT6Fb1zW4mY9LU859MPoWGYvtLfj\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getbalance\",\"address\":\"RHrAStvASzi5pJB6xqgmsVGD5AxxpAFzZ6\",\"symbol\":\"KMD\"}" From b42f760ecbba981ad1bf343f68f3ad12c08719ac Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 15 May 2017 16:44:20 +0300 Subject: [PATCH 0518/2705] Smartaddress fixes --- .gitignore | 20 +++++++++++ basilisk/basilisk_tradebot.c | 4 +-- basilisk/smartaddress.c | 68 ++++++++++++++++++++++++++++-------- iguana/iguana777.h | 2 +- 4 files changed, 76 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 27b6205c6..d11ca0576 100755 --- a/.gitignore +++ b/.gitignore @@ -431,3 +431,23 @@ iguana/DEXstats.dSYM/Contents/Info.plist iguana/DEXstats.dSYM/Contents/Resources/DWARF/DEXstats iguana/confs/dc54d862abd6809d9fd200759538014248f18a5a69e7bc22c0a1f2111a896157 + +iguana/confs/589983f94d17d8e0dc6fbf3fce34b20efc81183c0ab0158cf81a60f03711e15c + +iguana/confs/67201409eb7644e398c8090ac6e3ccf4b69d186b8478aa8488211e9b474dd245 + +iguana/confs/982dfa0e535a6e856cca3cd919af03f50050408fcfed1cd71bb4aa1e2e69070f + +iguana/confs/aa45c35599c9c75a9788fa9740ce8713cc457919e6f6f7d8d8115da5193f5722 + +iguana/confs/ab828d4425655df6bf409f0e23be49ae4a19b2c974008385b18a7a9c79b0314c + +iguana/confs/b29fa937dd00ed7dd73ff4eef8b49bd3103ebddaee9fae05f44ffed42c5a4611 + +iguana/confs/LTC_hdrs.txt + +iguana/confs/LTC_oldhdrs.txt + +iguana/DB/LTC_peers.dat + +iguana/debug.log diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index 481640038..e98a64509 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -329,7 +329,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk printf("set destvolume %.8f\n",destvolume); } // else printf("destvolume %.8f <- minamount\n",destvolume); } - printf("%s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %.8f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); + printf("<<<<<<< %s -> %s myrequest.%d pendingid.%u noquoteflag.%d havequoteflag.%d maxi.%d %.8f destvol %.8f\n",list[0].src,list[0].dest,myrequest,pendingid,noquoteflag,havequoteflag,maxi,dstr(maxamount),destvolume); if ( myinfo->IAMLP != 0 && myrequest == 0 && pendingid == 0 && noquoteflag != 0 && ((profitmargin= tradebot_liquidity_active(myinfo,&refprice,"DEX",list[0].src,list[0].dest,destvolume)) > 0. || refprice != 0.) ) { if ( profitmargin == 0. || (aveprice= instantdex_avehbla(myinfo,retvals,list[0].src,list[0].dest,.1 * dstr(list[0].srcamount))) == 0. || refprice > aveprice ) @@ -370,7 +370,7 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk } else if ( myrequest != 0 && pendingid == 0 && maxi >= 0 ) // automatch best quote { - if ( minamount != 0 && maxamount >= minamount && time(NULL) > list[0].timestamp+BASILISK_AUCTION_DURATION ) + if ( minamount != 0 && maxamount >= minamount )//&& time(NULL) > list[0].timestamp+BASILISK_AUCTION_DURATION ) { *issueR = list[maxi]; for (i=0; ictx,pubkey33,privkey); bitcoin_address(coinaddr,pubtype,pubkey33,33); bitcoin_address(KMDaddr,60,pubkey33,33); - //printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); + printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); return(privkey); } @@ -62,7 +62,7 @@ cJSON *smartaddress_extrajson(struct smartaddress *ap) cJSON *smartaddress_json(struct smartaddress *ap) { - char coinaddr[64],symbol[64]; uint8_t desttype,tmp,rmd160[20]; int32_t j,n; struct iguana_info *coin,*dest; cJSON *array,*item,*retjson; + char coinaddr[64],symbol[64]; uint8_t desttype,tmp,rmd160[20]; int32_t j,n; struct iguana_info *coin,*dest; cJSON *array,*item,*retjson; double amount; retjson = cJSON_CreateObject(); jaddstr(retjson,"type",ap->typestr); strcpy(symbol,ap->typestr), touppercase(symbol); @@ -80,11 +80,15 @@ cJSON *smartaddress_json(struct smartaddress *ap) item = cJSON_CreateObject(); jaddstr(item,"coin",coin->symbol); jaddstr(item,"address",coinaddr); + if ( (amount= ap->symbols[j].srcavail) != 0 ) + jaddnum(item,"sourceamount",amount); if ( dest != 0 ) { bitcoin_addr2rmd160(&tmp,rmd160,coinaddr); bitcoin_address(coinaddr,desttype,rmd160,20); jaddstr(item,"dest",coinaddr); + if ( (amount= ap->symbols[j].destamount) != 0 ) + jaddnum(item,"destamount",amount); if ( coin->DEXinfo.depositaddr[0] != 0 ) { jaddstr(item,"jumblr_deposit",coin->DEXinfo.depositaddr); @@ -125,9 +129,11 @@ void smartaddress_symboladd(struct smartaddress *ap,char *symbol,double maxbid,d } } -void smartaddress_minmaxupdate(struct supernet_info *myinfo,char *_type,char *_symbol,double maxbid,double minask) +struct smartaddress *smartaddressptr(struct smartaddress_symbol **ptrp,struct supernet_info *myinfo,char *_type,char *_symbol) { char type[64],symbol[64]; int32_t i,j,n; struct smartaddress *ap; + if ( ptrp != 0 ) + *ptrp = 0; strcpy(type,_type), tolowercase(type); strcpy(symbol,_symbol), touppercase(symbol); for (i=0; inumsmartaddrs; i++) @@ -140,12 +146,36 @@ void smartaddress_minmaxupdate(struct supernet_info *myinfo,char *_type,char *_s { if ( strcmp(ap->symbols[j].symbol,symbol) == 0 ) { - dxblend(&ap->symbols[j].maxbid,maxbid,0.5); - dxblend(&ap->symbols[j].minask,minask,0.5); + if ( ptrp != 0 ) + *ptrp = &ap->symbols[j]; + return(ap); } } } } + return(0); +} + +void smartaddress_minmaxupdate(struct supernet_info *myinfo,char *_type,char *_symbol,double maxbid,double minask) +{ + struct smartaddress *ap; struct smartaddress_symbol *sp; + if ( (ap= smartaddressptr(&sp,myinfo,_type,_symbol)) != 0 && sp != 0 ) + { + dxblend(&sp->maxbid,maxbid,0.5); + dxblend(&sp->minask,minask,0.5); + } +} + +void smartaddress_availupdate(struct supernet_info *myinfo,char *_type,char *_symbol,double srcavail,double destamount) +{ + struct smartaddress *ap; struct smartaddress_symbol *sp; + if ( (ap= smartaddressptr(&sp,myinfo,_type,_symbol)) != 0 && sp != 0 ) + { + if ( srcavail > SMALLVAL ) + sp->srcavail = srcavail; + if ( destamount > SMALLVAL ) + sp->destamount = destamount; + } } int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *type,char *symbol,double maxbid,double minask) @@ -184,6 +214,7 @@ int32_t _smartaddress_add(struct supernet_info *myinfo,bits256 privkey,char *typ bitcoin_pubkey33(myinfo->ctx,ap->pubkey33,privkey); calc_rmd160_sha256(ap->rmd160,ap->pubkey33,33); ap->pubkey = curve25519(privkey,curve25519_basepoint9()); + char str[65]; printf("pubkey.(%s) ",bits256_str(str,ap->pubkey)); bitcoin_address(coinaddr,0,ap->pubkey33,33); for (i=0; i<20; i++) printf("%02x",ap->rmd160[i]); @@ -267,6 +298,8 @@ int32_t smartaddress_pubkey(struct supernet_info *myinfo,char *typestr,double *b break; } portable_mutex_unlock(&myinfo->smart_mutex); + char str[65]; if ( retval < 0 ) + printf("smartaddress_pubkey no match for %s\n",bits256_str(str,pubkey)); return(retval); } @@ -346,9 +379,9 @@ void smartaddress_coinupdate(struct supernet_info *myinfo,char *symbol,double BT } // else printf("skip\n"); } -void smartaddress_dex(struct supernet_info *myinfo,int32_t selector,struct iguana_info *basecoin,char *coinaddr,double maxavail,struct iguana_info *relcoin,double maxbid,double minask,cJSON *extraobj,double maxvol) +void smartaddress_dex(struct supernet_info *myinfo,char *type,int32_t selector,struct iguana_info *basecoin,char *coinaddr,double maxavail,struct iguana_info *relcoin,double maxbid,double minask,cJSON *extraobj,double maxvol) { - double minamount,minbtc,price,avail,vol,btc2kmd,basebtc,relbtc,baseusd,relusd; char *retstr; cJSON *vals; bits256 hash; + double minamount,minbtc,price,avail,vol,btc2kmd,basebtc,relbtc,baseusd,relusd; char *retstr; cJSON *vals; bits256 hash; struct smartaddress *ap; basebtc = basecoin->DEXinfo.btcprice; relbtc = relcoin->DEXinfo.btcprice; baseusd = basecoin->DEXinfo.USD_average; @@ -373,10 +406,10 @@ void smartaddress_dex(struct supernet_info *myinfo,int32_t selector,struct iguan minbtc = btc2kmd * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); if ( minamount == 0. && basebtc > SMALLVAL ) minamount = (minbtc / basebtc); - printf("%s/%s minbtc %.8f btcprice %.8f -> minamount %.8f price %.8f vs maxbid %.8f DEXratio %.5f\n",basecoin->symbol,relcoin->symbol,minbtc,basecoin->DEXinfo.btcprice,minamount,price,maxbid,myinfo->DEXratio); + printf("DEX %s/%s maxavail %.8f minbtc %.8f btcprice %.8f -> minamount %.8f price %.8f vs maxbid %.8f DEXratio %.5f DEXpending %.8f\n",basecoin->symbol,relcoin->symbol,maxavail,minbtc,basecoin->DEXinfo.btcprice,minamount,price,maxbid,myinfo->DEXratio,basecoin->DEXinfo.DEXpending); if ( minamount > SMALLVAL && maxavail > minamount + basecoin->DEXinfo.DEXpending && (maxbid == 0. || price <= maxbid) ) { - avail = (maxavail - (minamount + basecoin->DEXinfo.DEXpending)); + avail = (maxavail - basecoin->DEXinfo.DEXpending); /*if ( avail >= (100. * minamount) ) vol = (100. * minamount); else if ( avail >= (10. * minamount) ) @@ -391,6 +424,8 @@ void smartaddress_dex(struct supernet_info *myinfo,int32_t selector,struct iguan jaddstr(vals,"dest",relcoin->symbol); jaddnum(vals,"amount",vol); jaddnum(vals,"minprice",price); + if ( (ap= smartaddressptr(0,myinfo,type,basecoin->symbol)) != 0 ) + jaddbits256(vals,"srchash",ap->pubkey); if ( selector != 0 ) { jaddnum(vals,"usejumblr",selector); @@ -404,8 +439,8 @@ void smartaddress_dex(struct supernet_info *myinfo,int32_t selector,struct iguan free(retstr); } free_json(vals); - } - } + } else printf("avail %.8f < minamount %.8f\n",avail,minamount); + } //else printf("failed if check %d %d %d %d\n",minamount > SMALLVAL,maxavail > minamount + basecoin->DEXinfo.DEXpending,maxbid == 0,price <= maxbid); /* minbtc = (basecoin->DEXinfo.btcprice * 1.2) * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE)); btcavail = dstr(jumblr_balance(myinfo,coinbtc,kmdcoin->DEXinfo.depositaddr)); @@ -473,7 +508,7 @@ void smartaddress_depositjumblr(struct supernet_info *myinfo,char *symbol,char * if ( (basecoin= iguana_coinfind(symbol)) != 0 && (relcoin= iguana_coinfind("KMD")) != 0 ) { if ( strcmp(coinaddr,basecoin->DEXinfo.depositaddr) == 0 ) - smartaddress_dex(myinfo,1,basecoin,coinaddr,basecoin->DEXinfo.avail,relcoin,maxbid,minask,extraobj,0.); + smartaddress_dex(myinfo,"deposit",1,basecoin,coinaddr,basecoin->DEXinfo.avail,relcoin,maxbid,minask,extraobj,0.); else printf("smartaddress_jumblr.%s: mismatch deposit address (%s) vs (%s)\n",symbol,coinaddr,basecoin->DEXinfo.depositaddr); } } @@ -494,7 +529,7 @@ void smartaddress_jumblr(struct supernet_info *myinfo,char *symbol,char *coinadd if ( (basecoin= iguana_coinfind("KMD")) != 0 && (relcoin= iguana_coinfind(symbol)) != 0 ) { if ( strcmp(coinaddr,basecoin->DEXinfo.jumblraddr) == 0 ) - smartaddress_dex(myinfo,2,basecoin,coinaddr,basecoin->DEXinfo.jumblravail,relcoin,maxbid,minask,extraobj,credits); + smartaddress_dex(myinfo,"jumblr",2,basecoin,coinaddr,basecoin->DEXinfo.jumblravail,relcoin,maxbid,minask,extraobj,credits); else printf("smartaddress_jumblr.%s: mismatch jumblr address (%s) vs (%s)\n",symbol,coinaddr,basecoin->DEXinfo.jumblraddr); } } @@ -526,10 +561,13 @@ void smartaddress_action(struct supernet_info *myinfo,int32_t selector,char *typ touppercase(rel); if ( (relcoin= iguana_coinfind(rel)) != 0 && (basecoin= iguana_coinfind(symbol)) != 0 ) { - if ( myinfo->numswaps == 0 || (basecoin->FULLNODE < 0 && relcoin->FULLNODE < 0) ) + if ( myinfo->numswaps == 0 )//|| (basecoin->FULLNODE < 0 && relcoin->FULLNODE < 0) ) { if ( (avail= dstr(jumblr_balance(myinfo,basecoin,coinaddr))) > SMALLVAL ) - smartaddress_dex(myinfo,0,basecoin,coinaddr,avail,relcoin,maxbid,minask,extraobj,0.); + { + smartaddress_availupdate(myinfo,typestr,symbol,avail,SMALLVAL*0.99); + smartaddress_dex(myinfo,typestr,0,basecoin,coinaddr,avail,relcoin,maxbid,minask,extraobj,0.); + } } } } diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 2e1cc17a9..b02a38a68 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -95,7 +95,7 @@ struct supernet_address char NXTADDR[32],BTC[64],BTCD[64]; }; -struct smartaddress_symbol { double maxbid,minask; char symbol[16]; }; +struct smartaddress_symbol { double maxbid,minask,srcavail,destamount; char symbol[16]; }; struct smartaddress { From 486805f6a39fb646f7f4fdea110497d7ad7f6ae3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 15 May 2017 17:31:14 +0300 Subject: [PATCH 0519/2705] Test --- basilisk/smartaddress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index eccc1f260..a89bf248d 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -46,7 +46,7 @@ bits256 jumblr_privkey(struct supernet_info *myinfo,char *coinaddr,uint8_t pubty bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); bitcoin_address(coinaddr,pubtype,pubkey33,33); bitcoin_address(KMDaddr,60,pubkey33,33); - printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); + //printf("(%s) -> (%s %s)\n",passphrase,coinaddr,KMDaddr); return(privkey); } From 047534b642fc1b66bc2c1ed55f66edbdd4bf734c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 16 May 2017 15:33:44 +0300 Subject: [PATCH 0520/2705] LTC wife --- .gitignore | 4 ++++ iguana/exchanges/bitcoin.c | 7 ++++--- iguana/main.c | 8 ++++---- includes/iguana_apideclares.h | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index d11ca0576..fcdb55638 100755 --- a/.gitignore +++ b/.gitignore @@ -451,3 +451,7 @@ iguana/confs/LTC_oldhdrs.txt iguana/DB/LTC_peers.dat iguana/debug.log + +iguana/DB/LTC/.tmpmarker + +iguana/DB/purgeable/LTC/.tmpmarker diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index a40524d11..b23d59864 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -137,10 +137,11 @@ int32_t bitcoin_wif2priv(uint8_t *addrtypep,bits256 *privkeyp,char *wifstr) int32_t bitcoin_priv2wif(char *wifstr,bits256 privkey,uint8_t addrtype) { - uint8_t data[128]; int32_t len; + uint8_t data[128]; int32_t len = 32; memcpy(data+1,privkey.bytes,sizeof(privkey)); - data[33] = 1; - len = base58encode_checkbuf(addrtype,data,33); + if ( addrtype != 176 ) // not LTC + data[1 + len++] = 1; + len = base58encode_checkbuf(addrtype,data,len); if ( bitcoin_base58encode(wifstr,data,len) == 0 ) return(-1); diff --git a/iguana/main.c b/iguana/main.c index 90c3b61b2..9a224d3d2 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -1816,14 +1816,14 @@ STRING_ARG(SuperNET,wif2priv,wif) return(jprint(retjson,1)); } -STRING_ARG(SuperNET,priv2wif,priv) +STRING_AND_INT(SuperNET,priv2wif,priv,wiftype) { - bits256 privkey; char wifstr[65]; uint8_t wiftype; cJSON *retjson = cJSON_CreateObject(); + bits256 privkey; char wifstr[65]; cJSON *retjson = cJSON_CreateObject(); if ( is_hexstr(priv,0) == sizeof(bits256)*2 ) { - wiftype = coin != 0 ? coin->chain->wiftype : 0x80; + //wiftype = coin != 0 ? coin->chain->wiftype : 0x80; decode_hex(privkey.bytes,sizeof(privkey),priv); - if ( bitcoin_priv2wif(wifstr,privkey,wiftype) > 0 ) + if ( bitcoin_priv2wif(wifstr,privkey,wiftype&0xff) > 0 ) { jaddstr(retjson,"result","success"); jaddstr(retjson,"privkey",priv); diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 9ec461b91..48d39e417 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -304,7 +304,7 @@ THREE_STRINGS(SuperNET,rosetta,passphrase,pin,showprivkey); ZERO_ARGS(SuperNET,keypair); HASH_AND_INT(SuperNET,priv2pub,privkey,addrtype); STRING_ARG(SuperNET,wif2priv,wif); -STRING_ARG(SuperNET,priv2wif,priv); +STRING_AND_INT(SuperNET,priv2wif,priv,wiftype); STRING_ARG(SuperNET,addr2rmd160,address); STRING_ARG(SuperNET,rmd160conv,rmd160); From f274a5e49c139b759f4f9f02d182eebdf6855b0b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 16 May 2017 15:45:26 +0300 Subject: [PATCH 0521/2705] ltc_7776 --- iguana/coins/genltc | 2 +- iguana/coins/ltc_7776 | 4 ++++ iguana/m_notary | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100755 iguana/coins/ltc_7776 diff --git a/iguana/coins/genltc b/iguana/coins/genltc index df691b5d6..7b41fd929 100755 --- a/iguana/coins/genltc +++ b/iguana/coins/genltc @@ -1,4 +1,4 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7776" --data "{\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" diff --git a/iguana/coins/ltc_7776 b/iguana/coins/ltc_7776 new file mode 100755 index 000000000..df691b5d6 --- /dev/null +++ b/iguana/coins/ltc_7776 @@ -0,0 +1,4 @@ +#!/bin/bash + +curl --url "http://127.0.0.1:7778" --data "{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" + diff --git a/iguana/m_notary b/iguana/m_notary index 4bba148a4..633fb4583 100755 --- a/iguana/m_notary +++ b/iguana/m_notary @@ -20,6 +20,7 @@ curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"SuperNET\",\"method\":\" sleep 3 tests/addnotarys_7776 coins/btc_7776 +coins/ltc_7776 coins/kmd_7776 ./wp_7776 From 09bd8a818f1c5f39e5fb0cc711c19e5894b6b7b4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 16 May 2017 18:24:39 +0300 Subject: [PATCH 0522/2705] Deprecate jumblr setpassphrase --- includes/iguana_apideclares.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 48d39e417..709e8c04e 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -196,7 +196,7 @@ STRING_AND_INT(iguana,bundlehashes,activecoin,height); STRING_AND_INT(iguana,PoSweights,activecoin,height); STRING_ARG(iguana,stakers,activecoin); -STRING_ARG(jumblr,setpassphrase,passphrase); +//STRING_ARG(jumblr,setpassphrase,passphrase); ZERO_ARGS(jumblr,status); ZERO_ARGS(jumblr,runsilent); ZERO_ARGS(jumblr,totransparent); From f8a41b8a994ed4c65d26ed5cb06395d8b58fa140 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 16 May 2017 19:13:35 +0300 Subject: [PATCH 0523/2705] Add LTC to notary chains --- iguana/iguana_notary.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index 1cc427321..c70a4c408 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -437,7 +437,7 @@ STRING_ARG(iguana,addnotary,ipaddr) char NOTARY_CURRENCIES[][16] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", - "REVS", "SUPERNET", "DEX", "PANGEA", "JUMBLR", "BET", "CRYPTO", "HODL", "SHARK", "BOTS", "MGW", "MVP", "WLC", "KV", "CEAL", "MESH" }; + "REVS", "SUPERNET", "DEX", "PANGEA", "JUMBLR", "BET", "CRYPTO", "HODL", "SHARK", "BOTS", "MGW", "MVP", "WLC", "KV", "CEAL", "MESH", "LTC" }; ZERO_ARGS(dpow,notarychains) { From 63eb80661bff2922f97da76bf63cbd502c3c193c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 17 May 2017 09:24:43 +0300 Subject: [PATCH 0524/2705] Test --- iguana/tests/dexkvsearch | 4 ++-- includes/iguana_apideclares.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/tests/dexkvsearch b/iguana/tests/dexkvsearch index 5c2b68524..9992625b6 100755 --- a/iguana/tests/dexkvsearch +++ b/iguana/tests/dexkvsearch @@ -1,4 +1,4 @@ #!/bin/bash #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"foo\",\"symbol\":\"KMD\"}" -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"test\",\"symbol\":\"KV\"}" -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"777\",\"symbol\":\"KV\"}" +#curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"test\",\"symbol\":\"KV\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"2aa52428-fd9df866\",\"symbol\":\"KV\"}" diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 709e8c04e..48d39e417 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -196,7 +196,7 @@ STRING_AND_INT(iguana,bundlehashes,activecoin,height); STRING_AND_INT(iguana,PoSweights,activecoin,height); STRING_ARG(iguana,stakers,activecoin); -//STRING_ARG(jumblr,setpassphrase,passphrase); +STRING_ARG(jumblr,setpassphrase,passphrase); ZERO_ARGS(jumblr,status); ZERO_ARGS(jumblr,runsilent); ZERO_ARGS(jumblr,totransparent); From 59f923b88bdf669f77c31effdc8498c140206298 Mon Sep 17 00:00:00 2001 From: fadedreamz Date: Thu, 18 May 2017 00:26:17 -0400 Subject: [PATCH 0525/2705] fix for x64 build for windows, added libcurl x64 library Signed-off-by: fadedreamz --- OSlibs/win/x64/libcurl.dll | Bin 0 -> 366080 bytes OSlibs/win/x64/libcurl.lib | Bin 0 -> 14074 bytes OSlibs/win/x64/release/libcurl.dll | Bin 0 -> 366080 bytes OSlibs/win/x64/release/libcurl.exp | Bin 0 -> 8220 bytes OSlibs/win/x64/release/libcurl.lib | Bin 0 -> 14074 bytes iguana.vcxproj | 6 ++++-- 6 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 OSlibs/win/x64/libcurl.dll create mode 100644 OSlibs/win/x64/libcurl.lib create mode 100644 OSlibs/win/x64/release/libcurl.dll create mode 100644 OSlibs/win/x64/release/libcurl.exp create mode 100644 OSlibs/win/x64/release/libcurl.lib diff --git a/OSlibs/win/x64/libcurl.dll b/OSlibs/win/x64/libcurl.dll new file mode 100644 index 0000000000000000000000000000000000000000..c77ec1f0f175a2d2270cc100a66e00ab4c44dfdf GIT binary patch literal 366080 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 z%0A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 z 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 literal 0 HcmV?d00001 diff --git a/OSlibs/win/x64/libcurl.lib b/OSlibs/win/x64/libcurl.lib new file mode 100644 index 0000000000000000000000000000000000000000..92f23798cf7225b7ad93f89d53dd946d08d29617 GIT binary patch literal 14074 zcmc&)&2L;q60bNR2~IX^@?r92d+hl8b8OEzcF3~M!b%Ak6B%>Z3&X_o9FKOscE&Rc zht*0PIG~&mLYz3U5@!x5i#Q;Z>q>h;;$WSND6>@AYfm^BC<&<=0hR z-M`mg)m8O8e6!fx*?YcsA!Gg)b8GqR_0`4I6;qy7>~eM~N5waL0pM={7pDO(Zv$L; z4`Adm(Y4P2B;Cd*(#nXU2lzx9{efuUYXCtb9Yx3SiIjgxGJMCr#3Wd$rH#VXQ z@OPy__1m{!-+a07;;rpl*rHr*6hz~~ZoOG8mP%kSq5AvYeo!x%Q2lPx^8y9QF^!Jb zY?bRZQqWAazEH01)(s_+FinK^Y8}#1WmfAITW=S<)=sgZUWN;}9#^3i3Ej+=gYf|GB`fSEzbbwLyc%QW(|Wsd&X&yJ4tn8Pk^AxKV7k__iiKtQEYeY$VyR zPRrY`H`I8fmJ)>Z8eUV_26{Vs2PFw>>UWmQAvLumtciyWI z16f$R>ER&Qn-U+@+EKWYSZTh^AgFxqhUoMNF5D0-Drjv)*LK zOxRT^V!8@X*RYOl+G<`5?U0Q1jmDx>+*c++GpxQ$>j>5Bl{mjT|p0`PbQ z;InH0w~bOl^5c1IkL8c1upRQB&I0t$As$i<>uw-Fjdfp$h+rA<@%bTQe1PSjQ0EBr zO{8xZ0ZK?148alTfe{#mUbqHBFbKmi4r4F@8CZkUa0-sWad-;Oz)g4>2H*-@g=e7; zehX*e8JL1R%)<;Uz$DDUG~^%)i?9UG!7|LkMK}-VpdT*4I{Y41VFj+k4fq{A50~IF z{02_I$^RqrQM6A7hzi&?l?OZSz{g*=$~g{q6nB?f-4MG2W4UPJ?`r!kAHK5HJuaP| z@EhAqlGL~P^3hT2*ok#3MBxBP$Z&4>Z4y?o7&8=!V2Aasyidz|CG<;KUsa3KT(vp& z${XiRTQ;}d=I~2@z~%5nuQ@XQmLXC_jAP^QBEp-G`myXYs`v#@D|(Movt*tLpF}w~ z)J$GM(K>x8MrvX`j)*_!M@qa8d;Dfu=ZD>-fIldti;=s)y29TR1sc0F`Zv$B*4WVsppd#leU?YKIB#e`BPtYJ7 zJ4GU(aJZ=VWzdB`6C`5!6>TA9g>M^uPFO`^{0x$|gi@?*AeAYe)~12Wf+=8zFo?u` zTPNH2R*pC$+u(0_s?$52xUeqhTb{N_vEz4ral*N6kSg#}Du8^3kv`@?)0qrZO9MHeXit#zTOK7ZHR3fh_gm-=}1Wp}_i1z1qNcegBOkM}Efl z3tFHm1`UGrkk+WfZ930^&ot)6YM&Rq@1BsAl#2@t&y#ody!LJ9lkU5ac9=lO` z*>Dr>l%>4>sw8$wkK8H$#Mh$NweOTtFa}v-I|U;%`iY(L56!5j*eSot4oI@D7>nXu z$9xz`J!}4_x!`>L2LW8O<~Uy%Pt#AFPjSBZZynb4`NBAtenRgX&8Vl)JM`I2Ij9EO#<9?w~gq9b0C&F`i02e}d-QSaW9R`NZ?lA6(ehZq+k?`TAzf&A%>sgKHCtx@fD<_*t2hv3! zNvE(`@9EdfVVN%ZNGg%Rfzr>OJ@YOYy%-gO4W6R=I{UpO*C83l75#s{F@;YkG_xa!KFrX*^rEh79=pcLUeie z!(l|sj&d+oPPR84Yd2zI>C7vGNPn;8V@^1JM#rz!%J-nOs+rd94pk?4Lid1(sz*&! zl@8@_tek949cW`AH2R+&hQL=d8Jc58$8Bgj*UdrGp9+Ufo3Nu|BAr9Ba% zWH!LEIV!1lWzKP@&jnbAaHqRgYd%1-x+-isyI!pYhGiL6>KV+(_fUu?xa%BN zIUhnh6sznQ-HMOLKUuQ*<9jCATslT~-9+<0hjxSKvR|t{p8nL@6_Ud$uQ4R`8J9z) twkfVr-OyOpWF3P|v|hOw>m_n%&uJw6{h4*1{zSVXteYVu`nb*E{s*)~c7Ff> literal 0 HcmV?d00001 diff --git a/OSlibs/win/x64/release/libcurl.dll b/OSlibs/win/x64/release/libcurl.dll new file mode 100644 index 0000000000000000000000000000000000000000..c77ec1f0f175a2d2270cc100a66e00ab4c44dfdf GIT binary patch literal 366080 zcmdqKdwf*YwZK1)uc%R@QHaFHV1mxbgq)EH#HxUb8jFuuy@l!-K|vil z6Ug*1f~{7)wTgWxUai_&g#fK2fJu1c3#pHa)wX9Gsc0(%U-SE}ea=i0ANSth@6R6} z|1B^3SjS|3Ck)#O-no9lLI*>$!nD zj%{;?cN}|h^9{F@&AWN-^*3MrA7yi{{^1Yj8fD+Vw(RD}56f=&VOencMP>gn_nK?R z6&DXGcTit+PxEI-A1Hhx`!}Zbz9$NJKlSMWtGxUs8atjCrrrxy4OhRORio5z-m203 zZq;@?aSXpl9~kh&WBj%}oww=->bG#!QR?^b6ZUVudjH-HbDE{D@9J4&oy&F2k^!z$ zyrVD8!W?iNS2j3rsLOQZ>$*1`9aZ-Kk{mYe5* zLeUNyssUQ|ZE)A#G*YtvNU0!<0jG2Lp1D6D51ZL`sKio|R zb+h27P+hOytS92-?J8wr_5QH=iJrKrd{)>zY<^ldf%nH72fAF=b^K2^cLh2N-MYEg zy1&~kuh!g=jJ$8nv5?Uy4v}yr9GwcFZ$jn(J$Y|=t3urR06b%cN)qAn#*FuZ>U>wM zCu7tHo(I`;R!5=VGkz@3eU=SwY0Bw`FS&U zYIWWEoR>o8cB^o?+f`S+rNP`xF9OL6J=Uv_x`5PL3~C^UvVT1@-<53iNH^CwnKQ}M z&1H7uk{6dZS--m{PZgV_a)RXxl8u>`_DI1x(Hmy4ya_}%{4tb#kxa*UxV=zrLwveD}&fSX9*}5)s9`%t|0nAPOmQ6R8byooc*2`(0 zb?)6?@5d0DYVM^8gLQL{5b()T5;mnCf-KUN?NC@Zm(PRXddrsEPJ?EV5qi=a1f76~ ze}(KHL*r9FpoH#OR=$!KJz(%d>OHP>L7OCm&GwM_Dp;(CNer9adQ1DAH=W;^U#7|xNQ17> zsd1KWc7{BuP-O@B6yw7I>*$C}*MgmpM>h{xTOScli2P7DUlW3?KguRtHAEq~Qa4|b z~$d zZbWlLt_zz>RkM@cw@-O)g=mGHoY-I9;kEl1&+J5coD^!j&!*Z6_pBL@>&m_1NYrq5D;RDek{W zk9}CCo2as{SAF<`Z>{>2-m1YK+gx_}H}S1QGN8qulNY2i-YwwK%_H^1kEL(YqQUD> zyhz7lNzj5D`(VkoXGC=U)r>4^@ec}>DJm5S*W$nCU4}lfsNAokw5l@RrKbrM(KEW) zqpcnmXY91Gao{MwdTYizlP0TtQDxDIr$sadP8Y?bpd)VxK2Z5G-dYEhPoGFOGAgRR zSZ~QJDAp^x^h|qtFfX?i>t>gJXs@1#t)vn?v0jvbbWIwiXrgziEEyrvb7T^pED=#H zbvQjcuf;x`$E5bBkTa>FY8e#xecf!Sz-&`|VQLv~US&S4a(11}b_eRrzv<@FYL5Fc zDm!Fq%x`+)iB<^P&~h*`NO4Ch#%rDLI=68ECR;afF*;`AW76cc?wE|gOS-8A&1e`N z&3FTlAZQ+FX}@h$Sf)X5qaxo<%k@iy`)Hbzss^8K{=8MjB=%XxC=w0!@sT;Scj!XS zih#K@<2~k7nX`-&)XRQeY@{O{q)$GSMfw-jQDzW5u|(RYjSYej@h@BF^4m)5t1h%u zkIZY23Gf{9c)6QC(3~FKROQf?#u0i=&s`TXVj=TO2Oat^YwtD=*i&~;l$I@I=!+d{mceYlIhVK&X%8} zWIlRpIMdUvmUfk+)$KA5tA2mVpusUBqoNUSEs;5IcKN)JdAToS-slgRx9B1By_{Oi ziIhI4Blj$NGHh)t+c*#O3=ySH}p8oi1wi>60%?=8Lz$Dm$mF<;VuM22DZ2y<`_x9_wA8z?X zyRx7bo0)f>XLW4SJ5qptPzId#!wvxxkP(1vLYq`%ypNqE!`!a7&41yMW5&N-UKl#G zFT^}nxmABDrF*u5VBifM(j*Z=Y7E@auHJ&>XNVzDg}_v(e)})FMA?3#rKUQ z0X?=UU(dX#*L-yIyPbt-jfO~^>$S)4@PELqZk%qIjD{lh$RlPDphytLP@j(zA4n@^Rm0Jge4Z2qSF z0aa=Tw!oi5W>47sIFzV!g%bJY4J}(D!*ug)C7;Zn0bhP;{%-!D?m+vyc_g<7+CRu^w+aK%edh%Sb;mw%YjII0vCrJb6v>~Wy^voe<%1X= zRbodY%I9k@3}^1>z+$LaClfmfLj-E03;;TXQbVe&x#->W)l!&pzxuzIJ6p<~Y!|zV zV*f)GLjcudo%uq@mJMHJGQv??8WMM)$bFL`dgjGIw068Jaxj!QwOnQ>w2s)03uNsQ zrRi{nzgO>A1B&xqIqu5wi&0)OQ;A?EoE+_AtzG@5Zhl->{W2sTBqne4@T5pl$9sj0 zSo-9Ux$W7&b&5X%=X4lDwbcQUzd)v)rO*DLZ(w9LpaIX`fDG}*K0JUAme}>Ftoc zo}9@-5``lA)BHe;N^^G|N-$YGjILP^L}hu%bg~y_)#6(rQq;#JZ7uQRaafHDdR7}I?i}cRgjy~Z}rdqhCUFoV08!3X(rRipY_;=R$AjS zhOI+eLzZ2^`2YPfFPQ{XXihV`$8eF-NudTv9{kP-V!^;2C3F)^g}o>^`mKbs1hv z^Q8AfB*JRj2$+S;j_gjW zML{8V&rK?DrEWr?^&~V=zusBW58*^>CmhZ6mF?h6r-RosXQjj;!3wfUPcBmht*bkv zW=keehag$_vju(t@cjr6L0O!sF;*I5rxp1u15b#4HHKyMl5k={5!xP)#~;^!8#&LCN)VzO6rwCC zZG=KdnBzuzE6h>J%p+R`Q~)%0c&P4y2=<3p`Hk1|va9TZDQdMvF#)b=Co)&s|p;MiMK zi-s7U<1gI|RbaDVLVc?2Td~y5m&{Op>~NkjGIscA!&BW(?cWnKPLFLY!i-Mcf4k5$ zo0Km}agwA#YCco$Q4vI?yhn&Z+=Um8mP3knLoAy3S0_f?CkSFr+_mJ)d~{qVkQ$(^t;@+n@S4%|2=+I1M*>uOY!US z47Cf^_S^DY7yw1F?o3M7ZzB1Py_KF$w!`1$6LI<&w~NARmXb&59yD~Mllmrt*stB& zm7bleIy*Jd6Q-uEv!o}xq|xH>+GY*xf!9=LzS-8d0k+#3!3(#;nzT00mCh4=6)tav z9El-V<;u~97fH0VvXpRJslgNa)6oi-L*hFM+pxegn^M>Dqu8Z)ek%K4=8Gd~No;P3 zTTE-sdcI9)f&MTiDiQkD>7z^$_DsO%X9Yw2`U z=JCg(A^vNAKMk>lfl<~DCZaKFML%=r(CGf=PIqQSbP;+-Px`TUL@VmaW-OK$MKMk| zR$8Y-{F2xUY63IDGCg7M>;aK(UR0#dSt1!qgz>nYCSZkrWO> z=_=IKZ(0Ro9Qs`Bqf@pyi`1ZHM7oc5Q;Z4gsw?~Xres8H|5EIR5*%KCjvTF<1Fg^+ z!L?0B_i{aRLY`ohXGcEIFA^c}>gI(-IxFotZoOvrqQW+jsZEHgJwd#l^k6)R=)L;j(Pa^31}FZLD$ zuR|e~gfM||0D!pw$cjy&n(jM9Sk;Seuh)gfjrxP4cFIDBdP4Xj*igCdBl=Xc=?+b= z+-qBTWvY-UT>#ayU1jW1Y4RgvBo^yD@zZGkG}%AR_D_%4EQ!S~-ujVP={q4`nWOE{ zXosyO)E_pN_lS0f*(WP$9uxyR)lJ{EIK{c z!)^M5p+kp5I8RK=GTH6WYhJt~ztV~f)f0~>Y>71r6?}&wI~(&uS>{l;pKn!q%$~pk zO;6k-{fQ+iXn=o{O@j@3*J4SPf4yD&_WnIaBk13OT>nb?^zVUO|5pBg=--q3`}a>_ zORQ0-{$KP@2FmVVnbW^_=%1v1vwuZu=tRl>Ik8r_)9R!Vi+?TDQEUA~Y=P>@db=^} z?Gfx}CubR0=w;(eUIxO$)OE%Z_X=0Gk#CgY0NnumZAIf#L`x& zp;vj5678R2oi3C~EM3t*nJot!u-j_?Fq8R28@5#cPKbvch{o@PSmZ#=`c8<;9Ehgx zgzz~K&EJ4fWHh_2qa28N{UNlmt{JDgT+RI5!`~nHdyT(C{EdKC-{bFgo@@B+OYeU6 zf7XA!_(PWv+${KPf-}v;%X=96usIP|wK#=N2`8Q^k4h5mrv-Sf1Ll5q)B@%P;ekUR znHxK-v7X(@{O@_%D|@W}PRl;j{Z1D|%QTYmiB>YYnb|{|`Tlj<_|2c_+NlRV2`~s% zbWN-17S%BC)&i|!ciN*>yaLR2kQ7Pg%yytp*@&xhqZDfoC6@X~pAX!&kh#317p4Q4 zjx3CybbZdI(8Q&pf3=kZRTcn}HvO{eY2qhjmWbqp?mrLg| z9W`463H4}pXbl@`_W$%bcqVAuy&1t}xjuj)&2BaI zU_t8Qv^3*(eUKB zcZ$h4hO|=@dTr*L+RT^b^%1E?9-OhpQ9TUwlCoUt%z39#NiGmsgGmZ3R)i4VuCr;PuOIySujfq~ z^!l#@2Rq7)Ybd1nh$(3n_@%Kj{Rq9oc(WJxl$_*p-FYJZhR`7^lpIo`cN{L%)qITm zo?%wqRq*K}XxW`dgl<$x*T`JeBcxnFO@8BgYEr{RO_x)XO>ess=2=x{45Z0Ikn{i^glSg!B~3M5(p2p*l4OOG~C4OWRg*8!&Vk(~d0FMWG|CcefpR3uD$6h1p+14a*0e`RX2uFh zDYLG}0pZk_@t!{n?`^v*hNT~3E?b`xWsrQRTom~KwjrhLQDx6AKD=^?+jWN)HYK{` z;-m6iDfZsk;6Lp0KjgY&EZj?akaYdQ#edB(o9k*g|3p?6VTJc;1H1ij3?Q%ezb|Ve8P1 zvZP@zYI7C4H!=`ELblP`-PvZnC?N^bEb4HYH9XZRFaqr&x5)z*lqGXi-^>Y$46^p!Pt;3}63QOMf5Glh7`wgY<-0~Q zofcd;T&9F!Zf$kJG#*<6xZT+-3au|#^sgWM_0pI0kkU$FbE^!Vy+}Z`xaN<*4O^lY3Wsm9(F!p8ErPV; zGnVz)`ukMz+6_(>0Nw+js+bl@wW&5Tv-S@Ak28opvz;sWA__*H;+QugkZhr}(_$Q) zYM0CknxBNtcUgF7tuutj3Dg-Fo_MadOy_NF8K5GkglXJ&GFa@*u;bYalemE2WQQe1+rOR(wR?9iK|M}!}UaSN#F%qX}{;odoVGd zwJ%+u?tJ4I-908`=9kM{?9mgx5IdHHumyz6&FLj@&s%WMIqnGitpzX3W58|f6c-Nu z=;9#~1Q0n^TN5llajols%XQuH9cx{Ferq}iu|k>oba!F;;q{f$1o3>_UQvK4k&&r@ zx0`swCU}L#bDMyqcG@nMZ(VBR;}XvitZ6;eECQf*9R~}c#gUI!fRH%Rk7YyzRKF}9 zrs1Gd7Q#SP`Ije2by?^vGw`d{8-4aqZI_$u1gx7!vqEf>npX0HdotdaK@nyRDO*U- zOQ#aEpyr##NOp!JY#DSjhJM+=jIx=<{;AnxJD%`-iE@@%Ae1=20?Nz^B+f_WG98e> zf-^|mK;nGAJS^Y=HncT9&rPH?YwN55fyC`4p~MeLLy4Q4DNbzK76Z>xKnDnc-WX0? zsHcyWiXM=*5&t91BA8?a7Ea&{0EQC(%Z81j;w6d-EidDI`r{G8S!(A<3tH5w#s6D% z-e6{uIjS0mEL%U}R;FLYCMTUOJ++gXN{B`{wHY+4yZx zJBpZ5>ghvIPq#I;z5$B5<|I4Hq;>FYF%i%>p%XGPSGlmb%3h=s`dQ3@j`y{aK>9&h(fi)mh63i0VD|P zpDguz^_so9R=-KM?iF@OkH4L*&c3ez4*ePgqtgqY9T2I%MA26_M~HKqYR(p_SK0K6 zEiB5@&6>MVF;h!2-V@42?-HXoNP%-IT4!e#Xffc7|5Ro@v1p z9?_3DZGF~H*|Jd@64gL_>zl_Zg*=l+h$2$9=R7^}$MStNMD%tU<&UAfG>T0uK`~uW z^hm?zP^`h+0m$b=`+=OA1Mvew{(JrNhvf3h1jU>%yOHc2RyELuqU21r?x@JNdIR|V z?b<#qP^jAbqv|-E&3}#j5RQD^W!$JDZN56Tz{R!*oTDbNX6wugY=W);QV4nz1U;S3 zLC|KaxydG|-;M;*;y;r5m}!#*m-Mf4TCU1jfHasNu5hZYX)t#JKBGVQ*c|vc!6^NN z_Cipf^`3^#fR^dX0PSg9bs=6%x-iQX$zSC*hC9I9ZQ#{5a7JtS8?NI9v%!arqDE*) z{~CXnquCz;44GH>MWB4W`Z;V4rkx)UB+_SG=jTc-p_Fc3E)!kk)pSt{HQquJMK<&= z63i93hYn3I6GQ=|8VP%M;%zDWMBU6h-d@#U#VbAA!7p>qm zv7n^OUxbN?fQfoQW_&V_V*R+QGpT75k!l+#Mzzx9GGW6~)$VoVDlsdwdH)Ze_BMJr zc_Fi*6hmp%U}ZBM#pA>B7;r}hRTEkAmM7npF2-B29Lp)=9WDEnD$Y!c7gJh5)&df) zIiSVYQ+Rq9AhqX8E&i53JAH!_ zkJOWO?P4_(k4LOdZK>E2%2Y0vLbj=_#U*}C%;e-H?bylI*#~7JtuKKiobktQ$Xd)@ z^+jrcF^^#f=8r>+Ky@bLy~rlecr_qb+Aqh^MRb$hIq7T0dj>g9-&#&qCNyDxG6Crg z=6~o7E&Gj2MR?AlqsmH2z4E!(*;vBg9}V%;uJkrV!}Mmc(T{8}>tH52PV3?y z3B5qKK@LCIg3u+b>`Ff@h~MVP);$WnQDG~fNm9I5VL$xutcuK24S}^9%<}Ru8v~6v zRkW5PQOAOghz!P2^!eca7-l;dB8EuU0+}ihB)6i@1EUJyTjrAGJSejk6GdDT_9PpphAk{|U7{7FWp3F!U z_`3tKyNdEc=GeQKz^7vn3|DP{tb=(7o1cr~BD9Uzs?SC`t^1eFC7V7R=<30!rSj`P$Sac{uH{QYBjH{_}_57n9f@K4wuNX}f4ydaVB zuB0M+PL2#GLeh;XGA|dICvm6=d$}1hKV_uSEf7GbELMk1xC;xFqi#!?^GTH1;>bfm{O|xSWglS&g+~~ z=1$!X4yV0+O41eM`=G|XKTw)2>z_{$os4(=2pQZSh3G3%)-9lwYS^D3M|?Q-*?jKQ)-M#a|q@FJH3i@AL+AHdSk{r!A@@^oeAdhd7|MS z6rC*_E1YSQeb}dzw>o4V3Zr{PInkyt&aG#8)MGU+V}Kr8$gIgih>en82*bn{R=A8o z2PeboEk7Z_oLXyk#P$uW9jL{H*8uRlBE^zcRa>RSuM-$v1|fEF3E@82G0b4KwXn(+ zIh`#egYAx~jcEdsrj~{XANjR}6qwx^?~jiX@=lh~(&8g1*g4tfrr!KWFjVt)#4~vO>p2wiSv7Ny%)C)((^TKC{u9yM#y&wF=hay8!Q;TqKxoBvO=G!D37R zLxo`A;E!PFUw*tQKiSp>cPj*CtXd~Gh0UpibC4nR(;htX&En>O=Ve-##THr`P5Q<|6&bAgRCwlOzdV##cgq&EGW!g+Ie=5+*Ust;MMA)L6S{z*jNd_9 z(nGRL#aaOodeitp^}!W>-z`~wI@v3PtoFCwQbcNwpN>$;x0I4zMtY8)J{vCJw^Wht zBR$7Yf3?#aN$=&StS58@ONM!BPG1jL*h~wzrCGUuZ7N&ASpruJf6wvv9)IufS2D%r zx|F}`dH##;a{ZF$pYVHLJyDqay~^JYc$YNEm%m3yI~};}EUf0=UZ)_A7aYtG+nU3I zgI3t5O0v)rpRvVgzR33Cu>cn{-<--A)mZEeWDZVl%$LA0If?hdkp(W^XQ_AO@D1L{ z;mp`>`)L+&-0BGn_fP6Uxfhm9$-t-%Jf9uD3SGG~?qGOvav)|YDW4K8Ms{yvmn} z)>#p?#7GuZ)p9d~*kGO~YlW6!Jd0SAf2}{mvi&LQ(;qnlW7AK}(IzSr7FYB&ZK8{+ z6uRmrVWskmefsbl%089x4a~k`leB!OYWZkduJqB@>b`H7L(66AAxF#fVuwY)+n=bL zm(G%X2R24NF%OBHoh`1ZjQ2u?N(gK$ly%Id1b-+^>QfoEOKy~U7IW8_;rQwp(Z^)x z0h$j>HllAxxX(^7=87LyJhgtGF&HOHNaFpHLmJ#J8Lh4o>4h4t64l)oNU$SkujXU~ z=Cs(}QD9kLdTM8L{Pws=p&X~pbdbQBtX0m3$RUb%I>lfA7h>aBODz9FSmiYq3)XN; zI4om3orN3w2XJjziD7%GILIQWVmune*?)>9IRbA zJlZ5doVFfwFvCoil?3{7U4d*ww=0`Xd6 zU~i%7Mac!$U}#KhRF=-G7;e#t$3+mF4o+Yt&xe8HP+AV0`$KK0Ir(=N+h5Act(0(D zEqNcM!dShjO+1JXd5UPwCLEcse&%smlUK=Ji7`+au!oWBZ0<(MJt3ESnL8zm6zPH1 z@=_nT#{}-n#}yV1aZW=Mtr?9yFxQka`k4B0A4Jy*qURJM zEiQhFXw5i1xzN3CoUoNv_qkFrpYNx`^kS@p%_fU$rO;if5O3%37SihQ-m@9|KJfBl z9bh*_TfLVQV?1dL(`60j=5S?KAO7P&`1#uEe0SyU$NJjkiy<@At|-zcsR9Y%iquw3WR#aLSLCiXBn zwvi+Adh)Cn9#iDQmoZJxco(SZ(871w)#>TWvV(G;K(FY9MwlOX`LeCZG z@7vJq`AqY%|B;10-iF2!m#*9=YrGb&9a+vp6thx`xA3H`u0!cx;rOvv%9M z^LSEL>ho!jOKn_^6v!V&@BW6YY%OGC7S(JUwAH*hhppA$VWLh>clir^ylL;bU{ZDmRq6k;Upw20m zxuZ45Yw^o))U7KPTF5xO@PQH@!xL<+S|>Z(4e%4jAP#C0IH-rpfz>Iskfa7hB;+t9 z%DYPlFCrjnDdSyXW55s99vLmL=uMJuljN3mW-`K(r<8DJ{c|-+vNG_lr2W=;+ube> zmM6WPkBPO^1GLsM7wyD2peU2Y%T%|kZ2V%iXz?E-fqxnR3#dUec#C~GKx?^?2XUM> zLZ5n0(MN^_eD$T+;jufbPzvJ4!I{xI?aicR|P7KDeT|&QyJ?&`w88-&wfHf@3EiIzT0`yN<*HV6D-aYUI`0v(w|+zGBZzm+K4u zhR<@j9^mf{{yyTb5LCUZZF{|4ky~$@AqL={d?EH=>!qw7ib_JvUN6ghFuE6hpd}h# zPLFsJld-t7$8>U4CheO8%}tX*ivJyE3*k$={*ux$2k2-nd*v23a4`ej1wUt z?O&K{zvEw^=9-N6L62fG*loG}1iQ7^Pq5oU`w9B|$bN!BueYDzn=9-mSnwkCgigOe zJ*XArL;YM1IoimB5P(ts+SLzbtc%bqhvf<}Sx>S*#dRFjnd*Z?Co8c|i1baY*5Xll zU|zt*)o6_&>`zu_KZh=`t+tw(A01EyjH7>%tSX^FL8xZ?ossCmSuUdhO~W~6TxOCn zA-d4-GDhKjjo{bcV_nWxHR@)hN-hwm?0MpolUi2(QdvhR$*D;D7TE`Q%`&MPv*Z}s zWZgyhpwbEA+#^Iy&k!lYIEg%IEkBYuOZ=DjNN)1fPx+zM>^}|2laY{FUW>~mgu*Hu z`05t_UxFK`La4CwNQ`_;c*HqHFhv{xqX>s3p?n!(h>U1BIR!gMmIz~d4T{(;`LAt&Nxska~fO-LHmy%8qh=sCAo{%0pIDN8mGDL9UbvzroPy+S8uiMEgE z4*?(?bFpkpm$6G% zH{t!X*YB(32BoBTt{@aj%^-(0W1w|D+tZB1PU>`)lQEaj0RCx@Ojd((yCgvKk!;i< z1vm1_^+wi{sBh&)zl?;s`1=OY-GnH@AFMathiThWQLt8L?D!v!fv%JFDkvws$+>tS zq%(nB{G=UU=J(YW;Uk8rwCEytW>BOk{-!Z&!kg*5Ke+p#KrUz7%^+hm+mhX-CGuaI#@= z;8}ONFl_Fqo6ybxirsyT-Jk5TlhlAal<7cJJ`^Q~fV?g?ERSW@>-Y#$d9b@9@6J)V z2QB7#-2Eb=i>Q0z!r{hzkq*=WLi(n0#&zgJ@#`Ni()2FS;t0S$N3&4)yRCD7hB?d& z^R**Zk)4Wh1pz%)(Nl7Gn!#B2mFz_Cvfj8?OlSaPXEz7Z@1>8165j^iSUqe$x|jOl zS=ncf-yt?Ks;k)vtGKCrUXZw68ot0*@uJVwF1@vNR341-C+VxqjoRwxkHuY3y+34* zDi@Cek&YQ8U}l-Rz~@w2nU#Pp84o1^t3S+2KtB0d3Am}B1e~iRz)HdOC_a&Zx8+$A z2^hmlz~6dPc~h?p+$bnT2EIpLUm4I*mW~YE^`($Z$p9(<{<>8XdS&2xUPT5TCoV|I zzzh{?|N{<5~!Q>uEwy0E3BiwCj*~KE5Yc)&mt1v2VBPVTzkLde~^c> zzeOI(?b41sbbgVKhmZyt^OZoJNN)Nj!M-oY?&uLZ`I>dagZ~q|k96jb{}aFe0}p44 z^8y)M&mw;f2{rr;<~5uakuZf1mARS}jCVSHaG7XUQVh=35Tin;WeP zYSYc12{Z?Gg;A~NfrLu1eM}`Mz150L+pNnQ+1jaMLc(2`5R9UvN~|~+b#f$FRYBRl z=(mjE4o~jE(#=>aSwelTtMfPN6Jt`BaguJXmj@V&U}U9Shkh=Mr&-euiEYeU%pQtTeqQ$mrR> zdnCwcERT=LW4$|aO2BkbI@8b_x~hB-AzOeT@><#S>*cOHYrar;f$lDMkpMVU*W@fKOCZ zPOrfTenkVqgS_(v!x3QUEl^7VbucfzRcSdXoGa3YWMNZo2o0OuWwjLVst#!NyUmT8 zz^W`O4XngFeGOm5|AH^_Y{(>P7;>EwGQY>e%f_*sd)HPMoin6_)d+VuZHaswFxxlP zjcgCZy4~{Fdk$XNBX&Hnj3)8G$qTN^cwg)hD%%#8n+({_Cyab##``PDN=)Vz>+301 zX1Z!Wc}wg(UdfZdbjp>gSvuqWft|-|yMdriFLTnrXQ%VpZZrvdJL%`x>AWImq+`Y~ z+h@GT+3CEh1?lugCw-8e&TBh2{Fu{qNiWZMKRKk@%WFIP%rIGqcG=UJEhS8U^{lZb zb3s_Wzm?VA>iSu&lV|aBY3t-m`MIohGCl#ovU1f&sbtUl|CxOTmYNZ%jPb<&v7cBY zTx~zGMwn?oVI4KtPplCp+fS?!CfZM|5yq>h+zkh1yk=Q4H(nT?ff6qFx&af7u5p)= z*h&qEe{xcnm~C1eYoeEc5{hFU?&Yzfv@NZl7cx0p`?BLg^$&acuvab&stG()>&L9!El}= zsTEw=m(-88j&k2I*OR@lN7XxkQ_yvMzGgS87u^wiAV#(#@}O z^4%4!)g&H)>&^($(pD?8pC*YHPn0Zt!Bw=d2KSnNDx<$w=z4+jS+XX{c-^nl4w5{b zA`hKNq;rCVv;uCrl~4ifjB})LviKRyjf{6v4pSt5LVLQ7l~J^|TAERF=#~Qf3h5JY zOsmTZF+0Y-p*)C|Uh`F?0M|*nC|Wyqyxh8?Fz@>}v%G4!FfeMaZ|k#+<@`!dphxz; zQ)g9fek@kf?myEJa|~9RGJ3E|9~KdpMRLx+r`C^VjmX|Sy=KQ9H|jNGA_YWTq8}6I zvNi_*IccCtwwz41pOBM@_7ie4-hM((POzVllacllax%<*LQV##CusN8zlgqNxq~l8 z7SvixMAnXCASmT-t9C|Aml4aIg^(`$mF~kI1O}OT;HpArSY=El2sIai8uc9~p{b4B zn8Khl7k%_91j*oOd{dSoHJRfgMV-N#jHE@+8;>3qpzjOjWby0!gm?-iOvAk;mq|J$ zhe*lskpjDAz z59yvySo~TVVbyf7q|ZEQL)N?#IYNXaH+`z)=$#pS{Mj_^-gcWX4yV{Z(mvasQg>J$ zW-H**pLx_3;D+XGqwcb%U@CmO0@cmMRah7Y{R@ao8h^jc;(fHMoacC}|84RvH5(NK zKY@Do4r-5@XC`t&=?ZAfrK5>u<$INm@3ar+Lidj)y5a#6!{!FL$~kE64<#o5p4!_; z40KL@mZZm{m>->a?%3KMD&dG-yu6*iq8G_l_fDYn$<8cp}5O zAw)`&s3!Q-9<`tFP2Gs0pRBNW@e%YzPjb}c!2*u78bl)8pOTE@{(98 zIq)P=AnYZWORfPyV(9`&OyZJF+{nDePrQ6Lg-GJnIdW_+vB_!-FiNTFSZLe^3a;6# z+n4K*`Annjw=aN(19{lbgE1k%gphdxH)qB;v2zLg zN-lT0JUp?|SPNyFcx4~_BXt{Q;$eAB|2o+Ew1ANC(+Vo9x~p6c1z`jR*X~y?iUzq>1nDlDu>35 zu^SUmZWX8S_J68w+J(KHvMQu^ciXiYV=xK+s&>aX;qF~UuJs;StxNBL0n-b(xY^+@ zk8uIC7w$3wa*ZUS#bQ0^Q#6g7>3joV&AH0wH?UKccc({#)C9eC<@vDX2-q_98+Ijv ztsAoIFvWMO zCvqs1fixGPGXeSsF7Sx?i_`b#6i2DsZ9I9R!o$;SEzGh(q z%x!)4U)cT{q_)3K&O}&qu>FNTQ$0-WQ<%A>p}3M#)~_nnAgj)cKy;985A>{I(w`+h zDlv8AU`L)YWbq54I%Mn57<#b7Z3JT~p)pdUtzLpRRX8ZbFo#WB=fzpd?8Lo`X~%9= z@dV)yt?nhMTbSWQ>P{0^ku5s3Ur}36$pHmQV+WQ|>;O%c%j#?-2c-k=vUiBcNC!eS zFKY4gkXrjlGyH=a$EC$%EoEAgi#(WJFlEXx*(~ctJ7iN`l92Q+rWK-IenbI=9A=(Rip(@$5q3?a3SQiX zGVVRqmX<4av_DcJTqk#0-8O(*$kYw=_NPbGzUSw(%J+yE09wmOs-;VO42R+=C3J`7UL*<~F!33)#T*iaLN|JPs=uTq_H^a>j=rzwsqZd8RSgP*^aEXns zSK56`WRva^s&n>=AtcD4;C&yYOT+I8f?X!5lPE&g|)d*|$k zpAtV;C3aeQM=N?nPDOdj^-B~0Iz;kQ|0%d)UvQK|Su;uR zJO@)7pHQJ=kwrO7JO6>`Onk=0*xxZ6CQuzr7Eh-@h%e}*nPi<0&e*lFn&Fi9asdl_ zL?Jc+*^mrmtWh)|ePl0++0v>3y{%H3?OK94VjF^#9%NLQcZ-b}J3Po3Z7z+|0z%{> z1-#!`+|s^aAa6!Ky9s#{+T-w=cY`dtlEu%-54RoLU+TcZRf@NLsRZ4XdW~ zAReCPfrziHnKdMAz99A!!M_pKa);&9KD-J`4nu<&MWhkuY?cqpO#6gR(C*bD_gX3Xnx+L(7Y^YUUGO*&?`Q}-zMo>KtB&KiRx}?$MXO# zewNI#n?z;1d2?o8-q0YuSO3flC$5nb1$frOXq8!N_f=i~BOVaHcvc7(w+B&z-??ko zR)P}fSpoT4-h@;@l?kzZY_Y<+(i+oZ{mYr)y6X4CiN{pR()Y1^V?AZ_%k{N#LplG! zDZlQxg{Ai0(%Ovoo%dy?cuZc16>Ir#8S1PFx4<1aCia4`2y~tK1w%Sa+9{guLuz##(7VKE{_i|dHcM6rwak0V+oe%5 zO7^^9E>~D>8dd=l#83&ml;XC3w>9wHocnzj8!uK0RBHE8RCA-39w3@`7`_; zq1c@SQ-tbZ8ZU%1ND`Xmv(qi#M~a*sk}wJ8GBO&7xB$?(tf`CbSq z$QgO%_St0(bENtPnfc945}&lwTILAm#VYZSsEKY6liwAY zfZ;9Qr#eB=XQ%ZgeS~i!$HzqLy*3F+w)-u$F@`(DAY%X;cey7MXh5C&MK7=WG1 zS3~BD7y^6LCx$LAuNt}K(4R9~kl%__0N9Xuw3_u-(8uTtLItM%7%!pZTzqjmtQqUY z;xObxXoH=KCR0({aX_XdhFf%@5GzsNs3!~R0mnI@=Iq2XtH=m+)i1z2c4g^^G39+% z{Eo21T2UX+a3tqN2srZoh;zk4jCUC_A>zrZH<+!8ew7t=s+eGM4cY@>4dVfkUuo(u z{z%F{%xN_d{`Gx;Rck znHSHG))GH^@auxJMG4M_ui1mX89gAwSB7G(k5X=EA+o&!^pJ$C4Q`MMvm;|*)O)x$r}YxvLR2r zj8WPGjYkLC5EkL2JO|?xfMoe60DAI<0>%F#@8ZMSWz8oHHzij+G$iH<(>voFBE&IS z@SmsligQlL*NBjdh*&k0?d?A;O8auJm-8x}m5T$U%IQ>Tlf$^mr?jszlkODI(ploV z2J|5Z)LywfrCQvV_laq7G`z^K;{B-yEwlo zP|L2Di{y@yZO@R9_9hicyVJ^lLJpD@^6|}6s8Or?b3@IGi%#Oo0~-JAE7JE}*0VG| z_INWy`m%GW#KF3QiO1QS%CcdE&j6}v$rxaJu9Ocu>&@-Gk8##-z_)m_SYEmKuk3dc zd-qc~2W0#4*-_?jkKDQSacq4P#v3Yey|{)uW8%%^M|_zsV_`BrV zR~^)j=#B7>CGWxY=Tt&Hbe@Vsuu;9$(4VEIlw6D>IuGo5vfvJrZBFj9`|$XSs<+A zR*SKe+jf2P1&GpBuS@Cl@K{eiAMulY*4`2bVm_a#3`uPL`9a?cMf4{!G3Zkrql!7P z&6L&W{H$GmDtGIine1P_eAiJ7VUp=Xx;uItGY?aMd<39f_C9pk>uHpYiojKJ>woY5 zgdOL={>0jqZn-3h(qrFO+lbSAF-{V?BEi`DFtp8!6!~JD(svovvGuc<6Wqorkkm(t zY*R?+qFMvF|Dh)Bp}o60n>q(LUvSKA;NWK1thuFs#8C-Th7PTwBIt06LJ}E&t5@Gm?A?ZX1~R| z@(9|SLJ-C;h_Bof<~*J3+DT{uh$a_tgKZUOsEACswOP*{NFu^^{usHejJbZuS^A-u zrY5O?JKY9`l3Y{Z$#D7`Uz%VcV1;nDE!OA|-(whvaIx81srp|oLy8T%O)P0M5IP+`UcB;j>J*ON!WrvZ9=(gMGw$O}ywNGB}-7Vj~ zJ^N87GCr0J<>XQ4jr(pZ$)`)_I9KV(!gG)czkF_E34#+c#d2ON0|U()%#%Wu>YOiL z@E^<4MR+1IFt*NSowH)=?6uTsZ7#o*_$O49!v|Wur7!Lfb_$y>TIMsdlsG=Lc(bIW zJpz~Ho$CJnSY|Fba8bBl9%LLizJhCX!AtHMqwK_ffcBT z#XRcnxmB`pPJKHi0NA5f5}JCnT;^)F+Q#SfS(0qF%Jd|6?{GIyGrxoa)X&os)07;?LaJUt-bjC5iq1?Ka4tqoE$CM+~|r6)MHEK%GwdyD~XXG`K}p~X9e;T9-q*N9Y!hNsag~VdVD390MX~s8JlNu9=PI5RN<)ookb#Q# zBxcgSpA_nz%zCatf-^s^OB&^FK7~3!1-qq7gT6<_32qDtn0t5@AGpCKsi~SaK&NwfIy(op=dtH4zW@ua$TNgF8mEhbgVp zNx*PmSc{M0L65y4o)eeBuwru-4@G6!MwIpBJmrs8XGUUwl3B+Sai9)#3RE%WtQH4K zW-`aR$l`iKL9zUISywqwPx3;Q;w{Qmxk-Ty5-^_w7U#vWKqJ@M4f~yf5}&4Zgo28E zpOeMVq=ux7_r&M3G%+s7b=DwA4kG-tO%b6ummVROPL52MMHgmjBFA)2&YWX^T6H#+ z$Qq`RxI+{s9{#(ER20Kq>@9>cn;UBWt}UCxvpvN%$`ps(Nys_6QbHZ=SY-)z^rP0e z!7xhm2%;JD3cP6t(JY9qohS2xy6p4!;`b%iOWjNOu}V!WAXmvlb{EBJ^zyZ}>;ia` zT0!ixo;(qY?>SW@Sl)~^DNQc4Hxsxls*!-99wPU3J~rNj?zjeCL+{B)$H~2zH~HZB zEPnZRQ~YK5;JEtCIBR7%cW1+#ZhR$kr7mGoKxgwS-yPp7-yOGh3?q=>e(4Bbel$kO z|AzAE$HRTuFPK@Za1rjCni~ppq#hat_ zNIq`u$ZPNU^G}@bl}2mNA<81U_Df_E(v2{Vh^`mO!%ox9UntQVz(aPI`?zfUkj!%I zUGK5-{zGkSGrIP5dw;V>lU~a)6ecf;Btn-;h)AC#TYr34d(LZNPX&kl!yoc%+d@UH(OYf#8|m#ALaVfz{%8>h|c`)fAC2(mRq;y-7^txk!6E zy1(X~TSv%xpVRmmZ@pa`XHvH5HSf$%>y;dVl#{Jr?UcFafYemd8>wS6lN@wa^Vd#m z^y3~^XAs3JMq@6Z#|Fz1!ukCM|BqnIIn_`%VN3Nv)0A~cGVoBWXU_a1zRACS-yaUJ zbTP(gt7D}o+k<;Yw#W7z^>v>1`_{N*HalbSVYQ?gMuIp&jN=y{K9vgYAhyKZ4I*pY zD2yNW^q}v6&Y0kK1M3#pbL_?}KCG5Q--=?Nph%BYD7yQgsN?yXI>KVFTD)F5Bz0=Z zHSjPUc#A@O9z(sTR@wIq+6$mew~8&%;y)3FH%-}5<^1OkMuBhOfJSVHvpQpf#GS?x zG9@wNy;2}-a6Rz{JMFT5r6S&(rQTQk`&DZkP3JlO?c&2mOc#sUAd}C2ODxJR%R?9i zm5&VCi$%2G4YC5mYC2rza=pM7m`et~zjo=jzL2v>xsTHEk?F(nm)FYjH1J1RhK9_& z?7zOtXnbN6w++Vw9B2~)rw6x{suvkBrZ-s{$OmKaQ=ZB-Qt#1!z9*BjF9L1MJcv~B zzy2hxd&OGM`kQtyJXl|pA1St;y4Hh>Sc|i)cf}f9`LXFm`LVn5^R*W7P6rODeaZvcwq|EgmJ4a35i#Kv%vj^j#^rt3S}D zbb7M*MyE|D*=?Fmn<{8i&sBDtUICUi715?5vpzr8Q^Xp*r%Y>EM@FB2Y%|6Pavxf z|NBE#bTZe;I?ku!)E{k%-e6;`pp=^;Zpggg=NA)8c{CF86w}_ z1BCOya{Tpm#pUUjb6V$X_VLUaU*G8;;*S1F_UT>5S<&@ewL+QGxB}V^%-dod8~qa(QIc5736VA)tp6g? z2B9qKtRLbwJJaP(1#JFMfpQ$IA}Y{4kRBuuQo%RPI>(|THd^Szx!;@kewrM$a>(Q7 zGm+{rl`I{SYgbUOS`MZVH5Fc$lQ%pv&GwA}iRtqi%mI8)#H*%z%bY9ve367qAKnvziN6*3YvFhuIFrX=*33p8ZTI-{MD>aZyI8J~(l1W29b> z-PKfZt3PCKF6!oe0&&Q1xLo-zV?>Tq=eFZW-KglqH39aAM2`fu2)-ZtKFl|}zzMJC z$?bDL9prM=7Hjdl`8B6ECIfD^LAXM$WsX{&t5`I%(Kxt~%PU@^TqyZ)55g^ZRoD%H4VIp%t^4Z{TC9t7r&DyVA$j)~qVS|!VcZ8*)b5eK zov2#Q{ml0RPn+45P$cQ{3{`e^6u$t-b<|kp7QmwpLNYI3cZ)B(W8j#CnDslWk&4oW!};8fV6O1}~aK z)rZmBkuw@5KHUVH8I{UovcpPzmIn;i7f0N^O1ilh(K$fV#aI}~?fTmC#jpagu?yI=;N-+uD8W}gO02mI zW9l?)4CUh$l6+~({*jz%x@Ch+u{863Y9KJZZRuW#WG1K&29y zg)xD>zJ4%?co!by6|*1__V|HY*~oOG>zS?KiIPcU|q-iMV5w8QEwr4R2jY!14?5j~6U zyk2xGZFDc;y|DiMi9&a5ju~S%#<+vg5R521VFyKGR(&b7-PksJQ65^h&Y=9}KZ9*kQiprWpFoc2Tpd**C&f#bS#^{U8&e&xH@+qOej#@vo|$Qc10EEP|GR@xXlJWTBUa_ z6|^F<0`FJwj(HY!;9Ilsl5WE*w-)en<*@CG0RJopewKpA7DdEW&}08HZ(*49(zB96 zfi~tlmsRGJ>*57{Chj9GF1B7TafkI?@~(U=yC}@Ly>f(k$}!HiU!e#y#Gy%QI&I1k zRti}HYReHOcdY{+ceqN;b zM!Cs+c6GP)c8hz}WF^miYl>gy{#NlzNwnsazSiM;$`t&b$~4BSHM_0m9{)9R$(J~V zR1;g&JkW9-wRbL+O%QkLGM>W;H9@Fb`5~^v18MQ7lyGK4VuqiVpb^_%pv8SBKCt}Y=c%NVo#X7j?6{nIDSGB`xdNvnm zw8M&lE!CkUC#&Xs>!p50BClQlMb1PaCk}qcjf_OS%fYBMzY$$*SB6I!Z%)Thsmf)ul~!A6txBtMEfPQz6uD@< zptUVp+dk`R#riD*TKE6{%sjgZ)PDazUTmIc&Rm`|GiT16IdkR=LppTdTJNjR6mR@A zE`Ncm0yxz5J4)s1rmLu)+osPSuLZJ}{BybyxXd5`Uk`Y@E-|=%M^nDOJ*n{Rg}RDY zAEq76OoN((ndW@HgOjDSbhv62Ty_T%C{>9XLlhCk72BO;6gz*QoEdzmFIE=hN$v2b zKtKtOeBLg(o}!9T_mANpAF9E6KP!)?%$~@hareB*hL>Z4rcBU~c0j8cpkcct+Teo+r(f~`oEDr_~Q<0%B`xwADhNEr0958Lx`a< z8O5bDFY;I48H3+t<$IcZ&8yYqMyGR^1Zb)wv<;6nGWrdc$ zaWZmTsI>xdA^S@WDhOkI?TLv2U1Q?}1KIod%R8-u3E5D4?<1vO$@rCVbRe4~0iXTa z|7<7yuuM+(vSLZO6^(74lz25RTDqs7gt=Y@0 znM|wXu42LL^`mMCOBb0HE^Z>U!X4|^=D)6RGpK;QZK$lE%EAiwBoJX;(% z%^q6?BX_V-;4C+$?kJ8U?Y|L~hg#aHyL+cr<*fKHIVD){rduHUDEyFR-OheL4EMO(Jc)Omh)8c0P$udCxA7j&oWfQ=x;A&NoE_8HXPb4%@<0R< z!GL}Wb_I89XVUxIzr^JpFsD=e4f*gPB^=5^$wBjS^;R5Zqsn5x*le0!9jgVMj5$*+H=YzuO_^|E)|wyVZt*7kuf9v!nBwIt7m=s2 z)}EdW)tk*jsW%Jd8j>*WV|U5iS`9?BmB^hBQC}S-7-)5S{-{AFgW}!Sv~Bq}=c8VU z_d`n-XmZj3$7{k5YG}_g4*le=O0C4{BNLDbU5K4_Vi-2siNP8z4agepkTWh|^9jxo zbmT^kccbMw^pf51GQrtwG!~@NG=%)~Z3WwgPDhg;Vljo3#p^of+~E303Ca_d?z}h7 zWvuQhPxM2>EiFk^^0at$XJhluEwJs`S2!yr4FrG71C9~ZX~^!YXGgzYKJwT8|161Qp=^O3M3C$MzX-V)N*N%?Ua`26Iybo zgqR}#Ei$=+emd^fj@%Jig6fbChnVb6$qU*kVTYZalF!DMei2Qd=AOeoK`%}r)ZSc? zI4N3tbFbOeaND;zz3`cc4}J5)@0w|%^>Fa$Y#0!XcJzY$e*^f=4lH?(NqQ!oqtKT$2`Hk5PCIPxPiS;0w7>W*DHAm#ej?PbB2B#E}49%TF zv|1ujP4rwp`eqxQ9PEE(jt~D6yXtVG?+b19=cNp$tqaZQ(zduGzQ9hr>xdUnK4bm@ zvc_GG;8mWlLNx9(WvA&?$6Y{>?VLDAZM^-Uv()Va0{9(hZy1>C)!8smHbV^UrXB_m z8jM#m%nMEf+~9A6M?}jP^-Ap5740R03@usPCDUZc-s&-@K2?SfzUfLUr!%`{aR zMc9k?Dus0PiHX{J=WdsC3;XDi=LhC1A2SJdk{~(QZly<_$3^X3MR4LE6o#FB^tp?F zslqmSoEXF1*@?M9_3m5^5~4=^%tpORRQD{Y(dN&Qd)B909@%ZK(A}3CQg_DOABpeb z?+{D$pe=Qf-?(3^KIAQjiIlb};wM{>2GNnxs z-!z zgZuiabR8M2Dek_6nVt8uzGO7I!A#`|Mxfm6JzY$@u9()J-!^+cP=+Ug`$NS%)Tfn= z<}!{Hm~eh$4fh`~K6Yf^XD9nr-B&K@s`=w>#A32_Eh-G(vB?%7spSNJivG>)X%PM*Ht&xak1V{u|O2Bc= zia-RZv*HsK=Pnjn@SqW?m5UoGD#>=JYZ7M4GDxf|q;By>=a{V>B?zWgO2-sPT&Nk3 z0&RD<05biJEvfpuv3XaXCH0I0>w`-VZwPQ?owSo{q_Bbf__o4^=6z_h%?X;-)Sl z^8bODb%={&oW}G8730&Rhm22;qhie;H^J+mpktmaQcwg)YPrFVN+;^6>iEpKAuEDP zX}a=|LRVU(MV~&tc0;j%i^0sBAcSaem8%B7VuopOeb~p*$irfKY+9pU>#?8z4n;MI zgW20$%&=~BcNyc?#+lx_A0hT}(wA1zc99ciRVbH&rMM{6xr6CoQ1|Q*2n@AlW0!4^ zTJ|oU^n#K`&5ES4ZdW{X&gR^)SmjxW+pcv>>&sDhO{if_-Oky4TVF=fBfKjoj1B7K~?gwUL34Y!pB_w-8P)fha>@@5ulGNz#Z zMKjN$sADL?+QV~k3`a5Zl~Y|xnzA0hA^BugzVZoz%hlv7&gajWBaf!>>R)l!Xw|Fh zDf{yg^ID)T?184Njjh?n384eZW6lbVXIacTD<+#aoU7eAT~(^Ra~hAEOBV-w%ylZ| z8|9rTYjuaZv2x}N&>C6Qdu$PidClSE0FBngkYaATmRi)ay(v2h{F*)ZL#o4Sv?(^l z>p~nP2d71o=j1Cl660<)HAH9NeWNU1>54?o9f z?doG`@TG5-a(w)eZ?v=@;`={S1+=<1p2;7v71$42FzCv<)5vNOgKk3T?z9Ao)3|)H z9{;jE(CydNTj(;+pWyyp%F9{IK&(+g_;ebDxyu_1!a#h4d!Md~LtWkC32hQl&+XyL z%yeQmtLtGdGA-^h@9sv*(234P6xZmk_fGn|DBc(k?i11uR+N4VbUY|6H;UD5{Z!B!h;LV?7LZ*U8YQ^KsbV91+g3x_c}~DWDoDpn6XJ zzSk_OamHVo)lJ8&0~o;(X0QF7o#*2S&eE(ILg97hlmaan?q=1dKfaNkMs`3>{`7XGmFzZUr=h2KzH$@60{O!+89zktj0e@yt{r12tv8x`8Bu) zr02ph7s0x2=gmW7)z~N9?*2AQy*TXDwjJJK z4P#Zq8JBnGy3ZL#LOYems&A{<5lLXb^r)yZQ}#R_L(Z*jSrew!xvx_|UF%uKv4F%K zji{L*kH-E`%qH)Z?d&a}!eTW^33Id6dAPk;mQ3sKU2kTE9bDjj$YB$Y5B3$ zNqe)h+H=(tbN8q4Sm^~7^=co6S4FFcZ#~SqS1hRGT6<6TYdue#thB*x z?_iM`b+WypU#yYkX(9vzINUY?-G3#nbbAE6A7k1_!}j+r{jNAfMXR|?T2RpUhe#&f z^Y~eWlRy~qO$HZ+&y;sLA?h*N#ND4iWLm1=yl|DawvC5%?dCgQPPnCtd7}+8iO`ak zgMPgZx&N*^ALn7N?P);PIMfJQk@lr&Y6iFLY;$=Dde34dDu0>t<`c|U{%#>Og0sui zD%%7{vB}g#V?ZWc3E-?wk;)u($ZQ9L{1z6H9YAzv<2Ig=_JmdocbS9#C@_mMtnnAK z(R=e9Fx##zy5Ex8-yoKd&02n)@rbGm;OrqzTS(#jgyx$AW%yscHMLr(2a;E6>b(b=niAUBLf#l*YiMs>%dqI_E*x^Y|8*8sBBtH5~jjHUsP`jseV zqp?@Yo!mo7iGGFDxuK>JJKNNTYD6zNbx&O;QrznmL^&^LK4FaFLgX^6wcAObV9~K^ zp>ob?WI^?=7FQgd%~VGIhvny!b2(%~%b;Oc@7?`-Ed@G=`<+R((Hn(X)7~H7`CZ%> zq+X~%f(j%Cnpok~e5Q^OZSu10%&A}2LOIb|ZVm~xqE5$Z){uZ*Ek?q(RE1h()dr2Q zKTA^gN*&jo{1LL*-!GOAhL+(e;@M@3$gs|=7AEuufW2f5D5tNCC99pChnTZBr~2q- z*n-Sl^jG|m`Q+w}1KI3!$`?vvrlBRq3ItjI#A3V1uho8j5eHG@%tg9-%L|d0`yphh z&BocNdRD+fDcZdA10IQLUUU+TO<`qkJnLc*WT6v0skGg!w@3YE0!sMH07V zeQ3&QtXrQL8n10#NQ6-`6!P6v%y(RBwdf*{JVJS5PMAA67z=acXXHiyEA>h(`wr)K z!%gBSa@G*#vPLwlN+Gd>sUMnh_x>7C)*1MIYPLnBbGK{9=Mn1(3Ma?~!A@tKGOGiD zd-(-|{y*MKz=8+}ZexpS3TeBadqr6n)qC>)Dz5E>&$4vOJS^UZ+QK_yiZ;N?j=(2m z*XUT}mV+TNbbOhz*VuICbux#8o6sK=&ekT(X(0TajWU|i5mK37lv1HxZRLFp>Xf^| z8`e@1a8@o-6NT4OSu=16Ke7hF+-ofnuPu<^!LeLDHrV_Kz|A^CkX{A=&IjFw0q!o)3Oc7(?c?`J>a z1Afn6i7G_v`RU$qSY2}i#q>b3Mw+8Z5_~ZEQ2Ja^j9a9H7j=fNf*4{ECc|dd-gdF&7P)TQ)q{*u+ zX8&RU{olw?>~IO1W@|Fqe+%r#__UF1D9w(_3=QW>1zSIiFl=jCa^9o83bLV|-SStF zC2+uF18y0v0wsU^nsK2)9HQBgv3eAMW3~pGrW7T+vs}YJki5RpZPv2MI9G_JOByA} zaS1(9XA@OLRK2^V9$)wpllS$#rKHa(Z*aGSR%G`j%?Q$%*u&0E_j)~=iByE1T;r}` z>$q7&jzO@@_|7Q@#9>x(vg~8GnX5JSS zl*+KCBB|wO#2Lx9HW5v&mXC`-GK_H4g@^7~t!vcboL9J?P^N6{eUeKy#6k@yupFx@ zFC0pYI|8j7D%F%bPx5PL z+hqQ7oz?1FfRU3khVCMj&e>r!CEROmBNC@{GIDS^>K%Df5M>=#)CYp2qKQGH>bdx~ zO=FJ}znyIwBtcroK%n+gyF*sC*kIgyWQVS@)wQ1P%B>pb={fB6;C08@WT!}zYSYkCs#c{;hK)L?oUi;JFrrEE;7m+0 z)}}_Kc9#&ACXRLQ2JePTq$}HG)CxL(wh6-UUiJ{c#tzMW2f$wiXwT;JosKBap3P9( zrB@0YZ(wx^{c;koH2d6XJSB#+_jI?^gvDiV_(L|I1m; zWgZ#cK^&$~LokJ^YIJ9ez#OV41K4xC(Gt*(L<}Sg(EWv_Vec)futLm1pG;q=KH1>C zhQtAOv*e!gTN(kt{)i8kWpG9UdrAwwH?%|PHd?bW+&h8bvDq8X_6}i`CHUW?hL-v6 zm34}@7VpH?vq{NnENX+vsmW0R$w}aJZbBoJ??&> zv-uB!E~-4=$8Ej4)7?29JW8W!t!L0x#WT+tnGs)u+oQF;xlV~3h4mD?WZJE?7czW_HRha!j={;7%pR>{6t8+OOp;PQd8#G?6njSFfc+iA23Bfsf1x!7 zDd_@Q87yu!otteoO?n010E{a9E+dB)mlV>MR(qe_Tmoa>=?nG#F{GB^DY9w{koxpK z^XFigxK6$mnd3zHe6DY-ws)dez6%PT(S8CMvp`#XJtHhyncqXKI&-S)!82RBpIOm~8T@`AAW+I_o42-cYL~ zMrY*!DEM#`cFB7G=0Ocr_W>v%d#rotoV$N|JMKmS(pi~WJES+`E|9>9T1_BUjtifSfbD>3hnJ|VXe zMM;Afm2;#uQ@PnMXdVScJA3;FH21&+WgE)$$~XO#-~EqI9>FJ<4QY3RH)YSldorqB_7p^?8(gmV8!qQdNfzYpzbR>fSS#}<{z zO7>{){tKm_aMbjS2e`LcNpv}qz4cFxdg;2(W(#iK6Wm?8udmV#e^p$pLGiWMOi!5Y zfExE-wb#s?gUKNpS@+)s`%@N1(_`*{5cfUZEg50-^jPMOa_;p^U)N`6-He&D@gX4< zF3Ip~V3J5;NMAcWeeFyLIt6mvb7>;n^};m$q=g+MSo%o=qtPO&LeXDGala8vBWUtu zpQs_XNaKyA9R}|g4xi-x1m%EHwhR!Vcfia!p*z~SeF&m8N_i+l1A&V;UoH#`#*!F0 z&?>L$KxD81m?+5^ffd9YBZyhH4!QN%t25GAPkC1=e+)x8Mtbvwp(U8;9C(ukdtz*8 z$v9-8{x(!g2*(cp{(*_BPTf{omE?YPaIi;fMomZazux;+TS*|@M<%(NduWL(*@x>9 zD0ZQxkJNH5n-v|=Bz+U|@_02{>E55WL0}qBmK*?IFYrUM_QDlO#?=t(bOtCdnyZ;a zk|y1bRbI+$jeDQW&{8m2k$1i#sbv<26$|XxBLA!1S|97inLq%(el#mGq`v zicMi&iu|g3%0)?y?$zigbPa&+(0w0c5m65JQW}BP>IFI-7t}!cerX;>6VsiK=%)ZWrSs%HQc- z_kI7C7u<<(|C91)D5Zm#H)Tih1#|5^Tr*#}_&Tvq&y+Wen0V&QS!6W!og`?i&IoB~ zl=>NNUpr%Ff^C+!Vs)P;rp2a=!*v+`uSQRgS9is#ccU;E5#*);e^vK(JTqW@qdQ=@ zcle8_k#=f2`U<3FWtF)-=#HLUJ9_5qi-lZiM{LTL*qRTx+Icp9uzm>2(DV0I*W77J z%!iZ5vlYnwe2ScM0V7;>>h)TD3dMoKx$XfSEVqJbg4!DBuH=Smi(B678rYo&^qbFZR$xsA~Xgp+g`9gB*CvmJES$)0jEn2G;D=jbQ zd>g!3>;)msWKSkr*XWrhGw$55&%8aDJ5tEB3^X6=+MoTQYEWx5TcH+d zHX7ag4bd^}PPb*_U&++g6f5@m+8SG?ZY=C0O5r}}9mcUwjd3SLPV6Ei`e10ReeCJf zhx<6NM>!e$nelafWje;fwJ9+-C6>??8KNGDvNDZjeq&@1my?F6 z5fBXv&AE>dDRKPF@h(dG@Uh7dM>4wRE(EN6x!!5>4oO5Ek<=#dmp2$5dQq2AXKFE$ z>+5N$OAVv2erW}iE_$PM35$r=IQSCT)7>f^Sv#jS=V>C3wuex3=w8sb{y=9L?EpDt z4auAvkrj=$*pQ~WH7fpkY7hP_&BSNnhc&f@S|l35`-f=3WO*+ipNk2N_u2L6>O87? z3KP;Ba2jiMu^Ys++kEG{EF&)nw*N%s82rbxkOUKK*rxp>=wG%>B_Ndo}Yy}q06|rbrymLt7#pQ6|sU%=Uk8a zo2lJ&*A?rKU*zSV%%e7dI+VRI5$M&i) zY74dgi1+Ya!&5wx<;`Etr_#4y9Csf#-C^!#mLGVLk-4M!CME_b_CMFyCw*7LsJO&-o->MW9K}OTihe#F=X^cDVGo?*8(V}u-zV)>}og%@&reLB66x2SGDEp?W0zcnse?pvF_=W(Do{o(dtHXCrDJ55abXplHe z_@&e0+umW<7*>3t6=W*_iCNm=<+*4o!||-mU%I zWEJxdat^$r%Sgz)nv#v4<1)5+WIl&~?zH+~qxbJOkR6{F}6#n=Job(;B$|tI_=zxrZihNUbu;RxGZanN`8tuiz7NSO%c@$ye_B z4&Ta5GUrFmcfX8Qf8~4{Objddn!~Q;oNL2q) zAIV;d`fsHE@=Qe|QVs0WJBjrC$i+l9rk6-7!nUbcR8vFx1!-MUtIYmEqQNd3+j2(h zH!6(hN*oMkDlhU&xIxX^J(8lGb7f5;eL>HL_5RNB=E@D8mPbW8*_{Akqh(!f)ph(3#B zN%)fOkJRi^CTes4R%-STuHPE$%eb69sql;K)fv%b{$M*Yg{GDoxN!2o)M}~O$y+vE z_Nv??p$DhtkPbe)P6+*BysN`J4+BS*MUyu0Ui;eN{p)w?LM>V3Zia8g=ky9>8V=5# z-8#(vL3#L!K+^*aJ+ulRLMH8mb+pD(Sty|z1 zspSu8(6G$Jm3L8!8G@YSQU1$w)$HmUpB)DVlG z+J3dbpRmd+vZxit$XGt2S-dl>F+6Kd@gfcc{a4ORQS4*3*jct%88BERQY)m2cE8rddH?et@R>PKl~fJI37&zRVh0a<4L)aP^gXFBHSc~?n4L_wHSZRWG2ZM( zNJ<>{8f&-Jq@kjx3-J9d`TS}zA9GYa?mjDqCo@raPd(Qnp)sDU;DtsNBR$^L3Zisk zk4IY9dtbKrN6@&Bz0AY>_fE{W5bk_CCSN>=gp1<3q=8CS;%+FY3{9` znr^G13iaV9j4#B2vCMhX3FIXs^z_=@x~Vx`d^q| z{K94;WSr4j2X)Xge=#j{0)hJQ5s7d2I3K3ka&E@d-;8}mw$BP`)EpQFi2*>WBlyxq z`VxT20#tctN6fg#LPu^Wk4XNOB;$N!N`(xB6Ud$eGWzTX_2FMc7?Fufur5;7NZmkc zF^kJ+p?ccQa2XB$tMx^mcJR-ou>YS{a&N&-aF}v3@15WmJ6UC3=AwEw_sG}`>1Fz zM=w1ZRw}n`G7mA&m^?wT(73nGdM~6`FBFjbPFgjw5~vR?U8>|-UA6w4avMTRHTa&m zO-pz52AjMWU!nPEEW#F#m^*&Dj{IDEHeJyCVv6iYj+aOA?|JFv>nPEXl8?ZHhFJLI z!2dv^x+fBceuZVDB=kXzwz+xLFB`vS~N= z`jQoIsfsdrS@XlV%QB7q;m^jq z=8_uc%Ym~GalYJV&OXkUq2zvzZmI_Mo~z&`tQXv|8J#Fvw7&J}d0H;#dgt5pgz^*9 z-3Rp=bzg3MeNIS_D_HfF=hxJ|GW#KwA>abQbnYwrW0B5e%VUe+olD8rv(isA7|MVjpqV|A=g; zJ$Fa~hst-0t~m_2cV?DO9V%X1vBx%|9DTwt2@9lHO`G3TY`9&XMX8bRh>VqTrt(=j z(VIKTuVL~GD?L>i^!KbGi3ch1w~L7f+QdUh{0(RtvMG!o)Qt=w+q1Vaeol!w%k6Tb z$AamZ8Fs<+#l>a`bdVig2bsDW+7yLmuR%>%BurC&1aWJ@bYI*;KJ8u`q1!k(aeeb{ zS!E{Ab<6&Jk;W5qd#Ix9ecoZX+Kmk@E&Dqm7{gQ`r-YW2y-TpYe)wr4J3{-CoY&Jc zO{HFDtznwiiiN!YrC4*E&oOO12T_7lgMOXXIM9fjj&TC(KC2a!NdB-`-Ih5L*>1VU)YUs% zc%98RveinGzNiYDHED`T9cuYRABV=0vfO$jX|udXmfSevXPu!%#ux9z>R!8jXxx3p z9xHg$Pxe>ZY1wd<{F+Lsel3=sP!&rrP~qrb>bA^&HCDaFe9@Ux#no6NKap1Q-ha-2f6$YZDFCpv*d-B8RrDZwg`@53?~ zR(o2P*%Ub#By%I=M@W+xeqGrf_gClM_if4nHf0qlr4}%gl{p2dYf}8lf_^E`dtq^I zrX@r6?m4n2PVT)pU&pe?>utX=!4mvnHJM??blUO7b@>ry7ohTo%JAle27O;6*kgng zxOY9o6WL zO1#x}if4_*)=am$)LVuU9NIbobza!WL2Z<&iR4j=?Q{w%yzT7T7J8vsx|+JR39Pz|sA4rVg)POHZeWUJ9iE~o$&t^n;A^I#c8r9RD6GQXv^&pU7b8sywZ&J$VN$KSG zx9e*UhMha!$sb^Y*P!jp9p>aKlfCORV|V8II{87#3cX5(+T^|S1>)pZGqu_+p6=6a zMSP3ciJ}kNU*< z8epN;n@H|!U_}pEEo*#3VU8J^`wzt{)5Nj9*A0k_6=RM%Yvc}GJ;HRcN4rA(zrowQ ziuM~bG#S zs^g}K+wn(m%S_xCsHoY$hKb9DkC-{LV%3%>rVF4urh?Gi>nuY1ynu#Ue79h)x0iJ| z;3{e+^|f~=zRS1<*l^q)I_cc`ly{h4-amflPjtC6Q!BN_3^Of@5;@+T>$BE6C52cU z{cYI(O@@;V^ou;4JeI#s)-awXGMLV=i}=HMFM3TaH^xH@WG>URMo1j9X%2aCrJzvxvb?nGIPx^o_BR+u!?;npwPh z3VoIyjeTOl-Y4_x;Qqc3(L+j=zq+Qn=8K*fX#LTpvCz z$azNTN9KM?fr_!eA$?D=sHzJTrxnivDSCj7Bs^o@2{e&Pd|F z=kwfjbJd&4887BcG)N$$w|~D}6Q8%@Zdsdd)?9f|ta=0AZSQp;3K;B!KSvr{x;1+@ z$&4QH_wj0MZV%@(xk|E-n*DT>JacJ~^#2^$;ck_!@0FRRGoayo<(p#-!XrBbZA9A} zqBF<;daS?{k)!KGJfDsOkBk+8IxjeW0g0aRzjDukPpN%nQc5=bMhsK3I<=R zldzRB-aXt{FYo*xh$?Z(=dqr+mCjd_42Wl*Qnp;_c=uE8zzwykHF9O9?35IV@|Az4E|fSdU-=1d?iS5Smm(cn*{yl1=x$Rs$frU}>5@3tp^z`S zT-Z%@b`DPT3oSK@<*Rf3RP;34W95%ighk6(1W2*b1RL~kBfjRC9*UwSeX|YYI%znX z412!Q)IBZ(l9Rpnj^$omj&inK2h>o}omXRK^M~RX>FPI&sPqn zR^#29N0?4ezL_hdq~sA+T{VL}5=ZReWgtlra@C3ZC5PUR32x z7$v10G6c$*KStd#6QxkYAO%o4M}>i_7(gG~9!F+z@INlh+v zW`u&V7uY#4dG*x%x~b8+_d;_o5>xT(`#rwkOBmwO#8Yg(kMp zblub$1rez8pnT&$k3h4S}W45a6mjwx8agms4NWYMz7i^-|`8t^F4gHrSPk{cNT_v>juEEK} zrCO!Ke^3u8gqC)QYULK1%N`=Dk~vwq)Sy)pJ^ zYT4B$APCb-TEnJI7{k2!^itVRceY728SF9(mP5cl%Y}4|yZg1ui!MJ7h$@NcF9*N| zrFNZwqupqz9{a75#{Altvo@Ig3yRP6D|BX$t8dnz!TA+C;?XtPavWzsyj4-z(7&=! z1sRMXhIl5U@=5zP2WV*5JILZ)#8FN&>Ow8FXC4*ADLtBg8c9Sw+n(z|2~&>ZP`TS> z(FcP-mL&mrEbZ_=1_H((7@wh~Vwr|*Q?WXkT*5auUj@wN(pljcx*vtehG>3`w`FV* zi^tGUg2mG~qAn2qugD}UF6oKIACC+&v8xkkJK;m)n#Cg?#VjfR4?9@sX}u%JX82FZ zWUgJcVn9YSxK{g}BP2gPGQ3GseDjN%>5Z9#QCDAHTx|4M4{~Ux?63*SRZxS(+;hsQ z+vj#u+-Udg&at<1j1fl$SqX$eO0Lq*R0Nq$5&>(FZiijn>rL)lwnBgN?r~HuImR)1 z(Ne5;+(-qVe{{T=$@pg5_tcff`dZ)h+RO(-t?%*y`%$_a`qYQ)dVpoX3^c{QYOoIm z+|9e?`a3xR@p%z+iQZBcqm`$07wy&f#X7}eHSBD$B;A*!-tT^k#5lSLrnJR=X`@oh zO^uTyNt?W+h_UxhgJ~Y*FuzfX$4E?58LaJ689-@8%IQCOPeiJO_)shBQS)HyEiu( z??U6(;`at6WA5! z&V)oCUVorrn7$f)l|;VF2;p6G5vj3nX8W!x)FvOHv4_|mdi$%d^KMJ?$4o)7(lz;Q zeC%%|#7IYGOPjqe)_&PTNKM3hL?jMrK+A~U|GOg4jo#6}p;I9BK=uoolshSOTGL+K zfCKf1U{k0k!_UZTeW>LZq$7Z}4x5u^6Dj@lZgQQlkj%4XWzbu@=p41~01q5fOS}Qo`$dwU&_*p>G_HOppd|5#HQDC^R z(8(=DY(?kcZq25F`WSOU345Zia0Ffk@=hcKSYmqP_~y;@qc;T zKHRp`FH30Zt?-irY?WWujC0@9^qcG?Rn=QKRhjK)=@&;5(4CC$trE)DJv}cKR-@C| zi%K@Ek574D{GHq9*5oUXxumeX3ANm8N^Di)b29^~;&q?RI6AgM@-F{bqidqxajFar9zeQ7L4P(@XT0bKt$;JeULCtW~sA0(gyhg*llY`rXxsvu^ zA(qdxD*1D+w7&hAc9RojV4Z~(^yE8L!eV2A5AjD@;1Mibx)zySxZ;Gty(RQyQT+BtE(GK%Ri$m z)=I07*_q7!h*qph_EmH7lK4W+4N^4Yka+dKX#Y`FiGA9+0vAzcNw0lqy?@YlRJzLl z>?5DcL?SVs_B+skM1^B7r2T$-w%>jjgkj-T$G5W*R&;$QC_)FqCT)7bwv`!9r9G4M z?oN{Z3nB*9LkkVPy+uHj_zCCovRiD7Q6wH&U;FezwSYff??ar>czxqZIFU?HvyYS7 z68d&!9t{P4x_Pi!&xB6u!~mT1Lcu0(>U!j+vgv%l-OpUOL|G z#gbx^_lvU%tmi1cZfm=*kf~HX*w-PuXyF85$yng(PM5#I>=(=wdGitbDVXy@BI?G> zyrWlseeOoJ!8PxQ@o33o=9L%8@{JWroao;DIGHoiyk)Cc7W)&=CJ8}&|LI@(-_OpW z6pLpCS?tI2>s3Y2-Ec9rm3ZvB~l?OMi=D?6G$J|Df?pq4$c8!`apBb@cnZpcUM zeFN#=4OzsQQ6Rfu!gTn0zF(Li&+_r?Ej%wIBKsDJ)CgB&f=Qm2l*dl8AN;{Up6!No zY%`Fbc0(p$-$|}{-H^+&268))`KMw^*@(H%pZ(uwJdZ332Bz?PgWo>54|%jtFfgY) z7-Rjr8~HuPugm|v!&AbI+3K%~O=;d@rkY(V zb>1B1A{*{oy@U7B#=6l{)kr6RShm^QaU?kzmV-F>eLMPMw7KTANLa$3?je70J`;kN zLydRFKw7YRYw|s#r-Ie^iL9VzzHjVT&DOo|FH;*_pBcka?E7>s$S8LfpDHSn-YQX> znu)`&!O(t}(?LA5f54lJr9oE9M=5ghm9-aY{5xBSR+jTS$8!8~D10c8z-=nZq9J=G zsNtw?V1+h2Gv{XWl_kXb?k%gZQ&TbMmo7kA!8X=P1+DP~ru*phD(K2|Z@!acW6)2$ z$Ry@de)@dn13;v3t29WK>FiiM{p>bjn07op+}>u7%vrV*mQa%H*Ok%>>4@6o&FO-A zJSu}U>wjc4MG{aMMa1$8RF=z;yp^WV^h!l%e`HF5U8dEf)L&WC&Uyku9EUP~nV(Ml zZ)Jk~o`vROLYe(TqXKWQf`S^;6Il2R{6L1ns*VBb4QF^%gy;$bU#t*ke!OW_nI}G+Xx#k7TdRG<4@w*- zO3aj9s7I)NEfx6^QcU#4)@2*$<+x|S7-h08ZS+WF2^-?w=#@Xl86fop*oRtLd2vhe zt5Tb+st^C%1vhh|{bWD&yFX(Sw|6ir56p${QrmTa8&2L~%5my~$sv*g#?SP|on?-0 zfo^4t64>~xD@hJl)C$qIS8e0>BfiQ1!c1Ef=a(zuF4q-sw)PS}X3j4*xq;`DRvIg_%Cu`W;ab+$d((g6tMN*d-Hto^#Y%UH*}15d5wf;OivD= zLQh zQEH{;I#dqEV0DS}HKA~u{)SpV(%&U*GA%yC(ce((+x%rAad0fNU_05c{LsTY==-)V z%S;YOR1$8}UrbdkNYZw=O@BkJ_wqNjTHoNihTby^&}pkQJ-k=1v88=qsh2pia}KxZ zZ>aTRK+bAu$x4#nE)KkzScrjctdg;D5z4EVdY)ODkbtUx?rYFqlfpuAK5e| zCe0%>CO3osi==dLvR{38MvPkx3DS-+7#8ZdWWTBPwQXA2Cccfes9vVlnp*(4tA~_s z+l7E?9sR`x9uVp9PJoP50KFe-xnBiVcZ8NyoD*6yAW;2UvJV@Hi0z-quoufFKKG!y zt-(EaW<$%%Gcj{++e(G8xiOFbnzxR;q}^uIng?lzMrgxt{8oR```wV(Ke}U0FgY-_ z+PMA;wIGaA)&k+t=)&Ol^Vs)OT>u;zP zHKJ-RM7Sp;h?CMiJGy_?cJzUyb5@#;PV`?K6kpHw1qL6#&w9bd^6~Qj*Y@7PxBuVU zJF#E(M`ZBt;Nl8qVZNlroXr%WzCab};wHe*OsM60UNBRbWWvZvm-E8c6#w7JCu|cb zQ@nb8;ry-N|K)qpT7Oa%FlcCj_*_r`l~#wRVcP>#oVH*PE5Qo?1&ww8x`}&UI$=a} zCrM1%=pFWBRsgHX;@>J}-38~K@{N!_ovF4*@5KFievXeHAxDNB+G}lDzzdpOj-fC` z&$vDA{zXfZaBc=~pe65<_S&+66myCHk;M5ix5aqH@5HAbxjEjN_^x0JDK4I_S{%&X z!JN^~(ta)Zcp!^BBB5MTvrydH0@S05wQEEIa_=XVn{cG(fJR0GM96 zKCZc9ZSM!yvHt>)-H@#9Y9(Hx|eH%5?MkxjIuYobauN2t( z^M{f#-06*qJHw`5M1Xh;JF1voU~ish(kpMivY+B?K_IDH>BJk{^}Miu-e4jXz_4AB zBsHP%%8o)(-8Y`ETx*jmKvG3ginuX3Y>I_S;kpqEQxyBlz|2l3sZ0d3{lZ4|+6Hd~ zdQj3=(R}&JDK_&60wlGt^DJy9avv~7d2gU5W)^Ozd&o-H^YevNqX3=(E<_aA_{KC46PUGy(YC>A_PmH zSJ+T5y$&E-Yw{wOd+en`qWNsT(aJ_=8vF_1ypiK2{b4;0z zF-iKdVcdM3!WjG8Nku6%tK|CdqPe28`Cu9~=%x=KfQR_RWGy+X_2(iaVEGO1&zL?( z%Fg72D5TU9osKfmV!G7_A{jzn^}&dG+(}e5xTw%DbX-sc*xSBLj@Z6AJ@&TG?GK_#nc+tFj^s}mhV!VN-^4OB~;VXY)&GmMp?ey zqFn9;9Mfc>&la3k0a7NtTn^c%uWi!%Cna_Wd>1ome|C?%k;#%=`oSwP31Me=i(!?S zO3#?9ZuUmdIL!Ta`SE-29sHcoGU9#t%Hii|AU~-9u&oAGVPOgYs{yTi^vPqABxUAjakkg_Q_g_D7={T?x&JQ+l3P z~NyTUvv+WV|qRxCYx7G->i}%26w-oKyUAj+6b@p7}R|aCiPc zAJH?vPH%(suTB*5be2AInboOut5h_Quu(8KO2pk*Oge(n#{B#E$2DWdAKwLgOsk|T ztV*l6s*;Vgg*2LcZDj7$TXgvV+M+PukI$r13RWNuo406a-$*J{5u49TY<{RBvQUtP zKo$$K7)Xa89YD4SvIWRCLAC+eF39#q#z^w#rp$*YF&w0B-#`rYj8rtHBNfqQ>%qjk zc8F{ZK8)jq!2N1`^%ti7*ls!HF#M%Obk^z!^$!Y6w1NEqXiao|j7u)^IDcGMj$hN$ zXK%zyyB0TUshW80&xbG!@sM}K8KQ-ZLb&PldM%a$u+0Q1WCZU4GTAnd^src_C**9` zm@P*yTW7Tg@0zyOpYHkCO+Q2(@|9PeZDx;|1n|NlnEvG}&lSAO5nTUNCUg2;{pDLi z(>JD}UZ^FdcE9^mU*%7;r_a5|&Od_5k0Rk`3bWumI}85(EG2oy&VnYg5DGtIWkywWI3sF35@Rk)4`PX}agkd;z5HrfYVk}3-Y7dfzXJQ4Rhqx zZ{FJ|Wef9sfk2D(F^UlQ>*1vVj&-F+SD{bleK|xA&5RzAuk1^3YL~N}PXvRZ3d|f8 zQyQvpcN$E}Mvx%1uah!Dr;{Qhsmc{{%X*nOcfO5#h&XIRD~!KVD!x!@_jMMU*wNF- zHo_(prw;AwF1Dcn-yxIKx@0O>XkVwphAK>)gQ1f~QG^gXVR`ayF_6*IO|Zh9M6hdg zlZ|w?DdcP;HUEX~Gy`~qPBVag-R%IVwO0AT;6M2~YYu%@TNLfi-TeJ0AF1Hk<*)`Z z*}9zLcpF8Dpi;%FXn>3P(hhb=e7#;}bJ>9&osQP!!7k@<9>S{Afy)W-YaWl21WMrT z6Z0m8juLe_I(+!)m-)}zox6BzcZ@)nc4XT_+blM)SNYrJyun}L(&cRN-`bt6ymdN1 z(TAv}i)fPm!051Mq8vM$Su%0_{Fr-sYECSGDY5%NfR+}2 zSpQGTt9xk%Og?Wtv%m8yf-{qZcPgAOG2f ztK2w&uwn}Ww@?0mtQB*XmNR)kx8Ia*;WL(Lw^BL_ysnfML{I(UPaWPxm^fM22y)-F zJQxuR{Q+ey7d_A)c9C$UN>AGn%NNQrGY`&PiDbTzMBYtb8Bqy}kv>QH+@0Q2zd@9A zN0f6LDpOC|32W$gIg=YL8CVrGaI-g&b|#5CcR48@bfr9`Ab-2U*mE%M;@u+hr?9GN zRxsRyWda+#dvpXzOM(snI1Wf3rWUPnyVQ&k@k_(>yW3I(Vdf`)R(c2CKl0`Feqpza zuP06jyHXe$6_wN{W}OmR@-i-iYIN^ld&thF{&5kTI{7^_`Fr=tCS^U1^zFip66Ik> z226=pzUdALvBZ+(GubAKp8CQ8bI}Et=WyJ0FkG?ZnJ3tc&*3 zbDvmkKY4!iXD=Gfd2xg$EopjxcVIBE3|awMfW`G&LB3PZAe-YC30c2+_v<7K%{vrw z;t&FVowfgN-ulXtrJMy7S{GW482_{QFTCA1AsGI=h>+ z(b^FqY>S*TX{c-#K;snAwn#7gZjbn575{P%K(zq6hPP0{2mzkx0XS5E2YLVo13-!x z;E#mtt;9KxX;gfgy`e|CDrLO92VjT*@g4x3xTYjbH8mY;eG_Sa(qub|RB}s$o-&_a{SKPE7iOrd@iwn`yRhdRYwtr?S zc!r5A4=r8O{Jt1T+Pw>K+L29Q_Rtiql(daP;*}Fmo5@T^ay0f6h3z*FQ$*CrcKZL{e6_;UCaqf zXZJG$Dmw^B+G$bdz9zB)(X)U0$q$A77g%M>dv~wl!FK0QFxVYyD-yk(4?cBXDRDmd zv%AqhFXpbvuaOyA$k{b?_CJ@2;5~dj|utTmAsX` z14!|^|M-UQe$xlzWJ)hE`Ohwtzg|Rik_m~X4>07sXn#Zr_d+2uh$#BPy!TTwpEi%v z0N+Kr0^oS1_Id!06X5M00C`Zzb_$@1g%y$~szLz~0iFP0DRi5<@1a6!PoW}TO zMHGujfNoy&dXF+Z(4&Oy0<_u^SS8SNX9fc0fjI*Z=|oYy=Rz`s#gBslL?9AB9j~Fg z8_8Rk{5$Y+m9PA;#)u+jVZmoxk0wQC+QHeOJw7{19kUMr+dkVxF?r0;OgCzR%zjn~ zoubfR3L#G^-&DwNg0mF;Vh?~E8)TpD0f-9lvmO8qmFzt};67RAWPu%|G+R0wZXSY6}CuU8nH3gKl6YbET*FH)F-3*mo43q$c_!$)x-dxVlyn^9B@~+9 zBXPR`ck}?H1-PLH;D-WS-UFbWq-?wgV7>r#02;9!NH=$ggC0k)dG~WitH)m^KGgCY zf1B6-W2;V$ETE-AZSw{eI=%W;+v)QgOsBtE==4UH6M60=Xxf|B1o3&Pq zp)VAn(*zx5p^J*poe+(8l!e~wLlJ@pL~xxg3#J)I!#Pfe&Wwwprr6_kCMtmgvWI=Q0?;ky7%d(m?6DcF8j4|EtW*Rgk zpim>QP^#=(XiaVHXR4kTT2wm>REf$(I=?9fw~1DM)}2SytFn3S@}Y8loZ=luzLhU{ z@6&r)sA7X-0X1t_3&=GFB9T&LFH~yeOTCXNmYq`BFHSI9)2?Krk*~8k?2(8W$@M&) z|D;?p3btGYhU&A~GE)G0HLOB*!D{G>KZiAoaX#fG&0UETjD-w^aGJ*}#f}ohRD}1% zk=$vc*4LDGED_mdwt%1c1H+e^&z$Wmw zY>M;z6i3(;1BJrH)x@8w_}V9hU~+KuH`eK_Vy_uN{cYu`T)uJ*{KGd>P5K!U*A=Rx zsty66sA@!;3>-H^ZSuDFIp1UB#&1?>OfXKnZg>^#)Hj|vuYZ(XWDNN>OZoWs1ADYj zKT~hMTg!K|^I-B|u}Zyw|5Jfx1G1FWUPj~Yj+;R+wFnJ}-afQY9e6WC-Pxj{9xVnJ zD|m7-&oY&?m^|z`>Yedx_@X>!WcwF$tyiwEn1>i4Mq#WS)@8I{zS4yQLw5=wHY(DN zkSbwwk->%$q7ZGXRN3b!hwYDe##tn2X2C)wbuHo#5@`{y(LiZ02I)=?sTYGI6#RZM zxJ>iHr37uk9k$?QD)?ku@L49Uc$HMe-tWel)*DeQVUenMU@^FmAcG;)+8adS?#9r1d zLKh3#*FuxUtkXq%Qwzc7l!6x%Y~EcBmk-T5oT5W5f1y6jYsWFEJG-w6wXLEkE5?2M zMLVN!;ZPQ0+;AR7-nBetG6i`L#0(-O<{LHIW4nQBRq!FXBo0By9;=M7Xfm<*ykwh@_qw3yZ~twU|v zbP+0!=Jm1A8Aa%NK|dQ~>UMdt+=oO66N-r@QxWe~nbLc8(^!T2@Bm;ghqM;y~09YDMC|%#w_%?BD7u5lPy$x61Lp=f*xX_(oET2 zov%vaPqL6mAOE7k)SUBpK6IzDzHg!9i_icK>}{~n(~AYxsM$4**spF;)?e5}`xT*E z1)Xo9(50Vto1nK^=-&)f{kT;#!`sE+cDQv`stAk!WPMJ%YWf_ExnpYWAu^u(^si2BmINExV@-zj?o`7bI;WvTSwxYRcsT zXIUS^EFMdWS+s(^y%C^!?HimcZr;5aJ{W4tXd*PrzGJv2P5R*!=Wn#^&&RBN6uhq(3==HWW@RsG^JGL2bV*7lvmAeI zE^zj;V!m<(#}|VO6~ye#|K=hEb!5k)uvo#WVsNs8a^!4drzt4AA{(5k;O8`q4Yn)z zVKGSOp#LZaW9stGVz5cUrN!VR1s4^9&D)e$$FiG0dR!gS;_&W#6inRYd{mk^#`)+# zRL{GEi9V}ph{)Y!5NO^>uH01nzFqH^G`i?cmsju}%KZH!O<2u_Vb(SW1Z(}hfx(Sm zKdi{DVcLrHb*MS+@f68O@006i-vf{t=a9_axiLXxhp36Ihng$bO`U)73Bka3`5niv zj$b3cpYvPC@8RlTU^c%W@;mrg((pTz-*@@l%&(2#VaEjn#}j`Rzsvb;<##Q=CHzh~ zp7g{Y!ShSX+YM|Lc|JNO80g1y7tdDU8PW`(Q=j6QBkgm*-XU%SzuCYh5ceFv`-qbl z#dmqW0(=u?oWuJ-VB3j*iQgOizUKDGh2Mkx&LMmO zzpMG(#IKyPe@3|}-p{0*q2zy=@B+d=<@Xiu&+u%=aOeSkUBq9)j!R%-;a{*sZ>7D; z44}9E_9^dc0u%f7A24vAP{qCz_uKz~$`G(YgNGbAapFO|9el{dLnlr=Z0N*^RTB>% zHgVz+!6D>JF%LVK*Pc-~%DzvW zcqT7rogImuGrGP(urc~GHm1K58z-JSE^gk&PvCLhc@rl#nV|lhkDbm2>i7qKIeuUA z>rY(|=2y+Hj^8+bm-4%o-$V?t294w_B)?Pny-c`_=V*Qx@~bC2l3#}3Vt(HRb~C?y zXv;Ff5Age6%9+gb2mA){`#Zlj(wMdlmX!7yTsGMJ>)oe(aNog$Y01HZ2M*q6@Ziwk zihTzUra^7I{#NoEG2>FTZK0a3+)APkH}0&y!9K2KMK7 zKkuKBuCbPH^K^(G3;bf9D+rI`ca7l0Kg_R#-&_3h;95!E3~95x_W^b&zmfc| ztqqPlaRbGuiJB1U7817^dxn{Qt}Wz=QS(Hjd9rCVi9Q%)Q5+U$ASmFDI~o#iJE*v^ zMdv!l8)zwE<9Cb9G$5dBV538>J zR`u|zV->`={TosE(0gQc^>N?s;cPjpKuXKG5cqdD_PX18?!1gx?uFGkE?B z_bkHh<9UQ<1L$Qn@;uJd!SgoHGRk%&a7}{OxEwJ81dbR{QcA}e(PxDD>)UU{2nOPa5sq<| z4?NJk2aOnP-k}jAG%gRtaoC8%<<)2Ch$BWEdE|(S5hIQ=9wSB^eM}{Tvueb#hc7rS z%s8P;)x3}5QF#~gp2zcZp5OAUzQcJo^WBTbl=r}Y|1bE>phf$7 z7w_XN*~e9IlomdCgC~Cb^zh-cFHgUHz4mqWKM=y^dzE(w4K(@&MnBnCIzYiedaOo; zQ_F@&IQP%upt{tY*CF|ljQ+#H z%!nOnIrN86X97Y94nYgh8+(CaJrpXQBxEISMwg&F{f?G46BqbDVr~Fd#Z0XJv8vSY z_Ow(aNOPSuXuWyw7y;UuRwbc3nWap<0Ac^@{k{36HpT{T4Gxn%=o;upmUI&Cz(~W=DkY!1+*hU6LA=H?`g`Zdh9y#@4j3PL zl~IBA^{9dI2-0D_#x_3ONFtGq&*Jb)72?6Uh-%%&8AS2zRe4jdg%QChPq+R=LI3P_ zH5l!<9V6w*=?zPzqd}GpORW;}6s+;hH3}r&AA9M5Ua}&+tO;f$m^|1ud-?e_4|7^G zpDN=LT&gH#>NEW#dvk3J4tpp@@hxw2HLd|s{n2MCD`-_NozOo7OBz%!eow^ zqHO7mV~Ptp{-%Ga^*YSDRVrD04gt>ptmyu%@;^H!CHz34M4#S-w`iyg+bDF9GG&sf zbz8JE%YGIx9qGaR+CI<{pz~20aDtKv>Z#o6#;%x-)`5)yzLw0KlE)RWw$)Xe5m45& zHq`~3$B%P9WqwM7l+pq1CJoeL6bkO1S*+n;m36cmsq>|r)YD*THRt63c~BsR#Shp} z?fJHvi-7^vj&N&Q>t-CG;pvOTPt!@EB+J+#_~^&!f4t* z;NAKD0pEa>6WM!FUJOtrgx?U}MzE2*1hrC0&!p;eU_SIegG{ng(o%Cwa9gzFo3ZEe zo-{__*cdh&t8R-H28feTtZ!LhKf|$ojO0Relp{xN{#*GYLb0y9tV`8m;MyYkrOJnn zR1sWPMaYK^G!E3Z`tb3!LC*ND@~$3aQjvy`Pd^L#LEoVN?Y@W7k<)Z2J+EOb>yLqa zfU4WDKIpykCqt*WXgc?m(8Tq~=EBzFxv4p#?Co8 z?!Ft(_8%1+`EI=Uop|wEIuAA5R*eO7M|@;QytdtGI*1|Ka8v$xr>Q?*vF!Aq^1uB% zIG`Z=t%3H_11}I*I*rq`g{Cju!(fkNg@zVcEqCwDzhJ-=6jP;j-g+DmbI}oFZ4k}o zb>8c*D$r2)ZqL=$Q)H&w^Dov@1gG2czl^85i9GV5f0Ub^vl)l6E@6E)Sl?}GX>3av z$Ys{gvwjK!zt*qb`Y9+M`kD0`V*M1958Y<{rddA)TUfVw0;W8hdy^qjptfF1z}g!`ZZWT z1?5BQtY543Q&2wir1e{1{S<_KS?gyALS~tQxaZmWN!U*L6qFC$Wc{?T$4^1|(ACy& zqxDlzK6I}2TVwqcln&}JVl9C|26aPrx%(~Lc@V=#QsfzwwaCCj6 zN2w!-J?GQc>0)kXntCIo6Dzh?3z|li5AA4Q*VxxAy|_M1FAF`!LK`2Hv@Dn!Pm?}_&&i%n4cZ2uj4#`(U@SLVQO#>Cn z;yy%Qz~(ZllZIfi*`2Qwk;ZCttaek(nTWmOa|a01XBH(g&nS?WJuW#~{+SkYgc1@s zRxr42;6WzPSQ8}E)H#02`A{hVnlEfT3%*QyhsHq82Z(a9WI(QO+po=>|Kp1pDZP4b zw?#}YaKezrV$~!&UcM1rv}U<@ zHx8G~(}8)iHrpXH4==>Hn;7)N2N|fCCUB?F5(g+7cfP#fdrY2nn+?i4QLY5|p#m_i z^d6S@0G1beU~*(=0+nvL1%9jmjGovN7Fb@;LmUN6=YEF)E}=Wxy4<0h(J{|R6E%5e z!kxd94;qwqHKyBS=GI$vt5}Cyha_CTV}-_4Xi>Gn8#A5r&x4)T^GL9Lp3(}o&kN|4 zaO*Zrao1yGWV4V~@$CW%jyHL?Na*dO=Zo?}*nxz_vUiKRD$-5;)rppC!NTrd_HI#F z`Omce2G#O6#1{WEt-qLI18)c}{-b-O!%pDcW^}lBZYDXeFmq(8t~{0UYR><3^kk=Gp{?t z)>Y37hIuaiqjjEk?&((=GW6PVr>RjD&z?Vx%IE8=%mLoZW0?uyuYH~tqjWTLrc4WZlVwVQ3U5FsIgUqaDb>yHo|X1d<)Dx700=wso^P=({?~&}y zNBJEE6OO<7Tuu6#ccbYtEhbK8+BgWTwEU9;__!ucr!rwpL!+i~}`9pSkF#%l72ntP;N zCmKA2iUe!!Y4x2tiV&~%GTA#+|Of~ zA&D`|Ou`&BH|N$m55cEKS;;5NhYp{o+ej>0vrLP6#`=9!M)gW$2mFFhRxljQi`rvV z+0cLD`n zbhqCuQz>pV^Nb*(ttNPT%a$(itp)IVeDEVJxF7&mu&CAP!Zh}C+m-hQ?~P*%lyZn+ z!&=Hj4Q1514qC_c4D$>faa-=SR8n-rJNalu%KdXYw->mpDdEkB+5Yh8G*U%B+jrhC zC(U~DXL{GwFZ&L-PGo9wj}jBOln<8zuCv2%AOA^6VfAPEVS8TA+@GA@T7li_(c7{8 zHF`VZu5iuclCS8j59X(y_pWE99(A{g`_XPM2a*G(!PX`@fLT+lE+saT<8j#I9-<;Y z?;U#~M0dHEyxdtfPMII)fPARL#Mw!lO zf4)X3pxQ;E-dZyRQ``Xew7df;&X=1I28_8c4~^P`S<9!YbSm!{Em^nINpy2N)nX{j zDpI*OjNZu1=RGhv77Bi+++$})4f}IH5 z^nv_Y>>Uervv3O}&w*u3MPp-(35XO&m(zBg?V1t0J3^Bp9%(zn}*tsiu3@v6WJxm?O8Bl#n&?X2g^lP=!KB++dIiT!l zkKdUOtPVu%5lij;Vw7Y0zUM11R6_!@IK@sS0p7{K6i1e-j4WIxo9IV`J`Gr|I4AfX*h(4jv^*;0 z;oe~j&Mg8BYeZP@t2Ar%#?`9f^lnME9rIfM`u0}~W;1pp94|NH>2=h?hQy1*LsGZa zL}DpsJcErL;iROz$-dqZ3>;_Cn$F`{T9h-E#b3q6PjLB#UMD?z^owC<5o|HO zP>Sf^xIp6D{sj2c07J(RBzy0jo6nnDPQBhw<@1QeSugv?_O1A;aE8B|TJ@w?Ry1g> zY`VK8!W;dO_x6)w4rI&@w!j?OJ;fC6n~v=c1Qt2kt!TM!i@6_nAKO*AZDFKJaGlPU zexq$rmFpYjm42ayj>61XEIYo6S6oMf*$CpU&^MFcx(Z=p6V0RcgOI%94f}=Z52wZ4 z=~zeTC<7{m9f@ZlqlY@e*n02%vpI^R5#(>eTnDl!={|*XCncNb>F7vuRl{;|Hi2YW z^Sml~{7*dds~QG0OmXH{;<`JZER?^{AI2bOh`DE!8^gJoGlrP+&-u0nZA)S#gaeKZ zHwW{_r%KzS!8}B0BA2JG(P;?A2o-7|JE|KGHnq(?&{@PQ^=XebwZ?qm!m9;GOfT@2 z5swei{Up^$p|R^TiI(f?1qlomf`DDN%Xp82fF7Z?S1b;MvB0**Y54<*I!){>2h5PF zT{Gtlr)e0@{Mz)c)0~zA`6RLa_Zj7&z7^j!%0XqkjB=2{>?$#xfmJ&E!f%E74eOVy z)L84!8I>H)7YR8{>+oJ2URKP8ImUmsDZr`y#vA2Aq12g$TCx?K;SEK$p0%@Y*Pu8tSVzAcmU5} zo3*jFP$LSoRud%G=2bBV+l^yXKaUe!6#TY_eqB@sh%?YN!pQHaFA`OU;UC zIYyiTubS@mQaf5 zQISkZr7$`Uo+lrgjgP-YY!GO$xgVMn*-1f}mClBmAx2&mMI>${b80?x649BhS0dD7 z`=-z?c5HUh7hmX^s4Ua%D21Etbn<(9gie80ZQN~>Z6EhN?CmkASi1dCGOO%>D~;$1 z9%w5agNr&DNbmE79n-pg+jX%DQxCSNo~UdE6I^{T7UTcfvx2#1oX(==A_yJJlP}PI zY-*$YoqTAW66eOigxk!xP$s`bWat&0s$@5V8K)_!UWkMgd(HV(;Tj1?xlNs`=(sw; z%l%B`>p6F4K6DCeYMnQE)?_~J$gvoL8?Oq-ysuFd?ZEYMV6-Q^&@#=W^-K9j2mWuM1+Ty!$15VHT+3 zO1~(UbA^RE-Qs3y2IG2swC4EavEnc@f8A(mYw2m`ubXj^PJ6RNLP76bHh()gwY=VX zz{7oKhs2oF#BiZ=$JM#*(ac{ZD*}-((_Pz}B`>09Jm-aoEdziJBnlG&CHKFZ+j7Su zwJU_FxoxzsffWH3G3wS4_gQToi`LJjS5T zw?^DABJNwVV{k|W7He!iG;EU)zwOLy$*Hm0ZEfo!m`M%vB~P&SI^^#yo0Ji{W6F0oe9E z3w!gAW3Cm8Bcct{5&)>}lS8zq9u$Xz1Y$lAYzhd1Yk!|I^$a9WmW{7!-Bp+mU9U9E znjM00cw8jn3X?1!-{HehhTI)$RZL)F{Sr&|uR%$?pFCd_XfGK>0iH4?!$w{{G~A>% zN-K2qD=rAKbR|h|DzJi60VlPW9ESto-Ct;_H_Fm(tb2d}Zlk{@hbHBMRTvKc3x@6Z}_hBz}A?CWQiDBltH}Dgg zn;7dk*M)ul&dhhcZTfb;JHtBujrq=L-VPqZt+f!<+-^Q2i?v<{ZwK@?Zv@qS zpN4D)aw|mR%AarE5H`~h(H4F9v2x_ZP_g{eS72k2Ee%yx~rT4Fl}Ibeg}lfxR! z2g7rZ8#U*s*b=%xAlLwcoZqaNJ+Kj`j>*1HB=htPLORd46ZZz{b)KsFLvrp6H%u6n z>buxrSl1PqYcEXaEK^ZPzLtW<8vL{ysXD*Sf-4JWe&_9 zL~iT_#AWAjgZJ8TAY%ZXXe*3bKD2b@JXwd$Yt{!RGwjV=^~Y zMA8P2ftwwwn(7-*KdqXwRpKMqP^A-97Ns^4e!!Hg*sNnjJfbv+xs?R_e>PLj=kYPR zErEogKJH$Oas6v+;_mEl-2HpkJlA8bU{r;oF=x)F&RD%lNb0eN8X=uPn;(AEo7E7YBKS=k&ct7gjO7UlHKG5L>Ae$2U z3qBkf!&S|f;D-xZt4w>sl~&-*P(4qp=XKtH($tKr;oK?8M(X@&0Lvy&H{4yOd;+~1 zPzf?jjSyr!`J@VaAD1=a-?&;;F9mkaHJsah^ht-lmOVcuBo&(>e!L$tPtPo#bum9GSt$qS*Z?J(RE#wHV^ zx9irCdz6-Pm}YOOz2YFmTj!lN5i+1nHBBe2;7}X{U|)3Z3^+ zV=NglJ&+B{7Hh4}P5}<*Nn`IV(;~J{3_>x=pj{^8kHm9y8(6=FG@_N?(!gy zT4aPLIkqM(`#MRkLXSl{5AtpDFOHIYWQj6~a>NbxI`KYgJ!~1$UWv+UykU&PhGjYs zN)=0=h5KZqPDo+UJpV=!rghg)&)43w+;bBH3pa&O8NxBA4!gE#?KK0m2q1aaz-MC` z_8tixTvHkGZq;nR8s5}B5SS`+IWc*piXcx7BT2x@k4v+sAJ%zJgE4O$NFFJHF7rS> z^z2rewZojxrKm^}wG~cw3l(f#!Spj`-Ku+nT9mo-WNcPuzWl^FSiEac&ehGEiN8|X z#?=j^GW{}?GQsyVvFs0mJ}HJY(Vwr$hmtg(T}n+>+-sag1F_G2Xw+Fw9oJFq&LB0I z5cWGj=iM|~toC`Q=?9PiWF1ZaL~{0In{Cw``v&4d?jer)fA2!H+$98bFP`}7k}q+o z3@e15{7l%~EBOXXXkB7aJ;i-b@3~XB;+;2~gb{*Avgd~*GD!MS#NC7aM8jE`5b+-( zQfQdNN34uxjK%p#db#$=i=3vA{H?@W{K;JP{c7z%F&C)uYvNAy+1SVzVtJP9jDBy% z7ov6)#cmL6RLj5$o*r(!StNkQhXAN-6*2df_H;SfXj$2wHk;|*<&|`lZDM@xCT3hb z;;SDDL1Y`xz+v4?lffvS5^cTCria2zA-&f~2z$0Rh18{Sw|^!29)9$>X31;rDu(uj zzaC$a-#^BWOzAA=X~_Gzg)}fF*$F$LLYVvCj6aKo6U|40Yu7`=`4nLfyX`({hpf*= zi{~3jyJ_dJxpw7z>=ZU`Z56`Y(nFM>NW8|E`?!V`oU2w)n+1>!RlaIR7^H5Oygj^6 zd^6HI#2CQNXefkFWFF;OcMUlhTLx)9boqLsLE1#I_DCm&nK4VBwiN3mVu{G{;>zEK zT`Z)5`x3a$R}-1vRyL4HHu8WrXXpvT0xX&1=?(dDhum1!kc%|zI%Lif4L=EvO$~wU zEudv3f#}bQ**l}j%mZjA8D*BZ`$F7Z8{6?lfnP;Vm^@_MsAOo|Sf@!X&*glvY)M~E z?v~%YxjQwdNwiNX?o2C1r^!(V&4%tbbuo#v&h_4S%usu$Su9G^o5?EiJI6HK8XScs zitGhNTyz-Ew@qvqSA>!$UxxL0WvwXQ0aTC*_0C3~8F$E>8sdyiohUYlqgoNeF_GN? zWJe7a2EEOGIa*ZcY$!-TZZ-pWbX&u&QBKoun6}iLf5}^S!n5ZGr7H%?yV2t0m~QW{ zcHuqUdh4o_5+(M4N%-_W6d8fms93f>2(8`t_2M5y@pJ5P2cSA;pvA3h!%SD2ht#;) z&<-*&0uwu4ANz|iRb(3aN`g916x*7;oC;4V$VNhcR~(x{f>Cm_i4(j?RQ0Z%I%5ll~@L)J(Ab+8)S2C z>rNtN2b>Dm#aK-^lQjpwiKqAbv1pJPB{8$-=xd2R^bcJ%?F+S#3DRC<{k|d$t0c>e zRY}v(`4uSfRmb9PR_(Ji%n$pq@QGG=jD-i(BGuau&xdpyt<|ndPDMl6j$f8?k%nw~E;VJ|eU zSYSZ08pf5eN#YMXu+z1_gN%6`mkpp?2@&Q%Lu#cWBrk@kxGHxSy1`0bb?P zpKWS7hb}L9Z@cMF-sLqY$nB#=I7RZBS2QmS`-c@l80C6O&K&ki0=|bSXF~!v*U4+f zzYL8Ak+=`Z!|x{zV=i`@rF4?5AC?dOb+z)61j=b*NCcJ@^Fycn5oL(7;C45n56HG9 zqfob`T;><8{Zwuvrs{z9AK5MCW{UmdStWR0WsSS3VeF-;qbD}pJT@4ZlD#dM`eF)J zJz|=hdy{JGIOiQRuNWOt@o?8%DTwuj^{cRc3ZnkDIL5D_HPWIaD2`3A#k>moA}xwWm`$X`z80DYnT0mOLIaXn zXw#hkm_g%1@0e=KA@mr(yR4ra_^AtH|3!Z8{EhO_>+73MwE5<>$Qa&jH8;Q6v63-2e0jYeRcY3FKir@N z(+2Nq-t8?Klh7~!B+Q#{tB~$ygGkd(`A~=T^D&{Id}yKd^U-1(<^k*H<48f+zp{Ql zG8L2$&9Q#=fQ7*&_y1TwDTGM1s(aV86$vYcCytO?gFQFl+l_zu|mnIw0w zzNO@i1rrhK@dW(c1Uzj6gc2#I{4F1PWM5F`b0&tndw^lp$;e``;Jb-v?2wExZp7?} z(=i-|I?+{vZ*C(?4-ntf+%C7Hv(!w_eihAPThjR+^(>GLQ{R0^MIZK;-Xz%$O@*YM z*Tp-mBX`S_nZLY8(k4L`o)TPqgE4TQ-k1BTd)1@g6v@|yxO7c;vwqygEXz`C44bSX zrPml48La3!#DKgwS@Acdrz>kp2Bvl@N`?0et`Rrt*V9E9>m_3yuYwI%S&!Bht5lMH z&5|P@sUIKt6Q10uppw$y!hnV%P zd#~xM>)ud;?pz!QfaIq?`oH|M?gAY6D_DP{UyLj+=iA%#KakLl^n>`ZGGnxvoANqZ zMBD@$bL&yIc~SPuH{@TWmNdKpNk20~;kWd0!?Q9i`u@g7D4Y*&4A7hsJ!Tqb!9NOL zq1YIsSC#7D+IYGAXw8dPH7wEnWQJ|eT*FsB^y%xW+0Se=nN!aW`29!l>^~YpXGZ7H z9Kb{$P+-mKi;BiHZqBzVG1@oPCmT7;X3(BiW;#=D@+)*i|84Lq5xX6KW&^5ALnDmt zr^HF_uch2I`c0-X_h}=4$UglTg~nEVG&@OFF2BpD6Xkjv%`h>5kANS7*bvob!&!uS zEB&AaHmH{ks!`A%{GgN#DziZkE9eeCsEO>l6Z|g){m2BRuE*Pt(IW4QtoH@kbK#vB zM-!J)H1V5S57$f!a@`Q?=7zCjQ^oB?73%7Tran!ux?ytwS!bFww1YkS1l#L#tI1ik zsXF&E#q&36NcY1fs`5^fPM*g3&F+8~On{ahoY+BKpcSgO&X@ZBRbd3MrNW*_K3N*B zIW>i0&d@k1Uc&Iab(|!DFe4|Y#*&jmE&Up=QkZHiU)31BSX1LOw%HngNHM7KxpJz;Qo&J;O*pisRI5Qe zPF`YIeS-oc7P5Lky$yNnMDNE46-y5z9fJ|1qdqDg8r6l0pTBBQ(fp;h?h3kRyv<1v z_K4!_9Z95BG5STx06)IGFwAF2kO}!rve9hV{4}?8Ooy?*#GlCg@npt7gjehNX|3Fg zCL&v}jSel4G}`LDRtHp|%u(+&-9`IpyxgHq#>xScduFq*{}fsUTJZKOq6MatovU?L zJ?eGk2%1l0yvLV3EfSW`_s&jycih-HePhn@wm2JqH#pgezZrMbjb-^&?ZHb}jIva2 z9mtX7{0bXAwLUg;ReMQ|$+DjFuO=5bf8`DRy?B+O7P^b=s`QwHQ&&5S&MxC(&`6&Z z@0W32rt$qYI$rYN#t$3z^6rz~9ZpTkPF%Tau}ZxPz=QfmLVY8H`$h)!jU3oFGO%x? zyl=$m8#$nFWI*3Y|GtraeIxw0rTRDg_~2lwmytP=E9dw)3Te+Cr8npL9sDuLEnN&ik}HU$gJ@u0ELdU;zqu=R;NK? zGtpaL7aNJF`^DQPMX~Cr$l1^nA459k(+w7DjbKToSy!f)2?7dWl1+xbmsV;fDbks_ z(febY=_5XIRYNzb0A2h|0xc&tsk(Give#9<=L>fe?g81h2kSF+w?&rh1+R%r>NR&$N8KFp2?TyXx5(6e5_LC6xp?Kb6nzRu)mY0CzZdb< zfA7RMlD#mTJ!1v>Auq8QS*s0|%#_~XF4em(dvoPQog*bWfb@I{la{IbAxLGCS?^te z)2;iVmM^K^c%p26%MT->sO8!t$%Y;WWn_|Y+q?^gvp%1oa=ANlRq$vCKD5Y97S`bl%?!A(MjyI8!Plv_%)>hK z)zsBppb0!5x(t7z+$zPSkV#*EH3dDD(s4FIdkA%IR-lN{+DOa0{#zm?sdtx2kdhm# zeB92itc zRZ%F_T9^Qkt#*}tVN>I8k&?=jTS%`+xKmM@soN2CPp>e?H7;OMN30lgPe%%$dY4v> zGLf;#1}VyiA|y?FlbNwZk~~iNoz$IQV|RWx7V;aeYERZUa?eMEMS7{*ujohnJ4JLO&5&iT*;6M3_# z85+dYtR~O6JE=`09Bra{JqkK~c~?R2J-SfK%Tfm+bJv@1Mqvh6^4xHp#G+xy0w&&Up*05!@EcpX@-*G5UTZET`wXX*-eQp!^Q zjLRT+-6tBG9C7==bc(23gaE3{JLo_58kXN_KF*YA$|q8qJBK4mACRjGw&f@dgef10 zzX)%zlWIUkD8A*B&SR&zy^M_rAnV++DJTGX3yEM)5Wfx@;%+auELOa$tKD9PP4L?- z(*^kh5{#$YWga7*M$4pG2YzAB@}XBAQzwBIy~RgYBJ;ZwiFPHDB|9^Mu(9EqZNaL0 z_cD6EYX-9VCp5wI&sn79H-B@9(e0UXwbn{yqhI8FoXPQJ19&Rm`MTS>yL)mp<1JT? zUXLlA!cFNW@Bx;(Q#sjq(DUeNqNfC+NxwGPD;qHz~>5gM|0LFsYeaD!Ug!;d3vHoR4s{UUz}L$^DC(gpEBJ zjd}NWqr@PB)faa|%_ygtJ$eHEQ!_0q4{c!$M#I}%c#YxYn$V*NWTsa{T%)F&nOx@Y z0U)%CyLHSqY{|#mR+Da?S$U93g?4PK8r4X~QvpuB*(X)xVMditccK6^ge zPMaR3SR}Yl`>?QDdYpjr&*npmEJP}|6kd&Z)a9^s+T#$13yw)Gk!`AMFoDu9zy1Ri z;dAd5boG?<@I>vGvyU#ooS7-v0Z>LoaG!D)o>WR!yrxA18KsY#oGI{GfBbj3s>%0Lt>c{&aaRVNSzfMbNII8d9nOt z7DMeZZh~KAM$E}%rk&2FhpB==rx{VpwHMH{!6G$>S0;xM=B)!TGr0n@)TvN*+CiPO zO*$W~Ee@FG>YS;Oewpn68d0-J%HMS}jnZCoL~_*EoBmZ>iJ`U@L^%B- zHAgJwnkY2*Hc8f9qumR%aZKY|t#bG#ilH@+^qBYQkS1nV_v{`{h5KW(A@?7u^6TEk zSDMb(&nyjmzM6BWCUl)Q-h`&!rxm~NdyTLW%FGf(cG0q-3;iIckd_#zuCyY4=%+I= zJiFFj+(2)t`rtrOK8ax}DfgdFgAo zuF90|lxtDxo48s_KT^W1I*o`yRIbK3wzM73!hR~}t%~7~o-tHEd(x2D$er8^9K7*} zSoT5|&QpV4jKZp2`!mD0_o@&;@iv%*27?$D%=Po3O9Y2@RRwb#_Kp6)J|+wCK=K%=q`|M|Og?v5EkQQeem$RRH?CIl zTCcj@AuT;Zx~pcsa#-~1sZoW#4HE$BHtdg0k*+rhy)lJx@2F99-UIxj83LV|i!dIJ z;|z*nxNGfVrkre@J1f4pgd;zS0u zs_V^uCdJpVpJ8`2dsa^*yZ%`;aB2QP=PUGo3A1aMncX+)n%jQd#|+yV<}A&0^+Lxq zO&e7NCQIWp+mK+Yx98i!HRFne)>)vHv!NeTkJW|kZmTOSG=fVM$c#uPk-e3pL7c8h zlQpUoXJ5HDzra~ED4yRCbwA8bd?~&2>^aB8?nTDYRB|O6ml5}lrb~Foi=X2*$kxFV z3=QfW7fU}|6s!IC#)D$T+u>4J{(8eOJL^-`^W)k66Y30?Jy}YTjQ@a#aYb9@Sn*CU zsU>H#If%g3t)iJ=O2uS^(R-<~s3k&oEw<9Dg^kYFuUhc>FN1+CJXX@oOMgN8XC2@4 zt8j7F|J$E}yF0n`VI{v+f2NnB1ZW$^Y5hA1fd5nh|IwP04F3IYJ$se5DlHD2rp*A` zzAN@wO-Vy=IW71e8E)9KU+=w;4%pp$_TCeJZ+h=cSP9#EJ@wv+t;d}LqBXhF zWmBy}Eq#)5Ol&VX#Vq_ou}0X){B3izH{%r(Kawe_)Lpu^!-}JYp=Hi|V5J$dIs@J# zsONVV0=XXt(*~p0=8l1x$2XQAb~&+ohD&kXfGp4&AzOMjb4C{lWh1{lHfCbk?DCjf z)XK`GD3+h7yS7%*>w(g2Q>IZ-ZZ?59?kF9Az7pA=wxj}FL+4gND7gb3>T+nuq#M&wz$UcMgc)<;io-(^ znV7*#EEC(rUP47IQ}1z9V-slkkd74V2ya#+c~5gd)7>bfAax@HwaAgNTJVvgMX02^ zvOSVlajCozgVdZJDW~m%rs$>;-R0k>(%H~222)=UQ0<*XZc4SfU1Q7Mw`&?N;r@-b zGb=+%c#TR(iy=Is1p2Br?N?6p|HtNX17D%%-xMBS&xh`_d7sf0@}vo2*?hYVsiq|9w$16C7tLY2H}vu)$lvePwHlWo znc`ZF^LUw)^95tYs3p-B7jw_T83aw_VXpJ1J2M0JnA7YW*!61x3sYm4ci}?;Ca?>l zyVG=^2ems1`yMc^(QzXBcp^J=5EY2KD~u6_*Q4%7QTHF=nq#?kh?%~Je1YTPnufHF z9yiQseu7Y)7$3$o>U-xNG=6K`J(2vg?w9#c5bIP7>r>47QtdaD_PbNo{IVz627LEH zL8Si9GOSz;*e}M}U{f$zRT35WvUz*N{m7~Nc=UGn+03Jr4RlnjK}Kq~Mx3duk@~y-C`)fBF;|zQHGubq^)wz4n z@7l>OK`>BP`&FHD)(8D|=H37?g|iuS*0=BX3yxHKaR96VqN_{N8_IKk;oWbKxw<60 zy`y4r1#YMASs;F{uce>#HV0b?D@m2$EaPE8cP3{JA%u2mf*i1r1LlHeFdP9ofD+4C zP}u{f;cNFFzqb7uzkc&?{*`I|Ei}KQ=I>kRN}XmJMt1aNr1p!bbJjn#-Z}#m(9q3C z)8GmJNH?ce8YoiseD21&&1s=Xwz=rnwcp`PyoTzs^v=;vOKVrl6tA`|lWyW2FJ7mX zDdUD5hD5f1IG!E6zC-4;0y%TeXkUMNIQMcYseS#m4mXXvpT8Cdxx+0y2{cE92h<@my-w^tc4JF-yUyEt>SobYItKvZC95N%qfjuLb zfXi$tuxakWGcNcrp|BH78n^#5OA5^j?@(jAj|h76MPwz340MXf&BRCk)I zjX}ev%6svcGV|p+DyO?lLf~ZKq>^HpHvyQ0}JGs?JFt(nQ0scIZNN`Gy5|?s4UVE;b0{h zrdJG!b03k@EdJE4PP-0P>YVsh3(omnFz^GO)*dm|Ni`b^Iu=Q`zfdkqHMu{hajOmTgm5l zf574k?L@Vv`YMObg%*YX_6^9gWg@owR{gs^}Ubh`hF^jX~PHaCGdrSj<0x1Zzm zcLq4l0W%=ih39(z`vu;5=D2Q2z7*;*Dkyj$~RHet;IrfRljl9LM#yHIGG=0HP`OGOl*?CDjUd2m>(f(ss zB#+~eI{NC7{L65&PLl?dZ+Io&p(*rfJebj6&ppx|g8LBZzH2(N(e5EI-;rxEFl$8b zhy0>2(TDfp*SDAWv3HuTEu%|z$G@ru8`? zxygLV^MKj?<1=BlRjI^tGuTWvptE~Vbdy^y=^Tg_-vCp8fw;-%n5~=7R^HkB^+J_l z>9@%;{ay(NQ=8Ye`hm9SPTi)+_Ku=tulC}R>IB<6g8D{ZOy6btK8A0}0-M*)9T{od zbvgqNp=)|$QDAW$-zXnNohfTHg}?SG%Z-_9V#Ti~Mt<77eQx}-iB5TR%Z$ZQ;I48; zwcijb@cW-Rm$k?8Yveim^V)5<7GnV}9NW&U_tpF*A9l6X})O;-^B2h?L|&Blk4odY9U{G0fFob(nxjfon} zIz%8#vFu-;0NzZLQ777_Et;Vb_j&1|wa0d#gSl;@v#8|2)?TsvdID4b#5=!4C^6MnLtd8vHkW@ZZ1(uKY_sd?jVybm{sJfx2w=&Jd&x-U(+@{5d5|d@gQUJIz6U4d zI=f`461eRz8nq|KB&5!=AA|zF*EgqiD7;$|Vy;^w3Kl$M0!PN6%3|rYY-#fD%;S9HzaF^@C zqG;=hUMF;zY??oUHe>YtUb+<9>Vlf(O{c3UOhjLsOqu&CD+u?76UXWz{Y4?jS2ioB z?0^H9V-q+x;`CMw1!1H!*VhiL$cGMcMV~@DHt>>J-Zt-&y~tfA73D5aLY$*l2>j_L z5Nhz;{10tpoYr3M0E|f_1>3h5Z+>o!0?)bOG?k zCP};dm=C2b*kD3C>j0}QfSu!~H^WcwA`3WLfQRQ_Q&#nU$E&Af1ycQ=)@zAJ^v=FUzhudkc+laa&=YswMuX|Q zDjV=@Zi~8Wp9zF%&gYR0p}&z2okM~&x-nP5F&(GrB>=}GF=PcSjXXb}jT=iyWKFO={A-XJgBIYUa`;VwC{_J#1TpcI<5 zY0`IFZBbMLCZRA)xq6n}ohS^OsB}fqO9TEHAO1H0A*+M0W&etx=e+Y7#HPnKNewI4 z@_$R^$0n8J<*@pdVLyJzkDolZbE@OnJz4>KGU;=d~VjMiZe2p3{In29mhI-9im1VfKXY$l^{<_}P4u>2Zv&bmJQwcyshP}yQ!s72&bs^>fstpXqF97kIsf}v~VH>$NWo{hB1qh z4{e@jmV1ExlP|!2*bVj-DaKj+7=1QW>3f_#kXMCDIrju=0WGy;L?&uBQ^o{u^&VLx z5fzKMcT~2?4Q;>s2jtVZS`^eCO4!G~b>Y51s3^M)i$x-J660jfJU&L{yoYLG_B&ei ztv_}J(Xtm5_RoI@G3LZ+M}yq@({@5(p9KmoF)dog*HsQNht9C0ZHiWUr6NiS&{X-L z@!4gKQdL+B*IxZC5DCmw-BI}S%4Ye}bY+2qxC!ey6-XAv?j4`;uCW%tr9|yTxOwDYx=9gDf)Xsx#z+-;E8U-+hfU+&$QG<4e zZFN>nj2qJ>88??*%Y2``uTq^B3q4gBU*nYg-+P=tWWTI&tL+G-3;w&SPq(SPWLOO4 zoFyWC`OwNHjr!zZODD%Yt3s~x#!;5e5$vxK>O4sYLg}UdRV%zQtYOQny{sHm`LN}{ znu*p7ZRJ1_mwlgv8ds|bVxjE*9a%5kcm%T~zGVH{uQf_Hs<-#aPV~?HnS^Br&pk2vz+^%-;zqcg8%V(xAKMG^wYipBfopE)S;8j=7u$G(~mq7!+W?gJtPa z>0D8=JiRNJIx#xtq(Q0UGW`d24o{C86igiz&73r-^RSL411sz^hc5jWZ_P~qMd_6^ zGhQ%t`MyaLMA9cH=^;vbVsy+Cg982GI%+cH%tz;_^i$>|m>Px|Ve4nIB5on8J$_cB z@PofkuPRCBtDHN~(=MoKbR7ZKT&sQ1h)ig(p%d-G?xcdV&s&>a-oV6N1dLbWLO$QM#(Ux}y;-y;gXKgXA3 zg%d6r%MNH<3D-9PpRWo&bL4XzKB|m?xn4epii^pXewS~;_7awGqHCo6e@P_0d-!eN zrZk%-s5DI*H{V)`^m3wY6#Qc4d6~&`Z?SXxHfruHy6)7yQeKOpyq7#R z-?+zAWvvH3O@uNdlxB}5Y{=manDxLz2Wd| zv)UP$)oM{-N(Hm|Ghm#kD=Yt7SKzS$4-&-8H7SDeFZ>ic5IlSTBj_5+Vv?+gWalZ( z#7tG@_W%HIQui_@S*$e^@Czk7SIK5WKjmA+{vJ+Ad+4Vh7jbqZI9mp%FhCQ?y$-^h zMNY%6;d3rx#n!Ovm^p)Z$CgryMmoRjjIO-lXu^|2!4Y=4LNjfu%3Y=P`YHF5{J;Y! z7g=@%e*7tc2NM__FD#r!Txw65ULm02v?ICG)Rf??ARTZ7(&yyi`Z+*jmmTBKIYj7` z>8bJhV4o^vGD(&H3(+%Z-+d))BkDQ2O8?zS`UAB4EiN{&KV zN@|E+?nh4$oo)SRW3}x!{5|(Ha1FO1TyI{e%A=pomalRd2H4Z|IG9|L)A3X#7lksJ z^jt~dkms41j%a^wqZvNkM&(1e?!#ru-0>H@-@v<&%7vv&D*d zGA&hd<0xm*WR4(&LIjc3S;d6&o*ay+zF}CoHCpb-;CSxT03m3pb?r^c{UQv8O{K1=21<{WCGPa<53bn^;(;dt+Ovw`gm% z+UGL&j)fxowA?{*Pt5?;(PaF93v`a}h%Qtg3UrR{2Av?#V-zB63LHAFzo^^3RKyE~ zJ`Z!CAfijx1sWUnX{;hrpg`x*>8A`o5lkIV%!0R>B$Psm6a=BUEcJxWKd$!%QrOOi zx_s~arg-CtXQ45u6v)kC#C4G-^TDi_a9>Z%d@JcX-EFDLj3~>s;C_x)HZ?qT< zvWz>|N@OE!p@d&AA2~7a(LbH0d0>uG7A41+QeJ0r1phSQp(^FYlT|LDCw1`l8)lVp z;Hke=J)#`1LRJ+*)tqs6UC)>*rDhm&Ay`*3YQ9yI(og+Vd|)v322h1G6tq;q!7W0}#I@}J$Sy%*~45a!}o?J8V>-TSzX#N|9WU+XFC z(ahBGUhuC`$YKCu=uper#@D@Zg#I|>ll;HAggp<`_k;b&Z0!+cUsXV z>dGwIig+GZKSd!tT6uOW>b_m!?SXxZw#|kmvMoy~LP8?DmNu%A7zw6F$D!>@CxB6{ zzGfrZi@SHKg^WVbG*@K<<%fg>xUIDEj*& z)KL8t36rfZ5++p+MEsrkW^z5HYi8yL1)nBj0*S zO)_Id$X4#Kk!*co#H#D8FoHhf`#g@%6n9+Z(s8D68{+N*YT$(H8gyjSYUjjASM7|3 zNs)Kuml|hjxt&F*eYdfymLt6j#$z{8)4Sk2w6&7nHQZ^2Z9wEghbDP3qI+)QEOw%@ zDzZGllo(-~7iEVBRRM$#^~93wRJTJS8Y2cVD|YktZh1-BE|Uynx$tP@7E*YVQ2SoR zM?&9oe+YR7M}WHTn`*cj$!IJami_Intddv~B` z2rDyDa=LnLN7EtEsPzl!15>;z%8WvY39pD1YXkeo#HU5QwJ)m7m`n7R_}^ooO30<+ zCPr>o-L{z=ZKBG=#IGa1t-d#pB;u^&)%&8^(~Hytk+29++|$G4F5#KbWjoDu`EX8f zkvZ2YTKT(witnLRO_h=fn_i9d*Sr67mBpgoTuBhirX_!|XpF-B-8@A2x)^*>(3lF! zJFG?#Dr&kKRX8{X-_8jnQRXKhdy)SS@!?MPYjDtb;FFSm(Mt+g_vXIP6C0Cy?SqYL z+4iwm_>MM!vZ0AsZ=kBe!UO*R3)wSEO!W)65E||_*GGbX^&qI`DHjp7akWO2l`nRk z8S7gAGo5LVie+GVx2+54B{nWbf5Zlz%uu`U#ogr^N0Qq%m9kEgA>)}X5=T(8hH4hA z&Z0{>#kqka>Q2j_=+fwsHQe>GG#1z7-|H}-UJN2FbzT)qSa>xAKud zw*^|+UGy9_XabG@GHc1jF>IX^*(m>#p1wQ({O{%c9h>)`u{~h(z5@^Mms|GD`^|mx zzG&aPcM-Xex4!?~yx#_vdXMeOyIgr6xnJJTFq(SQo68n@*87$odF%V%&HHkj_sYi$ z^}Y)a?>97gPn^&GVxPRP*f;NBkG%EW`Db+x#}-zLlH3WR(AgFSwOoNhfN zmJj3x^VRULZBEk;K#A!z{f!Txn; z78*TyI<1L5ky+Lck7OI|vR<}+M^WW2F;KQNESx{`K8wLY^t=;s0dp8I-rabr<9&=K z9YMptz1MFC^+@GTvb`X??6o^BAF1f~YMd=DjI(_zPECT;Bw&#v&Dh*v()qvDmb$}A z6sr5Rs;X$`QnVg@V#H)7sT!m6 zI_rfGBmBpgxnFi()a~4G@kiqnxaq7pNo7YZJHM^q~1Uu`u*tM6IjopkQM`;x0w3*Oie z4E+7YV4x2|;AWoS3&FrGJio$!7w-{-Eq*B&xS7Z0`7fS_d0ynP_T&p!ticqi<=oO| z-EOAH_+VG$bt9dNJfl7$I$kZpPy=h9?2Db^WNDrIi7ub|D12g`8^BK7j!k(j3AmZ^ z9H`hM8ic=Et?5&{-A+@OhJ-}?QX|dXNH6?_zR-=j6TsiC72pQ;SvfDEvXF|=_Z&bh z<^aj39{#anqSU|OhkP)(R)w4Ln8TCT^Z!8{b^vvr-D!G-BK!I_7|7AuqTcKe{wcLfwHn zwVLo$E!RS?%{|%`cZK3!XXExSM8p7>pY#p?P4E;O+*@Z^vU7@v&psLev}7*ASA;7B zv{u9T$3@q}?zx=mvTUH(kiVQwYr=+5sC`tpdx&7ff9!uUZf#_-_-xwKY1+;QqH;~& zjqe2l+vpVZ2YZR8wGyuHih$GfQy}%tiN){f9S$U+%7H*Vec%x#=MJIQI!zAye1+RRlPm8*#}M>d0ojXvuuX>y~{?p*Ek;J*E{uCQ3~XNU>oUW!M3bw+PE^$b*t&!)lSQA z)Mzs~8#>_NZy83jDfrkMI;?b8V=M1?@eBF)(KE6p)CRmDZn?QF#`QS5BDajDYg8FI zSRpfYZsVqs9*!Dt&=sQ6`;Kg*D$wOnHM+ny()e8t)y6tZUtN_)^nNI%8qRZ)O35>o z=Ng`ic~U&L^91_r_ZRHbr>NjnTvEzsFFAYreq};RkH5y1d-5B=&k;_G*@HIt*-;68 zK+E8_y3wLG?<%eONS8xBrOToI(&bRE>2j#=Sch|A+vv8>V$O)ha{NAvI0La6*yUID z4SqG>;1}-l+um5kcQ`q?JCU8R05)OH1C&mFR2oUvZGkJ2A9Mq2F=Yd3R&{DyOxqCX z93Av#FmMb{HP0D5SMto|xr66Ho_?UI=ko-9@9|vdhwc3an4a+e+xK|l+5O(em3#B= z!qII??>^pX(XOxQ$fZ+{u^lu@qOV%8@l6TR{EzDnBxFaMKXgh z(@%q2RWWp+M^d5)J)*YNG>Z6O54YRXZJfJb{cqmS-LS9wrvZ{kf7qAJj1Pm!q3PXy zl6^;$pe;j3vG~#gayyEl(>+{ZqRZtribQo6#7;$~B5UY3J9*094hDwsczoCJ-o!h` zdm7I*Jac(kc~9n3~_ zmU`#h0hVb`f8K!auGxR`05g_%8)p(f=5McceoCi9qf& zA~f#dr#y8Ag7a!tJ6J+5H#au@(vS4!OGJ_)UTz?OX;;iqMWH;X;+nE-FQnKBU~DG4 znH@JO=Q~Nn4^jcw7Nh0=ntbngL?Qu-$NXLgz{eb zI#C%Px{#!i+8e3R(tZXSX4iXex%Q}cN^zz-aqKdoMS6a&K~SXl6YqozNf9m(v`KE+ zzJNt)Kat+EGEMbvPhUq`2)8>L#-WV9qxh3Z=6JQfEJ46K&YrAv zv8Q$!_gZv`uT1;;_mR`0rGMfugWte4W_^>dQya6<`8vBuoOzm0W>L3s8+qZ8PaY8+ z(=7@CYpK881SUv!@@IJB#j_H-YVq*Ffxo(V8Vk(uB#Wd~9Tbl2Q508b0!& zJ-1-`CbLYAXzMZsf)a5e`Os$sAxu^f{7B&Wog7Y|5MTWb9^5UnQ?qTIyzdt;~I-<}5l0(O=|o_AlG9Fg(eg7jYJ?Y}j3q zJZ#))=tv@DjTF^6(G3l|8)7=xl8psB52$Oxej!Tf#hsiBmxW<0MCRL?UQDgR$pRxE zI#^XO87Ake4bcmY9;`B8o28gA6dZ!7{yyKA8$e;S{OJuQbPr;*#$5X+Z22hJaI?Xd zF~Qer0yW4o%Pi{_iv1D8QsyQ=BoOPo%nL|{Tuq0Kxo?wp^83;un9A;?wYxmVWmH4p zgudJ07UeYEusrlhg((!(}-=SE~RCNdcZmeMpP)w?EZGjE+Yj`mY8wymq)T%+FnJI>zG zo5NZL{U6581wN|k+W(Umgy#upY82F&2WUWI`*gGoi)QnRr6- zL!yasbtZP7!>%szCSQ|@?dI7t&%1cW|M@pTzn+A|a{WuJ(Nq=3aG#mj1*|Z=a1&($ zT4K#k)5~O{lWOH`v)6ldp^lf9Loo2cJyezC{`--3g&-f%k;bn)iC0jdt$h z%pLBjF_9FH!>D$^#GCvdU(;k-$D@ziMaM#k zTPgyvGOv0PW$1`m!?8k<(M51y1I-*$@7v$Oue#fGr7n>8@m!#TSBEtLIst+IyAlml zik$X0%%Bo7MG#)F<9EfHja7SgyHpPA$e~?js(kSeEfQb2g{cghg5v-5;0oq5(dySR zE#fA+cs2|W7-YBG;#b(>xUYVT3Q(KP#gLC`ukx$SKL78kEtz{6t=1)k;JSHWxUB77 z`Qd!hg@hxiCG6L->fh9o6AMgFbFk8{;AQQZ4d>#}*I1cVyT7R&0zgvVUB)PT+VrA- zn86UBg@>@4cGq*}!?r&V7+=n52M$Fi7sQCwcYg?=XNtoF)`-7xLVRDL5^ta3CvHNl zhkCAD#%Kc3qQuq$t_zLQ5f1so?sMKRo@JJIW9(yA&hLIKh;Q@W?B(9c)SC1#z`7@) z9u!2+Y}nIX5F3h8bCjkzda~@~tOI)P=9q(ObAfc5w+Hz`i)#yb5Ud^SbUeeu(NC%x z>L`qkv1fm}egL)J=FJ&t^Zz&5yd=jo+-8`;Qf+LA9)+t_qbg$+HNu7H?9Xl>ke2Z)Wbd{Je>K(UZ%`v-a=T}Vi%kp6j_7^@D5 zceAe4>rY7}3RZ)9_WTcR#IYiJR%hT4y-rG(l>NNrY_d`&x!sg`AkOZN4pMZ2H;yhu z+-a3k8KR0ze42&Dq{_dm_GMt`#h(NHP|gR^KT+va`Rh_)U6W6hEI?RX@d>PXFORrI z1nSF1Po#m$aQ!A67bey%pkIO5p^*u)jeFY;%{xw2jOIgTIt7oZO~~9<=3$E~i=&DL zvB%GNfP0QM}>;a2mBt!Ak@i0 z5=_ebMZM`0&2t3A`+dE-n@|_wP5fV=)}qG{tVQRGp~M2zcF+dgcMaH(q~F~ybt7ql z)xQz>2hht9@l@G?*1r%V(ChllFgD%nJ9-SSNG{c~4$a0wLz51#xWj%xmpLPpyi4mF zvF$;IFZE_C&w^1?r~7R>7)d5XND!T3hmfRs#11G^Gv0y=A?3A9wM4nZ#xBf(+ zpG=&{ivTtI92VHZ4Q1ewO2hNq;Q6wJpjbM=Vq71*i)Y@KOhLt*(nZddPGS|e8 z5vI09hP@5h@{i9asRM#BuaKR~hnTF#>j~ESGlq+c{rA5_Ps1gYiPW9)@m-l#^ql;tLB;!3z|A znRIpjWjdW4=Uri2OOn z!M^x?2=R&iS_ZQTM2O$p)OmVlB2rm(cH$|x`@~izRK!?{ama6-P2x#Qci%on`s6-DquDP1QPl3ZFvd{$ z+ByZ22sji6COUlbSiHgCerD>5724M|{DL&Px+O=yH0tdBSmV@Cfa$wCyw_dX)R1BQseeb6XWdP|;F zxRSlP<8}>9>#mmPf|d?Sse%3~PGqyWll#);vR-rh-pJO22RS{@P&Y{mEapvH4Wa2RARi9}?81 zYPosmKO#HK^{G_Eoxw%E9no=wA!y*TA5j^A%+_Fb2e4rE{HV6M!Rfe=Qw0Gu`d?(5 z(cL_Qt*-L@Nu9a>CkAj54!&Uyx=hHfT*WoOt1PhO#8Beay@AEY{QG8{4uXMZO;gxW zX5+W&oafKl93>Xcg~46TquO^mt}uyIwPXljblRuu%UVeReAKBxV$DjPdHHYtSC)=@ zdGJS@=csX|CDs}NA$oLE?au^br{kZhJyqWHfcCI|ArAu8R_|F9z+_fTut4<4_?k|B z38R!)tF26dc!aXj%{zD}AO8o~^C#BMRS8MS_lRe!s{J?*L11WC#E@)4J@qYJqK%1# zk-%ydHCGYI96cHVsWsx>-T-2FWnE19!bm~vF!SB!Q~;P3OnVyVdb`(&YZ(NJE+VSJ zULeg3ozFyX^J-2uE99;l)IlWlOML8$xbv&!?BZ-$reVL&xQX!Ly|`YYf#Wm$@B(kP zxKUTM(q=o!&-N>_MUG!lg*@B6R8nt2lN;Nuaj^U>Ok%L+#@0|lBSoi`g%bO)*4SoX zp%m6s(FWa2y+dlvhoj$jjW4C3mVf&ta!9H?rT z?y@i-iVlj@O>13J+;95*so3VFpUy8fd7q$$!dn}1HJt9FIa3a%2f9E*N2nk)@Lp## zpBXKDF_jsl`JSx})p}#ZIFPv0$RlO}BgV~T)2+kw5%G0qQ$xrszSDgKAWOdbWS#2R zXiPi7wfVyf!4;?dD9kT#`WwtDPR(wpLwgx1g#MUSvm-r4lAvJX+_~Qfh5crC&sT&C zb|Qt~&3l<;{E(L)eh*@6EqHFgef-jX^OydeYDtw(QkHVEq38>1MvN7ppiyqwS*B`~57pD@(1i97PsR z;nRolyIL}!;Cs5?VOn2Vs$8G!lT>XMd;=Ib*OF#ChlWB&lGpFe&X_9#y`8)wv+eCX z*lk}ydI8U78=l{P>wcFpxW*hAUUr6>|I!~~rrjXmAJ%~@#qoveT5OnVCmKqitlm_M4;;newZc@Lf60;Ro zSZ5zk&@JcAC)L&Dlj^wc#do|&ADU{Pl!D!9@8N|}JsRdWR=p|^*Dh)ERoW#blqlg+ z%ESxJy!Cop*D!Bm$eiw`zM9P}hmJjquj=Q|6!t4{U;|dn_)R6j_}-zhiSTAzny&ZL znmUUM;%khSpXi>H5lNF!W4udS{aB`0xd@=BV)ZXAdL&f8RnDDl&ybcZ+PyWy-fu!St$-dv;Z*-i(8gp77Ui!(W#QC*ZHW-q!(~&5OoX z?bff4P71MUFEGaq3`MD#ukTqZ9I1@W^^qn1w9%+VXK5_U-qkcmBbmrR+(Y-M()#D4 zA=lU}vgOJTSNR#Hd<+Yxi|B8!*NUR0-Kj8v}kp_x( zW{&MFTB$J*n?7?`113(+oSvd%PVH_iMBTTsC^N|VNkb}cs68e2orX^Kax^U2yH=uj zLry7}dj~;nl3Dio|5Cw+CLcP#I2GJQ7(sS;(j?&>oq(+AQEI+p2f+f>k&WytDdj9@ zlkx)8d9ppPU?4+vAaPPts^K9p`_TD?CvrD3{7`%!)du6~%HX8+F^3Jx6iz8X-3@49 zp5ttzFh~J49gKUGRAM_)L;D_&zkx!z;qbNK|Ih_AOa(Wd7@F{$-##5DDi|YW zc#O2OcoZpSRMA0UjMHMT^~aXypHHJp>wje}P4vzF@4(yXxN2-xzUuYwbNZrvtGA;^ zmk9!-=kZvOb`E_-fgGF913{z+c6(LcYVhkMcThf=P7yw%r>BF0c< z^?H}TBEGt@C$R~b|LWD(x~%G@PjLkcQ?I61$Kj>Wc+{$$H9FzNqUefIpnvA>gnU5gv= zuG~o_GJ><1W&da2U6nZFLm(4~E#UyRT?bpqlDAsb_mUgz+w1mihJAb4zCG7$a{j@- zO}5{*@YYlEW2yr~0^VyS#wSCw*TESXUyPKkM_@fxw)>nXXFoFZ}Fn-9=A4pOVV zZ1|JODnf#7E@7Y);h4{~xg@r`#MNf&~bA{)K`>cES!%9r9GT(@a=H2{+*wYqw zFaAT=exm#to%m~Y{NrkDQjmDJdd)&0sqSNsBsv_n6@5$UCT=sy=H+`(M@@i)1-xYo|amycD0{#+bK7R|-u`CNDk z1H=E9xwvJ>lPlJiBY_jBKUSg+t=Z!s(-BYrSmx5@CH}PZapsu*4Ah4(8DUu4K z!?NYIX90;zc57Y#gf#v8+=~4zdn=^y{3JAC^9pNd75lzKZZ0m2xOnfAJ_;#LFd}V= zTk>TpB+IaDSF$9;vk6sPe&(e-?Fc1DT);!n&1XaLFvVaVn9%e!R(Vl8Xv$Zs*A{f{%XD&0Se)nTuSD;a8VQtBeY zL=<>iMK`Qv$3dyHF_@4}2aP zq=xm+STPD0cv^$F({x#Tv%RYxG_|NF^BAChufDCiV_pauPNd*}}!gC$d9tJt*jIHFWF`yU4QU zF$mhIm2yAF+pqM7t7fPH_c>Jmn3=YIr{hZ2yV{s*m6OUbPdTn;?HUTNpJRSEH)xx^6*o5bDGyDOD6H)rIz_V*Qv#f z3U5j~p}BN;irSYgUHkYhQdSj$Rpw+!<3L6 z%zuw#EN#!I%8l9b(<$dKmA)+B?3ac0hxZ)qCbZt|Y1^hWq|ut*_ni<6)e-~**ZmwBAW~<$;7#P zJWzCFI%tYsVsEjKpvmCS%ovw($mYovvMT!$1sH_8wKh_W0Al7n{XCV_-ZB1*e2b27 ziQhMdrqkwx_>S>9aQL2CKn$G@VAV~TfZbtT)%Ydo-Pd2+}n%I8_hB~QVf{38#w8W>Fzb)c>Lp*z#({Ufk zEy;=F%?dy;$5<nV);Yz?P!bMZa4HqEDkbo-j!e}&vb z;Q!9@!;D+)t+Z=`9DLb6M6Z&q=;88Y^HTid%bfPVfx47(mT&AXu0oqLII}kX@g*^* zyZMrWpmo7O+AmCA>C4->A@(f4+_`0au!Rr><&HQBxf;?pi|~GYDaUH5DTIMSL06%@ z_6vS)JS1|*n6|Gm50}P{rCF{d`q_TrXVXfgQab1NtYOk?&TWTNH|z7Cj4@k&m&qC( z*?>=c_WkB9cBc6h8Sv>$`{`)&>1y-hv?CV;Y{`rK6q#c}T%K(>(B0I@^~_2CoPRLS zWa>u8^`QDe+Rg8hMwiof>Rk2XlVV@!Za%4iPGv|8uBF?7^v&keC5({=1FKiRWXOlp z4^A^prc0d;?Vkt0;HM_D(|!pb`W2|mRd%PX45qj-xRyL*`X@TS13skEA3?MMaqNiZ zc6?5XxCK`*o!Ub*b>4cJI{%`{a!G6wkdH4Ym=rrIlo*T({g0A-FXVJY6Ze=?mA2{M+{=DA^cvfCD8}O~)A!RKsgIPApIE!E?eP5~75&s`Ir!3c2SXaAVW+#<{Acmq3?uDar1ByAu3T z@W*~j9JTp7+)xg?qgpsJavt|W?ss>w@rNN2J}l&pX{x(+xU6`erF>Pc=ee-G=2W|> zZUPIj<2|SS_hvyA5QO2x>d8Z#``2gJa|KCXzNaroY8-6(dWg#~xiV6BZ5exwPr*1$ z8_JCQf67qA+K0(Rd|xvLj-Qi32Gv*=shd03X|E;&p&{ofPb7J5WmEFnijb?&p;H%x z+;itPbWTRvyKr78%X?}{HdHrt!Hviu=gtkaZLk$T-vTUzdI}d6YMW~63MHq`b%z-` z_I0{yEZukV-JMpfJFs6+nu5IC00x)`a}q3jczO81o>RGs5Q|0pPB+D;^8uqA`1eq! z<2JRW!)nfOl8sf~N5hO{*l`!TO2$!~9!G|3V+FZK#117uDGgG9ZZoi^&g%-Y=`6L| z%0A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 z zwbMjdXc}46vJi1Va`a)&JGNIO9aNXng`ZG1tLyF|COiiV)M3^u(}Q7-qNvuH_la5N z@9F06ln_@LCC1I!Gx#FO?;TZh|LCEQ-ittcZ|KB(3-mVW-a@?<-aDq|{z5DFgQ4Ab zklOpnIu0i5C@(iFFF%5#OEw4fNj!O4^?xSEYH4q1vQ*6KH;d~Yg;pxT(#JF&*P=D( z*{s@gZkT-?a4RItx-au%N+{8QKSB&pJArIJF$ZRw*g3=+S05bn9-K>B&I3i9?!fcq zhX;zoKjrLf@xnbS1zz~o6)NqH@)8;hFBIUkmVPupjA~27vmpLGhnWJ*+V_{E?q~PU zH^8gv$wUon`3bGb{rD77Ne%NI9E1#hqFQf0Iii!tq`gg)_Liw-6&Y{XgFQtY-N2Au z{usMPP3Tkq(@zgFlg>A&i65HvN~T_Hih8l0wW#3>?RC6p4UJu7>OaB+*j`zJeQ02` zM#fH=V8YfugmN|Fd@d6$D-*Q@y~bMEFy$$0;!UIUg{9pNoI!DUF3Pjq!=Ra2QQq7q zr64q<2X)q~)|%goq>AcON*0fF%^?i_th}Fvt73H^oMes(qpkrMiAJ*H>_K#PimgQ-JVACzDX|Dhj^4A=O2al(kCZkJX38aF;zbA7ZU8>3& zzTln5wcKJy-1?#k>Rmh&SXe=k@7UXYQ(rST4QeO5XKK2y{E!JBE`Pz)__DQu zOmhWWUx%d}n-a;mgG!lE&gUzu(dCbjrTB+8m;cy=x0SP}U4(vH`H$?w9p$u&6nB(A zWWtBbA2i{88%5gyZP4!F0F-4tp=qV#jhfD#MIPrDo9nG*p~d0Bk9`= z%q8Q!vmcj7oC8Vvi1e&O6s{e125RiEgH-@;3stC}bAF6b-wq(=$|!v3E|Ug%Vh7&h z*)LgGg752~x#_IK<64@>vEFE))NPLom9D(PKeAFMjKTtpmOH5cGD=NoNXeX;7~eN< zVeyU*7JBg4$mw{7e+=7u0p{`CsXd1iir)x5l%-8!-P024dv{^tRNPNO+5HrC0!*uJ zCx0JRdQv2R`NSwQb;|BturP6gJ$a@`R>czes+8f>bOw7cvU|BBmn`ES%))8HoCl6a zPxdKFTmVxBQQw)6n7Uwc;^Pa>NYpNvkvIXnY~A*klQrR;MfVoK)`rG$5^M4t#G{lT z%A<_r!=k$)ZLpWYS~k|yai;3W$Xcij2j;v?3CcfU_G@Wv5r-qZNOv-?=`{pZIBL72 z#c*RJz2lG>4!q>QE=j-<<#$KZKM>aAcM(a2cd;f(Dh)7iyCLOoGd^O0y;p`Cz_gW8xu)4xAQE^i}DUy31pO<(rbJ~GL>c6L8y8nw!~ zG>VVT>*O5bS4d&*jqi}vh=a@nRNWRyH58>9$g*GP(>)L#!{ncfAf`|+4Z6Ne=eg_+ zSIsC+zU}o~pUrZU28jp4rMoYKqiq=yZ8i+&;8E{u~> z`Lm4?6O=Cc3|?=k&XW56zbj$UbRk{P*?rZ07X}jNYsbM_X6$=ps|w=FCD|HXF;biB61w^PooxzX7)tuD1G$iJNf;hU+HQtr_B zG7NWlUo!>Y-mv30$+PIm$AmcN94%I@zoXzr;W) zf@Y&0WE(3pJOA+hTUj*A%@+aBhJ`1L#)n}sDZ5CS*V@}pbU?m9trBjO&g4l*VKf08 z|?mE{JM?y?v<>jx9RXM zh7~v6>43A0*WJ<7H0Cwrl8WT$6fQ41Wq=x`GImFJ-uAfohwpZI)a+UNLz_MYyD`jW z7tE&7Dk%fTHpMI#oJHk!BAv<`bpVK)_U1zYrP$k+*7aj(<5D%UV zlViuDsQOHc1q_fNTe|D-KpJcV_VNUJe><5TQYQB2NgdIdH#LNH>EXn0WI3wedSdKDxZ^p_x=fUh&`h;iS2|r&pDDshBAv! zk&v}{TmulYY5;AUrjdDmu^AZwn~_;_#pUd{#bfXjx<8G3dBZGH{2a#T{SxPu^a}#Z z)5@JmzA*RYp)qq`PX7t&yDN`ZG%zh7s%V&3Jj4i!S4ehA8!%+*v;7s zB<_>SB5de|%Oq?voc`!X>iV7DKboX{kcT*v-xuhZy}jXEt$_kE)?K$00Ud|S^iadY zJ_^oJ@pFJ&z2o0V8V2DKmslEZ1RuVwQKB+OdH)V%P3Pm+xz1l@9!%%2sck{;ne!zxN-wf?m7y1{i10q!uX{yMfM4y` z{r0u4?mwCbQ}?fVOg}dGAe(}b0oNlZG(Y&k!S}Pf7XrIM?Ox8)*fp{M1}PvDXbsYq zzWzeR+3B>r#>|T38=B-uzHAcu69W`bx9dN3|Qf_H9h`Z`p z43G}H8WJ<2urgcvb*`4T)`%}#*?FHyj94ah;6X9rY-34YhJ-Ry5j}X7$-r8Mm~JGJ z3h%T=d-~IuO7;ze4ey4PM<_nkaFXuRs!e@2^VRIF z2YIDtTrf)4b07~w!u#cZ@k>|*_g`(MA%?@fNhl zZ1~O&?GURg4u6m>ZK619dtgg96Sy`6bdo37Q;nK>3ONTqL1EGl0)*C{(RW=n`ONwo z-Xw+D(upLt>O%4MSINU&?wp56brWeQ5-5}!D}$?VU()h<-N~%XnDz5Fn2cph_a%M9 zk-fhK5x8q0d@F?k3zTr`Nr%6KN;VL_O?+k`e4iDw$=w6t$7vdEOz!he@AgM5d@Ir$ z?Ext!lwb;lP%lh@3IpMP*UX8z*bCWP_wmI1=u}R%8@+1JXwEczsxJL|{EBFg)0?=M zlkUtW!U)q(m@lXlALGG*NSctKBMXFpEqc@7p$Q!lGkuyNhxSBP{tcW+)m^9~>|WaK zornz~y=E6tdwAc6dHUmCHmb2=q-gbMC3}Hg7~UYULRe@Iqq7K6cU-^^C6~{iowHN) zqluVCUt=C<>(x9U1G1%UJRo}O#XK^lkK%bQ9G(B9k2(=PNMCl|zgB5}2c}>Py zlBYpNumkTbu1l9s791n#%wVq?rf}`* zZpCP$BUrD-=5wl>ZQ#|b*+$_EymXI9vHpUP(abjt!?>+bqyAH`ZonUPfCYM3{TILM zFc@d`-$&|F$$^3Je!fFD4~gWwA9Y9pz8{A>bl31rB!7iottPyM)V~-Azid;dP3l`r z>YHqV0Dr7bsvp9SisdE7JJT>g$Lfpgp23`y+(K`j&~4Kea;w9q0M_sqL;bHB=&3$q z{gtZxI|EzpZxvLLN|m_w!jY#*xgahGSij65G3PamHGPIj6j)u5oPel%JyIRwDn|;q%oKo5Ra?ZVF~2K5K9COIL?_r}7%lIXA(u^tfD!_| z#f+u5Yr23wRH1V`f?(?vSh2IEqo`P|=%%ln%Vdt{=Wu=*z#HBci}=<&24LIcA~Js( zi#^dT155vP`=Qb=vi_@G^JrJ74TTSY97gGr&+g6L!jx-^AXDwR3(k zOq3t4uW{Mgr(h#@(L;P98`5vor}t@=o&LS|Y38-G^$!9P<+TB}Wb<%&2}k6k4UvPS z!&LqtS@Nm;GhKp!p>m&%{8Xro_}W9ol7?dVVSotjRMb^nq(O=U$)B6+ybpMd1=gN* zqsbPJi0H5NiGHdr-k5UR4aNU-tx6xJc=(+`OJNK*wB^%0PJ~({$XQZo*kxt!!-k90yNhAQW7-m*jN6S@1mHJbuC(KK1lpA4QIzeP& zr=}mZbcW%uaJ+DfG42)e8I#fW@NB-c*RB%~xcl5=k%n_C&}li%0k!cR;`W77 z@k613TCv`M_reANYI!5g=oJ*&e9&@Iy=h#x9Arr8plbk)q0vD3%O>+B*kcQ?xLhq> zE)1b4P}}fTE}ha4zCeBlXE&atfw$R333K@;Qld&pU}A+&gB6k*{1dD(o&e)1W;vk2YCcs)S#JnJxKB!H4pnk^B?F zvix%^Wmx_RWxZsr*5YLg(SDAs>$0vIeTbn^$=g?I5<%R)=^$+A$ab)#%T z!2Mw?G{?^w!WXqXe40D}#R5ZPaLRPHxzD)sii+!iX0`&3Pb*meLa;0z%Ry)eG zS-=>M^-Vr13}%Cqy}2RNS#Dp2l=m1kUUP$4O!!MQwP~P%)xOlGN6u-}`?Oo2t8+QB`LB_A7gJJ+f%r*r<`6{B-Dg0jA_(8=$lTbo=7xvkM4W>%q1 zO@8SzAH7nwW594Hk=m6!-EhDPq}Aj(i#$1j#LWk9V5>HWPNq9Fi#n_x%)6EwX-!|y zM$VM}d4|kbRLb&mqk`ps`(I6 z)R9|RF%(=FXOs~|e&1?o;~;BezBHO)tCKV;-agk>XEjhdzeOY5Wlbw>D4{1YZO2=B z)g#`H(|!GOo;opa(<4Uvd>(t8<{VEv>}#JN)i9hXstZ*XiG)z+}&Jn6R>%ynxlM(Mn`$k#gkH5U5v2(ZkSzPBFg z5yEU8XN@y+3(e}wk%BG3NV@QS!8Nn$6?!9CXuwa(DmpqeUTP?ek$vvSKVglS^d3UY zaaAzs8kn@~>LKn*95#&^5_0_UpH1=Bo_6wTAAuRe53{HJ75;cBW#std47zhPf2=YI z=#BW}M4Q0!$4|Xu_#^s>RLsLM@>*`mZ0uKhOI^D*b?q1e2xo+rY50riAMwpqSGd=W zM`hf(XuMoanc<~h+PSDGU62};4vk4I8iPJuCM5hg_ko#mYkA$1oMKDO-Up6mRGrQ7umGDerUPzD$-WEv>&l)dHwLTFn#W2vhDqStKd+}>xZYE zM%tiD`(vAy*AGw27yv~r!AoW6&r{iR{F)>j_E%q)Ep1j|pq;$`ujT!d_8nD2Gk{wA zR>@lx_cz)%6xVAjv!!R+w;*rRvZW{MEp@G}+pp9d6(#MZq)C=VdyZvQ{{vBIa}*;P zNuPzqpsya)BR(y80>@bNJzR7$mdQY}Fm!*x&}e+)!rQaEdzlwJpb36)cyDC%fRT5^ z>t3~6wDL4Gj)&c3%a;CYi*JES9#_9`>mLsoG#Djo(5oL%GZq!uiiUNionZE|sZT zrY&=$+}tG47o~4nE69&c-^9p+LKv=7wKF2=o9rSCV!Np%l4+{)E?`#$zWW~otZHwz z^pDNP*2FqD50)KbtJdMy27LJg<|_g&++9Rl^LQLeOx_#%2G+wzjcRaTnD;G> z=jN+LQpSW6sUtRhr%I|%M^7_jHP3sA3N=#osgBdi>PKS$?Ko|kmjER7=}D)-{{W(r z@_SsUZi|DfppcgJn%PH(%J$8Tk`A8@zO-XkT| zk6wQg(}j2cjBfDtdr>H+YRpVVl^w!ORC836!6&wtNxLf;*j}dUz>a`76~vO7rA>zu zGmVAbn`fi4V3bi7TYIMT3YA?yvg|x$;?d}<=AeXV%g@ZU@^telx;epib6Wkzy~Ex7 zXs(+jwwu7s44{s{$?NOd{JxghzG|`HINCF`R7Hl;ID(Aqo!8CUpy^U^)mW+Ardy}v zbt|v7OzCI-MBg@jU+O-M$N}$)5#;ss;B*Sj>vFz4IeD%DSX%fhLG|fK`pX6_=QWij zPGTj9y*A+UUfe~8@xy0ov%T+8vSn%4mLX8QPud-0+0s30e3n+7ExlJS#;}z`vApIy zZ7xB}i?H~{rd(q#e-VuCHU}A5GOkMhCl@KsHyhp3e=+{$>GUp>bkaPp`%ltZ`ptXh zhNA2fsKX@BmY!9_p#8z;o-`>z{Yrma_Fi?@G4WS2fsR^rThQM$IW|424*!MvL!dy}*4s#|8rzv>n% zaS%7$V*2D;hI8S3Yv#eopSRh7NkJFnSgP&SXD&iyTV~ZO?#e;A0K!PRXc~w!a5eHb z4`s)N(&!h=i>05X5t=DjoH5}(nczchkcc^ZhJL_xeGla!ACH_zkf=;=y9+kce`GZ0 zT<6XuU~o8op#R9I5s`E&@EGS8_@(qMd_(JsiLtxQmnRB;#cRRfZ{d6OhaBJbL22Qo`;d*Z)^-{~Z_M^XbN{F@p-fU7`iDON2EO7Lj5($@DYC=M zVN6Ko%8_2KCWhA!%HJeZwLt#z;8ORpOnG%Z3&x{Z_g|gUN^w42e9GW9YSO9SnZmw5 zqA*|x9ff}6rEll3w9&uhP(}Gfv5(EmR?;MP#II(ZWYJF6TO*lMe`4C6&NyCmviIlL z#H$W#tWPuAYnu8Zc?rJy#}BfPXc5;%YPtSgV~1&!i~L&Y5p7~sxitp^f=K!)HsB3@ zo?)}_(@nuS-RMM=+{AI_pf~mjeK7bhn{yX~JE%jDdFhLleu7Cq_?%*e)pUMIP+v>M56ppYp%^B$yDYWsUtP#LHHzTjRXydI5egQvh$@-Sj> z;?M^p{EJ#1jY?TSFiSd^`Z@eLi8JqWf2R3QwsaB^ zyVW*{>Kf|gypn9`Tj#k5z-po#z4o`W{}QHfGM0=vAf9nLv*)65e`w%SprTQsEI+ZN zWbAp)?fXf$8Wc^R6Ulr@kcx_%y;IMSM@GNkWF$t!{zuCAnB6VS?}0H4CDXzF1y!Ro z54^t$#L+zPek=EGF|!ixIeu4!_JoM*ivRI`R#$<{Yr$u`p5#vZDBiw6FPU)HK$vwM z9#cA3coq6&c-%mE92F_*<8-g-5_t_w6lm&Fv6BYErzm~4u@RI#mCZyLs(1G3?!rCj zXWyV|)%%fefuNk+TqMG0eV2OCsxug>(igK1aB&BPb9~|x(Nyg1NM=z9AqZ_&2Eu1* zK@%F)0-afWDLg26!ij3kE(j?HEWEU8;ia`aNTbdi2v4_-s-#il7M_G(Z}N&dEiY!m z8#oJ90%B?UwyZrN2SoAy^WUWRm2ReFZ3=40WJN#KLm5m3gZ*95MC#QxkkJ)l#N0NN|AJ0quTI%Hq+0t*=!d4T_0#r+cPix($ zwEeV}=o{xn}JYY0* zh`K!(4c7={0r!sPu$K!uz}_c%m!-e+hQQ2Xwg)DI)BV?u;qKSa69om_j6@>?{nr)+ zl1tzkkSfr8cPgA5GojphHgia-;-3Eo)0tCg``{U5FqbbK@IpLlMZcIZ=TF00V|E`( zMe$AFB6+URuiHXeHR=}DVN$>jGW7eN%?gx`C1=msK-w^#ER;+|OU zpXkh%K6oyD$&^0!hUt=a90b&>sT47^92ksA7Q51SvZoF%G@r=A?2_WZdJOYK^Bz2hcL00pgK*D4Cc;LLr|L2_qr6LO ziDOV-F~jU!yg7<%e_ho*nk*zP*Xl_j=huhvQOc~k6&a$KxqmV`^?4Z7Z>5H(ZA-Y# zsKh(+HIe>eY(J&Hwb9ucYzT`>>e4l3-b?1|e(zU0R9u^9c05D}C8qFk(pi|L(`4h9 z;uxS$eQLwpfpAff_XmPyioEAZICo|HDIztWiTXTI z-dbv=#BG$AJh8u_2(Po!_iY2cI<=~$UvsSfBjbv1I#Gk4DgEgm-^+5m-o7bg*rmwv zdIRAjeb{q`IR552HQ2ijB!tP94u)tFU)9PXM8*->sUFZ9_x>#dgY0Gwv+5CHG&E{~ zuY&)^uWk&P&AQDheH!*5NJU^X5d%Bl2^S)4!H8r+Mjq6_()UP0ROwP;W}9xC z3``x|{YIl%%%OpoF=h+T7(Ko(S&}~J{l`{#4Cf?L+t6{mKX2bJ;9Y`?wzYmmW2mhj zi)g*@Vem3TcBLyE#1@faa4~V#H}m-ic;q~Kv^r4iL?T%}em)a9$vewL8GIe#908Cz>O>+Y*WH+2_nUhkZ3F0p=StKnP2kRPgvj_-qK8^*j0Hs@h%+h@~Zk+~%xO+YTb}+^)qOx4n7tt0E zk|8iUv~gzB-2>t8DCxlBwo|uh7|&@i!-!drrLXhyov#?9684D~Z=XeMG`$SbzN|z2 zgI@ZeWLWCY>)n89t?F(k(iui4(*I(Bj9OWjUPk3I<00TVF-p$}_71bkpWC66HItf zsDD0#&+}iDOS5jNIIJ4dgjoSHun0mBD2RPSn{7Eky{SnL2kMKC4N1v;o zS>OL~`LS$$QU8MAsKkVNw-;upNKd<|tpA20j-e>Mn%;)-zYv$V`e-DT{9^IvAM*z2 zf298gw%2Xn3IpO1H}&nE_Hk_>x$uEN3DE;fta3lFq(<-A(mR(5BbT7^>@kex^E45}E|BCr{QfkeCf$(!cRX`}-{yp-kB@(lA%WFDaAK(Pv zREyJ>zzLRj)TNi>c*8y)9m;5x`U8#wumWi~Kt_wpOtkn1<=4qdT{sA&d7s9=pmFhO z_$J=koPQY6sIU2EXj`@nhF-k=Wa{E2h?-x#{c#b>wybe#9MAEt#XBw}MjNQsyv}|C zqkS%`OOKXeYB8|f=*F=2pGE$h_!?%Fxfa}g`r`C$W^B}+p!Xcy7dju%*o;?+qwA}A z{6LU!J~ESO^tm+JIz3=6<&gFM4@O^??!TVXDRyA1MvV#IL(Rq8;p>b>>33c2KeuE+k#b#btY)Eu6!J_;{WOPEoXewuEY zGth^7e!QY^X_Vyu$uBLSu2(5W1<@uUp#;Ty#;>(YPk zRN?|0AZm_-oz5se1f{>4U? zn8gk~(K1n;A{?01kI&+E#9WEBq1b@)tTNMbrsdWq6KN;(cSuPV~HkADGPR$3nr58k{~>OA2`c+fL%V~v0&n&q z@Y17mtoc3TolY%epX0L6xt;a0pA70O2vdHhG-AJ?{CmIUqw@S=C`-E!k0w#ESrwqG z1t64h5Hvt+;*;6q!&)T33I-DOnMRCD`@Q1_)g%^~wL>&n@m4`WBFKGXH0R_fURP%J z+>n_R@I2%H{SiC?C z-NFJW>Q6M)a1$!Volqtm){AU>p_k)Dg8^?BZG`3C5>8#H%?W2Lt-f!x2Oexes+3k6 z;2!YOCQje^&<5@GMxBpML?Z8-ToIct{Zx|` z4Poi%+sp^#b50kDfUJNGATIOAg`#v3zzLN6Prss=Qi?&xxoK!~|B)&aeXpWFpy?+1 zO6!UHydu>f6SHF;@17D~L&9bA9yYxyzH!eelul^@_wyhuDqA}5zNx~Zp5qu>Q$3eR^Um;C5Dm`H z0-~Fz?oy7-s(Vu5NAOr?=nc@sPq<~x{6&kAW1(~xZNV@;cyF_@2PNVWUfC8>SiVT+ z(#OCZf_oWIw1b2EHAj3UPFQ%l&K#I%Oq6W;rpEs3pW{k}mrWA(o@7c-_>~>puiOTI zX*j?!Vw9pGe1X)V>U{!*`onEnb;V2e)=%GyV$#F))6d7}sT)W5c5!A*L8O}fDaEyi zjTW1{$e>^G_V4hOQZXx;giBNRnR3%_U|=lwv)84cSUTFTWz{ddO()TU0t-f?*p+_% zRolqF{3F1pQnih?e}ia^jcwln@0WZQD)e9fr@|z9Vfb~aVJ)Qm8a>wNJxmJ43*16j z`m*^9wL=KYNmoW6I+!h;5|lply4tN|dH8UZt5eY`@hVCjnzVGlCIqfh4+Zw(9XIhp z-QBM7HKYush4`lT;M@q=+HID`fCaAhiToa1llOZWLgLUhkrA@ES`c zr#(IG4X~rj@*!!DZ4{zi7n#!Eshp=iNBbtzCYh;=x5xRKtF-v08Wg*{&XvA664^6k z&V%=?UyX!!C!eWjIne^em3kF>+VN!Zb`}avMH(Amf!-Qe)Mp8TW>mXZu}Qwp;FTln zjEy6l-kVuk=$-L>BT=`%O#(wqvr9oim!s#60RxHN&TZ)NPKNBfl#3e^>B{qwWMWCXhbi+5j6Pfk;%5*d19`AIP0wB**k!B!lxU0)_1ENX9aG zLp0+X7|d!h76!Be^np90qmQsE5bD2SS|B++nx6b7OHmD(B|&b#E6X$$hO(br4MiUR zzy&H6lRfPld=+#IrI$>LR3F~*A3T(Yn<$6}EGmUAO6j zVhqrBAe}_mWJf2d_?6MgSBkg4L}cFinQS9~$LPGs>+kdqOfX9&#XI{*#DKqE0xD_I zA~NwQty?U=$*fx}O0!x8P+4SAo^U$mlh9a;V*w z+lHDA#P(;0R^z{odZIlH&>!v8@TO59@Zr+pY%T0qz(^E=t;VDV8OLz3eMQ?>h7bhm* zTRyt~(BUZbG?z-AynIlm<=m`z_`J|a_2f%0CdbwG)z@*R7t*=!*K!SkxpDcaB z1;!Zx^wYCg;_08qCa%azDqZy{tSDQ0mf{(lIg$R>@+!V@JeTIt_*U$b znXgiZTN1feFVp6-V_OEj(%%~cw+>p6o7rOqPpnIzsqJO+`CipF7oUYas&XwHJ6rmI zzEI!1;riO_Ic&N55Sa2#8&TgiWaDD6?5OL$XKKtHQAo{s_}u?mNi;R3JW3;r8s@$n zrP{LS^n(q>i=K-`)2CLH(4dCu=iZE;v_7=$SAoL~nJ)(pYn^wriB7&AO_Q7TSFrc- zk~h^ajXN%W^EkISF-?Cy!nJAao66Cw_YrZKLhpAlE)GXF(8udY;b5`qLpprkIKB)@ z5fcExaQ1}AH!OFDCA+@3cG~+aW#Q~Mj@5OKyxs%~{p<@nL46K8>|c0>G`qxv2PE^n zm-stSIEg5=#am8N>?0ez2^d_!hvfv`--E2))g&b18UpWnMO?$2sIi(SVwl(h^UiRl_rqc#Y!Bh1=UtAo*0O>%tr9SezcFXb7g7%k*k6YnXcy3 zbB!7rJNISqvC?+Dmp<2MtBJvTi>EnX5e+~j{jtz5G!m%6SR_+d{_GO%x z;$aByi(Gzh3o%{~e_W*Ue+X=~cN>HP9)q54Gi2aT>VK~Q(Ts|Bz#n+Q_7~!ptFa}* z#E%8?-~lrGZR|1yC0KBud_=-cJn5&zd2eDSp@u?lKX19V($^>5``{iPtnBAjgdsBT zc=93fnc}*~b{4+OySIo&d0!%#gTfT=X8SUpa<=g}^!v{OLa9D}pI1fFuZeWhFQQfz z-}DX2^Y$|ojOTQa=}g+$sG>hcZsG*nYlvH^xbY?qBk<4$mT~`e7CTLt52PP`poUWV z4_!2U->!oC=TLbbWnyxOe;y}YC_Kzn9}S0#k1zbs^U&Xq`F8x|KM?Py88pwwPkw_? z;BBM>HESMwfW8L2Hn<2~kxVE(xdEj~hX9CDQmT;88^)kWPj@f5l^x`yG4v~q8 zoLoCDa#QIa&ovmpaM(0`3s0nzfzQ5}7{j5v$HCB_CJVt&2n@1n-l;GojLxIK8R_RaIN#~pMe=kPS$@Nqx-N{z?q7Ze>9g2 z*@|EC0i5ARdfo@eB5Vu{u58CaufJ#v_fvv3{Y4x>t{DKnVM@mZLIAfz<+3OSbE1keMDnx#K}z6fTtM~ z8QOijYBdVI*;(kxSmNhECaz`8rxE?LhH#~L3x0Mqs{aV;tj_EpNexr+!^O7&4ZKHH zX|vgohObGs^a>u~VH4hZ`IJ4U7p|S7!Qw;>z{G@8&@$VJkCHiD!2N~i)Zp`OAsE7A zvsx#pfWZg6b~WJ_Ec_Nls(;z@+oOb#bOFn^(cO&vqO8koSxv{3g|+8zl$EV0L_IWR zmPi#W^O3(l=0P{uB?^CYmQ}ZkzfzapJ5cy6uL9GyH(Ejsb@G2p|17lajaX-*J+$r3 z_Rd&+Xxrh=M64q`@nBv0<+^m?@^jb)y6sP)WTGuR@x}CWbrWCQ_U4jUXL9b79Gy1t zX9i!3zXFe}OFvncYB-YKms<1Z)T;Nxu$mQ-{>klBnGN;t8&h%kqHJ+ps_-wB1%ZWo z#ufw;(-y8BJ1W4@DBTJ^TDa>SnIVE(PKh8VY(pc(Uwte-k?dS>Qur7-!!Y@ix4jxD zK3vR1ym)P(M_sXlUD`P?T>)6}AdBQz?t#w&jC*W*ozqsVhL zc|yexzB(n|IZ$}tGz+VN!hholnPNVj5^qw9Q{zzzD>xY0`>SAN;=xF26|?4WN%`0X zW0P~zg?;4c-&ZtH*u?{+6L>4^1yhCXyd_TT-xnMx{1lI1R3KHjk|$wC6|)+2)f&qY zo_^YZ5*(SkXI^0)X;2rK@oOhbw&GM&-)zPC=5LkxJKy}}D1G8*f%Dmlp!qw&{GDX} zZZ?10%-_q*->CU}q4`^B{+?m}PBDMSn!iV&ifqMF!*g~ONFp5l8=fy^57n%K7X>-H z=(7#BCxZ{OagBo%U9|UG934N~VAQZRgLmb=p{)O&J9E-tF4IE1y@Juqv2saN!SK_%#>a z>cVSWxXy*gU1H1eYhHTP`}3FD?+?208!o)rg}p9Z=fV{(ywHWyTzG;D-(PLZ`wtgB zY zR$XS>d#VdpxUkKIf9Jy6U3i}hpK@WJYfq7T_u)LtmG8g5<$u52);Gb0Q(SnO3#Yko zjtdvKaHR`h^UHAspJl_oIWELlrC%Rh+Jv)Qs8j#=^?lTZSV{Hk3z{I%ce)Fwx^TG* zPjlfu7or*Ir<>qRXoEl?=Y{Z1(di?qjvnI673iNfk_Y+-sf(zvz#;*_KiV0`9_Re=9ti;66b0N&k zykqDxVYdryz^d%0ZBMRq;oWY0e&*i&bl*7YeVTi}!=?Ar{n^ET;KJ8j_$wFs>E^Go z^+u&~^1IN5pK##>7yi+ud)kHHci~+w{G1DKbm4U_yvl`*F06B*U;iQ3?uT7?jjON6 zg=<~-DHkqq?XPp;?_Iu^-240P{Z<$5cJaGhIM#(h7hd7Q<6KzgLce`&?)^p=u5{rY zF06F@`GgBkb>RsvY;)}{a_`^w+voDnap8?F-mmw0_kM-T=f_7~djGwob9A3@wQ=4U z6Z-N0x8dUYXgI%&%Eh+)U8MnAPl*lJ`tL6B;S=5W{LKH2=cCIpSs?00m$$Yn+0oj0 zW+K?t9qSCPZ|{f&D@4<^&AG^mcyN7JPjE|5d!oH_gP+fQ-w;a#6K%0zy#1P3uxq`| zYEsm8q4jkpW=3P38xn2vgBA7XpW8ZlLLk)A66;RP>}l@Y5R1)T_kB#+MsR#eVuQj8`|2h+SswFv#a~+o_Hd;c}wrsYbwu~Gxyx{&cC2)-t^gd#hJ(dyYgmUsX{7R zDq0pUv?c4AHxs8P^F2PlqSby5M7rXM&Sv`A-WjZ0))Z`MZee`3G{=MSL~}=MM(~>E z?(SHtW24ME{PX}?sn&NTJ6lI&wn;1IoOj;kSIl4I*ObGX?&h9&ELgj0MRa-N$}3ld zo0dmE6$aRwx;8g=1VMqGt-&)Z;%A|s?z;-cXY%y zGA_L1sQ(WBhZ_Fb$bGbH4fCfh|xmM+hnu%MXG5T)i6v)I(b?{RJjIP;s6@ z(w(btqbp}tMWtRF{P>2E@k{*pB`)7e7d8g`fvIio=vdd>vN71auB#^z^M^NZ_SwM| zLS!g0hr+@2Jzbj&DFwT`;!tTRv3kEAHf-Aci`yfA_SHxOk?VAOgir{MSzcm;P zZI1OcZ-@n(x?{u#gDcy?pS;jT)Fyj+7>5b^^k4q!I=Y%EXH~ZibJbIRXF@rnvGs(e zI={b@Eucm3!N2mTFK~n5|NXIGSMEjTx#pId!xvkAdc=ieqV~PSg{L0%Uhdv2UAVx7 z5f`p>;aV5Y+R(mUb+vB-VzcebtgE_xw&>!o>W&dZyn?{2M6XkqSSgA1CT4ecG`DvW z--`ulxVTEDI0kPPbGwq9C zPF;K4$Fcbm3$~Ezpsg_wIK!1Ud4iwg=$bdR_r_X}sciBDTa%w_L_N)k1Z->**h8EA z6t-LmtH~3L$Re~tp=Vtn&~mI?Gw`tW%oM21&wqE~g#Lc`ucET5SO1hrOul_XXIGDi z&Uo4SDaHhXYS=!R8O9;a7}Pw#kuq5%`6(eb+v#(sS%IGJHL(wKZ ztcZcEEtdZno=Tj4kfE!(B5p9v^xD=*l{13sgn6(v`3$MEtJCzj$5BKR7+h;$r(R*U z?A+MdwWTxQ=0nt@|HcphFTQGD16wF#YH(RB5pQYkjs+ttS2hN1S;56f{RvZpf@&OT z51cz@wKezl&Wguow|2F}XY0#M+k?2FLsGA7YexV|1(GD(5bK03!g}GX!H)KID&zEE zxRn8JP6W4hC3}K2G}zM~-#BZ6&&C2%DQ7Wc)!}Ce#(H|Xddzo?#3i8>%j%acfp&6= zNxXS;%mLHLGc#c7jNqZLNe}L~y3z5oo2)+A*lEL(9V7L_TW=is?&tTz!z-%afC zP>qlt+~*Rk{XeY#@TQUNsC4c9@7Avc9?c!MsS*4n(WNsq_H^}bg^DZUvLr%^*BBl- zKe(tl-rfS@If7mh+tQ9gW0_>Id3_?*6O6|?a|+P1mC*(hF(cU0(S;_{-WgBCASAR| zr4xx8-PNk9xp7{JR@D=`IvFE%YY^>+w?wk1lNU4K(4CRl%VHb4678T7ZB||CLtQ(% zufu=akLD45P@0jw!eLO|BHpAYY>M?j(uNL|Ihc%_mZHRo6C~qwQ+iRZy($m>=|oAe zyQgbiM{LuqV7<@B5+MJq34z>uYtjmySg_SJH)yJ912nN7(uFs5C$`e(?vAZi{h&rQ zh>fTGs|xHZTiOIL&Mb#^6!@nm|IjeWNB8C7W8Ki?07 zXU{&{RAlA}wz09;Mn~7AxABsoASFG@qgjienx?jQb|)R(Nk9afJCt@S%y(0FM~qbp zA0SrVtn@W6E{oF65OBz^_%h zVbJm_et{PcwuDw>P%-6DeXKvZDWu{Se(Ews%Gcj2*=yR_L0)F4r#G~pN z?u8Q;t{WekE%QodECi2YSWdK^&zQMtig#QisCov7*a?{Oo zD$h~-I=d|2m;nu2iEEx@K$;Z{#f^!^3SycNN6Q8k^2D{q$zim~js6_m(k5E&bb?l5 z(1@yO2KF$pi_W5A^I|Y5xGqL-Vk*@a@-u=PAp&3CtC@c*eLT@MGQFtCFCeISl}rxC zEY%f{1OMhN&0A#xF?c<@qIFgUJPHlLzRz*m0(P*i>VOrdf(%Rxyh=%#*7#1ZNUs+IUqU<_LKy? z0Ul{5l2E{~LC-2p2INMw@{MW}oPIJtAi&N<0&h0b-{B{NA`PThoHsX|aoG~P>`0gl z#$se}!HtJbwfOLSCY4D)j31Wc8K|kgzfluJf|8Oj^Dn9kVCw6T*0$lA_HMoR&a_XI zZ|s^m!K#n^M#}p@;F3!&nVF|^`C`QJWg)23#@v@E^E+uZKA%227+4StTo?>o8w_0U z|D_)BcKw=!zUyJ8P=Hht8*Auo^M}P>g7ua`%vqJtICiffX=(-#H_+_F}VZ}{mfbD>dn&cqNgiX(CgQ#k=AIce#B2yVk|V@Xr{12)F-#uK$-TxM_{cH!w9dMFT6NO~lxr508?+F(35P z|KEm!M?qd8K0N+^)h~GD*T0x)GXHV_32U|;Y&P2Ow6lhJsZalY(}($lODuAb8P&30 zpUt8t$67Y37)e0;%`eKNv3hDSfyvYeQ}wiE9O@VyvzM<0;3QF)_77L#1l4+Gar zVnHU(!RFw(bIu9Q^xnFaa2TjysKrS%$w8Baz>kcek&Hta8o+1>FPjG3MS2Nbpj!` z*{EN97gHO~sX`HW$8hjb=hLb17H8qAtD+er(#rDEqybQPIl(X3mfk zK#Q$N%H>n9kItv2Ir_7s?yNK2s46H59nwvfMeQ6pTJPq{E5a+y_$X{zx!epEwOhTe`Z{7SGZW{=}81T zlbhDXdb9>+>ND0D(+l*ESbI;aY%`eX)sEJql9-{h1LzN<$(dV+Yu7}q8>5y%=s9yP znCX+7N!Nt^891ZH+W!rI%<%_np_u_q%)}H0ynVBp559n(kKCrbMGS)aJlpleQZ|@Y zX;oai&g;{dRUTyyr)-%O+&ZxTy)(8YnEw@hE)T?DWHOEsJa0Up&sIyK4t^hopUv2v z9C`*SD$i}zdi2r%T=o&)KVUYus_B9>@aE01 zCfEU>+O#RwD%-K)h|KYfw}dT_d7Iz#Aey)uU|_Q(mXMc*TgH$rSfHRXm%{KVpOS~k zE6}*8=`!(6Xs}8AF;rV?_^kD4HPCJ6rNUVuY)1|rL41|qigIVN) z=7vq}!{x1S-yi`htx(Aro#jol&#iR!)Ta8C;o!1RLwIq+N}VJ6$yKz=uXw!`PR5k) z7+}N2Rwrq)SZU#`RVejY4Q2hFCpCYAVI8edWJ?0ujp?S3e!d~_pV2_>BIph}Wk!`kh*w!F&v3Vy19Ky6>;#ce8q7sbDFP>r4M<-k; zca<@8gMvvcN|=>+I+{`VT9F|YOKWEh+pmmi*>9b)(ko+!vqZTJ0U}b?${~O^E*8?P z%(%i*1iz!eYhbeSQt1)kqw5pN7$XGcw2JsyR?1h1vLTKuyJI~P=dxV6b)Keh?eb-H zp%s@3#|`~o(%#Y9(u`Nf%wQv)IjR=NA9;|N&w;$}O)Eo4Lin&9NgB&9@4KRd{yH<1 zt3@SK$R}6T`)uu)ao4vG8+WXI)|6&JVA9w|#GX z+J*;Rc!qMe+r3yXWId;KIul!VaMg8JSBQn`jN=FwwhdHrb zGl~b#!O|FHu`S7{k&nexjqWh51}i$iK_AbV*zk@th;1_7S?gG5gahOzcrDCQy4$;B zvfc|gdbi#y9Wgm!fQzsR>o1}2i;dsfIviLKoSG2(>R+&;JBX2KjYW@u&p(gSElkly zSKS&zVb{FfX84=wr;z~zvt57kTRbCZ1trLA3~h-nzhgFCt|xyrVIG{O3Q!1{c%q$& ztH?qs6?0AC3sW?Xm_0G5Q!PF=U(S!yDtJfbXavS8e0{Q`V}_x2W8Ra=-2572;+NNm z{fZU%(SZizNyJ#dNb|RV zK=1rOthra~ggB@g$2KF~a{Z+CW7s9onkJZ;J`BraTFC;nCJf3Fsts4GGmVZG3==dQ zdRQ+9i|n+4S`d292gJg~pNAoOdzcsCT|?KL>m($@dcE-q0NPy;ih*!D4xD7&inGtb&vL?Sd0G-0t7z_lG_KrXe;_UL@H=PD1+yyo?;Q7TV~5wjO&zmm ziz@vos2RRm~tFK+D7lmqPv@T>mD%5*@gMC-1_ofD$IlhU^{2G@x&Q<>IuI{;d zmoJaP7!q|==N700%3$tmtxOs`H))oehI5pF^>j4H+bZIYFquZqX3;aJsH}*sOSX3; zj9^N1NrRby59fJ-MzlmUdzECD0_8^uagyNY`ybRdZa#n5 zfaA~dfGavg5>7X}$97`@3lXdGqGaEYzrBwffrGZ1j=k#Ssp67pl~>>2@4gmtylK^S!;Z=O2CW{_7ubl)Q}q~xT>Ljjkn*Ubr3MNJCKcE4sWa-B4=u9 z%(Kt9m0I)^8ti`g-(ix}Vzm7;D_ShXbMx!f}moHXv^Vx}|4^=ht zy9U*&rn&z3CK^-vFoGTP-6B9PfrGP?E3TESmr092UTdQ3W~s)9PEe9C&IvQ@$xq6YIb%He zY)=m={kcortgvrkuv{OTZ5rx zb#`gIRWo?xtfo|&^xE%+6Dqx<)c=EA@DUU;=f6a^tzU%tu^>KD-#vU|L0^GB{6G5D z2`)Gc*0}O#H-uK!M&<`*H}G$9{jxf@z^X}SvOBn?i>VSkYg0R>=gtii0*;OX(qZ+h zjn;>kt<15v3uc{n?ySn0b>UAJ4zWH3D&PPyF?re6M)GrI0 z*370+v!lzGU%aZ(weG*H*XBH`*8ifN8jf7smNSVo3(a61D(WAz<@#g=x~UBA2iROg3BV(u$9Gw)qa%miB_DO9goZ>^35+t$^k;ZXKOdpY1alr zKyvDL@A>K3`XUAadE@RW1Akl|(Rp+YuI8t&#oUAq!_mF+NvL#~s`Aryv^IBN8E+Ra zzf$WzR|*C5>(}m^gmnw3TV{Q<>|cDf$bgH#TYqeZBN?`2M_)!@ByNm;J2!2G>@SD~ z)}i&Nig*&|dK;Sf8Rl*H&#vn&y)WpoVWq>5-7bEQ3%9%Yoe7(6pNl`}!WUe4olAGf zy?ZV^?7~00u*0Q$-@T9dJ6rA~7y2!1ZErC{g*=QaZbMf$E3sxjhtVO~*I_;g#`-QD zQwdopGw<jL~Ud8Lo)0Rt^iB9wCLe#4ByM)X#lf93h-&g^cPi9hn(IRQ7Bn0<7* z;3e&y^>xbv6&0*3tPTW@)?7Yp|CwqSPWRV$oGIP3&h`%3GX1cgwxEIrgl4lGt|^`U zamLp+3&)5H8(p~Cg&i(TxUkQKH@omQ7vAB*uetC$F1*i$54-Sj7e4L6e|O;_7an%u z5f>JH#^2BxG?I%Mi;Jh;c6Ft+J&ty>~LYX3wvF7 zoeTXD@BV@1-v=N3f5XSM-@L~CQ=N6Y{$7y4RcIg2>Zn{G3~X|kv`nkcZj%I_3vrx z?G|64CI)Qp>rnf_Eb*`(%zFF&{T?1Q_oL?CE$;H`Jf7`@Y-;Oo@9GkJckh8-#J1hO zSHr(Q+}7TwrDiYNna+0hQI!mzBpSr1hoV_-9{DYN)tret8qI4j|_4j_=_pRqJ)k zTFLV1&vbU;-o3xO_n79!H$=$c-j0yHJKoXNpV1V3fZpzoU7bBgyZW@W@C!LdfgtJ% z73l0~?|XG7>v}qmCE+@I_fzkFZGkq<0i@oY923ZeBCgcB4(%=4kUr}oR2yyB_UbHS zfN=EOfi~J{AH3);n3MdD_4Y^-u7hwL_TAOiPTO_&nE1Rq*5B4Id~RquJ3ZNfL@Rim z{q4zEUegIx%O&f~oqEf8hFUH@CKU{B}> z@e~Qq;4kueLJa63K~V{HOlbZ3+K*Z zUi!K8?V#m*kc0u&%wv z9F%RSj|N{u?~xVz7rc}E(`?xF7PT+e&WCr(2Z`V+KAM~l;S=r}Pxl|$$5m&huP`U& z)RTVQnYPY5*591l)7;qMM=rd*M9xGnS`@t5nacQN+_oc?Jw4LNdH-}AUN`>5-f(Hh z_3n#BrbrS%?k!pLD8D3r;=M$4iLX)nRW@p={3Gur5|H??O}K=|R_cs~)ix{CJCtKl zuq9F}ZI9x)EIqJPev3na?+{zq1>?o{T1h)C5n(?>ZucmxoyiM39u*|f9E7HPTOaK8 zYmaBWIQKddPA{+FKIPD9IieVwI3-tlIlr8ml1*jE*TaS1LcN0RyMj;}Cu&0`j!Phs z*GuenY9K7Q?;@V-7(1L~hGCK1LBnPIfG7~qw<4q%z6T7_lxym6cORy7Zb#|`_?;UOqQNlTl2%iihuO>3>gc6Zu zPJl^Iw}DHgnB0Gph6rK^y9xsHS)7@u9IkUjT@bnnH;KZr^+;$4mBWWO!jeM-6KLVk zD_(n~rXrTdt-!`~yWa$oHO$CH*N=3*2%@J4m5Z9*)6|j_OV3$MRKP3eD9EwVU|>hP zqP0s|)ig5eJy-81Wc{!ZuIFCdUlup+FO|Weq2-i(Cr1H` z1Xkd~QS%{=O{S$oe7JEP(b`ke!T;+1JqH(Fw2>qUzO;LKI;TlMYuIJ$_(F9>`bJJ#Oh-uGl>=RHSBa_>Z%TpPOAk`4vIMZxEmU@iG zJT1to7SB>YzdD447sQJNQN$N2lhPn_lHeT?lJ&QS{3Q@!FfPY*1es0G}hEsgsvc?UM1T4s3F2hTA(6-Vuz649g1MkCd@n}VdlTuwt z3KA2(sqpk+f^PGBZ6j3loa@0`<@}BFpdlys6y+E0$?TxnZYO^)UL%NyZib2LLvh}N zJR4mMQ3hLqa9(H+8mPyq!kW1^iFI3G=6ZX& zUoGQbY9z9L+bqETguao>PST@HW-r|AxHvp23-I6=6oSJ1=|SLm^T;C=BmSo*2lJxv zU@DKM0pN+T!SORdPKrig&9JsUsxZBa`!M{bRh@}^!IydT{I2QjRKK^yd=L)R__bvY z7g!^3SMTfS>Jzz#-b3o`vT#8~l7X9T=aB*&g8#!AyUNvSfN;*s3^N{aQOGIjU~UC7 zKJ28E)xlpx_G^;Q1^Pqp-{>l-PI8V*&*)vErDF8@+kJ`5%;?E&dJeI;-9;R+zc+WN zvoq7y-F386Q1HoQ>rv<*4c8R~%yA#OKMBnOAe)us97Y(6GSyTL_#_?UPXpzi(pXw= zX{zIP#fl;eJY^?QLH7ORAlT(Xdi$u3ydDu-kkcG!FLP(KsKmTxQ|x8(6hbS6a@a}G zQu6qILeRG3a7;})-IvqOpH81k=F>i_mL7VWd=+~gPp736{RtjeI)((5dg=JmJ*$kz zYk#!|yRM5LgKWO}@emPlu@{?KXuz?8J5b5wrl#N@;ojvM3#5X;K;{LX~NPWq31 zGfOgbEDQ&oN6b}Oi*hntAOxi|Shj66%6`ZsoOHCl7~SGqFRI^nBXl&vK@)`WIO+PD z&lJ5;|T_z2t;2>0#lN`HiBAsO(~c#D68s>^LUe6dP0_mf>A8l#ojt8Wr71DzcKS zkG6Pu0X3D%)AB6x*I6dZgL)U%R~h#RG0PI`w};+e@9mfiRYSdscQ2B!_av~K@#z|R zZc@o64Tzl8-n48|ZO`cuwM2+ARB~8wIsG8vC2^$dWSIJ$Y6vTL0h8&pWcoqy+RIwe zm?P;}q+HufB5FQCs825$_{x>KAGJysxpVtSD(bIC`mvye3F!{03}hs5FU8P?*Z!qQ z+$>5`(5Rg{oy}V|>CKSKP$ski6I;nm4X5Q8nlL4qvSx|YOStm0 z27i+mr#FJom}Gd^q)YHSI72id;qEWcaFC#b*>v?F|D4RA(8iKy zJm2M#P+$Os@B+wkn-}1k{rv|ifuhngBZamL+e6py5n?g{Wn(WD z+X4OJl^me!j&B+5G9z@Hh=d61;5aN{6qAHiM+*phPhA9)EDlS{1_2~rov==lTv#fR zK3xGM@J{%T{G=Dw`INIoPrAsG_bNp)k8V+1#L4S-Gu8BxR;h+a;j&mZn~>OGUeCj z=diX};A^Rfrcv0wyili8=Rl|oR$(mhquax2a8g%wr;K2Wv*&2e$&piByu}tS!@v|f znoCfnk(fTCxE%4!FQPXD=@^yK@AUvkP+2>@rX`uhETuz_P%rd2rQ7>Q-YD!Ruh^3Y z95t;ilv;Qjn|=H{SioxLze?TtS;KMd>y_u;BX&?@jf<6{?c7L6#{GE)Hv+ zq&hZw76h$4z`}Yh<2Zi~*|s4x_i)%F{7I>dFDf^P<)&RBfa1qMWESv1FQ)XwlQU^O`YC=^ChIwAf z3k~iO|5O_|p&u-x5YDqe3u|L2k6*+X=d^E>mNaV^w(vP$-*_tG$cA*#v;j5` zsj=>;U6qfFPs4U&vNFgEc*}?PJ9H`de!o}JzT%1xq>o=t<(R_=39X+D`Tm1SU!F77 ztlnK35~cywJ{O5Y>ira%gc^uH!snE|!IaHIwMPU)Xs_;mr3x(E9?Ij`eVlRwQZxXaG*#0V-3 zD5c0of@g!?wuk^-{#70!wzMcbixL_=~LW})YJBtorhpo>9t%Z z4;LKmJ;Z9mjcROd-3NO6y0Qlk=MH!EAC?;gmYwyo@r~h>bD*>2EvGndIBslSQI2O3Kpd>+SFF>ul>joP!zPc|fHT zbFu&*=_4|~5Dr;C>VhJK&chU+6C|U+ynjchZ_h%^;GQI!>Fw@nf3>9-W!Bfp9fhQN z!Jm2^=xgifq*z&wAw%s$c})5+Dyh#8!9gm~ojZ&KsaD_8>*{ImJ)G$#tz0{Ki6A3q zV1@cc{)MPf{pm1zw5wh2gpl~*UJ+d_@<*N%5zt&`U!T{DVCC^Gl{?549RL1Hv3sVi z57}1YCgs$YW#Am@^c`#A`}>bD=5p{W^uJ4~a)X^T=i_e^njbtqOc!_(M z238Jnw_aw3JanX>&!iCVNKf0o?oNtI2nKsmdq{j6p1Dqy@bmFRinfP7?dd8m|KYad zK9xSYg;Cm$ys8i3<5{OLKWQuVF!v+f*)IAuhq{tpTBhI1f0!1^?d$YS5cQKxK89A( z-rO3D1zTxhu?h+(?q9+!Ic{+8I-Ke3>+kI`!Cqf3anI!1Iyyv@xl;yO;(n;JZy$%Y zi_*`u17Yd>nkFTsXyf39D;uBTmQ zvUkrM>gwsr=KQ6hX!ex&i@qg0;0!fGEArT*>;C-q9qFj~u@ptu9&Fp?NCi+|)UC zLl@E$qI43mAkpCphZ#=fn6L;{D^jX|!n9lX)3~>ryM#Gx?jMwIbC)m~bDx)QbC)ndjn$SizRg|29JKJqaX)D8 z5(dmo?#_vOn+1|@e=Ebeck|uV(S1z9%t?5wyVMt|Mx34hKBgA`?K69fFzr@h`DTTG zjf9u){XV$H-EUZWzV2V-+ZQ^`H|onI87JSbvba~jOzGbwB(eN?810PHJ(Nomi-Js3) zTX^X&uJh6b2Zm%a%50%`wn7e(6tu!WKK54cI%*{&yPduA+5H|`JFcRk;M zX1hXLh4thKzI`ho>(2KP3oq>%bTLbNYNz8T?RMP4NP7mlM%qU^)cge8gn1=K+@+n~ zi}^U_3g#a$tEn^ZD7zlaVYqTxo(?(2E;!3Il>L*Vu77aa^`9FTzv00PMBqo5DX|c4 z+<%$-X;7nuB5o3%G|o+$jkNUZRfFU3#ZDm0H|g5)lfVn^Rpj%kb7Q>6a*DH{yzAxq zXwSqWu480KGuXao_iL|zcNqE=6efSd|e_sBWmjjvm zWe*3;9>Ohr)VsHS+{25%;^9IG4B-RJTYAB+W3{?)pI*+bL?VE*TM>Rm|C34eywaX| zL)6TKP({=S7BV7rk$_C$e2zUXJZaISA>rR33ftdv{-W3+-ynz;+RcaG#bZi)clmoFi<(XoHohGdl+IRZYfb^cZJwWJ?nYb?L*JwW zBIr0cH8eWvODFaBH>$+0V%_FpV@dB$=j7ZYcT)5u?WHvEmJ`7%*JtAAUI~HhkZkaH zHn5B}J^c#uZb|ra$a0#Zqora6JxIbj*0E$`wIHA1HF!(ygFnin4mGCJeJaeMw@M1~ zUvdXLH+la0<(I)3Cl(hVk|Wb}rb&k*P$?VY2(h$(QWPeTwqz2%xZOxyNHhc-ttSMR zZ~!!pE&}B%Cg&G^9@}-M!U>Wb` zXTef3i|!ST$p|P;!YF9r^Qt_$`bN@aJK=$fJT&}Y5t1yVE0d-qE%H(xC}|eL*&Mx2 zP!4I%ND-`1UK_D+%^#f<>3C!B?hGH&<$4A)l5WwG`*<{$Wt~Q-pBX$H=A(6+>1htv zUrGui=PuHW1+~(2PNQDHlQqKMrAU;?(u98RVoj%6v}+^%A4&hj$j~6I?aP=*#x2s( zp)ZHPdG;Hmp)t8>Tqx21h4RQg%xB{dxi}V;8%kCV(}2oD%6gum17>p9=Wsuj={#aD-K*o!{-W}U5indUp9xqm|LRB6*H!^vl&|7WO2+pHZ zc_egbAw4+Osv1R67&>dgxAa#rM)n0|{_AdB@v@*K6>c>Y0iilRA^KvbM@~uiTE8-_ zPx`mvxTS(?ak_?~rjj*}L{%K2fNzWd_Vw{YCaz4O9#FS%N=k=};AyM5;sr!fMY{N~ z7e!ind?3XlVTu;iLOz9Y7ljj12~EEcuBe})pkcG7!HdVk5~1{_L^Kw@d-}d8@Yjm! zSv2mJ%Ezcgm@G0(o!l)5$X|NIy3-|&B^{l(mv*>Cw0`%ZY&vl0>OwCs+U|sYY#bgN zlO)uRVi>b3KIu2~pnGMxP1^>qb;|Si=KtCA>oVUm{++>45BHDW{n9^qSa0FOyLJI4 z;q7C=;sy72$wxhJ+*Np&nLqsA=KojaN|AfYQP zo;F<+jb`ytyaxr}*W2-Gd3WHx?Ng#}V3E7EhovXaiJ|#T7Nn)iu{d0EFGgRr_Cnpl z5T>&HEI|sg<8}SWVcwqpK4rUpe{sIPo1=Vf6=Ka9*F#+kkknt^>xo#ZqAs)a(H_k~ z`xRYsA{*3!3+marcXjn?Kf=~a#z8T|41G89D2Y5LXjcu|3YS7;JsTQi`vg~B={?EF zZW{Q|jcGJ?_+Rg#^lRx96{BL%r?>BZMWhA%;c)!I8ISgNIu0vjx{M+w5obQ4hsEek zlGck3s;eewykSceE`8DTqUQmn4snQ`u|>7N=#6XPb0|Mu-!3VvizcTpb2FL3jiQfC zpHzy8(@-FK2){oiE#p#So zf~}ly+WPUC?{WTrE$hb&c*^n*_5WVsZ>fI~{TlywAsw{92Gi{f@Cx8P*mkneuO*|Oymdm9l-@pG`t-Bt-BzY=^Q>U0<3 z3(*ZIVFgE|<%6H(SBe|Ny#ybeRQ5XiKtTw1N}+%&Y8n$g+;e~8=R=d#+co;}J77@K zl;6T#-aX8Rmr74vY$~1)4VqdinGer?kMsXy9Smj3d@&T{l8cFOa0^g zgI;KnCHN|3d)_=t=fk{>4|!`ux=^6Zht7lDy+Ussqk?zkd-6Qn=GAPd7DqueCbcs1jtqJz-mn*$V*eyh+T<6 zDB+MQA*ry03r7TcC(*c6z7*_LR3mCXdXW3u`?~h2*ogSaMF#{()!yHkRkg?&)cuH` z>b8^*ep&V#BB|?b-74|bCzp2YjF`6`R7aZz zp-Fs$39%j#!r?BZ5%zi~Sk+1S5*F-W1y-Bur?0h+5{_c}3*F|JFQLkN@R(BJpA}c+MpWln7KYPawDX?lJ#Jpa z(&sz1Zbkl!TVuaJPZuVZ^yZ?WXye%*jRox&Ho#-S1KUqY2+l&%OL2+~UyzW46=3sIG!wUM2zwr1el)Lre7so>(+`ko?JfmVMNu#8{ z4(M|WVb0;-iQI{Q86%S1m_~ao_vl3wKwozT|M(C3!|Nl&F8}oDXDzDSE3@gLb_+)W zDiXrMz>1nM8YMtUxk7NVRN)c1hldDBa1Q!1hQS*IiB66~hy=0f9YB#Z+ot7s(R7wr z#EQeiN(r|nRpV$u&Zsz?m5&@%pKG%Cp)I{rRx8dgPK}FrcdSuU@5*_OeL=ykg)_ym z$$F6lNc7`|iQMf^=Q%D8O;Pmdv(Me~ml><*k1g-6&Y&mpMWcp9ef!GAXe*i}ETaaD zv|WyKrJmU%=&S6`LEfOBe+qtzXqKVRgm#fA6kF9Up{hmY#nK!C4*I7PB|3QAt2y<8 zL`D>OalE_^39mfWip3hHj&i&wr?|a`WOx+HtSgI_RQ15WP%nwtmCB24pAzY-(43-oaF8p&qvIzhO2cueR|qQaIr&GQNIZH7R^8<~xW5Dt zgldxXOZ-oQc13;24q=-Y#PU=HvsPh|{xVHKmn-!@bfAA*>&tH0p1$hwQQ-FmT75@} zdq5yf=8g!e{wfT%ntLd4@b5PFDhpR{@OVi&X>;G%=gX6%Ywo8l{4%r87|fe{t=Wq< z8^JAt$_K*^&C?~sO*YCBNHu_ zpFg_Bai){MJ)s%(t+hw(xd8v}`dx_U+>S1`@PMd{_8RnAv))R=2rO}cVlTYP0yuO= zR8m;h&?l-g8}v=E65qzVoNMIIU1}UqTomG-6jeW(8}DvxY24!kHou~A_sfgD-R0+e z|37W;GY01kE*Px-TOV$t!6t*P29Fy&ZE(imMT1Wo{Di?dgU=ase`o0%Y%+Mz;DEur z!N&|y4bB>zGx(fA_xC>EYJ+Km zI}ElOJZNyhV99WIyBnJu?``3o*rq1_wlwZ0!0^=IBKJKO5kFq6nm)aYbwa|%@tIK? zUxJPdWmF5yp^*z3vpC!yd6`z-hnn-_CwAYn=Mir$Nza$Zr`EaA=$Hy@+Aee$eD6nv@hEk69+FEza4 zd}+p|A}mp!-A!abL0A=bWx~DHrNT);NVmDUWpT<&g_j1A@OR(y(!xu_5Pr|SFEM=? zJA}V`_YzH6Ql92U5~s~e+ZS{#?swz9r*St3oGx#^$EU0P+1`VNpU3YluD{5Bw}Wql zUQw@Qt`P2?&k zOVgv%K@Eqcw>wNL7j)XNC)W%uon(39i43lBw!@T*%hRIyh=_}K4f(Zbe&VJY(|QU4 ze7Y@3z9yYCRT5vvvc?}7w}(m|Ld;eaQch}6ODCaQj^EwXbYy%K0=G*AszN{uCtan# z;qj%?xhF{{KQ(fW#}+P}weTh5V|OESSiD60|5%|LtUX_@^`4wan%N;9DsrD~W7ED7 zq&%|j-)reB?`Jac)^x=G73R-7hoeJm66p6qXx*rtcHiR>C#X{fWeX#cR`c^t`e6xw zO77>`b^Iy4pI6uMr`P;EV*e}hc9gM+(--!!dYd*KT|V93*fO9jn(-oK6eXrX-xU6n0Qk+9UlmSRZ+y~Tt=Z$W}T>W=a zTCXEdi{mJ_x0>%!wCTtk#N9sepdxbPdhC2*e*--VK1nACh44jAA+!F`Qz(#H%oVLSu81M!Kn}o{&im7o=F0dZsb%57&d3s zv_mn09}plNlXAa~2d5sCpIG<>c{nfpQQ&NzVRt?<#-pD0>qeVow^t0?dA^Nwbf*Mg zet5WJY^;N^G=yHY3%IvB*-WzG3R1oQR;W22^ZLtOVSihqazMEWs`*M}EfDE|zm4p@ zYFK01!2lVPnIo&9Oo{19E&=o7=@9rBxv8oA=-%|?adn+6L_pPRaWyR{_O1SUC(ObL78{(Yz?9+_lONF~EJ_{$BRe@!?!TDc!?!}SvG z&xj_Ce|`UXePX8XH92Xp8?SOL1Fqd8ql1ZRPxNLSMURhvoRgju{fD`NBidJva}Fl= z%aCv5Vu(L2D+xtB7E2um{US)jj6^9r0u2xj!p{g-5T=5J8sj_(7c_T7yx&JzMrh^2 zb0s@ql;qR9@7fc(U-Obbg>+EWK~l+uJ+kFh2)!vL%02AFN42cMvb4;EdpU(BIe0+A zenFVoGrWa6BPWdgJzYD|Q)vqunvX}OhrEFEqnu6TU`pof{*aVqd^$+G#^sun7bb)g ztm;|iqabOo{W~TiY=wHz+LLxqV{u3r)F;ud?jH~nu2mska-q!EB~~F!tViTxwn~(V z=G+2bwGdxb>PqomG=9J@QeXKM;?oeLCojl6AO){eJWsw{I6-}i^|og$>uAz@W_krE zxe_F&2-7Oi?njyTRXWEj!eb;ZQMxJVk?V~6?>gcOR~>h06}G#JvhkJ|01KezLe-7(=21IM&1MwHFJIdBmRYiQ4gcH#ds!fJEii!PS)s z8a#K(s136&nQ?M0the8U^C{rz>FGS@2vF?)S4gj|JJYk1!Oxk6j0WSu7yNBUmF~LU z4UwXP7UG2?%n-l8jF$yLZb}5Eku3CrV!sZm(EzZ0sJD#APm5>hfLojsd$`{ zj~wmmI~);yO$y;->x*qg^XsMKspbez70O>2UtokqL#z<4P*0P}C=?RS>!P+*U$B?* z7M1Ts<1JBmAAWKF+hqgtkt|Fr>0TKSa@a1fBihviK5L?JYo(Q*NvXxXKcS!ys9rK1sF+GHq-SJKYD zQQ2~g>Em66a)z!e%$Lx-f{Pc2`|j)Lo+Za;Vf@g~=km-)m>qI?Q!X6oRYJ0h@+%E5 zXM!xWMWJ6TJmoC9X(Xw?Sa^?&BVFp>CA@I5xGK(`lnJkE-}TZ@UMUgOCr7~N#&o|{ z9NyzaTO37BOw>RNI)VgLwt;kqD+)Di@<@YdX4ZprUQDsYLIV@N(0@X$ETRkqkL#8| z^a1#%n0(Aayr>`8*>F`pxyNVJg%m5w2RRwJ>AfhJUtGOH^&wGst{E+rPtsmeB#yUa zX$x2WG&BB$Q5%iMNQ!{+MDKkf=N^KKZeCH4!=7eb&#*&!g>pzTs;M|xF%(bj@NaAi zc4rd3DQKQqoR6u&F3F>izF{M|)XZZ*{_Ragdtph?A{D}qj8B|9b((Rn?DK#&>9?S` zc`&GzmIf`vLrCYGKF$E)q-3ez$0b+sp><@qj0)|*a$y6e5Z^|kJUrrW`H8A$eQ#l@ zn1y)EX=$*Wf1y=|yS@#f*gP&@yJ(G~QP} z1;I9)UyG#K;&xghUP+PTfnLZjDhcFdnCNkz6}Mj$9>n0WTimaUQ-~_N1f5X8kJd9v zA}m3YNHL;zD#VjX;E5qsQ{@MsF$W9vEa`VYyZsK^ldc7B}=q+>F&H_{I{Xu zK`)DQOp%qV+S-S(zof;Y`V`t%=`SsQ`s|dv%*`b(kIhBg5b;Tm&`a{srv_OA;23gI zIjldn=4n{Z5zuaRmrqpA2-7Arb$J^Va3=73>uMxNBi`=?2 zoZBDA?b2}7MQ;9nO?|POhTB-==5<1+aTA#)UzV(fYr-x2UvNXAq1<$q{*r$4_FLZc zrZ)|rkT(gQU0&(yF*!YSOIMqgZ@$RwHJaXYv0K)MTPSk#;hx9sIQJhK&-;8c2P@qN z5xi;~@%C#ym98~~-M6jsq+2qTZk?3hyK%zBT?*WyK4=lQ^wCQ9#PTGZKTjN>qa;0_ zJP%7(x=RRXHJ-3%KJt}rBL{hnc?)p4(zn$q2-`#TuXP(*ZgCq@n_T_E%K5svn%V07vVp1$x=wdgxLG2mR#v%{!zNZxf-uCBRyu4=X-U!Eyz+E!EHYOd9}%B!`` zZ9=~)<_XDP@`DNx`$sWPTA7ONbSiP3#1)Dmil5pdWvQnut0>D#w`HSoh|ZUbi{* zDz|Q7&3t{{_hBnZG;Co0PSS=0zKl(zp=F}Jt+%1S6fP1zmprk2~>O{ugiw6HJd^Px;F^gV~8@5Ovf#|;%I zacg*41^QK2RaDHDWu(np)6{2IjoWptregcm+KL;e>nhd{uc)YQSy?gH?c9xrd0V#5 zm%Z4|I3NyVqQVi!5yzFpN!66On&zq|ZLjGnH$Zx4FqWW2#q5y_rk+IsDur zKUWks)j*qke*MDQ`PFl)W>@6vGPO-w@8ON^a))zuot)=sn)Fd*Z@6)pTlw2bOEUZY zI5{51$#k8Y0i(`g-fi)V?X*WpnAB>g9oo27kk zt#h|tt8&|}E^}L0D>e+Ta;vf{Dd!5eK%CkW@U!cE8x`3V*H^g=2dn=96XzYfr4CiQ zL)3W{_;VFFjP|j$tIAy-bMCX4kL<8=6E1d3t*>_LhnKtcSzyaDx4wC`wJrT{#<_1` z>R0=+#dbe`>Rip^tQD)soA|4UpX4obWyHBZz+^SPZ?j@I=1&~P>U;Sjx-ovVxW2Jl zYJIs|zi)NEo-v$yxY|8DU6lVos-ea;w5)awebHPTsLeENs&KX6(6vEvDb%DN`z<%P zng8hA?_gfAy2kd@);hO!dWGA{Sl`N;xRv#8Yu~1Yjq^9mHrz(rrP6NYLfw4LT=i^K zzH*=<6XAKmdo6dk3>5B~3D&bUzAa;WYE89U!(3R?vfQm{CZ&9>$6?@|`X6%c!4<|qBL@bk{y z^9#l89J{49*0_z-c_Ve+NS!zK`PEkYdx^2O@N>+uC($ji*2Z#?o&IO+#bHtdE8M{J za`#$jl%wQvn7MbuZ)+Xq>Xpu$K z!F(9uZ z+EU}TfX~+H+*{7vXZ|-c?$%Yib#(ZEDz%Ws>r96PZ_Scy4PL&3i3dI3oUSiv@2tAk((1B{(tqjPZ(y!UzC!C?SwXwksoN~>*Ft%4 zmv99)A1}7YX{FeM)SRfA^O%)-Zmx2huT{8JS1VcLR=P}C%KaE7yTSVU=_W zMw!LGU}vHe-x1#t7CLot8q?Ko=8Mo#n8!ByG-A7sYxW%L3AY}afOTy_#~C>2^0UZk z|0#R|%R9E~TFShsCtf}M&G?!3W16v?UCx+heD^V?bxmL`0C#Q0eJk!;oBf*L$8(j- zH>BKKFkw#^+x?tS`qSfj#{b0|Q|`kUt&j8><4){0JfK;zPPkv+At%&ly$X$o!UdQ)yS<_QZM+daLu8hVX= zZ0R2M%{A`L(<|e(e?aJPzfY}oEBcnt%RW}~p-c+{Dc4CkJbq+vAK6o%sd1mVvfOQa zT=Dhn%KQpVtKlZbMrySqrMZChWp8$xw%=9{zvtR2SN(Lon|UPVwm*t)kxe!}BYVS5 zmF$}v+=|o;x~-vZ)Q>e}%i{%F)W_*2&cP&36J1b3KPWcP`dwolJGUe(v`?43?rQeIgq}X%T?b9`EwrqfQP@K;Gb|mHA zi#aao2>xXpR)fdfbcvtrvv70x%i3HNk9LXesjbYpmQ{fUn_D-#Cck>1K9lOGb{$u1 zTwP0@tLyXJoz#uX-Hl(qVPW0;nz?%4gH5&IWM95&*ZTI9o59rY^z|&VYaN)!KgKx3 zg#ActPu*DKZe%R1URX81Vy<>}dA@pJSyNRewY1qbhm>qQRKe8%5A?^<vt^B71ZwoBOvGymR{`vxY2iR}#yWo}vOcIA^bv5uvdmAhppq-M0E(Ei}* z8rIdyY>jLBsg!#arsGD+D}L8xodI_|U8nBvz%L_y6hp!l?DRWf73UM)5#Eue>=ENM zl~(G5J12ZHcCp%y*I36GH?!|cx%EGtaeM>`AHN2q*%aR>=;Ge9fO*dA#ji+x+)nB{6ta|u?vh**c+)rU1 z+v?k`*iKmq>j>*g!ZvI!cgs_IUD)f-O5bg(bKBS#Y|E~6+n6WY`fgm7~>zwXQYT28xKZ*AyjLl2`CFMScX#$t&SYy2v`|97O|HX|yF15#T z8n!V$QoB-yH53PBm=d06(vq6}1M2(?V?@$Y{?X2q*q^|BFt}y+q{RLi%qJ|*QhQMx z$`q$-e3JRvd`-sBNugPw8$X+Jw_)njRyW3`*mq;Lh#TpY+T%FBZa2Ds5oLXtC63ku zK6L)$tT~v|k`_G64Ocd~YG_$;`v=U7xNDs^tG)eKpaCpj@sI6AamXW1+w-2`IcL|g zo~(6So+_*-QYKKL^Yr9>&YfUB&$P!?4bY5reh)Mt^Hb8kH?-Guy<7Mz`uEH9{WjnBvE9?- z(Bj~LjnFt@pW3jg%GEwz*vUznts%{8YhC?(%IziHuUVS0UH3QAUXK^^5d3^t!F*s& z^m)qL)8{4pk1X`gKc(CsW3t*F&^wVm^3|vc64MC~m#Hy3BnG zlYN==9XK9$!K+2?VXaMDHunxZ1qWPu9kUt&HPTgNy0H%hG<*9@590tw@+v!)w{k(cYi0%}ZH@cJ%wlwCo=P zWtr?B7o;wN51zi$HSH~P$6i_H-gk?i3&nQkT}haRoy$2Zd7!}mRc^g6^PJ3I#WVN2 zi!EiY?Cvsm&C-qSO3(Dsx{NU$SK!0>2g=;vV(#5eIo7dWux78Ch7MqSi2LRT%Up-} zN#8;vhNnsl6x;{zd6a8qAY)dzov+1bRKTr`A@uwZqkJZS$(Uj=!wu1<$pX zxo={=Wce1^+p1h!OBKAbYG{aME^~nKhw=PU<_Yc&ci~+X`^gyge#P$a_@XpY7wgs2Yd{djRRc>y7nfof{9k=>+DzaNU%y*Qzzr*M}Q96sU zb(K0Wuf_czF|!uG)E>vR^>40rfb~z(re6m-%iJ3=^|z7#2Kd$V-75OF#`;$L9>Z)A zfBLD^9>-T&ai7tO8>`($(q9FQF0^kYbx-p!VqT1!?Qxujn;ApjNKQ+V^=KgEF%8ZB zx-xg<;WBqi;HxikV=oznDLE(geGR?TdaTS%V$N$iuE?IM;;gl~tY|E^A}H{BjE+yK zFJn;b&tg7iX_VUIIEsgc^_(oP?Zvphe6-9xhjF+2{*3L#G$H&xXu=S$wY$tsVEkO6 z?2%pfVw7za^!qBt{HnfM&j-xvI+s`aoAFvhS>(JXpDA-cf_bx*A-4PV)%aheqxqB0 z?BO!^4a~4(bP%Q4k*_A6~W zU8D8`xUIAEVDXRbi{i8_bC)iZx!=TOUm@*DyDoBbMPWGJ_58)=!nsZUO=a%qG4IxV zB@NoB$PGF#wo7@hA%`$f=C%)(CHwu@?%Ofp)#g+1zczeXPYnE?cq=@tYv8FXocT}7 zzGx*ExyyKCv&_}qDRlwg;qUNw_`5~^G;ADR%9Mr2LYv*tM|&6@6x%(&$ar+rQO=)I z>&o4_ef9ZOO*W^&X)`}q=KcYryfjIdwLt7{rp#T|vhfyai9L?v&xF>yhNnvCIhkX9 z@bZF3Mb$1!iVG>YxAMtq+6 zP#n&WZNW9*oPZ-3BfPijzKMy?KZ@O4Q5a9(ucV!!@h4;Y-sX+qF+E?bk9mx8&Yto6 zsLkx7z&j;;d1=drUs&#bfisJ>(>J-b^vzmik?Q7s8_r5wZz^}2m;=jC2)(GX7=E1q ze++!C%zZ!R$;JXsDRPs3n&!OckIG#69P5F~JTN~NxiMv;Fb&9(Y)QSMcyDLCh|4mz z)PHJ8{~2VkJf36?`Ag_!OrYCiyUJBHt9-*8axCy(z<1NgHVJ=czRc~xOy5Pl6kmY1 zu^+;`RorNoQhOXH)wIktK{M3uW1lzY&+Ce4QE0CDzoJ}UE^~91UTkmJCTFj!=x_Sm z`dh}N>^&PEt#yxHyN5HKoi5rHB{X@4_R;mU8CqoC_-)WMGv6q4zk|s%QGSsvVI8Ri zf4EXVS%biBDs%Ep@I5B9-=)}Yeajmn?#D2f_xN^+?RvIFo7T5*zQx&=wk35(FSfe_ z^Q@GGI>mO6H=xDXlSrL+;P2xtcb8vakMV8r{%(oKIHLT;ZtQ2HFsU0V!12n5Z8ExL zVB3uq?nbE}W4fuL+}(p2*7RJFJ+*on=cp$Ck{3y$P!8z*%5wMXn0F`TD0b7l`pO2j zN&eH&l+6EpdAYlYnbSDn3*6lzcUK%v#~$Oj4A}zW`ZG`Joh@~v-f;5H6``IIf0-+C)4pUsQB&@YVst%QgWM~)N@a{1du{}ADgC?|d<^|0U{FFgf=Hl{lci!T~c7JAD zIExE$cn`t72L5K43q^M2J^23ModkCg6WT1c>z=l`a)I4RX4|b*?pF2=8yM#@hGx^{ z?)NcuEq>m_cHO^oKC_BCuX?I>K<3WzFn8Do%-ziRd0DyZu(+{3IUkdDU~DAvHq4RP zJIdX*JImcn$TPC19;k5-Tthx2oA6@woX6AWoVDX#IB#cvw2wa0oeOhG+5;RZXT9^J z-?X#bU9~)l?4jLcEK-O4n5XYCToc)KFC*t@#_icA_3Ct#xt0XyCtse z>F_IdXKs|Z`86DR2plHo+uV&WWqb!S&1wN&?-7N2vd97bxbqo&DO={BMDuC9icwZ@@; z-F=}Oyzz1yE4aHw?ye}DuDQ$?`Z1rnROc>Tt93uc+%b!Q*`aJgIkdI*|(DTm@{`W*WWn0j$zeiz#rV=X1|2otB%z*$l)XSG2tLhwWr z(LAl(<7RT@?&Fv-OFy=2dqP7RmsQU{(5I`9O8X^J!OrkG$MX2;Z;+yfD2UJh2WOvBqus zM!oK1@{-m%$w$u6;FT~&^$hJ(weC~wE5Gjwa#3H_-I(N%scs^?$j~BxxZ$bdU7FvA zfbVI0&fN-U`rxq4JIdWCMrjA3%@(=AgN(xX^AY6t=+}*;x3Sse_>^A?Zk>c*s(l2` z{Ey}C5lr1HZ5~i}vHv7yqqtGWQhOXnc^TGTeq6vegzoU;0(svbEq7-zV(B7f@fIQW|}xruPHr`psE9+xxuzRLN8hYc=leNVZ2 z6XpfUTjUeK-CjPS#7}56SwpW>x(^Zl8O)aZq&;YV+>6~@k=^4f=xo{{_4*q3`m1X= zr(f+3KtI$yrM!WR&QH#y=08;K9{4$E08N|iQDjf8<1S9B$N3t7M_yLtUUse9ZJ5qd z=6*N#M7i7f6Xouc5?65SmBZlJBkK0`pQOx|ri3ZjpEO@OXEeAay zVV3ffag)XW*UQ~rOpq0f?a8{6E#`mgn4piEexuxd8Z&*rA790G+P5T3>SUce3BG^* z^m3QMZ)HoZLw0BZ>D!E_7g-y#x;FZK5Nl)WFO<8Jn0d)V%FLJ$`&%#zmT$3L_6?rz zUldp8TSBjk*sZ`H z^m5!v_pruu|7X5-&fovhax!Pp-{yW5v-3e~PiO+Me;(5+ZnR0MJ&xmXIJ6V=M17y_ zS6NRppJtq59Fg2T;iu4_{-rN_;UFu4?@gA8IrEbeA z+_G!T+7@NJ-w?0Zi?)l)=7I>hjmT+fibXcM~&NYZ8P#rTinJgH-cZcLf_ux>i@Ld{W9jb zr4`$?pQpmHve1NK=Kv0Yd5L=pK-eu+^(jb*!TS%`~P-dzEZoS zk;Kup;U?NE&AL&N2YJVNrs|QWg*RFcUCZtfYTVl8T7#?Rj?~NoWBlvo?#-5OY)`FS z2EU?#z2HXX%?++D&-~gd^0#St^*6b#;8du$IhCoGbhY2Ny35}Lmwb!)Z)q0UWo}Hv zGi8tZZH%XFQXA^#0&?%H4e!Jrk4tH1ko`8gc8#WIKGD zmfGv%c$yyjIo8#MvI3zmu63%&H|y!(#=~IHqCFG zyJ2=+KGlJ|~QdNa} z3KRM=w)^pNBjaTY<7J(U7k^uZ@zS94Yr~TB>k{?!vKcpoxh;1?lus%1`y&22-kx6X zGTSTMUt#Xu@7pJ~`}+p1$o<{3yrFtndg4q?r;n1D%=D-&r6z*v}LIq z=g(0Xzt%Oe)`35x^`@0PQ)MaTgOI$#>QZPotp?w!Oydcl^gncf(yy{M+5K7#FLI7+ z*c;0|GUzdtwP(BwU+XjXR%m+P*;(Pr0>O88CBV#iZ~B;Kf6Ktl*AHiu)()TYjB0oKHBxQK>amZp}3Nuom{!%|d11CV%V~ z^e=qzRh8<_l~&cwdj4Rg8|&i!I_~b<$P!{imbLXeDVN7IK}*hK7BH7nocon=W>C&K z#k-N+K$g}03}GO<<=(B_<*mn_|IfrhR&|DO^Oyxp{rgkyGG-prbSdR7Ve)v;g?WkppHl83W)9Qz0m?j9u13yO z^D~qWbD21;oKwhI#rzB0BfzAk%ui5u%J>!P{XC}bP^G&Oa~I|TOb=!NGlBU*%sVmf z$2^7kUCbY2{sQwg%s*nvyU`1P*@9`pv|)~7hB1?vAH=*9^FGW|n5Qv+f_V<}ZOn?p zl`f5W1?CXuVay|#cVI4Iei`#Sn9pPW3iCfP-@&ZxsdU>huf+6VUXRIR-imn-=I1e= zzUol_C$jB&j<*X)^V83OYm?Q7tYF(W}uYgfLH|T&zW>!g|N9-)(daT+iR^ zwm9&TyUC^9Hg~gonY+bpcelFRIFq^E-NDPSJKZkV=~_s=k85#vyL;TrIj4Gs z+v{HG?sH?KCx%dYq%YRXM~-)rF62xfi|QrzF2m>YqKa*7Byt;>8XC;U4k)ser;4H= zqH!>?>H}-BePogclFvpiq7J6WidweFE=p61tkVR}Uih>vQwhtNftwoU^9Sno;>?6gk z{YY_hKT_1BkCZg{BU7<={@m1Q|IAa zQ5~n`^`smRCMNU1yU55bw2mkNd?OD#__o3}9$Aa$Lr~b4+XcQxb47A^tyy!`WWA>to2d2`*53WgXW0BoyP4r;VwsRfAN}1cN({iQQYa* zR=PRj&KxP^@z&Q@x_i;VGoLNEeF(QFI-oBjx8K9<+4c(eTz?_l*KoUp+w)O+D|6J1 z^y;Zk_%-788F7o!%ZM9s?~U9Z!EFJzfynJWxNW2?Oa1=E^7xv;FB<$kgTG?%g9a}e ze3QWw23JZuN55B<*#FzBz5lNp{E)$S7(8$Aguy<84;b8GaE-wij{Ee!V(L{*RcW;Pp48{B5_Wd?fl9JyH(trw)Ku`z=MIk#Ag}zvB zX2R^KR8n`g4hlK-Q;3=+g*$D2>@^5yOWje+qOjT^5{hci8}xwpN?zw{@@9iiTK|0B z>>=ETO6)t#{yqyI!d)}>e=+zqgI_in!tH(7=i3c_lHUUcZ#7tB@b4|$GX|eBc*)@7 z27lP#n+?9fV8&pF!I1yFmHU$h-(>ks8XPcq)Zl$q{tknGXYsyh_7}{4(cmY{{j$L- zgK2}WH@MQ^MuVYzr_KJu2D1j=XRyiYbF0BE2G z&z1!>=<+`D`RO+2{>;1gp*VJMYNXw}yDQ%Hz{vE$!Ku?3d0N^1j(2NEZ{zfcIJ;-P zi+p#8%DCV2_70xbn4GwvLENW{+~i%iFM5}*v+`JjKJ@lk@6tK0x?Y|8V{bn&GR}L| zyd{bL-;SfaX&LH;o`T`=>_pqt(CDahJwj!VjlRj(xz)+LF#Bl}f#{SUqO_q}yqo#z zOxBY5r!uOS9UVHuqpIW6_p~_oniP-VkYnfgBcqcO<7ZKN+s|w5_g!@3`I?V{4viv7uuc0aWWDU;sqsZM#3wH=+0G}stQ_~lgt##(vz$lxO* zi`@IlyAnP1C7z^KmFi$P(d;G3T`AWp?L!THcH$U1{o5g1-Je&6&+J6v?>8b=;1_@ww89i5zp^gS}pTNT63 zJzjZa+;547JI@cHy_&=s2Q((y9Hf`7>%B@!-F|Ko&8#{Ar1SHY*^$Y!qrCkzB4a|w zL%zIg$}AI;`8xArB+#4uu$H<9ur%sJb zhEg8l4cgA`Fne3&HN2tIv`?FS>F0fp{pwJjHojlJP{}<4|3KU%+&&4%f7UH=V-Mrt zEr{<~7T9W+%eCjG@*_hs+ihb=*zLGaO%LbfEgIc%&7EUBW}OTjq!l(nNiR}y~~|MS-4_|At}l91iQrdI>5xE($YSk(TN-y zQ0^{AK5)F{`nJ=XQ(L| z2}=U3B6$tLJ<>Lg>u!74j2oPu06V|U@xZ~z8A=6`9-A0)@Rnr767`Q%Nu4%0aE|&- zkS`CH(5h$n^6fjUrQ&5yH^!GH??(ALH943+4PPopTa81&X+5mnv|Jaaa=b#wNTAhD zowc4==W-`TPQeh-(LZvYH}mivna+<6!?|Ldh-zFoMlUaX=SJLvwEM{E+)16-ITzp{Zq`w-1s2f^=OWlR%n|&J|^$Hp#eO2(Q08y;n1Nd!~{?fc#l6T~5c*?J|BQ z;kCIw$%hej#^r2m4CY67ot@&D*704Wwu^AA5xd5A@7le~=EtHC!=n>%fD(UNYh+5X zN*u_QgrXH6VWp0Pl!TC;i@i%zI5#~yhOXi`NJ$D&>%T}SxGnkEyELCkFl%X10)h6w z32h(aHvT}xOiI$a$M1Z0nEl65kNIN1`tP@RFBT~ByK=7&|3!oI26w!|yMM*(r!RW@ zn8EMxlVqAd@Rz%O;!gA^Je>ag$t&Oa&bcR|#Q6;2q%N}8x+~3}=%;mz?Ek<2tat9O z*?fvFnm_So8g@`l?spW-OBd>@Mke{o_HDfRr_8527SK*e+`o%yufEL!+g&H zpWlcG0pFJ!&@G7h80p0Ncw@c2qR;p1m|4OLTm}>13f}@ZV6O6=1|G(2T!%b0@R1wo z(b`Hk1KbZY;L0m;2L|1{v5sBQwcEf^{WRePwqhRRTi`>OC-@ea!+eDA0pMR_W=V4a zxH0X^p9a1IvxP7hfnUQs{c^$p-?@!+#U1#zTcG6R8~7=VlsUbfqoG@!+kyKm@J-62t{QGy9`*0WdqnHfebHH^wefiVC$9DPei@+b* z!?_({E&{vn=Im}K$G5`_Fz9m?_*Km1m6Zyscvbjmz6Gwmmp~{kyO;72M&JcZ6W;>ghUw<}GVmu~$+)6_F9A2gG?KnZ1B2dN zfn%7fD>%ypK8kss?^qvitixAy`Tlb|^(2hI@(#ud-vVETc^}^bpTK;CZ-F1cJk58k z6SuCD_Bg~H9VsVp2j`z}%Pkf5x{-E3ozX|RVpchwQ>%+7sVFb2e zF7qAh*cIKoUw=Kg2zP=N(~Frph);Nwu^!+Z<;Wz2cL z1^zDP9eiIt<=j_J`?w3h2M{pPT3}%*Zfq!k^3&7jPeVJo@ zuc8O`xwkU5*KkG+toGTsLKHGhcV)Q3HZ*pGoGcsz}o*nT)yjpKky%+kV$g}7y8yYv;P^BCA`3oV@~re@L9}xzUP5|^kF}j=YU`RdFFTn z=>UV?TY>vO!u%q-|$JHbx0HV4;aDu?o)hYq;1`A zvKC-k8c7Fu<8S#fmInUw@38I?*F8-bjD)`geDHVucPlXHsTFt?^FhK3yzkQ#oo|6} zvu}aFZ{Gr|KjXs)T!(pv@M+)?jM5drANYOR_Xg?<4Ek&ZuKFzFgzy5_{sHrpZ-G1P zy9s#o8DxQw=@|evea@Fz;J5#f`9pa3M~n^33xrt!p8R9dzFpv3!qywz`0`vgi^}x4bq+S<+E3WwT>w%ABq<=2~Km07?fU?E9 zNkwPrk78cfP^s|e_^#hb7~s?wecV_Fs^~^N@@M2lc!6gz&+?rI-uxxn0=*ecz=!|B zx5EHX^twuYWBsnNE?Ch4dt#nGBOQT1gGuu(@Q*Mpd<(qwuUI4aZUVmb%j8AhT?GCU zM#uACQ(laG3w-NWD5r!02Hm&<{}l6P+y#CM^Fh7^_I#DG&9}hs!-)F~aQth2oaBMi z|HG$01N>F{o(2BG|MX+vGH}I$4^t1U{JLK|>VZG?4dzb^eF1F#2Op*tc<(jl^sO}Sy?m#E`!Le} z8Q{0;Q|=({JT~FZG^E_lO{577`fCLq+Kj$l#+$%j#GIG02khH|tQdG^0Qm1wMJTjx ztb;bzPb<1?Ke;vKo+Pe7(PjHdzGI!XqTBW~W*+y8z;C4~8{b@Va3HaOF{dcVMR&?R!F%^Ut_#>E&d|w3q*V|Gq zO&R8aA41?<`n~D)lpDu z8(Z2=g=)5?dXq_JMw0okrWzG>wxC9fI@Z*tia1hqW2I&MBx>sR_s*S>gU|Na{d?Q+ zy!_sroO|xM=bU@zBXi$WEh(`EnN#tNr6txdJ_ld*v!3K(F$Y&%fhs5$!)Pqt%^H)tBF2{Gf@lP3x`qu@#U)})`LiE(#&sF9_%Bifqse;S27lOu@<%B#Vb({-VamP zaEy5Isjss(*jEPL9$-x9n+>;L&stJHVKKW_JhZli*Uelv;E7Gl5nkMa=HYF4{WoZz zHqFdlW%r)Dp~Ujjrnm$(i3tvTA8##E|_ZVN!BQuXyIkiWBpLrR}djjx8G!`F(XK!}$X?<|j7SLKtUc8wft87~3%QjJN=FBR8w)_spnR0Ow+JP5mq1|{d>__UqnH{T4 z*(yE{>Kez|gQubiczs6nJ+y~y%{*G=)SizHP%d7EEb9BGi2Tk9&&EIIBPKr^tu5;a*gW&%%Z_gxBY7pF;U{1!uH7<@)^XS5O^w z{O}c|YfBd1A9lt(4V4QUppKajtK8UUdw7hXTs(-f;)S#!{Yx zrB89qq@QMftC{Vp%-0>LnmXd;zh>_6;-jbzZ)VDxd9!8~tuktFdYbcv{ff_{EM9ay zLm$*nIQd!DJZ*YlrXNqa_{-nX2gc3JP<@@Ur2}M)QZC+v8t~#>1us5Y@ZyUFFYZG( zQa=YD|GhIup*>{K?sewEdZolF%NEu-Eas((51{h#yypoAQ6=8YWmR75o%^|V)4q5= z+J(=;OI~x@_rbo`$@rx_1K<5Grw`U(i8b&?_N)5v{WqOHSO+*S{^Zn2!Mz7Lf7x#q ze(Mm|8hj9Te#m);H#1k2#k%w(p2JWsu0hRseJ+32e>?5#v-$PNrd*%VA8(N_cP?`Q ze}nXVL!Z|VmypGz_TjQpvIaTd_4)nt_&mPK^*R0xNbTse`u#}lm|3jKWPKSOppIBS zqLep^Xa{cM9*NzQhv3ymJGp0mxEJl9+~WSGACVC?#Qh&3c>nRGRwdh};oOnrZ{fYL z8R?oFgbAegpv>G=<+5f+m0Atd7dMY9wSssXK8mz$2A+75bBvzPms;1lIUdF#0KbjY zruY(SWm|C%>Q%xqP5>m}2<$87@7SK-xY0$yB)s_}stWFryCpy#U|aVGadP%i!iHREk~ z^B0`#x)8j%noLv5&1_US*HPHw0G1P(=GpH3WzK&w}99-*V9(ms^ z2=7Drd57;K<)(@o&m|`kFSa7)oiA`r-p)oQbRoIA>`S~DrSN8+tFmE_t)*Sc#q-fLym&RL#fx76ziv@UV3E#e$nb?+43%xqP5tBqRNRvgK_ zRon1pey#FtXI({}A^R0?LEF>^cr5o}_26|s)^E8VOOF@2FKf(V=X})tSzj)A-KX_9 z(zVyjmQ@bzQA;@Y*spjBYQT#xEM<)FViu{~>u1c7UbCC|pvn#1vz&Fp+=&O#0lcri z)cO$VZ(^GHp7U3fTF0!TpR^-RMRW0D3tEg1!L94L-tu0qnTx7?)H&az4sDA6h5~r8 z9&N;%`KHQ3E&UebL%H}F)PooQ3H9OK(7SnzP5~R!I zA5uFx_^VsFhG<(@%pDb9_&(!Lxp)A@@Hv>+!u1@Vf=_Ox9p1}w|FqQl_~%YPtvks* zMEUC~9CMdb?tvksKHKn*DBlOT!{(T2GYvl%W^D0pSda9)LiaoV4CS|leH~mIPo>Xr z(ss^GyqOQG+|YI1JU&q_-honhabkjNEMA<2RBq;zD!25Gdl(bdhYz4ed>Z}{<@*d* z-|L(^0k{*XZ)T>b@a4c*qei04h#jB8u=PiC1L0TIrSo6!mT*FQGah;(~2)>3? z$8|rCCrDmQ6}-EbIuG)=K>ZvX^Dx&Lyc;f0JI|2*;l{TKX5KkF8({RJd6YU z`hMpe3BY?_qtBG5;mEgnE`fK$Zy?RJnI)=B(Q)rEH`EcIK>>UQj(*n}XE(eAX|4KT zU%_YK+3z`Rdg1BsJAKgoyIYX zG;>LnSNbCAVO#M{)TcJ#T^|o}* zRJo(CqXG6Mjv@0jhZo1A3br+~P?d@LC)7wCaomV9Ya`ywJyrgxn~cnu%HaiQ2j0xd zRDR~GX!B{@!we508*k=}DsOZ>3epGhF|-w*f!{sW$ps3*la3?DN!MZcD#}0KfW=%> z@rTIAwqhr0#HZj+%X$!E#apndUZ)Q1<3A)|BvFMboL+{`LfhUp^yR_s{DL2N)Cd;sQ<`Xef*^j)?! z^GcOty76B)M(T^br~#jb3&)%pp}i z=^)xq9q}DBjJL*-0f|)Kds3P8ukNz^>v}VbR2ii^PiC!Fa}PWG7**rV{7&U~-h;+6 z=HjnVHQvl6RbJ@_XffN0l@rKh#Jk~)iHsx9OFi(nNRM|}_^nf%V-LbC%9q10Pjc$} zVQG~!r!M%r$&4dyW?|11#twf(=IK<{71~O<_%e#AJ}hRIikVZHFUs@8AIGs+)5#k| znin$*R2iY;XD}Dk5oe=*y!bNOkI%DEo`ah`&T)m{)S1rsd*FRY$7tr5D(Cc_(>Pw* z5ywRIfIb>f8|p&`nx*_?N%Vm50Y7IQnrYf(St;s$g8AB6v0p zhLQS{f*%*WHK)w_`5BA@^=&N=9UC!FQ<&CDlNp6QQKE$xWb zIpp)<#Y>SNFLoBnQ?T0W?8^&_*`;F7`DIos^~Ege!HXsHocb=f8R?pnhVK{3-4{^* zLaq<2f3dWd^^bSKyO3VLm>H$YE`8x5+N6${LsfXO`Vy|;cr$PG`2}UxizLOjK3MW) zryUoZk96#QXcx-Gdr%MUyRR;@W+HhnY(u){q~IHiSsUy(2W!6Kv}tCLnwh1_GJOqA zs2P#xqNQwu7gwQLytoc6#+!Mh$|-#lZKPbB>Ss>zX6~r+NFQFs7*Q@hi~8|q#;CGK zKSV>6i<28Uf9EhJ@aWZ??|3s?RGFjGuVdUO7tcfUR38@eMa>*h<%vFwny4eX0-S?* zaSCe1o4KI%l>Hg?Q!b9Yo@+7Q4Lxh0A$kaLSDwBjrIj^ljET-nzNW+KckP2mcO_ zmB>$d2;Seq@#51kbSq=1ayavQtb3kUd*PpvuD3ZjbF*_SW=5#;MBhd`*jD@t%HYKj zKj3)rF8CFs-&L8JpJpDYaze9c8pkLeL|(j@Lq5D%`9m~{F@fzUzn49+?ZOe9#+P*@kkl3;FQkPE?OK^E%B;PGxgO z!>mKWD*0 z#vE^ETq^r=@E-b1xp?+3=ri66KikWg;@xoV16=Dk_8>fjG)HFUsIo{y$VVNq3)O3^ z;IxOF>!g`8s{GNTcCcosBf61|7eDtfYepU}L0SW5Zl*Fd=RU%?&^K`%syK(f!5L}R zGv3U;G;=YPm-*06#*I2+KWe~><-2&y#k*htX|0McAw34UA0rPE>Gu>V_@&34$3#Co z{|V zaS7Um7nNrzZ{}Jm@3QWNH{@K{E94$l8wVNT&oNY5e7Y)fTc9zfM> zE0+D9e&Ef_N@ZD&d5L+VTwH~=;%%sW#}2%i^QipC{w&9M9&-)fMj^bJLuqDIj^D@e zq8#mrt5G@i#aq!Rytr*YkMDT#mq_JlxZripQ@jsuLt4W&d;<00GjQY}Yo0o0X5+nY z9L{<)b0C!u+3+S~bv{`yFn~OGu^D;s;uh417e^o9e8h_$q;m10gRB+x6VA^$Yug9c zA@%Ku9LTrItY_Y4tk_oEhhq2~oc%8C;Jxr!qef zs1KioAFG^xnpu!$PNec9ccI34yzd0}p^bQP5N*Zh;0CKazuzD%=30tpmXPO29r1GH z#`|G0*HRo^N=7~9;%R6e-Us`Uj>XKDG;=4FKY1D2L49#8%HYNID2ormVy2{-8>u|W zaU;sDYQ{kvj~3v?YP1+HEb52Tmi~Fh@T_@GnTm>m@V%N~C#7!6ynn11}>NG5D+fh!@9=VGi)(B&2c=Jcqxrqt5_% z;iVHf7QC4`sVvH_N&I~h%Ec#9BR&HksdDN{s*eYZ-d8^0qMoN;q}OeZ-Tp!wiOSaN3V$so+~+s^G=P3ce3cp6RqX4K7A% zM+_9a_y8J3`3|^=Jjvr~`TQ+BnLNq;^lbvHMXDpNE%+w5v*35Zmyp`u16!(@FSP@^ zkjneu9}4~eoH?8Eq)s*5fONb;_*B97!=I9KSxp_^94BM57JoTj`I#H(o2ZOTc~Lo- zd+_4(sGRzLFJH4c&en0?+?YeoQ&{n(;G# znrjd*%Rc>;E~}>KN^7CDl>aZ_?*D~k0$gT&k?$|!|M|MXkgtc!4}NU1m)T^5>Z{0e z@Y*-KvG|SA5nm^iv62M>00Wm-vQdVhJLKh@7LK&u_ZT0r?%Em zzn(oVIHC{QU^Zv%;dZa2-Wpmy+}`Q*VHQU}oufY0n#T-Wnct6x^pcYNI5p+BSk;;sRDwdRwRclgZUKF0i6wTPdp-)q@w*%52; znDUfPyMKKBe;xrZuWvZMfzE8FH&Pq%Md~6A5jzsG3&fk_!FWqN6mN~&@mM?+?~SM9 znRqTf6t@x;30I;r;Z9T~Jc*iwH{nYJ6D^5QqBUV9E0V5cWzzCHeL8acK3W)vXXAsP zYR8kX0_3RDC->c+yR9x)mn&WwcgL&Zo_I~%8?TM~;&pL<3Ax6x$V|I#hOWPTHz-GG;&wD{O+z<&w znj3)hAH;f8P^+#C*uTf(7mYuFCQ!l`g?I34Z_XTk&F zY{n7*Pdw~XwS8~ z!j)lnxXS2p;FEs3Ix0Kd9aSBnj#x*kqqoEEjCH0udpr9&Go4z0gPm5y9jS_VA~l7T z=w~ekS&gwsD$*NqN2{WqXie0P_D0juzNodmV!La5<@T!WwcGvM8@AhtRKm*gnjk-B zwTx9W`;IX-1B^-9*iWu=h<#N=T#?F8_E=o~+NWkASeS?6-qVr3NG386$wmevxyVq& zidIBj(aLDCSKerC)EBLb`lAieK(sj;jJ8BW(N=mJi>3-a&O`^I+2~+27afXPv5J^0 zRvB~0s$!m4P0Smsjrn4AF@LNfR-C;M^T)yDcx|b9YpZK(Xlrf@wzaf{+FILEZJD-# sw!yZcHmkj&-PK;%?rG<)O|sOv&o+{d)aLubH-54hKm}{l`>B=qS3eM%=>Px# literal 0 HcmV?d00001 diff --git a/OSlibs/win/x64/release/libcurl.exp b/OSlibs/win/x64/release/libcurl.exp new file mode 100644 index 0000000000000000000000000000000000000000..fc2bcb28c341030ffbabeb98ca53768e2e4c2058 GIT binary patch literal 8220 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 literal 0 HcmV?d00001 diff --git a/OSlibs/win/x64/release/libcurl.lib b/OSlibs/win/x64/release/libcurl.lib new file mode 100644 index 0000000000000000000000000000000000000000..92f23798cf7225b7ad93f89d53dd946d08d29617 GIT binary patch literal 14074 zcmc&)&2L;q60bNR2~IX^@?r92d+hl8b8OEzcF3~M!b%Ak6B%>Z3&X_o9FKOscE&Rc zht*0PIG~&mLYz3U5@!x5i#Q;Z>q>h;;$WSND6>@AYfm^BC<&<=0hR z-M`mg)m8O8e6!fx*?YcsA!Gg)b8GqR_0`4I6;qy7>~eM~N5waL0pM={7pDO(Zv$L; z4`Adm(Y4P2B;Cd*(#nXU2lzx9{efuUYXCtb9Yx3SiIjgxGJMCr#3Wd$rH#VXQ z@OPy__1m{!-+a07;;rpl*rHr*6hz~~ZoOG8mP%kSq5AvYeo!x%Q2lPx^8y9QF^!Jb zY?bRZQqWAazEH01)(s_+FinK^Y8}#1WmfAITW=S<)=sgZUWN;}9#^3i3Ej+=gYf|GB`fSEzbbwLyc%QW(|Wsd&X&yJ4tn8Pk^AxKV7k__iiKtQEYeY$VyR zPRrY`H`I8fmJ)>Z8eUV_26{Vs2PFw>>UWmQAvLumtciyWI z16f$R>ER&Qn-U+@+EKWYSZTh^AgFxqhUoMNF5D0-Drjv)*LK zOxRT^V!8@X*RYOl+G<`5?U0Q1jmDx>+*c++GpxQ$>j>5Bl{mjT|p0`PbQ z;InH0w~bOl^5c1IkL8c1upRQB&I0t$As$i<>uw-Fjdfp$h+rA<@%bTQe1PSjQ0EBr zO{8xZ0ZK?148alTfe{#mUbqHBFbKmi4r4F@8CZkUa0-sWad-;Oz)g4>2H*-@g=e7; zehX*e8JL1R%)<;Uz$DDUG~^%)i?9UG!7|LkMK}-VpdT*4I{Y41VFj+k4fq{A50~IF z{02_I$^RqrQM6A7hzi&?l?OZSz{g*=$~g{q6nB?f-4MG2W4UPJ?`r!kAHK5HJuaP| z@EhAqlGL~P^3hT2*ok#3MBxBP$Z&4>Z4y?o7&8=!V2Aasyidz|CG<;KUsa3KT(vp& z${XiRTQ;}d=I~2@z~%5nuQ@XQmLXC_jAP^QBEp-G`myXYs`v#@D|(Movt*tLpF}w~ z)J$GM(K>x8MrvX`j)*_!M@qa8d;Dfu=ZD>-fIldti;=s)y29TR1sc0F`Zv$B*4WVsppd#leU?YKIB#e`BPtYJ7 zJ4GU(aJZ=VWzdB`6C`5!6>TA9g>M^uPFO`^{0x$|gi@?*AeAYe)~12Wf+=8zFo?u` zTPNH2R*pC$+u(0_s?$52xUeqhTb{N_vEz4ral*N6kSg#}Du8^3kv`@?)0qrZO9MHeXit#zTOK7ZHR3fh_gm-=}1Wp}_i1z1qNcegBOkM}Efl z3tFHm1`UGrkk+WfZ930^&ot)6YM&Rq@1BsAl#2@t&y#ody!LJ9lkU5ac9=lO` z*>Dr>l%>4>sw8$wkK8H$#Mh$NweOTtFa}v-I|U;%`iY(L56!5j*eSot4oI@D7>nXu z$9xz`J!}4_x!`>L2LW8O<~Uy%Pt#AFPjSBZZynb4`NBAtenRgX&8Vl)JM`I2Ij9EO#<9?w~gq9b0C&F`i02e}d-QSaW9R`NZ?lA6(ehZq+k?`TAzf&A%>sgKHCtx@fD<_*t2hv3! zNvE(`@9EdfVVN%ZNGg%Rfzr>OJ@YOYy%-gO4W6R=I{UpO*C83l75#s{F@;YkG_xa!KFrX*^rEh79=pcLUeie z!(l|sj&d+oPPR84Yd2zI>C7vGNPn;8V@^1JM#rz!%J-nOs+rd94pk?4Lid1(sz*&! zl@8@_tek949cW`AH2R+&hQL=d8Jc58$8Bgj*UdrGp9+Ufo3Nu|BAr9Ba% zWH!LEIV!1lWzKP@&jnbAaHqRgYd%1-x+-isyI!pYhGiL6>KV+(_fUu?xa%BN zIUhnh6sznQ-HMOLKUuQ*<9jCATslT~-9+<0hjxSKvR|t{p8nL@6_Ud$uQ4R`8J9z) twkfVr-OyOpWF3P|v|hOw>m_n%&uJw6{h4*1{zSVXteYVu`nb*E{s*)~c7Ff> literal 0 HcmV?d00001 diff --git a/iguana.vcxproj b/iguana.vcxproj index 5a0050e59..fbdc95c13 100644 --- a/iguana.vcxproj +++ b/iguana.vcxproj @@ -78,6 +78,7 @@ true + $(SolutionDir)/includes;$(SolutionDir)/includes/curl;$(IncludePath) false @@ -87,6 +88,7 @@ false false + $(ProjectDir)\includes;$(ProjectDir)\includes\curl;$(IncludePath) @@ -118,7 +120,7 @@ Console true .\OSlibs\win\x64;%(AdditionalLibraryDirectories) - pthread_lib.lib;Ws2_32.lib;nanomsg.lib;%(AdditionalDependencies) + pthread_lib.lib;Ws2_32.lib;nanomsg.lib;libcurl.lib;%(AdditionalDependencies) @@ -158,7 +160,7 @@ true true true - Ws2_32.lib;Advapi32.lib;$(SolutionDir)OSlibs\win\x64\pthread_lib.lib;nanomsg.lib;%(AdditionalDependencies) + Ws2_32.lib;Advapi32.lib;$(SolutionDir)OSlibs\win\x64\pthread_lib.lib;libcurl.lib;nanomsg.lib;%(AdditionalDependencies) .\OSlibs\win\x64\release;%(AdditionalLibraryDirectories) From 6e01e3d96faa2d100c095f1c91cf9bac5df48427 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 18 May 2017 08:29:27 +0300 Subject: [PATCH 0526/2705] 7776 --- iguana/coins/ltc_7776 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/coins/ltc_7776 b/iguana/coins/ltc_7776 index df691b5d6..f8b8de5ed 100755 --- a/iguana/coins/ltc_7776 +++ b/iguana/coins/ltc_7776 @@ -1,4 +1,4 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7776" --data "{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" From 90c83baa88aa2180f2cf324f37f1e5f241eefc07 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 19 May 2017 18:23:16 +0300 Subject: [PATCH 0527/2705] Fix ltc_7776 --- iguana/coins/ltc_7776 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/coins/ltc_7776 b/iguana/coins/ltc_7776 index f8b8de5ed..7b41fd929 100755 --- a/iguana/coins/ltc_7776 +++ b/iguana/coins/ltc_7776 @@ -1,4 +1,4 @@ #!/bin/bash -curl --url "http://127.0.0.1:7776" --data "{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7776" --data "{\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" From 20571acb9428c1674cbc6cbd9b9ceaabbc856a77 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 13:54:06 +0300 Subject: [PATCH 0528/2705] Test --- basilisk/basilisk_swap.c | 2 ++ basilisk/smartaddress.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2777b4f13..9883f5a76 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2449,10 +2449,12 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d) amlp.%d\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock,amlp); free(retstr); } + printf("connected.%d amlp.%d subsock.%d pushsock.%d\n",swap->connected,amlp,subsock,pushsock); if ( swap->connected <= 0 && amlp != 0 && subsock >= 0 && pushsock >= 0 ) { if ( (retstr= _dex_psock(myinfo,"{}")) != 0 ) { + printf("psock returns.(%s)\n",retstr); // {"result":"success","pushaddr":"tcp://5.9.102.210:30002","subaddr":"tcp://5.9.102.210:30003","randipbits":3606291758,"coin":"KMD","tag":"6952562460568228137"} if ( (retjson= cJSON_Parse(retstr)) != 0 ) { diff --git a/basilisk/smartaddress.c b/basilisk/smartaddress.c index a89bf248d..8fa83623b 100755 --- a/basilisk/smartaddress.c +++ b/basilisk/smartaddress.c @@ -298,8 +298,8 @@ int32_t smartaddress_pubkey(struct supernet_info *myinfo,char *typestr,double *b break; } portable_mutex_unlock(&myinfo->smart_mutex); - char str[65]; if ( retval < 0 ) - printf("smartaddress_pubkey no match for %s\n",bits256_str(str,pubkey)); + //char str[65]; if ( retval < 0 ) + // printf("smartaddress_pubkey no match for %s\n",bits256_str(str,pubkey)); return(retval); } From bee18024b5e9e713888624bc44bbdef18daaa5ab Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 15:04:01 +0300 Subject: [PATCH 0529/2705] Test --- basilisk/basilisk_DEX.c | 6 +++--- basilisk/basilisk_swap.c | 2 +- basilisk/smartaddress.c | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index 63064c6d9..d61aea803 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -242,11 +242,12 @@ char *basilisk_start(struct supernet_info *myinfo,bits256 privkey,struct basilis cJSON *retjson; char typestr[64]; bits256 tmpprivkey; double bidasks[2]; struct basilisk_request *rp=0; int32_t i,srcmatch,destmatch; if ( _rp->requestid == myinfo->lastdexrequestid ) { - //printf("filter duplicate r%u\n",_rp->requestid); + printf("filter duplicate r%u\n",_rp->requestid); return(clonestr("{\"error\":\"filter duplicate requestid\"}")); } srcmatch = smartaddress_pubkey(myinfo,typestr,bidasks,&tmpprivkey,_rp->src,_rp->srchash) >= 0; destmatch = smartaddress_pubkey(myinfo,typestr,bidasks,&tmpprivkey,_rp->dest,_rp->desthash) >= 0; + char str[65],str2[65]; printf("%s srcmatch.%d %s destmatch.%d\n",bits256_str(str,_rp->srchash),srcmatch,bits256_str(str2,_rp->desthash),destmatch); if ( srcmatch != 0 || destmatch != 0 ) { for (i=0; inumswaps; i++) @@ -312,7 +313,6 @@ int32_t basilisk_requests_poll(struct supernet_info *myinfo) myinfo->DEXaccept = issueR; if ( smartaddress_pubkey(myinfo,typestr,bidasks,&privkey,issueR.src,issueR.srchash) >= 0 ) { - printf("matched dex_smartpubkey\n"); if ( myinfo->DEXtrades > 0 ) { dex_channelsend(myinfo,issueR.srchash,issueR.desthash,channel,0x4000000,(void *)&issueR.requestid,sizeof(issueR.requestid)); // 60 @@ -322,7 +322,7 @@ int32_t basilisk_requests_poll(struct supernet_info *myinfo) free(retstr); } } - else if ( issueR.requestid != myinfo->lastdexrequestid )//if ( issueR.quoteid == 0 ) + else if ( myinfo->IAMLP != 0 && issueR.requestid != myinfo->lastdexrequestid )//if ( issueR.quoteid == 0 ) { issueR.quoteid = basilisk_quoteid(&issueR); issueR.desthash = myinfo->myaddr.persistent; diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 9883f5a76..db1713b20 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -1869,7 +1869,7 @@ void basilisk_swap_purge(struct supernet_info *myinfo,struct basilisk_swap *swap { int32_t i,n; // while still in orderbook, wait - return; + //return; portable_mutex_lock(&myinfo->DEX_swapmutex); n = myinfo->numswaps; for (i=0; imyaddr.persistent,pubkey) == 0 ) + { + *privkeyp = myinfo->persistent_priv; + return(myinfo->numsmartaddrs); + } portable_mutex_lock(&myinfo->smart_mutex); for (i=0; inumsmartaddrs; i++) if ( bits256_cmp(myinfo->smartaddrs[i].pubkey,pubkey) == 0 ) From d811364082897bc55521528928375d34a0de233c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 18:48:57 +0300 Subject: [PATCH 0530/2705] Test --- basilisk/basilisk.c | 7 ++++++- basilisk/basilisk_DEX.c | 2 +- basilisk/basilisk_swap.c | 2 +- iguana/exchanges/mm.c | 8 +++++++- iguana/tests/dexkvsearch | 2 +- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 8c65f62bc..da477d3b3 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1897,7 +1897,8 @@ int32_t InstantDEX_process_channelget(struct supernet_info *myinfo,void *ptr,int INT_ARG(InstantDEX,incoming,requestid) { - cJSON *retjson,*retarray; bits256 zero; uint32_t DEX_channel,msgid,now; int32_t retval,width,drift=3; uint8_t data[32768]; + static uint32_t counter; + cJSON *retjson,*retarray; bits256 zero; uint32_t DEX_channel,msgid,now,n = myinfo->numsmartaddrs+1; int32_t retval,width,drift=3; bits256 pubkey; uint8_t data[32768]; now = (uint32_t)time(NULL); memset(&zero,0,sizeof(zero)); width = (now - myinfo->DEXpoll) + 2*drift; @@ -1905,6 +1906,10 @@ INT_ARG(InstantDEX,incoming,requestid) width = 2*drift+1; else if ( width > 64 ) width = 64; + if ( (counter % n) == n-1 ) + pubkey = myinfo->myaddr.persistent; + else pubkey = myinfo->smartaddrs[counter % n].pubkey; + counter++; myinfo->DEXpoll = now; retjson = cJSON_CreateObject(); DEX_channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); diff --git a/basilisk/basilisk_DEX.c b/basilisk/basilisk_DEX.c index d61aea803..17ed0816e 100755 --- a/basilisk/basilisk_DEX.c +++ b/basilisk/basilisk_DEX.c @@ -286,7 +286,7 @@ int32_t basilisk_requests_poll(struct supernet_info *myinfo) { static uint32_t lastpoll; char *retstr,typestr[64]; uint8_t data[32768]; cJSON *outerarray,*retjson; uint32_t msgid,channel; int32_t datalen,i,n,retval = 0; struct basilisk_request issueR; bits256 privkey; double bidasks[2],hwm = 0.; - if ( myinfo->IAMNOTARY != 0 || time(NULL) < lastpoll+20 || (myinfo->IAMLP == 0 && myinfo->DEXactive < time(NULL)) ) + if ( myinfo->IAMNOTARY != 0 || time(NULL) < lastpoll+5 || (myinfo->IAMLP == 0 && myinfo->DEXactive < time(NULL)) ) return(retval); lastpoll = (uint32_t)time(NULL); memset(&issueR,0,sizeof(issueR)); diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index db1713b20..15ebdf1ed 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2772,7 +2772,7 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 m = n = 0; if ( bitcoin_swapinit(myinfo,privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) { - for (iter=0; iter<1; iter++) + for (iter=0; iter<5; iter++) { basilisk_psockinit(myinfo,swap,statebits == 0); sleep(3); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 137a84011..d1a423cc4 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -323,7 +323,8 @@ void marketmaker_pendingupdate(char *exchange,char *base,char *rel) void marketmaker_pendinginit(char *exchange,char *base,char *rel) { - char *retstr,*orderid; cJSON *retjson,*array,*item; int32_t i,j,n,dir; struct mmpending_order *ptr; + char *retstr,*orderid,*pairstr,relbase[64]; cJSON *retjson,*array,*item; int32_t i,j,n,dir; struct mmpending_order *ptr; + sprintf(relbase,"%s-%s",rel,base); if ( (retstr= DEX_openorders(exchange)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) @@ -334,6 +335,11 @@ void marketmaker_pendinginit(char *exchange,char *base,char *rel) for (i=0; i Date: Sat, 20 May 2017 18:50:43 +0300 Subject: [PATCH 0531/2705] Test --- iguana/exchanges/mm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index d1a423cc4..b49298d2c 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -338,8 +338,10 @@ void marketmaker_pendinginit(char *exchange,char *base,char *rel) if ( (pairstr= jstr(item,"Exchange")) == 0 ) continue; if ( strcmp(pairstr,relbase) != 0 ) + { printf("skip %s when %s\n",pairstr,relbase); - else printf("matches %s vs %s\n",pairstr,relbase); + continue; + } //printf("(%s)\n",jprint(item,0)); //{"success":true,"message":"","result":[{"Uuid":null,"OrderUuid":"81ad3e37-65d4-4fee-9c29-03b050f5192b","Exchange":"BTC-KMD","OrderType":"LIMIT_BUY","Quantity":885.19934578,"QuantityRemaining":885.19934578,"Limit":0.00011184,"CommissionPaid":0,"Price":0,"PricePerUnit":null,"Opened":"2017-02-19T19:14:02.94","Closed":null,"CancelInitiated":false,"ImmediateOrCancel":false,"IsConditional":false,"Condition":"NONE","ConditionTarget":null}],"tag":"10056789044100011414"} if ( (orderid= jstr(item,"OrderUuid")) != 0 && is_cJSON_Null(jobj(item,"Closed")) != 0 && is_cJSON_False(jobj(item,"CancelInitiated")) != 0 ) From 3eac58b332fc48f08ad16d76cd658d4d62c17ff3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 19:08:32 +0300 Subject: [PATCH 0532/2705] Test --- basilisk/basilisk_swap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 15ebdf1ed..0fc5a09b2 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2772,13 +2772,13 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 m = n = 0; if ( bitcoin_swapinit(myinfo,privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) { - for (iter=0; iter<5; iter++) + for (iter=0; iter<16; iter++) { basilisk_psockinit(myinfo,swap,statebits == 0); sleep(3); if ( swap->connected <= 0 ) continue; - sleep(30); + sleep(10); /*basilisk_sendstate(myinfo,swap,data,sizeof(data)); basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); if ( swap->connected > 0 ) @@ -2797,7 +2797,7 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 { starttime = (uint32_t)time(NULL); printf("statebits.%x m.%d n.%d\n",statebits,m,n); - while ( statebits == 0 && m <= n/2 && time(NULL) < starttime+2*BASILISK_MSGDURATION ) + while ( statebits == 0 && m <= n/2 && time(NULL) < starttime+7*BASILISK_MSGDURATION ) { m = n = 0; sleep(DEX_SLEEP); From 012d22d4b0cca5b55b05b5e4718ee671aac20fca Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 19:09:36 +0300 Subject: [PATCH 0533/2705] Test --- basilisk/basilisk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index da477d3b3..73e419316 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1914,7 +1914,7 @@ INT_ARG(InstantDEX,incoming,requestid) retjson = cJSON_CreateObject(); DEX_channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); msgid = (uint32_t)time(NULL) + drift; - if ( (retarray= basilisk_channelget(myinfo,zero,myinfo->myaddr.persistent,DEX_channel,msgid,width)) != 0 ) + if ( (retarray= basilisk_channelget(myinfo,zero,pubkey,DEX_channel,msgid,width)) != 0 ) { //printf("GOT.(%s)\n",jprint(retarray,0)); if ( (retval= basilisk_process_retarray(myinfo,0,InstantDEX_process_channelget,data,sizeof(data),DEX_channel,msgid,retarray,InstantDEX_incoming_func)) > 0 ) @@ -1926,7 +1926,7 @@ INT_ARG(InstantDEX,incoming,requestid) else { jaddstr(retjson,"error","cant do InstantDEX channelget"); - char str[65]; printf("error channelget %s %x\n",bits256_str(str,myinfo->myaddr.persistent),msgid); + char str[65]; printf("error channelget %s %x\n",bits256_str(str,pubkey),msgid); } return(jprint(retjson,1)); } From 5148002497f24ff1efaba24c4610c9a621e20bb2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 19:45:08 +0300 Subject: [PATCH 0534/2705] Test --- .gitignore | 2 ++ basilisk/basilisk_swap.c | 4 ++-- iguana/main.c | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index fcdb55638..e2939de55 100755 --- a/.gitignore +++ b/.gitignore @@ -455,3 +455,5 @@ iguana/debug.log iguana/DB/LTC/.tmpmarker iguana/DB/purgeable/LTC/.tmpmarker + +iguana/DB/SWAPS/654629381-1010651560 diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 0fc5a09b2..068677842 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2776,8 +2776,8 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 { basilisk_psockinit(myinfo,swap,statebits == 0); sleep(3); - if ( swap->connected <= 0 ) - continue; + if ( swap->connected > 0 ) + break; sleep(10); /*basilisk_sendstate(myinfo,swap,data,sizeof(data)); basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); diff --git a/iguana/main.c b/iguana/main.c index 9a224d3d2..3874ab0ee 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -756,8 +756,8 @@ void jumblr_loop(void *ptr) if ( (coin= iguana_coinfind("KMD")) != 0 ) { n++; - if ( (n % 3) == 0 ) - smartaddress_update(myinfo,(n/3) & 1); + if ( (n % 7) == 0 ) + smartaddress_update(myinfo,(n/7) & 1); if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC From 20d7e6f89da03a369b11db9b734c94672051254a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 20:51:04 +0300 Subject: [PATCH 0535/2705] Test --- basilisk/basilisk_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 068677842..b4c8021a9 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2417,7 +2417,7 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, swap->pushsock = pushsock; swap->subsock = subsock; } - if ( swap->subsock < 0 || swap->pushsock < 0 ) + if ( (subsock= swap->subsock) < 0 || (pushsock= swap->pushsock) < 0 ) { printf("error getting nn_sockets\n"); return; From 9bea85f6d4ed9c696a50ab3efbec7202ec9e404e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 21:39:26 +0300 Subject: [PATCH 0536/2705] Test --- basilisk/basilisk_swap.c | 41 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index b4c8021a9..a40a8e03c 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2493,9 +2493,11 @@ void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap, int32_t basilisk_alicetxs(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t i,retval = -1; + printf("alicetxs\n"); for (i=0; i<3; i++) { - basilisk_alicepayment(myinfo,swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicepayment.I.datalen == 0 ) + basilisk_alicepayment(myinfo,swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) { printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); @@ -2512,24 +2514,27 @@ int32_t basilisk_alicetxs(struct supernet_info *myinfo,struct basilisk_swap *swa break; } } - printf("generate fee\n"); - if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) + if ( swap->myfee.I.datalen == 0 ) { - swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); - iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); - basilisk_txlog(myinfo,swap,&swap->myfee,-1); - for (i=0; imyfee.I.spendlen; i++) - printf("%02x",swap->myfee.txbytes[i]); - printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); - swap->I.statebits |= 0x40; - if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 ) - return(0); - } - else - { - printf("error creating myfee\n"); - return(-2); + printf("generate fee\n"); + if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) + { + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); + iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); + basilisk_txlog(myinfo,swap,&swap->myfee,-1); + for (i=0; imyfee.I.spendlen; i++) + printf("%02x",swap->myfee.txbytes[i]); + printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); + swap->I.statebits |= 0x40; + } + else + { + printf("error creating myfee\n"); + return(-2); + } } + if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 && swap->myfee.I.datalen != 0 && swap->myfee.I.spendlen > 0 ) + return(0); return(-1); } @@ -2619,7 +2624,7 @@ void basilisk_swaploop(void *_swap) continue; } } - if ( swap->I.iambob == 0 && swap->myfee.I.datalen == 0 ) + if ( swap->I.iambob == 0 ) { /*for (i=0; i<20; i++) printf("%02x",swap->secretAm[i]); From 2329417a0cf84710486f70baf647fb6f370ee8a9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 20 May 2017 23:21:56 +0300 Subject: [PATCH 0537/2705] Test --- .gitignore | 4 ++++ basilisk/basilisk.c | 2 +- iguana/tests/dexkvsearch | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index e2939de55..992a4af4c 100755 --- a/.gitignore +++ b/.gitignore @@ -457,3 +457,7 @@ iguana/DB/LTC/.tmpmarker iguana/DB/purgeable/LTC/.tmpmarker iguana/DB/SWAPS/654629381-1010651560 + +iguana/DB/SWAPS/1780095668-2225891679 + +iguana/DB/SWAPS/3085356347-2346291696 diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index 73e419316..a2a6d2200 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -1926,7 +1926,7 @@ INT_ARG(InstantDEX,incoming,requestid) else { jaddstr(retjson,"error","cant do InstantDEX channelget"); - char str[65]; printf("error channelget %s %x\n",bits256_str(str,pubkey),msgid); + //char str[65]; printf("error channelget %s %x\n",bits256_str(str,pubkey),msgid); } return(jprint(retjson,1)); } diff --git a/iguana/tests/dexkvsearch b/iguana/tests/dexkvsearch index 11ef23c6e..8391dea10 100755 --- a/iguana/tests/dexkvsearch +++ b/iguana/tests/dexkvsearch @@ -1,4 +1,4 @@ #!/bin/bash #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"foo\",\"symbol\":\"KMD\"}" #curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"test\",\"symbol\":\"KV\"}" -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"89bb7bb9-e6857af8\",\"symbol\":\"KV\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"kvsearch\",\"key\":\"ec474661-de713a84\",\"symbol\":\"KV\"}" From 7a66afc61cc52d8b896eb18bba2132cc82253977 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 May 2017 10:52:57 +0300 Subject: [PATCH 0538/2705] Test --- iguana/exchanges/bitcoin.c | 23 ++++++++++++++++++++--- iguana/iguana_wallet.c | 2 ++ includes/iguana_funcs.h | 1 + 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index b23d59864..452c8c075 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -139,10 +139,27 @@ int32_t bitcoin_priv2wif(char *wifstr,bits256 privkey,uint8_t addrtype) { uint8_t data[128]; int32_t len = 32; memcpy(data+1,privkey.bytes,sizeof(privkey)); - if ( addrtype != 176 ) // not LTC - data[1 + len++] = 1; + data[1 + len++] = 1; + len = base58encode_checkbuf(addrtype,data,len); + if ( bitcoin_base58encode(wifstr,data,len) == 0 ) + return(-1); + if ( 1 ) + { + uint8_t checktype; bits256 checkpriv; char str[65],str2[65]; + if ( bitcoin_wif2priv(&checktype,&checkpriv,wifstr) == sizeof(bits256) ) + { + if ( checktype != addrtype || bits256_cmp(checkpriv,privkey) != 0 ) + printf("(%s) -> wif.(%s) addrtype.%02x -> %02x (%s)\n",bits256_str(str,privkey),wifstr,addrtype,checktype,bits256_str(str2,checkpriv)); + } + } + return((int32_t)strlen(wifstr)); +} + +int32_t bitcoin_priv2wiflong(char *wifstr,bits256 privkey,uint8_t addrtype) +{ + uint8_t data[128]; int32_t len = 32; + memcpy(data+1,privkey.bytes,sizeof(privkey)); len = base58encode_checkbuf(addrtype,data,len); - if ( bitcoin_base58encode(wifstr,data,len) == 0 ) return(-1); if ( 1 ) diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index e17538201..e125aea2a 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -1435,6 +1435,8 @@ THREE_STRINGS(bitcoinrpc,encryptwallet,passphrase,password,permanentfile) { bitcoin_priv2wif(wifstr,waddr.privkey,coin->chain->wiftype); jaddstr(retjson,"LTCwif",wifstr); + bitcoin_priv2wiflong(wifstr,waddr.privkey,coin->chain->wiftype); + jaddstr(retjson,"LTCwiflong",wifstr); } if ( need_BTC != 0 ) { diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index 8ca911a49..ceb086e22 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -287,6 +287,7 @@ int32_t SuperNET_sendmsg(struct supernet_info *myinfo,struct iguana_info *coin,s int32_t category_peer(struct supernet_info *myinfo,struct iguana_peer *addr,bits256 category,bits256 subhash); int32_t bitcoin_wif2priv(uint8_t *addrtypep,bits256 *privkeyp,char *wifstr); int32_t bitcoin_priv2wif(char *wifstr,bits256 privkey,uint8_t addrtype); +int32_t bitcoin_priv2wiflong(char *wifstr,bits256 privkey,uint8_t addrtype); bits256 iguana_chaingenesis(struct supernet_info *myinfo,char *symbol,uint8_t zcash,uint8_t auxpow,int32_t (*hashalgo)(uint8_t *blockhashp,uint8_t *serialized,int32_t len),bits256 genesishash,char *genesisblock,char *hashalgostr,int32_t version,uint32_t timestamp,uint32_t bits,uint32_t nonce,bits256 merkle_root); int32_t iguana_send_ConnectTo(struct iguana_info *coin,struct iguana_peer *addr); cJSON *iguana_txjson(struct iguana_info *coin,struct iguana_txid *tx,int32_t height,struct vin_info *V); From 356953a6bc97f224eb55aeaaf5bbe0a1a3ebcf67 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 May 2017 16:25:13 +0300 Subject: [PATCH 0539/2705] Test --- basilisk/basilisk_swap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index a40a8e03c..2016af74e 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2804,10 +2804,15 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 printf("statebits.%x m.%d n.%d\n",statebits,m,n); while ( statebits == 0 && m <= n/2 && time(NULL) < starttime+7*BASILISK_MSGDURATION ) { + uint32_t msgid; uint8_t data[1024]; int32_t datalen; m = n = 0; sleep(DEX_SLEEP); printf("waiting for offer to be accepted\n"); channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); + datalen = basilisk_rwDEXquote(1,data,rp); + msgid = (uint32_t)time(NULL); + printf("other req.%d >>>>>>>>>>> send response (%llx -> %llx) last.%u r.%u quoteid.%u\n",i,(long long)rp->desthash.txid,(long long)rp->srchash.txid,myinfo->lastdexrequestid,rp->requestid,rp->quoteid); + dex_channelsend(myinfo,rp->desthash,rp->srchash,channel,msgid,data,datalen); if ( (retarray= basilisk_channelget(myinfo,rp->srchash,rp->desthash,channel,0x4000000,30)) != 0 ) { if ( is_cJSON_Array(retarray) != 0 && (n= cJSON_GetArraySize(retarray)) > 0 ) From abb3fa9bdf94c905267ec9b18f77f7e5b9f18edf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 May 2017 16:49:46 +0300 Subject: [PATCH 0540/2705] Test --- basilisk/basilisk_swap.c | 6 ++++-- iguana/coins/btc_osx | 2 ++ iguana/coins/kmd_osx | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100755 iguana/coins/btc_osx create mode 100755 iguana/coins/kmd_osx diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 2016af74e..24d935e31 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2545,7 +2545,7 @@ void basilisk_swaploop(void *_swap) fprintf(stderr,"start swap\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); - expiration = (uint32_t)time(NULL) + 120; + expiration = (uint32_t)time(NULL) + 300; myinfo->DEXactive = expiration; channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) @@ -2574,7 +2574,7 @@ void basilisk_swaploop(void *_swap) printf("couldnt establish connection\n"); retval = -1; } - while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 && time(NULL) < expiration ) + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 ) { if ( swap->connected == 0 ) basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); @@ -2591,6 +2591,8 @@ void basilisk_swaploop(void *_swap) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; + if ( time(NULL) > expiration ) + break; } myinfo->DEXactive = swap->I.expiration; if ( time(NULL) >= expiration ) diff --git a/iguana/coins/btc_osx b/iguana/coins/btc_osx new file mode 100755 index 000000000..d7dfce062 --- /dev/null +++ b/iguana/coins/btc_osx @@ -0,0 +1,2 @@ +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"bitcoin.conf\",\"path\":\"/${HOME#"/"}/Library/Application\ Support/Bitcoin\",\"prefetchlag\":-1,\"poll\":1,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"newcoin\":\"BTC\",\"startpend\":64,\"endpend\":64,\"services\":0,\"maxpeers\":512,\"RELAY\":-1,\"VALIDATE\":0,\"portp2p\":8333,\"minconfirms\":1}" + diff --git a/iguana/coins/kmd_osx b/iguana/coins/kmd_osx new file mode 100755 index 000000000..2374af8a7 --- /dev/null +++ b/iguana/coins/kmd_osx @@ -0,0 +1,2 @@ +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"komodo.conf\",\"path\":\"/${HOME#"/"}/Library/Application\ Support/Komodo\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":8,\"endpend\":8,\"services\":0,\"maxpeers\":32,\"newcoin\":\"KMD\",\"name\":\"Komodo\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"f9eee48d\",\"p2p\":7770,\"rpc\":7771,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0}" + From 8afca2e19b232bcbda3817887c82300e7ed5df3c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 May 2017 17:47:14 +0300 Subject: [PATCH 0541/2705] Test --- .gitignore | 4 ++++ basilisk/basilisk_bitcoin.c | 2 +- basilisk/basilisk_swap.c | 3 ++- iguana/dpow/dpow_network.c | 2 +- iguana/main.c | 4 ++-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 992a4af4c..c68d66ed4 100755 --- a/.gitignore +++ b/.gitignore @@ -461,3 +461,7 @@ iguana/DB/SWAPS/654629381-1010651560 iguana/DB/SWAPS/1780095668-2225891679 iguana/DB/SWAPS/3085356347-2346291696 + +iguana/DB/SWAPS/1819165332-1507632737 + +iguana/DB/SWAPS/283982730-556239841 diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index aeb233bcc..ad1165fd0 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -781,7 +781,7 @@ char *basilisk_bitcoinrawtx(struct supernet_info *myinfo,struct iguana_info *coi addresses = iguana_getaddressesbyaccount(myinfo,coin,"*"); jadd(valsobj,"addresses",addresses); } - printf("use addresses.(%s)\n",jprint(addresses,0)); + printf("use addresses.(%s) (%s)\n",jprint(addresses,0),spendscriptstr!=0?spendscriptstr:"no script"); //printf("(%s) vals.(%s) change.(%s) spend.%s\n",coin->symbol,jprint(valsobj,0),changeaddr,spendscriptstr); if ( changeaddr == 0 || changeaddr[0] == 0 || spendscriptstr == 0 || spendscriptstr[0] == 0 ) return(clonestr("{\"error\":\"invalid changeaddr or spendscript or addresses\"}")); diff --git a/basilisk/basilisk_swap.c b/basilisk/basilisk_swap.c index 24d935e31..a142f8a12 100755 --- a/basilisk/basilisk_swap.c +++ b/basilisk/basilisk_swap.c @@ -2042,7 +2042,8 @@ uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilis } } return(nextbits); - } else printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); + } else if ( swap->I.iambob == 0 ) + printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); return(0); } diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 5d9f4c233..f357fb887 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1173,7 +1173,7 @@ char *_dex_listunspentarg(struct supernet_info *myinfo,char *symbol,char *addres dexreq.func = arg; if ( (retstr= _dex_sendrequeststr(myinfo,&dexreq,address,0,1,"")) != 0 ) { - //printf("_dex_listunspentarg: %s UNSPENTS.(%s)\n",symbol,retstr); + printf("_dex_listunspentarg: %s UNSPENTS.(%s)\n",symbol,retstr); } return(_dex_arrayreturn(retstr)); } diff --git a/iguana/main.c b/iguana/main.c index 3874ab0ee..9a224d3d2 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -756,8 +756,8 @@ void jumblr_loop(void *ptr) if ( (coin= iguana_coinfind("KMD")) != 0 ) { n++; - if ( (n % 7) == 0 ) - smartaddress_update(myinfo,(n/7) & 1); + if ( (n % 3) == 0 ) + smartaddress_update(myinfo,(n/3) & 1); if ( myinfo->jumblr_passphrase[0] != 0 && coin->FULLNODE < 0 ) { // if BTC has arrived in destination address, invoke DEX -> BTC From 6ef9485e444c3b3acb5a3831a1b1f235eeced320 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 10:21:48 +0300 Subject: [PATCH 0542/2705] Test --- iguana/dpow/dpow_network.c | 10 ++++++++-- iguana/exchanges/DEXstats.h | 10 +++++----- iguana/exchanges/LP_unspents.c | 21 +++++++++++++++++++++ iguana/exchanges/mm.c | 17 +++++++++++++++-- iguana/exchanges/stats.c | 4 +++- iguana/m_test | 27 ++++----------------------- iguana/tests/dexgetinfo | 2 +- iguana/tests/dexlistunspent | 2 +- 8 files changed, 58 insertions(+), 35 deletions(-) create mode 100644 iguana/exchanges/LP_unspents.c diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index f357fb887..bab487d4e 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -88,9 +88,15 @@ void dex_init(struct supernet_info *myinfo) break; } mask |= (1 << j); +#ifdef NOTARY_TESTMODE + seeds[j] = NOTARY_TESTMODE; +#endif printf("seed.[%d] <- %s\n",i,seeds[j]); strcpy(myinfo->dexseed_ipaddrs[i],seeds[j]); myinfo->dexipbits[i] = (uint32_t)calc_ipbits(myinfo->dexseed_ipaddrs[i]); +#ifdef NOTARY_TESTMODE + break; +#endif } myinfo->numdexipbits = i; portable_mutex_init(&myinfo->dexmutex); @@ -526,14 +532,14 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 printf("%d: subscribe connect (%s)\n",myinfo->numdexipbits,str); } } -//#ifndef __APPLE__ +#ifndef NOTARY_TESTMODE if ( (rand() % 100) < 40 ) { nanomsg_tcpname(0,str,ipaddr,REP_SOCK); nn_connect(myinfo->reqsock,str); printf("%d: req connect (%s)\n",myinfo->numdexipbits,str); } -//#endif +#endif } } if ( freeptr != 0 ) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 38c2d1fa3..16889c2e1 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -754,7 +754,7 @@ void stats_updatedisp(struct DEXstats_disp *disp,double price,double volume) void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates,struct DEXstats_datenuminfo *date,char *dest,int32_t current_daysecond) { - int32_t i,j,seconds,hour,offset,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp,lefttimestamp,righttimestamp; + int32_t i,j,offset,datenum = date->datenum; struct DEXstats_pairinfo *pair; struct DEXstats_pricepoint *ptr; uint32_t timestamp,lefttimestamp,righttimestamp; offset = datenum - leftdatenum; lefttimestamp = OS_conv_datenum(leftdatenum,0,0,0); righttimestamp = OS_conv_datenum(leftdatenum+numdates,0,0,0); @@ -782,9 +782,9 @@ void stats_dispprices(struct DEXstats_disp *prices,int32_t leftdatenum,int32_t n } } -#include "../crypto777/jpeg/jinclude.h" -#include "../crypto777/jpeg/jpeglib.h" -#include "../crypto777/jpeg/jerror.h" +#include "../../crypto777/jpeg/jinclude.h" +#include "../../crypto777/jpeg/jpeglib.h" +#include "../../crypto777/jpeg/jerror.h" void gen_jpegfile(char *fname,int32_t quality,uint8_t *bitmap,int32_t width,int32_t height) { @@ -821,7 +821,7 @@ void gen_jpegfile(char *fname,int32_t quality,uint8_t *bitmap,int32_t width,int3 char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t leftdatenum,int32_t numdates) { - int32_t i,j,datenum,n,seconds; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals,total; char fname[1024]; struct tai T; cJSON *retjson,*array,*item; + int32_t i,j,n; struct DEXstats_priceinfo *pp; uint32_t *utc32,tmp,timestamp,lefttimestamp,righttimestamp; double *splinevals,total; char fname[1024]; cJSON *retjson,*array,*item; timestamp = (uint32_t)time(NULL); if ( Num_priceinfos >= sizeof(Prices)/sizeof(*Prices) ) return(0); diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c new file mode 100644 index 000000000..aab4d8283 --- /dev/null +++ b/iguana/exchanges/LP_unspents.c @@ -0,0 +1,21 @@ +// +// LP_unspents.c +// marketmaker +// +// Created by Mac on 5/23/17. +// Copyright © 2017 SuperNET. All rights reserved. +// + +#include + +void LPinit() +{ + char *retstr; + retstr = iguana_listunspent("KMD","RRyBxbrAPRUBCUpiJgJZYrkxqrh8x5ta9Z"); + if ( retstr != 0 ) + { + printf("listunspent.(%s)\n",retstr); + free(retstr); + } else printf("null retstr\n"); + getchar(); +} diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index b49298d2c..92356d660 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -19,9 +19,11 @@ // Copyright © 2017 SuperNET. All rights reserved. // +#define FROM_MARKETMAKER #include #include #include "OS_portable.h" +#include "stats.c" #define MAX(a,b) ((a) > (b) ? (a) : (b)) char DEX_baseaddr[64],DEX_reladdr[64]; @@ -37,9 +39,9 @@ int32_t Num_Pending; #define IGUANA_URL "http://127.0.0.1:7778" -char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies +/*char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", // end of currencies -}; +};*/ double PAXPRICES[sizeof(CURRENCIES)/sizeof(*CURRENCIES)]; uint32_t PAXACTIVE; @@ -148,6 +150,14 @@ char *iguana_walletpassphrase(char *passphrase,int32_t timeout) return(bitcoind_RPC(0,"",url,0,"walletpassphrase",postdata)); } +char *iguana_listunspent(char *coin,char *coinaddr) +{ + char url[512],postdata[1024]; + sprintf(url,"%s/coin=%s&agent=bitcoinrpc&method=listunspent?",IGUANA_URL,coin); + sprintf(postdata,"[\"%s\"]",coinaddr); + return(bitcoind_RPC(0,"",url,0,"listunspent",postdata)); +} + double bittrex_balance(char *base,char *coinaddr) { char *retstr; cJSON *retjson; double balance = 0.; @@ -700,11 +710,14 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double } } +#include "LP_unspents.c" + int main(int argc, const char * argv[]) { char *base,*rel,*name,*exchange,*apikey,*apisecret,*blocktrail,*retstr,*baseaddr,*reladdr,*passphrase; double profitmargin,maxexposure,incrratio,start_rel,start_base,minask,maxbid; cJSON *retjson,*loginjson; int32_t i; + LPinit(); if ( argc > 1 && (retjson= cJSON_Parse(argv[1])) != 0 ) { minask = jdouble(retjson,"minask"); diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index d69e369c1..890c157bb 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -305,7 +305,7 @@ cJSON *SuperNET_urlconv(char *value,int32_t bufsize,char *urlstr) char *stats_rpcparse(char *retbuf,int32_t bufsize,int32_t *jsonflagp,int32_t *postflagp,char *urlstr,char *remoteaddr,char *filetype,uint16_t port) { cJSON *tokens,*argjson,*origargjson,*tmpjson=0,*json = 0; long filesize; - char symbol[64],buf[4096],*originstr,*fieldstr,*userpass=0,urlmethod[16],*data,url[8192],furl[8192],*retstr,*filestr,*token = 0; int32_t i,j,n,iter,num=0; + char symbol[64],buf[4096],*userpass=0,urlmethod[16],*data,url[8192],furl[8192],*retstr,*filestr,*token = 0; int32_t i,j,n,num=0; //printf("rpcparse.(%s)\n",urlstr); for (i=0; i iguana.log 2> error.log & - -myip=`curl -s4 checkip.amazonaws.com` -source pubkey.txt - -coins/kmd_7776 -coins/revs_7776 -sleep 4 -curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"SuperNET\",\"method\":\"myipaddr\",\"ipaddr\":\"$myip\"}" -sleep 3 - -curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"addnotary\",\"ipaddr\":\"$myip\"}" -curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"addnotary\",\"ipaddr\":\"78.47.196.146\"}" -#curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"addnotary\",\"ipaddr\":\"5.9.102.210\"}" -#curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"addnotary\",\"ipaddr\":\"89.248.160.237\"}" -#curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"addnotary\",\"ipaddr\":\"89.248.160.238\"}" -./wp_7776 -curl --url "http://127.0.0.1:7776" --data "{\"timeout\":60000,\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"REVS\",\"pubkey\":\"$pubkey\"}" +gcc -DNOTARY_TESTMODE=\"78.47.196.146\" -g -Wno-aggressive-loop-optimizations -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c +gcc -DNOTARY_TESTMODE=\"78.47.196.146\" -g -Wno-aggressive-loop-optimizations -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c +gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm diff --git a/iguana/tests/dexgetinfo b/iguana/tests/dexgetinfo index 8aa05a403..0d89dba21 100755 --- a/iguana/tests/dexgetinfo +++ b/iguana/tests/dexgetinfo @@ -1,3 +1,3 @@ #!/bin/bash curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getinfo\",\"symbol\":\"KMD\"}" -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getinfo\",\"symbol\":\"WLC\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getinfo\",\"symbol\":\"LTC\"}" diff --git a/iguana/tests/dexlistunspent b/iguana/tests/dexlistunspent index 2aa0e56ab..7347339da 100755 --- a/iguana/tests/dexlistunspent +++ b/iguana/tests/dexlistunspent @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RSZ7dc164T9gpDLmXU7spYEScru1mGzPMB\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RRyBxbrAPRUBCUpiJgJZYrkxqrh8x5ta9Z\",\"symbol\":\"KMD\"}" From 7a40c21936512909e84f5063297ea78cfb01f096 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 10:46:08 +0300 Subject: [PATCH 0543/2705] Test --- iguana/dpow/dpow_network.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index bab487d4e..74c70971e 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -95,6 +95,7 @@ void dex_init(struct supernet_info *myinfo) strcpy(myinfo->dexseed_ipaddrs[i],seeds[j]); myinfo->dexipbits[i] = (uint32_t)calc_ipbits(myinfo->dexseed_ipaddrs[i]); #ifdef NOTARY_TESTMODE + i = 1; break; #endif } From 196c44c5b5f6e8382851f7ee51301f2ac2ac3c30 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 10:53:38 +0300 Subject: [PATCH 0544/2705] Test --- iguana/dpow/dpow_network.c | 4 ---- iguana/iguana777.h | 7 ++++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 74c70971e..335f6867c 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -94,10 +94,6 @@ void dex_init(struct supernet_info *myinfo) printf("seed.[%d] <- %s\n",i,seeds[j]); strcpy(myinfo->dexseed_ipaddrs[i],seeds[j]); myinfo->dexipbits[i] = (uint32_t)calc_ipbits(myinfo->dexseed_ipaddrs[i]); -#ifdef NOTARY_TESTMODE - i = 1; - break; -#endif } myinfo->numdexipbits = i; portable_mutex_init(&myinfo->dexmutex); diff --git a/iguana/iguana777.h b/iguana/iguana777.h index b02a38a68..778ab3806 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -164,7 +164,12 @@ struct supernet_info struct liquidity_info linfos[512]; cJSON *liquidity_currencies; struct pending_trade *trades; portable_mutex_t pending_mutex; struct komodo_notaries NOTARY; char seedipaddr[64]; uint32_t dpowipbits[128]; int32_t numdpowipbits; portable_mutex_t notarymutex,dpowmutex; - char dexseed_ipaddrs[2][64]; uint32_t dexipbits[128]; int32_t numdexipbits; portable_mutex_t dexmutex; +#ifdef NOTARY_TESTMODE + char dexseed_ipaddrs[1][64]; +#else + char dexseed_ipaddrs[8][64]; +#endif + uint32_t dexipbits[128]; int32_t numdexipbits; portable_mutex_t dexmutex; // compatibility bits256 pangea_category,instantdex_category; uint8_t logs[256],exps[510]; From 9a85b05bb1b50d8620b827b9b399077acb07ac21 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 10:56:04 +0300 Subject: [PATCH 0545/2705] Test --- iguana/dpow/dpow_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 335f6867c..38789f35c 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1176,7 +1176,7 @@ char *_dex_listunspentarg(struct supernet_info *myinfo,char *symbol,char *addres dexreq.func = arg; if ( (retstr= _dex_sendrequeststr(myinfo,&dexreq,address,0,1,"")) != 0 ) { - printf("_dex_listunspentarg: %s UNSPENTS.(%s)\n",symbol,retstr); + //printf("_dex_listunspentarg: %s UNSPENTS.(%s)\n",symbol,retstr); } return(_dex_arrayreturn(retstr)); } From 009aa5162ecc176d6577b1f3ca1f00b8f591f259 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 10:57:54 +0300 Subject: [PATCH 0546/2705] Test --- iguana/m_test | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/m_test b/iguana/m_test index 7e91b6553..8bf7b041b 100755 --- a/iguana/m_test +++ b/iguana/m_test @@ -1,9 +1,10 @@ #!/bin/bash +TESTIPADDR=\"78.47.196.146\" #./configure --enable-endomorphism --enable-module-ecdh --enable-module-schnorr --enable-module-rangeproof --enable-experimental --enable-module_recovery rm -f ../agents/iguana *.o git pull cd secp256k1; ./m_unix; cd .. cd ../crypto777; ./m_LP; cd ../iguana -gcc -DNOTARY_TESTMODE=\"78.47.196.146\" -g -Wno-aggressive-loop-optimizations -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c -gcc -DNOTARY_TESTMODE=\"78.47.196.146\" -g -Wno-aggressive-loop-optimizations -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c +gcc -DNOTARY_TESTMODE=$TESTIPADDR -g -Wno-aggressive-loop-optimizations -Wno-deprecated -c -O2 -DLIQUIDITY_PROVIDER=1 *.c ../basilisk/basilisk.c ../gecko/gecko.c ../datachain/datachain.c +gcc -DNOTARY_TESTMODE=$TESTIPADDR -g -Wno-aggressive-loop-optimizations -Wno-deprecated -c -DLIQUIDITY_PROVIDER=1 main.c iguana777.c iguana_bundles.c ../basilisk/basilisk.c iguana_ramchain.c gcc -g -o ../agents/iguana *.o ../agents/libcrypto777.a /usr/local/lib/libnanomsg.so -lcurl -lssl -lcrypto -lpthread -lz -lm From bd5781ece56bb6bb828e68c6883ca1e64a155deb Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 11:29:02 +0300 Subject: [PATCH 0547/2705] Test --- iguana/coins/genltc | 2 +- iguana/coins/ltc_7776 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/coins/genltc b/iguana/coins/genltc index 7b41fd929..9994529e0 100755 --- a/iguana/coins/genltc +++ b/iguana/coins/genltc @@ -1,4 +1,4 @@ #!/bin/bash -curl --url "http://127.0.0.1:7776" --data "{\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7776" --data "{\"RELAY\":1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" diff --git a/iguana/coins/ltc_7776 b/iguana/coins/ltc_7776 index 7b41fd929..063e53cbc 100755 --- a/iguana/coins/ltc_7776 +++ b/iguana/coins/ltc_7776 @@ -1,4 +1,4 @@ #!/bin/bash -curl --url "http://127.0.0.1:7776" --data "{\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7776" --data "{\"path\":\"${HOME#"/"}/.litecoin\",\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" From 1d5aee376fe01e2b7da93d3dc0b346c84d4da029 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 11:37:14 +0300 Subject: [PATCH 0548/2705] Test --- iguana/coins/ltc_7776 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/coins/ltc_7776 b/iguana/coins/ltc_7776 index 063e53cbc..d6b5e4e11 100755 --- a/iguana/coins/ltc_7776 +++ b/iguana/coins/ltc_7776 @@ -1,4 +1,4 @@ #!/bin/bash -curl --url "http://127.0.0.1:7776" --data "{\"path\":\"${HOME#"/"}/.litecoin\",\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"litecoin.conf\",\"path\":\"${HOME#"/"}/.litecoin\",\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" From 7a589eff02265f83260ecb42e3b4b3caa59428c2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 17:19:47 +0300 Subject: [PATCH 0549/2705] test --- crypto777/bitcoind_RPC.c | 2 +- iguana/exchanges/DEXstats.h | 2 + iguana/exchanges/LP_unspents.c | 268 ++++++++++++++++++++++++++++++++- iguana/exchanges/mm.c | 74 ++++++++- 4 files changed, 337 insertions(+), 9 deletions(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index a4a9499b1..37ef4be0a 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -207,7 +207,7 @@ try_again: free(s.ptr); return(0); } - else if ( numretries >= 4 ) + else if ( numretries >= 2 ) { printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); //printf("Maximum number of retries exceeded!\n"); diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 16889c2e1..5738ab91e 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -915,6 +915,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t return(jprint(retjson,1)); } +#ifndef FROM_MARKETMAKER char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { char *method,*agent,*retstr,*source,*dest; struct tai T; uint32_t endtimestamp; struct DEXstats_disp prices[365]; int32_t leftdatenum,seconds,numdates; @@ -940,5 +941,6 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) } return(clonestr(jprint(argjson,0))); } +#endif #endif /* DEXstats_h */ diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index aab4d8283..b522309c6 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -8,14 +8,270 @@ #include -void LPinit() +char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; + +struct LP_peerinfo { - char *retstr; - retstr = iguana_listunspent("KMD","RRyBxbrAPRUBCUpiJgJZYrkxqrh8x5ta9Z"); - if ( retstr != 0 ) + double profitmargin; + uint32_t ipbits,gotintro,sentintro; + char ipaddr[64]; + uint16_t port; +} LP_peerinfos[1024]; +int32_t LP_numpeers; + +void LP_addutxo(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 deposittxid,int32_t depositvout,uint64_t depositsatoshis,char *spendscript,char *coinaddr) +{ + printf("LP_addutxo.(%.8f %.8f)\n",dstr(satoshis),dstr(depositsatoshis)); +} + +void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro,double profitmargin) +{ + struct LP_peerinfo *peer; + if ( i == sizeof(LP_peerinfos)/sizeof(*LP_peerinfos) ) + i = (rand() % (sizeof(LP_peerinfos)/sizeof(*LP_peerinfos))); + peer = &LP_peerinfos[i]; + memset(peer,0,sizeof(*peer)); + peer->profitmargin = profitmargin; + peer->ipbits = ipbits; + peer->gotintro = gotintro; + peer->sentintro = sentintro; + strcpy(peer->ipaddr,ipaddr); + peer->port = port; + if ( i == LP_numpeers ) + LP_numpeers++; +} + +void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port) +{ + char buf[1024],*retstr,*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,j,n; uint16_t argport; double profit; + sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); + if ( (retstr= issue_curl(buf)) != 0 ) { - printf("listunspent.(%s)\n",retstr); + printf("got (%s) from (%s)\n",retstr,buf); + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i 0. ) + { + argport = juint(item,"port"); + ipbits = (uint32_t)calc_ipbits(argipaddr); + for (j=0; jipaddr); + jaddnum(item,"port",peer->port); + return(item); +} + +char *LP_peers() +{ + int32_t i; cJSON *peersjson = cJSON_CreateArray(); + for (i=0; i 0 ) + { + lastj = -1; + for (iter=0; iter<2; iter++) + { + j = (rand() % LP_numpeers); + if ( j != lastj ) + { + peer = &LP_peerinfos[j]; + if ( peer->sentintro == 0 ) + LP_notify(peer,ipaddr,port); + lastj = j; + } + } + } + _LP_addpeer(i,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); + } + } + return(LP_peers()); +} + +int32_t LP_maxvalue(uint64_t *values,int32_t n) +{ + int32_t i,maxi = -1; uint64_t maxval = 0; + for (i=0; i maxval ) + { + maxi = i; + maxval = values[i]; + } + return(maxi); +} + +int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) +{ + int32_t i,mini = -1; int64_t dist; uint64_t mindist = (1 << 31); + for (i=0; i= 0 && dist < mindist ) + { + mini = i; + mindist = dist; + } + } + return(mini); +} + +uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifstr) +{ + char *retstr,coinaddr[64],*script; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33]; + if ( passphrase != 0 ) + conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); + else privkey = iguana_wif2privkey(wifstr); + iguana_priv2pub(pubkey33,coinaddr,privkey,addrtype); + retstr = iguana_listunspent(coin,coinaddr); + if ( retstr != 0 && retstr[0] == '[' && retstr[1] == ']' ) + free(retstr), retstr = 0; + if ( retstr == 0 ) + { + if ( (retstr= DEX_listunspent(coin,coinaddr)) == 0 ) + { + printf("null listunspent\n"); + return(0); + } + } + printf("LP_privkey_init.(%s)\n",retstr); + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + values = calloc(n,sizeof(*values)); + for (i=0; i= 0 ) + { + item = jitem(array,i); + deposittxid = jbits256(item,"txid"); + depositvout = juint(item,"vout"); + script = jstr(item,"scriptPubKey"); + depositval = values[i]; + values[i] = 0, used++; + targetval = (depositval / 9) * 8; + printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); + if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) + { + item = jitem(array,i); + txid = jbits256(item,"txid"); + vout = juint(item,"vout"); + if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 ) + { + value = values[i]; + values[i] = 0, used++; + LP_addutxo(coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr); + total += value; + } + } + } else break; + } + free(values); + } + free_json(array); + } + free(retstr); + return(total); +} + +void LPinit(uint16_t port,double profitmargin) +{ + char *retstr,*ipaddr; long filesize,n; int32_t i; + if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) + { + if ( (ipaddr= OS_filestr(&filesize,"/tmp/myipaddr")) != 0 && ipaddr[0] != 0 ) + { + n = strlen(ipaddr); + if ( ipaddr[n-1] == '\n' ) + ipaddr[--n] = 0; + retstr = LP_addpeer(ipaddr,port,0,(uint32_t)time(NULL),profitmargin); + printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); + if ( retstr != 0 ) + free(retstr); + for (i=0; i %s\n",default_LPnodes[i],retstr); + free(retstr); + } + } + } + } + LP_privkey_init("KMD",60,"test",""); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&port) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",port); + exit(-1); + } getchar(); } + +char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) +{ + char *method,*ipaddr,*coin,*dest,*retstr = 0; uint16_t argport; double profitmargin; + if ( (method= jstr(argjson,"method")) == 0 ) + return(clonestr("{\"error\":\"need method in request\"}")); + else + { + if ( strcmp(method,"intro") == 0 ) + { + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (profitmargin= jdouble(argjson,"profit")) != 0. ) + retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,profitmargin); + } + else if ( strcmp(method,"getpeers") == 0 ) + retstr = LP_peers(); + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 && (dest= jstr(argjson,"dest")) != 0 ) + { + //retstr = LP_getutxos(coin,dest); + } + } + if ( retstr != 0 ) + return(retstr); + return(clonestr(jprint(argjson,0))); +} diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 92356d660..26eedc0ab 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -23,8 +23,9 @@ #include #include #include "OS_portable.h" -#include "stats.c" #define MAX(a,b) ((a) > (b) ? (a) : (b)) +char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port); +#include "stats.c" char DEX_baseaddr[64],DEX_reladdr[64]; struct mmpending_order @@ -158,6 +159,75 @@ char *iguana_listunspent(char *coin,char *coinaddr) return(bitcoind_RPC(0,"",url,0,"listunspent",postdata)); } +char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",destip,destport,ipaddr,port); + return(issue_curl(url)); +} + +char *issue_LP_getpeers(char *destip,uint16_t destport) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/getpeers",destip,destport); + return(issue_curl(url)); +} + +// +// http://127.0.0.1:7779/api/stats/getpeers + +char *DEX_listunspent(char *coin,char *coinaddr) +{ + char url[512],postdata[1024]; + sprintf(url,"%s/?",IGUANA_URL); + sprintf(postdata,"{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"%s\",\"symbol\":\"%s\"}",coinaddr,coin); + return(bitcoind_RPC(0,"dex",url,0,"listunspent",postdata)); +} + +bits256 iguana_wif2privkey(char *wifstr) +{ + char url[512],postdata[1024],*retstr,*privstr; bits256 privkey; cJSON *retjson; + memset(privkey.bytes,0,sizeof(privkey)); + sprintf(url,"%s/?",IGUANA_URL); + sprintf(postdata,"{\"agent\":\"SuperNET\",\"method\":\"wif2priv\",\"wif\":\"%s\"}",wifstr); + if ( (retstr= bitcoind_RPC(0,"SuperNET",url,0,"wif2priv",postdata)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (privstr= jstr(retjson,"privkey")) != 0 ) + { + if ( strlen(privstr) == 64 ) + decode_hex(privkey.bytes,32,privstr); + } + free_json(retjson); + } + free(retstr); + } + return(privkey); +} + +void iguana_priv2pub(uint8_t *pubkey33,char *coinaddr,bits256 privkey,uint8_t addrtype) +{ + char privstr[65],url[512],postdata[1024],*retstr,*pubstr,*addr; cJSON *retjson; + memset(pubkey33,0,33); + coinaddr[0] = 0; + bits256_str(privstr,privkey); + sprintf(url,"%s/?",IGUANA_URL); + sprintf(postdata,"{\"agent\":\"SuperNET\",\"method\":\"priv2pub\",\"privkey\":\"%s\",\"addrtype\":%u}",privstr,addrtype); + if ( (retstr= bitcoind_RPC(0,"SuperNET",url,0,"priv2pub",postdata)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (pubstr= jstr(retjson,"secp256k1")) != 0 && strlen(pubstr) == 66 ) + decode_hex(pubkey33,33,pubstr); + if ( (addr= jstr(retjson,"result")) != 0 && strlen(addr) < 64 ) + strcpy(coinaddr,addr); + free_json(retjson); + } + free(retstr); + } +} + double bittrex_balance(char *base,char *coinaddr) { char *retstr; cJSON *retjson; double balance = 0.; @@ -717,12 +787,12 @@ int main(int argc, const char * argv[]) char *base,*rel,*name,*exchange,*apikey,*apisecret,*blocktrail,*retstr,*baseaddr,*reladdr,*passphrase; double profitmargin,maxexposure,incrratio,start_rel,start_base,minask,maxbid; cJSON *retjson,*loginjson; int32_t i; - LPinit(); if ( argc > 1 && (retjson= cJSON_Parse(argv[1])) != 0 ) { minask = jdouble(retjson,"minask"); maxbid = jdouble(retjson,"maxbid"); profitmargin = jdouble(retjson,"profitmargin"); + LPinit(7779,profitmargin); maxexposure = jdouble(retjson,"maxexposure"); incrratio = jdouble(retjson,"lotratio"); start_base = jdouble(retjson,"start_base"); From 716ff52cdf4fb80134bdda921ef1b40c0df4d972 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 17:40:59 +0300 Subject: [PATCH 0550/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- iguana/exchanges/mm.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b522309c6..65d573ff6 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -172,7 +172,7 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs printf("LP_privkey_init.(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { - if ( (n= cJSON_GetArraySize(array)) > 0 ) + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { values = calloc(n,sizeof(*values)); for (i=0; i %s\n",default_LPnodes[i],retstr); free(retstr); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 26eedc0ab..4e3504fa4 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -159,10 +159,10 @@ char *iguana_listunspent(char *coin,char *coinaddr) return(bitcoind_RPC(0,"",url,0,"listunspent",postdata)); } -char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port) +char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",destip,destport,ipaddr,port); + sprintf(url,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f",destip,destport,ipaddr,port,profitmargin); return(issue_curl(url)); } From 897c9a147c326e149b037cd55765f6931ac3dfae Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 17:50:00 +0300 Subject: [PATCH 0551/2705] Test --- iguana/exchanges/LP_unspents.c | 3 +++ iguana/exchanges/mm.c | 1 + 2 files changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 65d573ff6..659c8b06b 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -29,6 +29,7 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g struct LP_peerinfo *peer; if ( i == sizeof(LP_peerinfos)/sizeof(*LP_peerinfos) ) i = (rand() % (sizeof(LP_peerinfos)/sizeof(*LP_peerinfos))); + printf("_LPaddpeer %s -> i.%d\n",ipaddr,i); peer = &LP_peerinfos[i]; memset(peer,0,sizeof(*peer)); peer->profitmargin = profitmargin; @@ -44,6 +45,7 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port) { char buf[1024],*retstr,*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,j,n; uint16_t argport; double profit; + printf("notify (%s) from (%s)\n",peer->ipaddr,ipaddr); sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); if ( (retstr= issue_curl(buf)) != 0 ) { @@ -94,6 +96,7 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro uint32_t i,j,lastj,iter,ipbits; char checkip[64]; struct LP_peerinfo *peer; ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); + printf("LPaddpeer %s\n",ipaddr); if ( strcmp(checkip,ipaddr) == 0 ) { for (i=0; i Date: Tue, 23 May 2017 17:53:02 +0300 Subject: [PATCH 0552/2705] Test --- crypto777/bitcoind_RPC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index 37ef4be0a..d10e23671 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -153,7 +153,7 @@ try_again: curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback - //curl_easy_setopt(curl_handle,CURLOPT_TIMEOUT, 60L); + curl_easy_setopt(curl_handle,CURLOPT_TIMEOUT, 6L); if ( strncmp(url,"https",5) == 0 ) { curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); From 88c4601f4c47959d370ecaae38f065d4a510a519 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 17:56:22 +0300 Subject: [PATCH 0553/2705] Test --- iguana/exchanges/LP_unspents.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 659c8b06b..b841be5de 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -252,6 +252,7 @@ void LPinit(uint16_t port,double profitmargin) printf("error launching stats rpcloop for port.%u\n",port); exit(-1); } + printf("peers.(%s)\n",LP_peers()); getchar(); } From 668c948dabefde35c71182e41317f519c8221898 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:02:10 +0300 Subject: [PATCH 0554/2705] Test --- iguana/exchanges/LP_unspents.c | 29 ++++++++++++++++++++++++----- iguana/exchanges/mm.c | 2 +- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b841be5de..c161d10a4 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -14,8 +14,8 @@ struct LP_peerinfo { double profitmargin; uint32_t ipbits,gotintro,sentintro; - char ipaddr[64]; - uint16_t port; + char ipaddr[64],notify_ipaddr[64]; + uint16_t port,notify_port; } LP_peerinfos[1024]; int32_t LP_numpeers; @@ -45,7 +45,6 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port) { char buf[1024],*retstr,*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,j,n; uint16_t argport; double profit; - printf("notify (%s) from (%s)\n",peer->ipaddr,ipaddr); sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); if ( (retstr= issue_curl(buf)) != 0 ) { @@ -114,7 +113,12 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro { peer = &LP_peerinfos[j]; if ( peer->sentintro == 0 ) - LP_notify(peer,ipaddr,port); + { + //queue_LP_notify(peer,ipaddr,port); + printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); + peer->notify_port = port; + strcpy(peer->notify_ipaddr,ipaddr); + } lastj = j; } } @@ -253,7 +257,22 @@ void LPinit(uint16_t port,double profitmargin) exit(-1); } printf("peers.(%s)\n",LP_peers()); - getchar(); + while ( 1 ) + { + for (i=0; inotify_ipaddr[0] != 0 && peer->notify_port != 0 ) + { + strcpy(tmp,peer->notify_ipaddr); + argport = peer->notify_port; + peer->notify_port = 0; + memset(peer->notify_ipaddr,0,sizeof(peer->notify_ipaddr)); + LP_notify(peer,tmp,argport); + } + } + sleep(1); + } } char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 5839546a0..9f9789bd5 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -163,7 +163,7 @@ char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,d { char url[512]; sprintf(url,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f",destip,destport,ipaddr,port,profitmargin); - printf("(%s)\n",url); + //printf("(%s)\n",url); return(issue_curl(url)); } From 16d968f2129812bb819c8ff8f2743cd51e3b0290 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:04:22 +0300 Subject: [PATCH 0555/2705] Test --- iguana/exchanges/LP_unspents.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index c161d10a4..2cc99bfd1 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -229,6 +229,11 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs void LPinit(uint16_t port,double profitmargin) { char *retstr,*ipaddr; long filesize,n; int32_t i; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&port) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",port); + exit(-1); + } if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) { if ( (ipaddr= OS_filestr(&filesize,"/tmp/myipaddr")) != 0 && ipaddr[0] != 0 ) @@ -251,11 +256,6 @@ void LPinit(uint16_t port,double profitmargin) } } LP_privkey_init("KMD",60,"test",""); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&port) != 0 ) - { - printf("error launching stats rpcloop for port.%u\n",port); - exit(-1); - } printf("peers.(%s)\n",LP_peers()); while ( 1 ) { From e5c39ce004d0df2f862912c3b52c34587483fafe Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:07:45 +0300 Subject: [PATCH 0556/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 2cc99bfd1..dde97d47f 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -29,7 +29,6 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g struct LP_peerinfo *peer; if ( i == sizeof(LP_peerinfos)/sizeof(*LP_peerinfos) ) i = (rand() % (sizeof(LP_peerinfos)/sizeof(*LP_peerinfos))); - printf("_LPaddpeer %s -> i.%d\n",ipaddr,i); peer = &LP_peerinfos[i]; memset(peer,0,sizeof(*peer)); peer->profitmargin = profitmargin; @@ -40,6 +39,7 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g peer->port = port; if ( i == LP_numpeers ) LP_numpeers++; + printf("_LPaddpeer %s -> i.%d numpeers.%d\n",ipaddr,i,LP_numpeers); } void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port) @@ -48,7 +48,7 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port) sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); if ( (retstr= issue_curl(buf)) != 0 ) { - printf("got (%s) from (%s)\n",retstr,buf); + //printf("got (%s) from (%s)\n",retstr,buf); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) From 04a4076c984af87ead1f22a1d8d82b855ad795ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:13:50 +0300 Subject: [PATCH 0557/2705] Test --- iguana/exchanges/LP_unspents.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index dde97d47f..9fad65484 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -112,13 +112,9 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro if ( j != lastj ) { peer = &LP_peerinfos[j]; - if ( peer->sentintro == 0 ) - { - //queue_LP_notify(peer,ipaddr,port); - printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); - peer->notify_port = port; - strcpy(peer->notify_ipaddr,ipaddr); - } + printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); + peer->notify_port = port; + strcpy(peer->notify_ipaddr,ipaddr); lastj = j; } } @@ -247,9 +243,11 @@ void LPinit(uint16_t port,double profitmargin) free(retstr); for (i=0; i 20 ) + continue; if ( (retstr= issue_LP_intro(default_LPnodes[i],port,ipaddr,port,0.01)) != 0 ) { - printf("(%s) -> %s\n",default_LPnodes[i],retstr); + //printf("(%s) -> %s\n",default_LPnodes[i],retstr); free(retstr); } } From d2759317f2807d200c639be26403fcf685ab316d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:16:47 +0300 Subject: [PATCH 0558/2705] Test --- iguana/exchanges/LP_unspents.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 9fad65484..cd74e3a72 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -92,7 +92,7 @@ char *LP_peers() char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro,double profitmargin) { - uint32_t i,j,lastj,iter,ipbits; char checkip[64]; struct LP_peerinfo *peer; + uint32_t i,j,ipbits; char checkip[64]; struct LP_peerinfo *peer; ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); printf("LPaddpeer %s\n",ipaddr); @@ -103,21 +103,12 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro break; if ( i == LP_numpeers ) { - if ( LP_numpeers > 0 ) + for (j=0; jipaddr,ipaddr); - peer->notify_port = port; - strcpy(peer->notify_ipaddr,ipaddr); - lastj = j; - } - } + peer = &LP_peerinfos[j]; + printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); + peer->notify_port = port; + strcpy(peer->notify_ipaddr,ipaddr); } _LP_addpeer(i,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); } From 9f7b951b508408eb1b750bc63fcbc2daea42192a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:19:31 +0300 Subject: [PATCH 0559/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index cd74e3a72..cd6bc5493 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -234,11 +234,11 @@ void LPinit(uint16_t port,double profitmargin) free(retstr); for (i=0; i 20 ) + if ( (rand() % 100) > 25 ) continue; if ( (retstr= issue_LP_intro(default_LPnodes[i],port,ipaddr,port,0.01)) != 0 ) { - //printf("(%s) -> %s\n",default_LPnodes[i],retstr); + printf("(%s) -> %s\n",default_LPnodes[i],retstr); free(retstr); } } From 7891f029d97ad3264b621b72ba84b4e83899f240 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:22:44 +0300 Subject: [PATCH 0560/2705] Test --- iguana/exchanges/LP_unspents.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index cd6bc5493..18182876c 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -79,6 +79,7 @@ cJSON *LP_peerjson(struct LP_peerinfo *peer) cJSON *item = cJSON_CreateObject(); jaddstr(item,"ipaddr",peer->ipaddr); jaddnum(item,"port",peer->port); + jaddnum(item,"profit",peer->profitmargin); return(item); } From 3ce6b61f5bd7c700b216170a66c1d6ecc5c7c543 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:24:53 +0300 Subject: [PATCH 0561/2705] Test --- iguana/exchanges/LP_unspents.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 18182876c..3462e0d41 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -62,7 +62,10 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port) ipbits = (uint32_t)calc_ipbits(argipaddr); for (j=0; j Date: Tue, 23 May 2017 18:27:45 +0300 Subject: [PATCH 0562/2705] Test --- iguana/exchanges/LP_unspents.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 3462e0d41..81faeacc3 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -42,11 +42,11 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g printf("_LPaddpeer %s -> i.%d numpeers.%d\n",ipaddr,i,LP_numpeers); } -void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port) +void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) { - char buf[1024],*retstr,*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,j,n; uint16_t argport; double profit; + char buf[1024],*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,j,n; uint16_t argport; double profit; sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); - if ( (retstr= issue_curl(buf)) != 0 ) + if ( retstr != 0 || (retstr= issue_curl(buf)) != 0 ) { //printf("got (%s) from (%s)\n",retstr,buf); if ( (array= cJSON_Parse(retstr)) != 0 ) @@ -243,7 +243,8 @@ void LPinit(uint16_t port,double profitmargin) if ( (retstr= issue_LP_intro(default_LPnodes[i],port,ipaddr,port,0.01)) != 0 ) { printf("(%s) -> %s\n",default_LPnodes[i],retstr); - free(retstr); + LP_notify(&LP_peerinfos[0],ipaddr,port,retstr); + //free(retstr); } } } @@ -261,7 +262,7 @@ void LPinit(uint16_t port,double profitmargin) argport = peer->notify_port; peer->notify_port = 0; memset(peer->notify_ipaddr,0,sizeof(peer->notify_ipaddr)); - LP_notify(peer,tmp,argport); + LP_notify(peer,tmp,argport,0); } } sleep(1); From 61bd7fb3b1c26d6485b0aa7c0c28a6b538927f14 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:38:08 +0300 Subject: [PATCH 0563/2705] Test --- iguana/exchanges/LP_unspents.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 81faeacc3..223fa7f93 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -63,7 +63,7 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) for (j=0; jnotify_port = port; strcpy(peer->notify_ipaddr,ipaddr); } - _LP_addpeer(i,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); } + else if ( LP_numpeers > 0 ) + { + j = rand() % LP_numpeers; + peer = &LP_peerinfos[j]; + printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); + peer->notify_port = port; + strcpy(peer->notify_ipaddr,ipaddr); + } + _LP_addpeer(i,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); } return(LP_peers()); } From 808333301fd7818412e6047a52b9769049da8ba4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:43:00 +0300 Subject: [PATCH 0564/2705] Test --- iguana/exchanges/LP_unspents.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 223fa7f93..b28ce8f5f 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -227,7 +227,7 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs void LPinit(uint16_t port,double profitmargin) { - char *retstr,*ipaddr; long filesize,n; int32_t i; + char *retstr,*ipaddr,tmp[64]; long filesize,n; int32_t i; uint16_t argport; struct LP_peerinfo *peer; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&port) != 0 ) { printf("error launching stats rpcloop for port.%u\n",port); @@ -263,7 +263,7 @@ void LPinit(uint16_t port,double profitmargin) { for (i=0; inotify_ipaddr[0] != 0 && peer->notify_port != 0 ) { strcpy(tmp,peer->notify_ipaddr); @@ -273,7 +273,20 @@ void LPinit(uint16_t port,double profitmargin) LP_notify(peer,tmp,argport,0); } } - sleep(1); + if ( LP_numpeers > 0 ) + { + i = rand() % LP_numpeers; + if ( i > 0 ) + { + peer = &LP_peerinfos[i]; + if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port)) != 0 ) + { + LP_notify(&LP_peerinfos[0],peer->ipaddr,peer->port,retstr); + free(retstr); + } + } + } + sleep(10); } } From ad4fafd6ee15287a776e23d6fafd8aa64e1ffd49 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:43:30 +0300 Subject: [PATCH 0565/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b28ce8f5f..8b03a70f3 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -282,7 +282,7 @@ void LPinit(uint16_t port,double profitmargin) if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port)) != 0 ) { LP_notify(&LP_peerinfos[0],peer->ipaddr,peer->port,retstr); - free(retstr); + //free(retstr); } } } From 9906517f47a334ebdb66c6287cee862c719404e7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:52:04 +0300 Subject: [PATCH 0566/2705] Test --- iguana/exchanges/LP_unspents.c | 6 +++--- iguana/exchanges/mm.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 8b03a70f3..ed034aeb0 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -279,7 +279,7 @@ void LPinit(uint16_t port,double profitmargin) if ( i > 0 ) { peer = &LP_peerinfos[i]; - if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port)) != 0 ) + if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) { LP_notify(&LP_peerinfos[0],peer->ipaddr,peer->port,retstr); //free(retstr); @@ -302,8 +302,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (profitmargin= jdouble(argjson,"profit")) != 0. ) retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,profitmargin); } - else if ( strcmp(method,"getpeers") == 0 ) - retstr = LP_peers(); + else if ( strcmp(method,"getpeers") == 0 && (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (profitmargin= jdouble(argjson,"profit")) != 0. ) + retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,profitmargin); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 && (dest= jstr(argjson,"dest")) != 0 ) { //retstr = LP_getutxos(coin,dest); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 9f9789bd5..e40509cd2 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -167,10 +167,10 @@ char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,d return(issue_curl(url)); } -char *issue_LP_getpeers(char *destip,uint16_t destport) +char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/getpeers",destip,destport); + sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f",destip,destport,ipaddr,port,profitmargin); return(issue_curl(url)); } From 50912375359a2b91c55eb3d05a2743480d7b351e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 18:58:23 +0300 Subject: [PATCH 0567/2705] Test --- iguana/exchanges/LP_unspents.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index ed034aeb0..9a475a6af 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -101,7 +101,7 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) { - printf("LPaddpeer %s\n",ipaddr); + //printf("LPaddpeer %s\n",ipaddr); for (i=0; iipaddr,ipaddr); + //printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); peer->notify_port = port; strcpy(peer->notify_ipaddr,ipaddr); } @@ -119,7 +119,7 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro { j = rand() % LP_numpeers; peer = &LP_peerinfos[j]; - printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); + //printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); peer->notify_port = port; strcpy(peer->notify_ipaddr,ipaddr); } @@ -241,7 +241,7 @@ void LPinit(uint16_t port,double profitmargin) if ( ipaddr[n-1] == '\n' ) ipaddr[--n] = 0; retstr = LP_addpeer(ipaddr,port,0,(uint32_t)time(NULL),profitmargin); - printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); + //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); if ( retstr != 0 ) free(retstr); for (i=0; i %s\n",default_LPnodes[i],retstr); + //printf("(%s) -> %s\n",default_LPnodes[i],retstr); LP_notify(&LP_peerinfos[0],ipaddr,port,retstr); //free(retstr); } @@ -258,7 +258,7 @@ void LPinit(uint16_t port,double profitmargin) } } LP_privkey_init("KMD",60,"test",""); - printf("peers.(%s)\n",LP_peers()); + //printf("peers.(%s)\n",LP_peers()); while ( 1 ) { for (i=0; i Date: Tue, 23 May 2017 19:01:49 +0300 Subject: [PATCH 0568/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 9a475a6af..ff080820a 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -114,6 +114,7 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro peer->notify_port = port; strcpy(peer->notify_ipaddr,ipaddr); } + _LP_addpeer(i,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); } else if ( LP_numpeers > 0 ) { @@ -123,7 +124,6 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro peer->notify_port = port; strcpy(peer->notify_ipaddr,ipaddr); } - _LP_addpeer(i,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); } return(LP_peers()); } From 29c79699e7ee385f52d7bb5de743a394c2d81d05 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 19:07:11 +0300 Subject: [PATCH 0569/2705] Test --- iguana/exchanges/LP_unspents.c | 6 ++++++ iguana/exchanges/stats.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index ff080820a..513fe7924 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -103,8 +103,14 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro { //printf("LPaddpeer %s\n",ipaddr); for (i=0; i Date: Tue, 23 May 2017 19:31:21 +0300 Subject: [PATCH 0570/2705] Test --- crypto777/bitcoind_RPC.c | 2 +- iguana/dpow/dpow_network.c | 5 ++++- iguana/exchanges/LP_unspents.c | 2 +- iguana/exchanges/mm.c | 2 +- iguana/iguana777.h | 2 +- iguana/iguana_notary.c | 1 + 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index d10e23671..db54e4317 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -153,7 +153,7 @@ try_again: curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback - curl_easy_setopt(curl_handle,CURLOPT_TIMEOUT, 6L); + //curl_easy_setopt(curl_handle,CURLOPT_TIMEOUT, 60L); // causes problems with iguana timeouts if ( strncmp(url,"https",5) == 0 ) { curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 38789f35c..9eafc39be 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -1183,7 +1183,10 @@ char *_dex_listunspentarg(struct supernet_info *myinfo,char *symbol,char *addres char *_dex_listunspent(struct supernet_info *myinfo,char *symbol,char *address) { - return(_dex_listunspentarg(myinfo,symbol,address,'u')); // 'U' old variant + char *retstr; + retstr = _dex_listunspentarg(myinfo,symbol,address,'u'); // 'U' old variant + //printf("_dex_listunspent.(%s)\n",retstr); + return(retstr); } char *_dex_listunspent2(struct supernet_info *myinfo,char *symbol,char *address) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 513fe7924..143c1bf06 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -292,7 +292,7 @@ void LPinit(uint16_t port,double profitmargin) } } } - sleep(10); + sleep(60); } } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index e40509cd2..daeeefe26 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -181,7 +181,7 @@ char *DEX_listunspent(char *coin,char *coinaddr) { char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); - sprintf(postdata,"{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"%s\",\"symbol\":\"%s\"}",coinaddr,coin); + sprintf(postdata,"{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"%s\",\"symbol\":\"%s\",\"timeout\":60000}",coinaddr,coin); return(bitcoind_RPC(0,"dex",url,0,"listunspent",postdata)); } diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 778ab3806..74412e6f0 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -167,7 +167,7 @@ struct supernet_info #ifdef NOTARY_TESTMODE char dexseed_ipaddrs[1][64]; #else - char dexseed_ipaddrs[8][64]; + char dexseed_ipaddrs[4][64]; #endif uint32_t dexipbits[128]; int32_t numdexipbits; portable_mutex_t dexmutex; // compatibility diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index c70a4c408..e7c02acda 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -679,6 +679,7 @@ TWO_STRINGS(dex,listunspent,symbol,address) } else if ( coin != 0 && coin->FULLNODE < 0 ) return(jprint(dpow_listunspent(myinfo,coin,address),1)); + //printf("call _dex_listunspent\n"); return(_dex_listunspent(myinfo,symbol,address)); } From 3e94d30bc4986e190f2e3bfddd1bce4addd7f4c0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 19:34:09 +0300 Subject: [PATCH 0571/2705] Test --- iguana/exchanges/LP_unspents.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 143c1bf06..a5811d6bb 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -13,7 +13,7 @@ char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.25 struct LP_peerinfo { double profitmargin; - uint32_t ipbits,gotintro,sentintro; + uint32_t ipbits,gotintro,sentintro,errortime,errors; char ipaddr[64],notify_ipaddr[64]; uint16_t port,notify_port; } LP_peerinfos[1024]; @@ -282,14 +282,14 @@ void LPinit(uint16_t port,double profitmargin) if ( LP_numpeers > 0 ) { i = rand() % LP_numpeers; - if ( i > 0 ) + if ( i > 0 && (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) { peer = &LP_peerinfos[i]; if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) { LP_notify(&LP_peerinfos[0],peer->ipaddr,peer->port,retstr); //free(retstr); - } + } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } } sleep(60); From 81b488d6bc876c1162bbef84850ab6874be481af Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 19:50:38 +0300 Subject: [PATCH 0572/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index a5811d6bb..83305a0d7 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -282,9 +282,9 @@ void LPinit(uint16_t port,double profitmargin) if ( LP_numpeers > 0 ) { i = rand() % LP_numpeers; + peer = &LP_peerinfos[i]; if ( i > 0 && (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) { - peer = &LP_peerinfos[i]; if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) { LP_notify(&LP_peerinfos[0],peer->ipaddr,peer->port,retstr); From 6b06854be2aedb8de2618e34be74f824b21b782c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 20:25:57 +0300 Subject: [PATCH 0573/2705] Test --- iguana/exchanges/LP_unspents.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 83305a0d7..f61445334 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -74,7 +74,7 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) free_json(array); } free(retstr); - } + } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } cJSON *LP_peerjson(struct LP_peerinfo *peer) @@ -276,7 +276,8 @@ void LPinit(uint16_t port,double profitmargin) argport = peer->notify_port; peer->notify_port = 0; memset(peer->notify_ipaddr,0,sizeof(peer->notify_ipaddr)); - LP_notify(peer,tmp,argport,0); + if ( (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) + LP_notify(peer,tmp,argport,0); } } if ( LP_numpeers > 0 ) From 29c1cef46363e9b34bdcf28fe38a60af1a9e86f9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 20:26:37 +0300 Subject: [PATCH 0574/2705] Test --- iguana/exchanges/LP_unspents.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index f61445334..23af3d5d5 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -90,7 +90,8 @@ char *LP_peers() { int32_t i; cJSON *peersjson = cJSON_CreateArray(); for (i=0; i Date: Tue, 23 May 2017 20:47:35 +0300 Subject: [PATCH 0575/2705] Test --- iguana/exchanges/LP_unspents.c | 61 +++++++++++++++++----------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 23af3d5d5..e1edaf6a1 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -19,9 +19,21 @@ struct LP_peerinfo } LP_peerinfos[1024]; int32_t LP_numpeers; -void LP_addutxo(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 deposittxid,int32_t depositvout,uint64_t depositsatoshis,char *spendscript,char *coinaddr) +void LP_addutxo(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 deposittxid,int32_t depositvout,uint64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port) { - printf("LP_addutxo.(%.8f %.8f)\n",dstr(satoshis),dstr(depositsatoshis)); + printf("%s:%u LP_addutxo.(%.8f %.8f)\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis)); +} + +struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) +{ + int32_t j; + for (j=0; jprofitmargin = profitmargin; @@ -37,14 +50,12 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g peer->sentintro = sentintro; strcpy(peer->ipaddr,ipaddr); peer->port = port; - if ( i == LP_numpeers ) - LP_numpeers++; printf("_LPaddpeer %s -> i.%d numpeers.%d\n",ipaddr,i,LP_numpeers); } void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) { - char buf[1024],*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,j,n; uint16_t argport; double profit; + char buf[1024],*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,n; uint16_t argport; double profit; sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); if ( retstr != 0 || (retstr= issue_curl(buf)) != 0 ) { @@ -60,14 +71,8 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) { argport = juint(item,"port"); ipbits = (uint32_t)calc_ipbits(argipaddr); - for (j=0; jgotintro = gotintro; + if ( peer->errors == 0 ) { - if ( gotintro != 0 ) - LP_peerinfos[i].gotintro = gotintro; - break; + j = rand() % LP_numpeers; + peer = &LP_peerinfos[j]; + //printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); + peer->notify_port = port; + strcpy(peer->notify_ipaddr,ipaddr); } } - if ( i == LP_numpeers ) + else { for (j=0; jnotify_port = port; strcpy(peer->notify_ipaddr,ipaddr); } - _LP_addpeer(i,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); - } - else if ( LP_numpeers > 0 ) - { - j = rand() % LP_numpeers; - peer = &LP_peerinfos[j]; - //printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); - peer->notify_port = port; - strcpy(peer->notify_ipaddr,ipaddr); + _LP_addpeer(LP_numpeers,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); } } return(LP_peers()); @@ -218,7 +219,7 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs { value = values[i]; values[i] = 0, used++; - LP_addutxo(coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr); + LP_addutxo(coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port); total += value; } } From 8b2f8592e60423664c15b8698a35a6b6f7f370e6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 20:57:34 +0300 Subject: [PATCH 0576/2705] Test --- iguana/exchanges/LP_unspents.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index e1edaf6a1..11ed28453 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -282,7 +282,7 @@ void LPinit(uint16_t port,double profitmargin) LP_notify(peer,tmp,argport,0); } } - if ( LP_numpeers > 0 ) + if ( (rand() % 10) == 0 && LP_numpeers > 0 ) { i = rand() % LP_numpeers; peer = &LP_peerinfos[i]; @@ -295,17 +295,26 @@ void LPinit(uint16_t port,double profitmargin) } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } } - sleep(60); + sleep(6); } } char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { - char *method,*ipaddr,*coin,*dest,*retstr = 0; uint16_t argport; double profitmargin; + char *method,*ipaddr,*coin,*dest,*retstr = 0; uint16_t argport; double profitmargin; int32_t otherpeers; struct LP_peerinfo *peer; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); else { + if ( (otherpeers= jint(argjson,"numpeers")) > 0 && otherpeers != LP_numpeers ) + { + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) + { + printf("peer.(%s:%u) numpeers.%d != LP_numpeers.%d\n",ipaddr,argport,otherpeers,LP_numpeers); + peer->notify_port = port; + strcpy(peer->notify_ipaddr,ipaddr); + } + } if ( strcmp(method,"intro") == 0 ) { if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (profitmargin= jdouble(argjson,"profit")) != 0. ) From dcfbe40679e1f2c3c5674a201c5e8617841af207 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 21:00:53 +0300 Subject: [PATCH 0577/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- iguana/exchanges/mm.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 11ed28453..469dc5e37 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -256,7 +256,7 @@ void LPinit(uint16_t port,double profitmargin) { if ( (rand() % 100) > 25 ) continue; - if ( (retstr= issue_LP_intro(default_LPnodes[i],port,ipaddr,port,0.01)) != 0 ) + if ( (retstr= issue_LP_intro(default_LPnodes[i],port,ipaddr,port,profitmargin,LP_numpeers)) != 0 ) { //printf("(%s) -> %s\n",default_LPnodes[i],retstr); LP_notify(&LP_peerinfos[0],ipaddr,port,retstr); @@ -288,7 +288,7 @@ void LPinit(uint16_t port,double profitmargin) peer = &LP_peerinfos[i]; if ( i > 0 && (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) { - if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) + if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) { LP_notify(&LP_peerinfos[0],peer->ipaddr,peer->port,retstr); //free(retstr); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index daeeefe26..a93d82b02 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -159,18 +159,18 @@ char *iguana_listunspent(char *coin,char *coinaddr) return(bitcoind_RPC(0,"",url,0,"listunspent",postdata)); } -char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin) +char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f",destip,destport,ipaddr,port,profitmargin); + sprintf(url,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",destip,destport,ipaddr,port,profitmargin,numpeers); //printf("(%s)\n",url); return(issue_curl(url)); } -char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin) +char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f",destip,destport,ipaddr,port,profitmargin); + sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",destip,destport,ipaddr,port,profitmargin,numpeers); return(issue_curl(url)); } From 0ce78e50ae279d3d9a84066967354fe7ed21164c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 21:09:31 +0300 Subject: [PATCH 0578/2705] Test --- iguana/exchanges/LP_unspents.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 469dc5e37..99628c42d 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -13,7 +13,7 @@ char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.25 struct LP_peerinfo { double profitmargin; - uint32_t ipbits,gotintro,sentintro,errortime,errors; + uint32_t ipbits,gotintro,sentintro,errortime,errors,numpeers; char ipaddr[64],notify_ipaddr[64]; uint16_t port,notify_port; } LP_peerinfos[1024]; @@ -64,6 +64,8 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { + if ( n != peer->numpeers ) + peer->numpeers = n; for (i=0; inumpeers != LP_numpeers && (peer->notify_ipaddr[0] == 0 || peer->notify_port == 0) ) + { + strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); + peer->notify_port = LP_peerinfos[0].port; + printf("LP_numpeers.%d != (%s).%d\n",LP_numpeers,peer->ipaddr,peer->numpeers); + } if ( peer->notify_ipaddr[0] != 0 && peer->notify_port != 0 ) { strcpy(tmp,peer->notify_ipaddr); From 30d1d2e9e61d7a333c3025e41b508be007cd2643 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 21:12:37 +0300 Subject: [PATCH 0579/2705] Test --- iguana/exchanges/LP_unspents.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 99628c42d..b76c580db 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -271,14 +271,14 @@ void LPinit(uint16_t port,double profitmargin) //printf("peers.(%s)\n",LP_peers()); while ( 1 ) { - for (i=0; inumpeers != LP_numpeers && (peer->notify_ipaddr[0] == 0 || peer->notify_port == 0) ) { strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); peer->notify_port = LP_peerinfos[0].port; - printf("LP_numpeers.%d != (%s).%d\n",LP_numpeers,peer->ipaddr,peer->numpeers); + printf("LP_numpeers.%d != [%d] (%s).%d\n",LP_numpeers,i,peer->ipaddr,peer->numpeers); } if ( peer->notify_ipaddr[0] != 0 && peer->notify_port != 0 ) { @@ -286,7 +286,7 @@ void LPinit(uint16_t port,double profitmargin) argport = peer->notify_port; peer->notify_port = 0; memset(peer->notify_ipaddr,0,sizeof(peer->notify_ipaddr)); - if ( (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) + //if ( (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) LP_notify(peer,tmp,argport,0); } } @@ -298,7 +298,7 @@ void LPinit(uint16_t port,double profitmargin) { if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) { - LP_notify(&LP_peerinfos[0],peer->ipaddr,peer->port,retstr); + LP_notify(peer,peer->ipaddr,peer->port,retstr); //free(retstr); } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } From cadaf55ede3ec232bcf4b13d57eb5fc0ca23f322 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 21:30:04 +0300 Subject: [PATCH 0580/2705] Test --- iguana/exchanges/LP_unspents.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b76c580db..1d447b9b7 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -59,13 +59,12 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); if ( retstr != 0 || (retstr= issue_curl(buf)) != 0 ) { - //printf("got (%s) from (%s)\n",retstr,buf); + printf("got (%s) from (%s)\n",retstr,buf); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { - if ( n != peer->numpeers ) - peer->numpeers = n; + peer->numpeers = n; for (i=0; i 0 && otherpeers != LP_numpeers ) + printf("got method.(%s)\n",method); + if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) { if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) { - printf("peer.(%s:%u) numpeers.%d != LP_numpeers.%d\n",ipaddr,argport,otherpeers,LP_numpeers); - peer->notify_port = port; - strcpy(peer->notify_ipaddr,ipaddr); + printf("peer.(%s:%u) numpeers.%d != LP_numpeers.%d (%s)\n",ipaddr,argport,otherpeers,LP_numpeers,jprint(argjson,0)); + peer->numpeers = otherpeers; + if ( otherpeers != LP_numpeers ) + { + peer->notify_port = port; + strcpy(peer->notify_ipaddr,ipaddr); + } } } if ( strcmp(method,"intro") == 0 ) From 06d872dad3614f93c0f473120060147a71bfa4c9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 21:36:52 +0300 Subject: [PATCH 0581/2705] Test --- iguana/exchanges/LP_unspents.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 1d447b9b7..b5bc910cb 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -250,6 +250,7 @@ void LPinit(uint16_t port,double profitmargin) if ( ipaddr[n-1] == '\n' ) ipaddr[--n] = 0; retstr = LP_addpeer(ipaddr,port,0,(uint32_t)time(NULL),profitmargin); + LP_peerinfos[0].profitmargin = profitmargin; //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); if ( retstr != 0 ) free(retstr); From 17a7943d9ebda48805b6c61b52d5856a3c6ac4d6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 21:40:13 +0300 Subject: [PATCH 0582/2705] Test --- iguana/exchanges/LP_unspents.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b5bc910cb..29eeb3634 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -237,6 +237,11 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs void LPinit(uint16_t port,double profitmargin) { char *retstr,*ipaddr,tmp[64]; long filesize,n; int32_t i; uint16_t argport; struct LP_peerinfo *peer; + if ( profitmargin == 0. ) + { + profitmargin = 0.01; + printf("default profit margin %f\n",profitmargin); + } if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&port) != 0 ) { printf("error launching stats rpcloop for port.%u\n",port); From 0d79c6de526d320e7105a557917bd4aa424cf146 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 21:43:46 +0300 Subject: [PATCH 0583/2705] Test --- iguana/exchanges/LP_unspents.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 29eeb3634..b6680ba94 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -68,12 +68,12 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) for (i=0; i 0. ) + if ( (argipaddr= jstr(item,"ipaddr")) != 0 && jobj(item,"port") != 0 ) { argport = juint(item,"port"); ipbits = (uint32_t)calc_ipbits(argipaddr); if ( LP_peerfind(ipbits,argport) == 0 ) - _LP_addpeer(LP_numpeers,ipbits,argipaddr,argport,0,0,profit); + _LP_addpeer(LP_numpeers,ipbits,argipaddr,argport,0,0,jdouble(item,"profit")); } } } @@ -111,6 +111,8 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro //printf("LPaddpeer %s\n",ipaddr); if ( (peer= LP_peerfind(ipbits,port)) != 0 ) { + if ( peer->profitmargin == 0. ) + peer->profitmargin = profitmargin; if ( gotintro != 0 ) peer->gotintro = gotintro; if ( peer->errors == 0 ) @@ -335,11 +337,11 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) } if ( strcmp(method,"intro") == 0 ) { - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (profitmargin= jdouble(argjson,"profit")) != 0. ) - retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,profitmargin); + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,jdouble(argjson,"profit")); } - else if ( strcmp(method,"getpeers") == 0 && (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (profitmargin= jdouble(argjson,"profit")) != 0. ) - retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,profitmargin); + else if ( strcmp(method,"getpeers") == 0 && (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,jdouble(argjson,"profit")); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 && (dest= jstr(argjson,"dest")) != 0 ) { //retstr = LP_getutxos(coin,dest); From 84c8ef0d62533ed9efae77ec5ab9e7c61b7d3e24 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 21:58:33 +0300 Subject: [PATCH 0584/2705] Test --- iguana/exchanges/LP_unspents.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b6680ba94..486670754 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -55,11 +55,11 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) { - char buf[1024],*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,n; uint16_t argport; double profit; + char buf[1024],*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,n; uint16_t argport; sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); if ( retstr != 0 || (retstr= issue_curl(buf)) != 0 ) { - printf("got (%s) from (%s)\n",retstr,buf); + //printf("got (%s) from (%s)\n",retstr,buf); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -316,22 +316,26 @@ void LPinit(uint16_t port,double profitmargin) char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { - char *method,*ipaddr,*coin,*dest,*retstr = 0; uint16_t argport; double profitmargin; int32_t otherpeers; struct LP_peerinfo *peer; + char *method,*ipaddr,*coin,*dest,*retstr = 0; uint16_t argport; int32_t otherpeers; struct LP_peerinfo *peer; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); else { - printf("got method.(%s)\n",method); + printf("got (%s)\n",jprint(argjson,0)); if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) { - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { printf("peer.(%s:%u) numpeers.%d != LP_numpeers.%d (%s)\n",ipaddr,argport,otherpeers,LP_numpeers,jprint(argjson,0)); - peer->numpeers = otherpeers; - if ( otherpeers != LP_numpeers ) + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) { - peer->notify_port = port; - strcpy(peer->notify_ipaddr,ipaddr); + printf("found peer.(%s:%u)\n",ipaddr,argport); + peer->numpeers = otherpeers; + if ( otherpeers != LP_numpeers ) + { + peer->notify_port = port; + strcpy(peer->notify_ipaddr,ipaddr); + } } } } From 45e5225c3b37892aad00cd5cc22eb512bc954045 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 22:02:04 +0300 Subject: [PATCH 0585/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- iguana/exchanges/mm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 486670754..1bbee5710 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -268,7 +268,7 @@ void LPinit(uint16_t port,double profitmargin) if ( (retstr= issue_LP_intro(default_LPnodes[i],port,ipaddr,port,profitmargin,LP_numpeers)) != 0 ) { //printf("(%s) -> %s\n",default_LPnodes[i],retstr); - LP_notify(&LP_peerinfos[0],ipaddr,port,retstr); + LP_notify(&LP_peerinfos[i],ipaddr,port,retstr); //free(retstr); } } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index a93d82b02..f53d09da1 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -163,7 +163,7 @@ char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,d { char url[512]; sprintf(url,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",destip,destport,ipaddr,port,profitmargin,numpeers); - //printf("(%s)\n",url); + printf("(%s)\n",url); return(issue_curl(url)); } From 9cde56351e63a18f5f4045120a5cdee3ff4dc54e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 22:29:04 +0300 Subject: [PATCH 0586/2705] Test --- iguana/exchanges/LP_unspents.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 1bbee5710..211858c67 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -12,8 +12,8 @@ char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.25 struct LP_peerinfo { - double profitmargin; - uint32_t ipbits,gotintro,sentintro,errortime,errors,numpeers; + double profitmargin,notify_margin; + uint32_t ipbits,gotintro,sentintro,errortime,errors,numpeers,notify_numpeers; char ipaddr[64],notify_ipaddr[64]; uint16_t port,notify_port; } LP_peerinfos[1024]; @@ -53,10 +53,10 @@ void _LP_addpeer(int32_t i,uint32_t ipbits,char *ipaddr,uint16_t port,uint32_t g printf("_LPaddpeer %s -> i.%d numpeers.%d\n",ipaddr,i,LP_numpeers); } -void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,char *retstr) +void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,double profit,int32_t numpeers,char *retstr) { char buf[1024],*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,n; uint16_t argport; - sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u",peer->ipaddr,peer->port,ipaddr,port); + sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",peer->ipaddr,peer->port,ipaddr,port,profit,numpeers); if ( retstr != 0 || (retstr= issue_curl(buf)) != 0 ) { //printf("got (%s) from (%s)\n",retstr,buf); @@ -120,8 +120,10 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro j = rand() % LP_numpeers; peer = &LP_peerinfos[j]; //printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); - peer->notify_port = port; - strcpy(peer->notify_ipaddr,ipaddr); + peer->notify_margin = LP_peerinfos[0].profitmargin; + peer->notify_numpeers = LP_numpeers; + peer->notify_port = LP_peerinfos[0].port; + strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); } } else @@ -130,6 +132,8 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro { peer = &LP_peerinfos[j]; //printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); + peer->notify_margin = LP_peerinfos[0].profitmargin; + peer->notify_numpeers = LP_numpeers; peer->notify_port = port; strcpy(peer->notify_ipaddr,ipaddr); } @@ -238,7 +242,7 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs void LPinit(uint16_t port,double profitmargin) { - char *retstr,*ipaddr,tmp[64]; long filesize,n; int32_t i; uint16_t argport; struct LP_peerinfo *peer; + char *retstr,*ipaddr,tmp[64]; long filesize,n; int32_t i,notifynumpeers; uint16_t argport; struct LP_peerinfo *peer; double notifymargin; if ( profitmargin == 0. ) { profitmargin = 0.01; @@ -268,7 +272,7 @@ void LPinit(uint16_t port,double profitmargin) if ( (retstr= issue_LP_intro(default_LPnodes[i],port,ipaddr,port,profitmargin,LP_numpeers)) != 0 ) { //printf("(%s) -> %s\n",default_LPnodes[i],retstr); - LP_notify(&LP_peerinfos[i],ipaddr,port,retstr); + LP_notify(&LP_peerinfos[i],ipaddr,port,0,0,retstr); //free(retstr); } } @@ -285,16 +289,22 @@ void LPinit(uint16_t port,double profitmargin) { strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); peer->notify_port = LP_peerinfos[0].port; + peer->notify_margin = LP_peerinfos[0].profitmargin; + peer->notify_numpeers = LP_numpeers; printf("LP_numpeers.%d != [%d] (%s).%d\n",LP_numpeers,i,peer->ipaddr,peer->numpeers); } if ( peer->notify_ipaddr[0] != 0 && peer->notify_port != 0 ) { strcpy(tmp,peer->notify_ipaddr); argport = peer->notify_port; + notifymargin = peer->notify_margin; + notifynumpeers = peer->notify_numpeers; peer->notify_port = 0; + peer->notify_margin = 0; + peer->notify_numpeers = 0; memset(peer->notify_ipaddr,0,sizeof(peer->notify_ipaddr)); //if ( (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) - LP_notify(peer,tmp,argport,0); + LP_notify(peer,tmp,argport,notifymargin,notifynumpeers,0); } } if ( (rand() % 10) == 0 && LP_numpeers > 0 ) @@ -305,7 +315,7 @@ void LPinit(uint16_t port,double profitmargin) { if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) { - LP_notify(peer,peer->ipaddr,peer->port,retstr); + LP_notify(peer,peer->ipaddr,peer->port,0,0,retstr); //free(retstr); } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } @@ -334,6 +344,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) if ( otherpeers != LP_numpeers ) { peer->notify_port = port; + peer->notify_numpeers = otherpeers; + peer->notify_margin = jdouble(argjson,"profit"); strcpy(peer->notify_ipaddr,ipaddr); } } From a6691f9f1d40cde0424f6de5afc0b05cc9d57265 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 22:32:45 +0300 Subject: [PATCH 0587/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 211858c67..2b8e94101 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -115,7 +115,7 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro peer->profitmargin = profitmargin; if ( gotintro != 0 ) peer->gotintro = gotintro; - if ( peer->errors == 0 ) + //if ( peer->errors == 0 ) { j = rand() % LP_numpeers; peer = &LP_peerinfos[j]; @@ -311,7 +311,7 @@ void LPinit(uint16_t port,double profitmargin) { i = rand() % LP_numpeers; peer = &LP_peerinfos[i]; - if ( i > 0 && (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) + if ( i > 0 )//&& (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) { if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) { From 83b502f5d6cbd992904cf8f2f0db331a3677c0a8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 22:37:03 +0300 Subject: [PATCH 0588/2705] Test --- iguana/exchanges/LP_unspents.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 2b8e94101..6c2079abc 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -343,10 +343,10 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) peer->numpeers = otherpeers; if ( otherpeers != LP_numpeers ) { - peer->notify_port = port; - peer->notify_numpeers = otherpeers; - peer->notify_margin = jdouble(argjson,"profit"); - strcpy(peer->notify_ipaddr,ipaddr); + peer->notify_port = LP_peerinfos[0].port; + peer->notify_numpeers = LP_numpeers; + peer->notify_margin = LP_peerinfos[0].profitmargin; + strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); } } } From 15358290ef700c0170ebaadd6dff7c590ab1b477 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 22:43:09 +0300 Subject: [PATCH 0589/2705] Test --- iguana/exchanges/LP_unspents.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 6c2079abc..1d2b2849f 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -305,6 +305,11 @@ void LPinit(uint16_t port,double profitmargin) memset(peer->notify_ipaddr,0,sizeof(peer->notify_ipaddr)); //if ( (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) LP_notify(peer,tmp,argport,notifymargin,notifynumpeers,0); + if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) + { + LP_notify(peer,peer->ipaddr,peer->port,0,0,retstr); + //free(retstr); + } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } } if ( (rand() % 10) == 0 && LP_numpeers > 0 ) From ea04dfb366688c09760118a9ffc6d6465c493ed6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 22:48:16 +0300 Subject: [PATCH 0590/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 1d2b2849f..ae4f78c8a 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -307,6 +307,7 @@ void LPinit(uint16_t port,double profitmargin) LP_notify(peer,tmp,argport,notifymargin,notifynumpeers,0); if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) { + printf("fetchpeers.(%s)\n",retstr); LP_notify(peer,peer->ipaddr,peer->port,0,0,retstr); //free(retstr); } else peer->errors++, peer->errortime = (uint32_t)time(NULL); @@ -341,13 +342,12 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { - printf("peer.(%s:%u) numpeers.%d != LP_numpeers.%d (%s)\n",ipaddr,argport,otherpeers,LP_numpeers,jprint(argjson,0)); if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) { - printf("found peer.(%s:%u)\n",ipaddr,argport); peer->numpeers = otherpeers; if ( otherpeers != LP_numpeers ) { + printf("peer.(%s:%u) numpeers.%d != LP_numpeers.%d (%s)\n",ipaddr,argport,otherpeers,LP_numpeers,jprint(argjson,0)); peer->notify_port = LP_peerinfos[0].port; peer->notify_numpeers = LP_numpeers; peer->notify_margin = LP_peerinfos[0].profitmargin; From 2a3640248ab239c7f08d729075f62de345a2c4e2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 22:52:36 +0300 Subject: [PATCH 0591/2705] Test --- iguana/exchanges/LP_unspents.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index ae4f78c8a..300920dc8 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -352,6 +352,12 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) peer->notify_numpeers = LP_numpeers; peer->notify_margin = LP_peerinfos[0].profitmargin; strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); + if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) + { + printf("2fetchpeers.(%s)\n",retstr); + LP_notify(peer,peer->ipaddr,peer->port,0,0,retstr); + //free(retstr); + } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } } } From 123d61ed737ccb273bb9a3d0ac948aa9f6e8d7e2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 22:57:33 +0300 Subject: [PATCH 0592/2705] Test --- iguana/exchanges/LP_unspents.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 300920dc8..b43e4c17f 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -59,7 +59,7 @@ void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,double profit sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",peer->ipaddr,peer->port,ipaddr,port,profit,numpeers); if ( retstr != 0 || (retstr= issue_curl(buf)) != 0 ) { - //printf("got (%s) from (%s)\n",retstr,buf); + printf("got (%s) from (%s)\n",retstr,buf); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -305,12 +305,6 @@ void LPinit(uint16_t port,double profitmargin) memset(peer->notify_ipaddr,0,sizeof(peer->notify_ipaddr)); //if ( (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) LP_notify(peer,tmp,argport,notifymargin,notifynumpeers,0); - if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) - { - printf("fetchpeers.(%s)\n",retstr); - LP_notify(peer,peer->ipaddr,peer->port,0,0,retstr); - //free(retstr); - } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } } if ( (rand() % 10) == 0 && LP_numpeers > 0 ) @@ -352,12 +346,6 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) peer->notify_numpeers = LP_numpeers; peer->notify_margin = LP_peerinfos[0].profitmargin; strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); - if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) - { - printf("2fetchpeers.(%s)\n",retstr); - LP_notify(peer,peer->ipaddr,peer->port,0,0,retstr); - //free(retstr); - } else peer->errors++, peer->errortime = (uint32_t)time(NULL); } } } From 62ae6e44157fbbacd77f55cc432050041db13b06 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 23:06:51 +0300 Subject: [PATCH 0593/2705] Test --- iguana/exchanges/LP_unspents.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b43e4c17f..50ed24999 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -115,16 +115,6 @@ char *LP_addpeer(char *ipaddr,uint16_t port,uint32_t gotintro,uint32_t sentintro peer->profitmargin = profitmargin; if ( gotintro != 0 ) peer->gotintro = gotintro; - //if ( peer->errors == 0 ) - { - j = rand() % LP_numpeers; - peer = &LP_peerinfos[j]; - //printf("queue notify (%s) from (%s)\n",peer->ipaddr,ipaddr); - peer->notify_margin = LP_peerinfos[0].profitmargin; - peer->notify_numpeers = LP_numpeers; - peer->notify_port = LP_peerinfos[0].port; - strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); - } } else { @@ -331,7 +321,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) return(clonestr("{\"error\":\"need method in request\"}")); else { - printf("got (%s)\n",jprint(argjson,0)); + //printf("got (%s)\n",jprint(argjson,0)); if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) { if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) From f3c68a5a992efb36eeae6ab7dd52ec6e4ea56a07 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 23 May 2017 23:12:33 +0300 Subject: [PATCH 0594/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 50ed24999..bbc765525 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -275,7 +275,7 @@ void LPinit(uint16_t port,double profitmargin) for (i=1; inumpeers != LP_numpeers && (peer->notify_ipaddr[0] == 0 || peer->notify_port == 0) ) + if ( peer->numpeers < LP_numpeers && (peer->notify_ipaddr[0] == 0 || peer->notify_port == 0) ) { strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); peer->notify_port = LP_peerinfos[0].port; From 94a9d840b94774d865be528328f2940d7dce4587 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 12:58:43 +0300 Subject: [PATCH 0595/2705] Test --- iguana/exchanges/LP_unspents.c | 339 ++++++++++++++------------------- iguana/exchanges/mm.c | 4 +- 2 files changed, 147 insertions(+), 196 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index bbc765525..ffee62c17 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -9,130 +9,24 @@ #include char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; +portable_mutex_t LP_mutex; +int32_t LP_numpeers; struct LP_peerinfo { - double profitmargin,notify_margin; - uint32_t ipbits,gotintro,sentintro,errortime,errors,numpeers,notify_numpeers; - char ipaddr[64],notify_ipaddr[64]; - uint16_t port,notify_port; -} LP_peerinfos[1024]; -int32_t LP_numpeers; + UT_hash_handle hh; + uint64_t ip_port; + double profitmargin; + uint32_t ipbits,errortime,errors,numpeers; + char ipaddr[64]; + uint16_t port; +} *LP_peerinfos; void LP_addutxo(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 deposittxid,int32_t depositvout,uint64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port) { printf("%s:%u LP_addutxo.(%.8f %.8f)\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis)); } -struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) -{ - int32_t j; - for (j=0; jprofitmargin = profitmargin; - peer->ipbits = ipbits; - peer->gotintro = gotintro; - peer->sentintro = sentintro; - strcpy(peer->ipaddr,ipaddr); - peer->port = port; - printf("_LPaddpeer %s -> i.%d numpeers.%d\n",ipaddr,i,LP_numpeers); -} - -void LP_notify(struct LP_peerinfo *peer,char *ipaddr,uint16_t port,double profit,int32_t numpeers,char *retstr) -{ - char buf[1024],*argipaddr; uint32_t ipbits; cJSON *array,*item; int32_t i,n; uint16_t argport; - sprintf(buf,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",peer->ipaddr,peer->port,ipaddr,port,profit,numpeers); - if ( retstr != 0 || (retstr= issue_curl(buf)) != 0 ) - { - printf("got (%s) from (%s)\n",retstr,buf); - if ( (array= cJSON_Parse(retstr)) != 0 ) - { - if ( (n= cJSON_GetArraySize(array)) > 0 ) - { - peer->numpeers = n; - for (i=0; ierrors++, peer->errortime = (uint32_t)time(NULL); -} - -cJSON *LP_peerjson(struct LP_peerinfo *peer) -{ - cJSON *item = cJSON_CreateObject(); - jaddstr(item,"ipaddr",peer->ipaddr); - jaddnum(item,"port",peer->port); - jaddnum(item,"profit",peer->profitmargin); - return(item); -} - -char *LP_peers() -{ - int32_t i; cJSON *peersjson = cJSON_CreateArray(); - for (i=0; iprofitmargin == 0. ) - peer->profitmargin = profitmargin; - if ( gotintro != 0 ) - peer->gotintro = gotintro; - } - else - { - for (j=0; jipaddr,ipaddr); - peer->notify_margin = LP_peerinfos[0].profitmargin; - peer->notify_numpeers = LP_numpeers; - peer->notify_port = port; - strcpy(peer->notify_ipaddr,ipaddr); - } - _LP_addpeer(LP_numpeers,ipbits,ipaddr,port,gotintro,sentintro,profitmargin); - } - } - return(LP_peers()); -} - int32_t LP_maxvalue(uint64_t *values,int32_t n) { int32_t i,maxi = -1; uint64_t maxval = 0; @@ -230,44 +124,143 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs return(total); } -void LPinit(uint16_t port,double profitmargin) +cJSON *LP_peerjson(struct LP_peerinfo *peer) +{ + cJSON *item = cJSON_CreateObject(); + jaddstr(item,"ipaddr",peer->ipaddr); + jaddnum(item,"port",peer->port); + jaddnum(item,"profit",peer->profitmargin); + return(item); +} + +char *LP_peers() +{ + struct LP_peerinfo *peer,*tmp; cJSON *peersjson = cJSON_CreateArray(); + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + jaddi(peersjson,LP_peerjson(peer)); + } + return(jprint(peersjson,1)); +} + +struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) +{ + struct LP_peerinfo *peer=0; uint64_t ip_port; + ip_port = ((uint64_t)port << 32) | ipbits; + portable_mutex_lock(&LP_mutex); + HASH_FIND(hh,LP_peerinfos,&ip_port,sizeof(ip_port),peer); + portable_mutex_unlock(&LP_mutex); + return(peer); +} + +struct LP_peerinfo *_LP_addpeer(uint32_t ipbits,char *ipaddr,uint16_t port,double profitmargin) +{ + struct LP_peerinfo *peer = 0; uint64_t ip_port; + peer = calloc(1,sizeof(*peer)); + memset(peer,0,sizeof(*peer)); + peer->profitmargin = profitmargin; + peer->ipbits = ipbits; + strcpy(peer->ipaddr,ipaddr); + peer->port = port; + ip_port = ((uint64_t)port << 32) | ipbits; + portable_mutex_lock(&LP_mutex); + HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(ip_port),peer); + LP_numpeers++; + portable_mutex_unlock(&LP_mutex); + printf("_LPaddpeer %s -> numpeers.%d\n",ipaddr,LP_numpeers); + return(peer); +} + +struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,double profitmargin) +{ + uint32_t ipbits; char checkip[64]; struct LP_peerinfo *peer = 0; + ipbits = (uint32_t)calc_ipbits(ipaddr); + expand_ipbits(checkip,ipbits); + if ( strcmp(checkip,ipaddr) == 0 ) + { + //printf("LPaddpeer %s\n",ipaddr); + if ( (peer= LP_peerfind(ipbits,port)) != 0 ) + { + if ( peer->profitmargin == 0. ) + peer->profitmargin = profitmargin; + } else peer = _LP_addpeer(ipbits,ipaddr,port,profitmargin); + } + return(peer); +} + +int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr) +{ + struct LP_peerinfo *peer; char *argipaddr; uint16_t argport; cJSON *array,*item; int32_t i,n=0; + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; inumpeers = n; + } + } + } + } + free_json(array); + } + return(n); +} + +void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) { - char *retstr,*ipaddr,tmp[64]; long filesize,n; int32_t i,notifynumpeers; uint16_t argport; struct LP_peerinfo *peer; double notifymargin; + char *retstr; + if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers)) != 0 ) + { + //printf("(%s) -> %s\n",default_LPnodes[i],retstr); + LP_peersparse(destipaddr,destport,retstr); + free(retstr); + } +} + +void LPinit(uint16_t myport,double profitmargin) +{ + char *myipaddr=0; long filesize,n; int32_t i; struct LP_peerinfo *peer; + portable_mutex_init(&LP_mutex); if ( profitmargin == 0. ) { profitmargin = 0.01; printf("default profit margin %f\n",profitmargin); } - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&port) != 0 ) + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { - printf("error launching stats rpcloop for port.%u\n",port); + printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) { - if ( (ipaddr= OS_filestr(&filesize,"/tmp/myipaddr")) != 0 && ipaddr[0] != 0 ) + if ( (myipaddr= OS_filestr(&filesize,"/tmp/myipaddr")) != 0 && myipaddr[0] != 0 ) { - n = strlen(ipaddr); - if ( ipaddr[n-1] == '\n' ) - ipaddr[--n] = 0; - retstr = LP_addpeer(ipaddr,port,0,(uint32_t)time(NULL),profitmargin); + n = strlen(myipaddr); + if ( myipaddr[n-1] == '\n' ) + myipaddr[--n] = 0; + LP_addpeer(myipaddr,myport,profitmargin); LP_peerinfos[0].profitmargin = profitmargin; //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); - if ( retstr != 0 ) - free(retstr); for (i=0; i 25 ) continue; - if ( (retstr= issue_LP_intro(default_LPnodes[i],port,ipaddr,port,profitmargin,LP_numpeers)) != 0 ) - { - //printf("(%s) -> %s\n",default_LPnodes[i],retstr); - LP_notify(&LP_peerinfos[i],ipaddr,port,0,0,retstr); - //free(retstr); - } + LP_peersquery(default_LPnodes[i],myport,myipaddr,myport,profitmargin); } } } + if ( myipaddr == 0 ) + { + printf("couldnt get myipaddr\n"); + exit(-1); + } LP_privkey_init("KMD",60,"test",""); //printf("peers.(%s)\n",LP_peers()); while ( 1 ) @@ -275,84 +268,42 @@ void LPinit(uint16_t port,double profitmargin) for (i=1; inumpeers < LP_numpeers && (peer->notify_ipaddr[0] == 0 || peer->notify_port == 0) ) - { - strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); - peer->notify_port = LP_peerinfos[0].port; - peer->notify_margin = LP_peerinfos[0].profitmargin; - peer->notify_numpeers = LP_numpeers; - printf("LP_numpeers.%d != [%d] (%s).%d\n",LP_numpeers,i,peer->ipaddr,peer->numpeers); - } - if ( peer->notify_ipaddr[0] != 0 && peer->notify_port != 0 ) - { - strcpy(tmp,peer->notify_ipaddr); - argport = peer->notify_port; - notifymargin = peer->notify_margin; - notifynumpeers = peer->notify_numpeers; - peer->notify_port = 0; - peer->notify_margin = 0; - peer->notify_numpeers = 0; - memset(peer->notify_ipaddr,0,sizeof(peer->notify_ipaddr)); - //if ( (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) - LP_notify(peer,tmp,argport,notifymargin,notifynumpeers,0); - } - } - if ( (rand() % 10) == 0 && LP_numpeers > 0 ) - { - i = rand() % LP_numpeers; - peer = &LP_peerinfos[i]; - if ( i > 0 )//&& (peer->errors == 0 || (time(NULL) - peer->errortime) > 3600) ) - { - if ( (retstr= issue_LP_getpeers(peer->ipaddr,peer->port,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin,LP_numpeers)) != 0 ) - { - LP_notify(peer,peer->ipaddr,peer->port,0,0,retstr); - //free(retstr); - } else peer->errors++, peer->errortime = (uint32_t)time(NULL); - } + if ( peer->numpeers != LP_numpeers ) + LP_peersquery(peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - sleep(6); + sleep(LP_numpeers); } } +// Q sending of individual peer that is missing from the other + char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { - char *method,*ipaddr,*coin,*dest,*retstr = 0; uint16_t argport; int32_t otherpeers; struct LP_peerinfo *peer; + char *method,*ipaddr,*coin,*dest,*retstr = 0; uint16_t argport; int32_t otherpeers; struct LP_peerinfo *peer; cJSON *retjson; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); else { - //printf("got (%s)\n",jprint(argjson,0)); - if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + peer = LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport); + if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) { - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) - { + if ( peer != 0 ) peer->numpeers = otherpeers; - if ( otherpeers != LP_numpeers ) - { - printf("peer.(%s:%u) numpeers.%d != LP_numpeers.%d (%s)\n",ipaddr,argport,otherpeers,LP_numpeers,jprint(argjson,0)); - peer->notify_port = LP_peerinfos[0].port; - peer->notify_numpeers = LP_numpeers; - peer->notify_margin = LP_peerinfos[0].profitmargin; - strcpy(peer->notify_ipaddr,LP_peerinfos[0].ipaddr); - } - } + else LP_addpeer(ipaddr,argport,jdouble(argjson,"profit")); + } + if ( strcmp(method,"getpeers") == 0 ) + retstr = LP_peers(); + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 && (dest= jstr(argjson,"dest")) != 0 ) + { + //retstr = LP_getutxos(coin,dest); } - } - if ( strcmp(method,"intro") == 0 ) - { - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) - retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,jdouble(argjson,"profit")); - } - else if ( strcmp(method,"getpeers") == 0 && (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) - retstr = LP_addpeer(ipaddr,argport,(uint32_t)time(NULL),0,jdouble(argjson,"profit")); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 && (dest= jstr(argjson,"dest")) != 0 ) - { - //retstr = LP_getutxos(coin,dest); } } if ( retstr != 0 ) return(retstr); - return(clonestr(jprint(argjson,0))); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"error","unrecognized command"); + return(clonestr(jprint(retjson,1))); } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index f53d09da1..65a2742de 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -159,13 +159,13 @@ char *iguana_listunspent(char *coin,char *coinaddr) return(bitcoind_RPC(0,"",url,0,"listunspent",postdata)); } -char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) +/*char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) { char url[512]; sprintf(url,"http://%s:%u/api/stats/intro?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",destip,destport,ipaddr,port,profitmargin,numpeers); printf("(%s)\n",url); return(issue_curl(url)); -} +}*/ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) { From 14b159b94005502afb63568e548681c6f5f64afc Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 13:01:28 +0300 Subject: [PATCH 0596/2705] Test --- iguana/exchanges/LP_unspents.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index ffee62c17..ba92098c9 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -226,7 +226,7 @@ void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t my void LPinit(uint16_t myport,double profitmargin) { - char *myipaddr=0; long filesize,n; int32_t i; struct LP_peerinfo *peer; + char *myipaddr=0; long filesize,n; int32_t i; struct LP_peerinfo *peer,*tmp; portable_mutex_init(&LP_mutex); if ( profitmargin == 0. ) { @@ -265,9 +265,8 @@ void LPinit(uint16_t myport,double profitmargin) //printf("peers.(%s)\n",LP_peers()); while ( 1 ) { - for (i=1; inumpeers != LP_numpeers ) LP_peersquery(peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } From 053de4c6bb3fc33c90fbb5c18a01c99356bde78e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 13:05:50 +0300 Subject: [PATCH 0597/2705] Test --- iguana/exchanges/LP_unspents.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index ba92098c9..bd05a3b7f 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -155,16 +155,16 @@ struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) struct LP_peerinfo *_LP_addpeer(uint32_t ipbits,char *ipaddr,uint16_t port,double profitmargin) { - struct LP_peerinfo *peer = 0; uint64_t ip_port; + struct LP_peerinfo *peer = 0; peer = calloc(1,sizeof(*peer)); memset(peer,0,sizeof(*peer)); peer->profitmargin = profitmargin; peer->ipbits = ipbits; strcpy(peer->ipaddr,ipaddr); peer->port = port; - ip_port = ((uint64_t)port << 32) | ipbits; + peer->ip_port = ((uint64_t)port << 32) | ipbits; portable_mutex_lock(&LP_mutex); - HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(ip_port),peer); + HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer); LP_numpeers++; portable_mutex_unlock(&LP_mutex); printf("_LPaddpeer %s -> numpeers.%d\n",ipaddr,LP_numpeers); From bffc996ca76578905854072db0ef9d8ef19d4341 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 13:19:28 +0300 Subject: [PATCH 0598/2705] Test --- iguana/exchanges/LP_unspents.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index bd05a3b7f..42fefd6d5 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -218,7 +218,7 @@ void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t my char *retstr; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers)) != 0 ) { - //printf("(%s) -> %s\n",default_LPnodes[i],retstr); + printf("(%s) -> %s\n",destipaddr,retstr); LP_peersparse(destipaddr,destport,retstr); free(retstr); } @@ -267,10 +267,11 @@ void LPinit(uint16_t myport,double profitmargin) { HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers != LP_numpeers ) + printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,LP_numpeers); + if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - sleep(LP_numpeers); + sleep(10); } } @@ -298,7 +299,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { //retstr = LP_getutxos(coin,dest); } - } + } else printf("malformed request.(%s)\n",jprint(argjson,0)); } if ( retstr != 0 ) return(retstr); From ee7d16313cc2bb93582495487be0255fb47723ad Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 13:36:58 +0300 Subject: [PATCH 0599/2705] Increase dex explorer lag --- iguana/kmd_lookup.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index b54fd4415..e52cef41b 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -16,7 +16,7 @@ #ifndef INCLUDE_KMDLOOKUP_H #define INCLUDE_KMDLOOKUP_H -#define KMD_EXPLORER_LAG 3 +#define KMD_EXPLORER_LAG 6 struct kmd_voutinfo { @@ -638,7 +638,7 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) } height = kmd_height(coin); loadheight = coin->kmd_height+1; - lag = (strcmp(coin->symbol,"KMD") == 0 ? KMD_EXPLORER_LAG : 1); + lag = (strcmp(coin->symbol,"KMD") == 0 ? KMD_EXPLORER_LAG : 2); while ( loadheight < height-lag ) { flag = 0; From e42c4d534301b4d70fc32fae984dc7d2cf90f117 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 14:05:32 +0300 Subject: [PATCH 0600/2705] Test --- iguana/exchanges/LP_unspents.c | 56 +++++++++++++++++++++++----------- iguana/exchanges/mm.c | 8 +++++ 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 42fefd6d5..7feb18e4c 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -17,7 +17,7 @@ struct LP_peerinfo UT_hash_handle hh; uint64_t ip_port; double profitmargin; - uint32_t ipbits,errortime,errors,numpeers; + uint32_t ipbits,errortime,errors,numpeers,foundtime; char ipaddr[64]; uint16_t port; } *LP_peerinfos; @@ -188,9 +188,9 @@ struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,double profitmargin) return(peer); } -int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr) +int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { - struct LP_peerinfo *peer; char *argipaddr; uint16_t argport; cJSON *array,*item; int32_t i,n=0; + struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport; cJSON *array,*item; int32_t i,n=0; if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -200,9 +200,13 @@ int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr) item = jitem(array,i); if ( (argipaddr= jstr(item,"ipaddr")) != 0 && (argport= juint(item,"port")) != 0 ) { - if ( (peer= LP_addpeer(argipaddr,argport,jdouble(item,"profit"))) != 0 ) + argipbits = (uint32_t)calc_ipbits(argipaddr); + if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) + peer = LP_addpeer(argipaddr,argport,jdouble(item,"profit")); + if ( peer != 0 ) { - if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport ) + peer->foundtime = now; + if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers < n ) peer->numpeers = n; } } @@ -215,18 +219,30 @@ int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr) void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) { - char *retstr; + char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers)) != 0 ) { - printf("(%s) -> %s\n",destipaddr,retstr); - LP_peersparse(destipaddr,destport,retstr); + now = (uint32_t)time(NULL); + LP_peersparse(destipaddr,destport,retstr,now); free(retstr); - } + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( peer->foundtime != now ) + { + printf("{%s:%u %.6f} ",peer->ipaddr,peer->port,peer->profitmargin); + flag++; + if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->profitmargin,peer->numpeers)) != 0 ) + free(retstr); + } + } + if ( flag != 0 ) + printf(" <- missing peers\n"); + } } void LPinit(uint16_t myport,double profitmargin) { - char *myipaddr=0; long filesize,n; int32_t i; struct LP_peerinfo *peer,*tmp; + char *myipaddr=0; long filesize,n; int32_t i; struct LP_peerinfo *peer,*tmp,*mypeer=0; portable_mutex_init(&LP_mutex); if ( profitmargin == 0. ) { @@ -245,8 +261,7 @@ void LPinit(uint16_t myport,double profitmargin) n = strlen(myipaddr); if ( myipaddr[n-1] == '\n' ) myipaddr[--n] = 0; - LP_addpeer(myipaddr,myport,profitmargin); - LP_peerinfos[0].profitmargin = profitmargin; + mypeer = LP_addpeer(myipaddr,myport,profitmargin); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; inumpeers = LP_numpeers; HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,LP_numpeers); - if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_peersquery(peer->ipaddr,peer->port,myipaddr,myport,profitmargin); + if ( peer->numpeers != LP_numpeers ) + { + printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,LP_numpeers); + if ( strcmp(peer->ipaddr,myipaddr) != 0 ) + LP_peersquery(peer->ipaddr,peer->port,myipaddr,myport,profitmargin); + } } - sleep(10); + sleep(LP_numpeers); } } @@ -289,12 +309,14 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) peer = LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport); if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) { - if ( peer != 0 ) + if ( peer != 0 && peer->numpeers < otherpeers ) peer->numpeers = otherpeers; else LP_addpeer(ipaddr,argport,jdouble(argjson,"profit")); } if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); + else if ( strcmp(method,"notify") == 0 ) + retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 && (dest= jstr(argjson,"dest")) != 0 ) { //retstr = LP_getutxos(coin,dest); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 65a2742de..baf71f315 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -174,6 +174,14 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por return(issue_curl(url)); } +char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",destip,destport,ipaddr,port,profitmargin,numpeers); + return(issue_curl(url)); +} + + // // http://127.0.0.1:7779/api/stats/getpeers From 86828f2a7b6c67721dd9b0b54ba184529bb4074e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 14:17:48 +0300 Subject: [PATCH 0601/2705] Test --- iguana/exchanges/LP_unspents.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 7feb18e4c..61642b314 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -220,6 +220,9 @@ int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; + peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); + if ( peer != 0 && peer->errors > 0 ) + return; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers)) != 0 ) { now = (uint32_t)time(NULL); @@ -237,7 +240,8 @@ void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t my } if ( flag != 0 ) printf(" <- missing peers\n"); - } + } else if ( peer != 0 ) + peer->errors++; } void LPinit(uint16_t myport,double profitmargin) From bd7fd9cd7febef9e495d53339bf41ad84b040d0a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 18:37:10 +0300 Subject: [PATCH 0602/2705] LTC test --- crypto777/OS_portable.h | 2 + crypto777/bitcoind_RPC.c | 2 +- iguana/exchanges/LP_unspents.c | 452 +++++++++++++++++++++++---------- iguana/exchanges/mm.c | 15 +- iguana/kmd_lookup.h | 4 +- iguana/tests/dexlistunspent | 2 +- 6 files changed, 334 insertions(+), 143 deletions(-) diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index d687df9e0..f986b5216 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -358,6 +358,7 @@ void calc_base64_encodestr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); void calc_base64_decodestr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); void calc_hexstr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); void calc_unhexstr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); +int32_t safecopy(char *dest,char *src,long len); uint64_t calc_ipbits(char *ip_port); void expand_ipbits(char *ipaddr,uint64_t ipbits); @@ -384,6 +385,7 @@ int32_t iguana_rwvarint(int32_t rwflag,uint8_t *serialized,uint64_t *varint64p); int32_t iguana_rwvarint32(int32_t rwflag,uint8_t *serialized,uint32_t *int32p); int32_t iguana_rwvarstr(int32_t rwflag,uint8_t *serialized,int32_t maxlen,char *endianedp); int32_t iguana_rwmem(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp); +#define bits256_nonz(a) (((a).ulongs[0] | (a).ulongs[1] | (a).ulongs[2] | (a).ulongs[3]) != 0) bits256 bits256_ave(bits256 a,bits256 b); bits256 bits256_doublesha256(char *hashstr,uint8_t *data,int32_t datalen); diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index db54e4317..2a4636801 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -207,7 +207,7 @@ try_again: free(s.ptr); return(0); } - else if ( numretries >= 2 ) + else if ( numretries >= 4 ) { printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); //printf("Maximum number of retries exceeded!\n"); diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 61642b314..1e26ba9ba 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -9,22 +9,303 @@ #include char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; -portable_mutex_t LP_mutex; -int32_t LP_numpeers; +portable_mutex_t LP_peermutex,LP_utxomutex; +int32_t LP_numpeers,LP_numutxos; struct LP_peerinfo { UT_hash_handle hh; uint64_t ip_port; double profitmargin; - uint32_t ipbits,errortime,errors,numpeers,foundtime; + uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime; char ipaddr[64]; uint16_t port; } *LP_peerinfos; -void LP_addutxo(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 deposittxid,int32_t depositvout,uint64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port) +struct LP_utxoinfo { - printf("%s:%u LP_addutxo.(%.8f %.8f)\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis)); + UT_hash_handle hh; + bits256 txid,deposittxid; + uint64_t satoshis,depositsatoshis; + int32_t vout,depositvout; uint32_t lasttime,errors; + double profitmargin; + char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; + uint16_t port; +} *LP_utxoinfos; + +cJSON *LP_peerjson(struct LP_peerinfo *peer) +{ + cJSON *item = cJSON_CreateObject(); + jaddstr(item,"ipaddr",peer->ipaddr); + jaddnum(item,"port",peer->port); + jaddnum(item,"profit",peer->profitmargin); + return(item); +} + +cJSON *LP_utxojson(struct LP_utxoinfo *utxo) +{ + cJSON *item = cJSON_CreateObject(); + jaddstr(item,"ipaddr",utxo->ipaddr); + jaddnum(item,"port",utxo->port); + jaddnum(item,"profit",utxo->profitmargin); + jaddstr(item,"coin",utxo->coin); + jaddstr(item,"address",utxo->coinaddr); + jaddstr(item,"script",utxo->spendscript); + jaddbits256(item,"txid",utxo->txid); + jaddnum(item,"vout",utxo->vout); + jaddnum(item,"value",dstr(utxo->satoshis)); + jaddbits256(item,"deposit",utxo->deposittxid); + jaddnum(item,"dvout",utxo->depositvout); + jaddnum(item,"dvalue",dstr(utxo->depositsatoshis)); + return(item); +} + +char *LP_peers() +{ + struct LP_peerinfo *peer,*tmp; cJSON *peersjson = cJSON_CreateArray(); + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + jaddi(peersjson,LP_peerjson(peer)); + } + return(jprint(peersjson,1)); +} + +char *LP_utxos(char *coin,int32_t lastn) +{ + int32_t i,firsti; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); + i = 0; + if ( lastn >= LP_numutxos ) + firsti = -1; + else firsti = (LP_numutxos - lastn); + HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + { + if ( i++ < firsti ) + continue; + if ( coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0 ) + { + jaddi(utxosjson,LP_utxojson(utxo)); + } + } + return(jprint(utxosjson,1)); +} + +struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) +{ + struct LP_peerinfo *peer=0; uint64_t ip_port; + ip_port = ((uint64_t)port << 32) | ipbits; + portable_mutex_lock(&LP_peermutex); + HASH_FIND(hh,LP_peerinfos,&ip_port,sizeof(ip_port),peer); + portable_mutex_unlock(&LP_peermutex); + return(peer); +} + +struct LP_utxoinfo *LP_utxofind(bits256 txid) +{ + struct LP_utxoinfo *utxo=0; + portable_mutex_lock(&LP_utxomutex); + HASH_FIND(hh,LP_utxoinfos,&txid,sizeof(txid),utxo); + portable_mutex_unlock(&LP_utxomutex); + return(utxo); +} + +struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,double profitmargin) +{ + uint32_t ipbits; char checkip[64]; struct LP_peerinfo *peer = 0; + ipbits = (uint32_t)calc_ipbits(ipaddr); + expand_ipbits(checkip,ipbits); + if ( strcmp(checkip,ipaddr) == 0 ) + { + //printf("LPaddpeer %s\n",ipaddr); + if ( (peer= LP_peerfind(ipbits,port)) != 0 ) + { + if ( peer->profitmargin == 0. ) + peer->profitmargin = profitmargin; + } + else + { + peer = calloc(1,sizeof(*peer)); + peer->profitmargin = profitmargin; + peer->ipbits = ipbits; + strcpy(peer->ipaddr,ipaddr); + peer->port = port; + peer->ip_port = ((uint64_t)port << 32) | ipbits; + portable_mutex_lock(&LP_peermutex); + HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer); + LP_numpeers++; + portable_mutex_unlock(&LP_peermutex); + printf("_LPaddpeer %s -> numpeers.%d\n",ipaddr,LP_numpeers); + } + } + return(peer); +} + +struct LP_utxoinfo *LP_addutxo(char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) +{ + struct LP_utxoinfo *utxo = 0; + if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) + return(0); + if ( (utxo= LP_utxofind(txid)) != 0 ) + { + if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->deposittxid) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->depositvout || depositsatoshis != utxo->depositsatoshis || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) + { + utxo->errors++; + char str[65]; printf("error on subsequent utxo add.(%s)\n",bits256_str(str,txid)); + } + else if ( profitmargin != 0. ) + utxo->profitmargin = profitmargin; + } + else + { + utxo = calloc(1,sizeof(*utxo)); + utxo->profitmargin = profitmargin; + strcpy(utxo->ipaddr,ipaddr); + utxo->port = port; + safecopy(utxo->coin,coin,sizeof(utxo->coin)); + safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); + safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); + utxo->txid = txid; + utxo->vout = vout; + utxo->satoshis = satoshis; + utxo->deposittxid = deposittxid; + utxo->depositvout = depositvout; + utxo->depositsatoshis = depositsatoshis; + portable_mutex_lock(&LP_utxomutex); + HASH_ADD(hh,LP_utxoinfos,txid,sizeof(txid),utxo); + LP_numutxos++; + portable_mutex_unlock(&LP_utxomutex); + printf("%s:%u LP_addutxo.(%.8f %.8f)\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis)); + } + return(utxo); +} + +int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +{ + struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport; cJSON *array,*item; int32_t i,n=0; + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; ilasttime = now; + if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers < n ) + peer->numpeers = n; + } + } + } + } + free_json(array); + } + return(n); +} + +int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +{ + struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; ilasttime = now; + } + } + } + } + free_json(array); + } + return(n); +} + +void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) +{ + char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; + peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); + if ( peer != 0 && peer->errors > 0 ) + return; + if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers,LP_numutxos)) != 0 ) + { + now = (uint32_t)time(NULL); + LP_peersparse(destipaddr,destport,retstr,now); + free(retstr); + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( peer->lasttime != now ) + { + printf("{%s:%u %.6f} ",peer->ipaddr,peer->port,peer->profitmargin); + flag++; + if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->profitmargin,peer->numpeers,0)) != 0 ) + free(retstr); + } + } + if ( flag != 0 ) + printf(" <- missing peers\n"); + } else if ( peer != 0 ) + peer->errors++; +} + +char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) +{ + char url[4096],str[65],str2[65]; + sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&deposit=%s&dvout=%d&dvalue=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->deposittxid),utxo->depositvout,dstr(utxo->depositsatoshis),utxo->spendscript,utxo->coinaddr); + if ( strlen(url) > 1024 ) + printf("WARNING long url.(%s)\n",url); + return(issue_curl(url)); +} + +void LP_utxosquery(char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) +{ + char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; + peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); + if ( peer != 0 && peer->errors > 0 ) + return; + if ( coin == 0 ) + coin = ""; + if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,LP_numpeers,LP_numutxos)) != 0 ) + { + now = (uint32_t)time(NULL); + LP_utxosparse(destipaddr,destport,retstr,now); + free(retstr); + i = 0; + if ( lastn >= LP_numutxos ) + firsti = -1; + else firsti = (LP_numutxos - lastn); + HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + { + if ( i++ < firsti ) + continue; + if ( utxo->lasttime != now ) + { + char str[65]; printf("{%s:%u %s} ",utxo->ipaddr,utxo->port,bits256_str(str,utxo->txid)); + flag++; + if ( (retstr= issue_LP_notifyutxo(destipaddr,destport,utxo)) != 0 ) + free(retstr); + } + } + if ( flag != 0 ) + printf(" <- missing utxos\n"); + } else if ( peer != 0 ) + peer->errors++; } int32_t LP_maxvalue(uint64_t *values,int32_t n) @@ -110,7 +391,7 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs { value = values[i]; values[i] = 0, used++; - LP_addutxo(coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port); + LP_addutxo(coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); total += value; } } @@ -124,130 +405,11 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs return(total); } -cJSON *LP_peerjson(struct LP_peerinfo *peer) -{ - cJSON *item = cJSON_CreateObject(); - jaddstr(item,"ipaddr",peer->ipaddr); - jaddnum(item,"port",peer->port); - jaddnum(item,"profit",peer->profitmargin); - return(item); -} - -char *LP_peers() -{ - struct LP_peerinfo *peer,*tmp; cJSON *peersjson = cJSON_CreateArray(); - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - jaddi(peersjson,LP_peerjson(peer)); - } - return(jprint(peersjson,1)); -} - -struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) -{ - struct LP_peerinfo *peer=0; uint64_t ip_port; - ip_port = ((uint64_t)port << 32) | ipbits; - portable_mutex_lock(&LP_mutex); - HASH_FIND(hh,LP_peerinfos,&ip_port,sizeof(ip_port),peer); - portable_mutex_unlock(&LP_mutex); - return(peer); -} - -struct LP_peerinfo *_LP_addpeer(uint32_t ipbits,char *ipaddr,uint16_t port,double profitmargin) -{ - struct LP_peerinfo *peer = 0; - peer = calloc(1,sizeof(*peer)); - memset(peer,0,sizeof(*peer)); - peer->profitmargin = profitmargin; - peer->ipbits = ipbits; - strcpy(peer->ipaddr,ipaddr); - peer->port = port; - peer->ip_port = ((uint64_t)port << 32) | ipbits; - portable_mutex_lock(&LP_mutex); - HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer); - LP_numpeers++; - portable_mutex_unlock(&LP_mutex); - printf("_LPaddpeer %s -> numpeers.%d\n",ipaddr,LP_numpeers); - return(peer); -} - -struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,double profitmargin) -{ - uint32_t ipbits; char checkip[64]; struct LP_peerinfo *peer = 0; - ipbits = (uint32_t)calc_ipbits(ipaddr); - expand_ipbits(checkip,ipbits); - if ( strcmp(checkip,ipaddr) == 0 ) - { - //printf("LPaddpeer %s\n",ipaddr); - if ( (peer= LP_peerfind(ipbits,port)) != 0 ) - { - if ( peer->profitmargin == 0. ) - peer->profitmargin = profitmargin; - } else peer = _LP_addpeer(ipbits,ipaddr,port,profitmargin); - } - return(peer); -} - -int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) -{ - struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport; cJSON *array,*item; int32_t i,n=0; - if ( (array= cJSON_Parse(retstr)) != 0 ) - { - if ( (n= cJSON_GetArraySize(array)) > 0 ) - { - for (i=0; ifoundtime = now; - if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers < n ) - peer->numpeers = n; - } - } - } - } - free_json(array); - } - return(n); -} - -void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) -{ - char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; - peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); - if ( peer != 0 && peer->errors > 0 ) - return; - if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers)) != 0 ) - { - now = (uint32_t)time(NULL); - LP_peersparse(destipaddr,destport,retstr,now); - free(retstr); - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - if ( peer->foundtime != now ) - { - printf("{%s:%u %.6f} ",peer->ipaddr,peer->port,peer->profitmargin); - flag++; - if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->profitmargin,peer->numpeers)) != 0 ) - free(retstr); - } - } - if ( flag != 0 ) - printf(" <- missing peers\n"); - } else if ( peer != 0 ) - peer->errors++; -} - void LPinit(uint16_t myport,double profitmargin) { char *myipaddr=0; long filesize,n; int32_t i; struct LP_peerinfo *peer,*tmp,*mypeer=0; - portable_mutex_init(&LP_mutex); + portable_mutex_init(&LP_peermutex); + portable_mutex_init(&LP_utxomutex); if ( profitmargin == 0. ) { profitmargin = 0.01; @@ -285,7 +447,10 @@ void LPinit(uint16_t myport,double profitmargin) while ( 1 ) { if ( mypeer != 0 ) + { mypeer->numpeers = LP_numpeers; + mypeer->numutxos = LP_numutxos; + } HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( peer->numpeers != LP_numpeers ) @@ -294,6 +459,12 @@ void LPinit(uint16_t myport,double profitmargin) if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } + if ( peer->numutxos > LP_numutxos ) + { + printf("%s numutxos.%d vs %d\n",peer->ipaddr,peer->numutxos,LP_numutxos); + if ( strcmp(peer->ipaddr,myipaddr) != 0 ) + LP_utxosquery(peer->ipaddr,peer->port,"",peer->numutxos - LP_numutxos + 10,myipaddr,myport,profitmargin); + } } sleep(LP_numpeers); } @@ -303,27 +474,36 @@ void LPinit(uint16_t myport,double profitmargin) char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) { - char *method,*ipaddr,*coin,*dest,*retstr = 0; uint16_t argport; int32_t otherpeers; struct LP_peerinfo *peer; cJSON *retjson; + char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); else { if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { - peer = LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport); - if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) { - if ( peer != 0 && peer->numpeers < otherpeers ) - peer->numpeers = otherpeers; - else LP_addpeer(ipaddr,argport,jdouble(argjson,"profit")); - } + if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) + { + if ( peer->numpeers < otherpeers ) + peer->numpeers = otherpeers; + } + if ( (othernumutxos= jint(argjson,"numutxos")) > 0 ) + { + if ( peer->numutxos < othernumutxos ) + peer->numutxos = othernumutxos; + } + } else LP_addpeer(ipaddr,argport,jdouble(argjson,"profit")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + retstr = LP_utxos(coin,jint(argjson,"lastn")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 && (dest= jstr(argjson,"dest")) != 0 ) + else if ( strcmp(method,"utxonotify") == 0 ) { - //retstr = LP_getutxos(coin,dest); + LP_addutxo(jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),j64bits(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); + retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } else printf("malformed request.(%s)\n",jprint(argjson,0)); } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index baf71f315..2146b6d30 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -167,20 +167,27 @@ char *iguana_listunspent(char *coin,char *coinaddr) return(issue_curl(url)); }*/ -char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) +char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",destip,destport,ipaddr,port,profitmargin,numpeers); + sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); return(issue_curl(url)); } -char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) + +char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d",destip,destport,ipaddr,port,profitmargin,numpeers); + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); return(issue_curl(url)); } +char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); + return(issue_curl(url)); +} // // http://127.0.0.1:7779/api/stats/getpeers diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index e52cef41b..8403f91d7 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -638,7 +638,9 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) } height = kmd_height(coin); loadheight = coin->kmd_height+1; - lag = (strcmp(coin->symbol,"KMD") == 0 ? KMD_EXPLORER_LAG : 2); + if ( strcmp(coin->symbol,"LTC") == 0 ) + lag = 3; + else lag = (strcmp(coin->symbol,"KMD") == 0 ? KMD_EXPLORER_LAG : 2); while ( loadheight < height-lag ) { flag = 0; diff --git a/iguana/tests/dexlistunspent b/iguana/tests/dexlistunspent index 7347339da..0f6eb190f 100755 --- a/iguana/tests/dexlistunspent +++ b/iguana/tests/dexlistunspent @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RRyBxbrAPRUBCUpiJgJZYrkxqrh8x5ta9Z\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RVy1qgs2HRmXKWWawoqFSo3WGBkjC19cmJ\",\"symbol\":\"KMD\"}" From fe41dd7704f19e02edece81112c89e0335fa67da Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 18:43:08 +0300 Subject: [PATCH 0603/2705] Test --- iguana/exchanges/LP_unspents.c | 94 +++++++++++++++++----------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 1e26ba9ba..ef7acaa65 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -8,6 +8,8 @@ #include +#define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid + char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; portable_mutex_t LP_peermutex,LP_utxomutex; int32_t LP_numpeers,LP_numutxos; @@ -405,6 +407,48 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs return(total); } +char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) +{ + char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; + if ( (method= jstr(argjson,"method")) == 0 ) + return(clonestr("{\"error\":\"need method in request\"}")); + else + { + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + { + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) + { + if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) + { + if ( peer->numpeers < otherpeers ) + peer->numpeers = otherpeers; + } + if ( (othernumutxos= jint(argjson,"numutxos")) > 0 ) + { + if ( peer->numutxos < othernumutxos ) + peer->numutxos = othernumutxos; + } + } else LP_addpeer(ipaddr,argport,jdouble(argjson,"profit")); + if ( strcmp(method,"getpeers") == 0 ) + retstr = LP_peers(); + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + retstr = LP_utxos(coin,jint(argjson,"lastn")); + else if ( strcmp(method,"notify") == 0 ) + retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); + else if ( strcmp(method,"utxonotify") == 0 ) + { + LP_addutxo(jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),j64bits(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); + retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); + } + } else printf("malformed request.(%s)\n",jprint(argjson,0)); + } + if ( retstr != 0 ) + return(retstr); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"error","unrecognized command"); + return(clonestr(jprint(retjson,1))); +} + void LPinit(uint16_t myport,double profitmargin) { char *myipaddr=0; long filesize,n; int32_t i; struct LP_peerinfo *peer,*tmp,*mypeer=0; @@ -443,7 +487,7 @@ void LPinit(uint16_t myport,double profitmargin) exit(-1); } LP_privkey_init("KMD",60,"test",""); - //printf("peers.(%s)\n",LP_peers()); + printf("utxos.(%s)\n",LP_utxos("",10000)); while ( 1 ) { if ( mypeer != 0 ) @@ -461,55 +505,11 @@ void LPinit(uint16_t myport,double profitmargin) } if ( peer->numutxos > LP_numutxos ) { - printf("%s numutxos.%d vs %d\n",peer->ipaddr,peer->numutxos,LP_numutxos); + printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,LP_numutxos,peer->numutxos - LP_numutxos + LP_PROPAGATION_SLACK); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_utxosquery(peer->ipaddr,peer->port,"",peer->numutxos - LP_numutxos + 10,myipaddr,myport,profitmargin); + LP_utxosquery(peer->ipaddr,peer->port,"",peer->numutxos - LP_numutxos + LP_PROPAGATION_SLACK,myipaddr,myport,profitmargin); } } sleep(LP_numpeers); } } - -// Q sending of individual peer that is missing from the other - -char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) -{ - char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; - if ( (method= jstr(argjson,"method")) == 0 ) - return(clonestr("{\"error\":\"need method in request\"}")); - else - { - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) - { - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) - { - if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) - { - if ( peer->numpeers < otherpeers ) - peer->numpeers = otherpeers; - } - if ( (othernumutxos= jint(argjson,"numutxos")) > 0 ) - { - if ( peer->numutxos < othernumutxos ) - peer->numutxos = othernumutxos; - } - } else LP_addpeer(ipaddr,argport,jdouble(argjson,"profit")); - if ( strcmp(method,"getpeers") == 0 ) - retstr = LP_peers(); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) - retstr = LP_utxos(coin,jint(argjson,"lastn")); - else if ( strcmp(method,"notify") == 0 ) - retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( strcmp(method,"utxonotify") == 0 ) - { - LP_addutxo(jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),j64bits(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); - retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); - } - } else printf("malformed request.(%s)\n",jprint(argjson,0)); - } - if ( retstr != 0 ) - return(retstr); - retjson = cJSON_CreateObject(); - jaddstr(retjson,"error","unrecognized command"); - return(clonestr(jprint(retjson,1))); -} From 78d3a5ef6a1ab83d480c5d7b61f1eae0094bcb87 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 18:48:31 +0300 Subject: [PATCH 0604/2705] Test --- iguana/exchanges/LP_unspents.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index ef7acaa65..1c71539f7 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -145,7 +145,10 @@ struct LP_utxoinfo *LP_addutxo(char *coin,bits256 txid,int32_t vout,int64_t sato { struct LP_utxoinfo *utxo = 0; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) + { + printf("malformed addutxo\n"); return(0); + } if ( (utxo= LP_utxofind(txid)) != 0 ) { if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->deposittxid) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->depositvout || depositsatoshis != utxo->depositsatoshis || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) @@ -437,6 +440,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( strcmp(method,"utxonotify") == 0 ) { + printf("utxonotify.(%s)\n",jprint(argjson,0)); LP_addutxo(jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),j64bits(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } @@ -451,7 +455,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) void LPinit(uint16_t myport,double profitmargin) { - char *myipaddr=0; long filesize,n; int32_t i; struct LP_peerinfo *peer,*tmp,*mypeer=0; + char *myipaddr=0; long filesize,n; int32_t i,lastn; struct LP_peerinfo *peer,*tmp,*mypeer=0; portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); if ( profitmargin == 0. ) @@ -503,11 +507,14 @@ void LPinit(uint16_t myport,double profitmargin) if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - if ( peer->numutxos > LP_numutxos ) + if ( peer->numutxos != LP_numutxos ) { - printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,LP_numutxos,peer->numutxos - LP_numutxos + LP_PROPAGATION_SLACK); + lastn = peer->numutxos - LP_numutxos + LP_PROPAGATION_SLACK; + if ( lastn < 0 ) + lastn = LP_PROPAGATION_SLACK * 2; + printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,LP_numutxos,lastn); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_utxosquery(peer->ipaddr,peer->port,"",peer->numutxos - LP_numutxos + LP_PROPAGATION_SLACK,myipaddr,myport,profitmargin); + LP_utxosquery(peer->ipaddr,peer->port,"",lastn,myipaddr,myport,profitmargin); } } sleep(LP_numpeers); From 6b4ff037b6585b0c0c788215a63e805b885fd0b0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 18:52:10 +0300 Subject: [PATCH 0605/2705] Test --- iguana/exchanges/LP_unspents.c | 53 ++++++++++++++++++++++------------ iguana/exchanges/mm.c | 22 -------------- 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 1c71539f7..e884c28d0 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -242,6 +242,38 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n return(n); } +char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); + return(issue_curl(url)); +} + +char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); + return(issue_curl(url)); +} + +char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); + return(issue_curl(url)); +} + +char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) +{ + char url[4096],str[65],str2[65],*retstr; + sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&deposit=%s&dvout=%d&dvalue=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->deposittxid),utxo->depositvout,dstr(utxo->depositsatoshis),utxo->spendscript,utxo->coinaddr); + //if ( strlen(url) > 1024 ) + printf("WARNING long url.(%s)\n",url); + retstr = issue_curl(url); + printf("(%s)\n",retstr); + return(retstr); +} + void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; @@ -269,15 +301,6 @@ void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t my peer->errors++; } -char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) -{ - char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&deposit=%s&dvout=%d&dvalue=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->deposittxid),utxo->depositvout,dstr(utxo->depositsatoshis),utxo->spendscript,utxo->coinaddr); - if ( strlen(url) > 1024 ) - printf("WARNING long url.(%s)\n",url); - return(issue_curl(url)); -} - void LP_utxosquery(char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; @@ -422,15 +445,9 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) { if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) - { - if ( peer->numpeers < otherpeers ) - peer->numpeers = otherpeers; - } + peer->numpeers = otherpeers; if ( (othernumutxos= jint(argjson,"numutxos")) > 0 ) - { - if ( peer->numutxos < othernumutxos ) - peer->numutxos = othernumutxos; - } + peer->numutxos = othernumutxos; } else LP_addpeer(ipaddr,argport,jdouble(argjson,"profit")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); @@ -438,7 +455,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) retstr = LP_utxos(coin,jint(argjson,"lastn")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( strcmp(method,"utxonotify") == 0 ) + else if ( strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); LP_addutxo(jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),j64bits(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 2146b6d30..5642cd9df 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -167,28 +167,6 @@ char *iguana_listunspent(char *coin,char *coinaddr) return(issue_curl(url)); }*/ -char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) -{ - char url[512]; - sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curl(url)); -} - - -char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) -{ - char url[512]; - sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curl(url)); -} - -char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) -{ - char url[512]; - sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curl(url)); -} - // // http://127.0.0.1:7779/api/stats/getpeers From 4fe66ecc26daa0b31eda533d1f5e9d7adf880921 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 18:55:38 +0300 Subject: [PATCH 0606/2705] Test --- iguana/exchanges/LP_unspents.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index e884c28d0..76dfecab8 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -146,7 +146,7 @@ struct LP_utxoinfo *LP_addutxo(char *coin,bits256 txid,int32_t vout,int64_t sato struct LP_utxoinfo *utxo = 0; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) { - printf("malformed addutxo\n"); + printf("malformed addutxo %d %d %d %d %d %d %d %d %d %d %d %d\n", coin == 0,coin[0] == 0,spendscript == 0,spendscript[0] == 0,coinaddr == 0,coinaddr[0] == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); return(0); } if ( (utxo= LP_utxofind(txid)) != 0 ) @@ -265,13 +265,11 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { - char url[4096],str[65],str2[65],*retstr; + char url[4096],str[65],str2[65]; sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&deposit=%s&dvout=%d&dvalue=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->deposittxid),utxo->depositvout,dstr(utxo->depositsatoshis),utxo->spendscript,utxo->coinaddr); - //if ( strlen(url) > 1024 ) + if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); - retstr = issue_curl(url); - printf("(%s)\n",retstr); - return(retstr); + return(issue_curl(url)); } void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) From 9ea4f7b3be80b24e63dbe20ecedb4c380ab7b9ea Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 18:57:25 +0300 Subject: [PATCH 0607/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 76dfecab8..137214eef 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -230,7 +230,7 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - utxo = LP_addutxo(jstr(item,"coin"),txid,jint(item,"vout"),j64bits(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),j64bits(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } From c652862c167bc7f714382e04033e773a84721ca2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 18:59:14 +0300 Subject: [PATCH 0608/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 137214eef..8edc1df01 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -456,7 +456,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) else if ( strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),j64bits(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); + LP_addutxo(jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } else printf("malformed request.(%s)\n",jprint(argjson,0)); From bd44a77a826e403e02294b834f08e9778009dbf9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 20:13:27 +0300 Subject: [PATCH 0609/2705] Test --- iguana/exchanges/LP_unspents.c | 78 +++++++++++++++++++++++++++------- iguana/exchanges/mm.c | 18 +++++++- iguana/m_mm | 2 +- 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 8edc1df01..5e5b2a0c3 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -19,9 +19,10 @@ struct LP_peerinfo UT_hash_handle hh; uint64_t ip_port; double profitmargin; - uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime; - char ipaddr[64]; + uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected; + int32_t pushsock,subsock; uint16_t port; + char ipaddr[64]; } *LP_peerinfos; struct LP_utxoinfo @@ -35,6 +36,12 @@ struct LP_utxoinfo uint16_t port; } *LP_utxoinfos; +char *nanomsg_tcpname(char *str,char *ipaddr,uint16_t port) +{ + sprintf(str,"tcp://%s:%u",ipaddr,port); + return(str); +} + cJSON *LP_peerjson(struct LP_peerinfo *peer) { cJSON *item = cJSON_CreateObject(); @@ -110,9 +117,9 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid) return(utxo); } -struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,double profitmargin) +struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin) { - uint32_t ipbits; char checkip[64]; struct LP_peerinfo *peer = 0; + uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) @@ -126,6 +133,25 @@ struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,double profitmargin) else { peer = calloc(1,sizeof(*peer)); + peer->pushsock = peer->subsock = pushsock = subsock = -1; + if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + { + if ( (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + { + timeout = 1000; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + peer->pushsock = pushsock; + peer->subsock = subsock; + nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); + nanomsg_tcpname(subaddr,peer->ipaddr,subport); + printf("adding (%s and %s) %d %d\n",pushaddr,subaddr,peer->pushsock,peer->subsock); + if ( nn_connect(peer->pushsock,pushaddr) >= 0 && nn_connect(peer->subsock,subaddr) >= 0 ) + peer->connected = (uint32_t)time(NULL); + } else nn_close(pushsock); + } peer->profitmargin = profitmargin; peer->ipbits = ipbits; strcpy(peer->ipaddr,ipaddr); @@ -185,7 +211,7 @@ struct LP_utxoinfo *LP_addutxo(char *coin,bits256 txid,int32_t vout,int64_t sato int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { - struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport; cJSON *array,*item; int32_t i,n=0; + struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -193,11 +219,11 @@ int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n for (i=0; ilasttime = now; @@ -214,7 +240,7 @@ int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { - struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -222,11 +248,11 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n for (i=0; inumpeers = otherpeers; if ( (othernumutxos= jint(argjson,"numutxos")) > 0 ) peer->numutxos = othernumutxos; - } else LP_addpeer(ipaddr,argport,jdouble(argjson,"profit")); + } else LP_addpeer(ipaddr,argport,pushport,subport,jdouble(argjson,"profit")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) @@ -468,9 +494,9 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) return(clonestr(jprint(retjson,1))); } -void LPinit(uint16_t myport,double profitmargin) +void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { - char *myipaddr=0; long filesize,n; int32_t i,lastn; struct LP_peerinfo *peer,*tmp,*mypeer=0; + char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,i,lastn,pullsock,pubsock; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); if ( profitmargin == 0. ) @@ -490,7 +516,27 @@ void LPinit(uint16_t myport,double profitmargin) n = strlen(myipaddr); if ( myipaddr[n-1] == '\n' ) myipaddr[--n] = 0; - mypeer = LP_addpeer(myipaddr,myport,profitmargin); + mypeer = LP_addpeer(myipaddr,myport,0,0,profitmargin); + pullsock = pubsock = -1; + nanomsg_tcpname(pushaddr,myipaddr,mypull); + nanomsg_tcpname(subaddr,myipaddr,mypub); + if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) + { + if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) + { + timeout = 10; + nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + maxsize = 1024 * 1024; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + } + if ( pullsock >= 0 ) + nn_close(pullsock); + if ( pubsock >= 0 ) + nn_close(pubsock); + } //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; i Date: Wed, 24 May 2017 20:19:57 +0300 Subject: [PATCH 0610/2705] Test --- iguana/exchanges/LP_unspents.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 5e5b2a0c3..ede9f77fa 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -219,8 +219,12 @@ int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n for (i=0; i 0 ) From 5487a2bb3596576c0ae1497e1cd98c50a9a12359 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 20:21:58 +0300 Subject: [PATCH 0611/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index ede9f77fa..b709cb5b8 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -134,6 +134,7 @@ struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,uint16_t pushport,uint { peer = calloc(1,sizeof(*peer)); peer->pushsock = peer->subsock = pushsock = subsock = -1; + strcpy(peer->ipaddr,ipaddr); if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { if ( (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) @@ -154,7 +155,6 @@ struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,uint16_t pushport,uint } peer->profitmargin = profitmargin; peer->ipbits = ipbits; - strcpy(peer->ipaddr,ipaddr); peer->port = port; peer->ip_port = ((uint64_t)port << 32) | ipbits; portable_mutex_lock(&LP_peermutex); From f75bed57fc5bdf3f162c4bb8fa1e9d391067ac62 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 20:43:40 +0300 Subject: [PATCH 0612/2705] Test --- iguana/exchanges/LP_unspents.c | 75 +++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b709cb5b8..7e0157a6c 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -12,7 +12,7 @@ char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; portable_mutex_t LP_peermutex,LP_utxomutex; -int32_t LP_numpeers,LP_numutxos; +int32_t LP_numpeers,LP_numutxos,LP_mypubsock = -1; struct LP_peerinfo { @@ -42,6 +42,28 @@ char *nanomsg_tcpname(char *str,char *ipaddr,uint16_t port) return(str); } +int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) +{ + int32_t sentbytes,len,i; struct nn_pollfd pfd; + for (i=0; i<100; i++) + { + pfd.fd = sock; + pfd.events = NN_POLLOUT; + if ( nn_poll(&pfd,1,100) > 0 ) + { + len = (int32_t)strlen(msg) + 1; + if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) + printf("LP_send sent %d instead of %d\n",sentbytes,len); + if ( freeflag != 0 ) + free(msg); + return(sentbytes); + } + usleep(1000); + } + printf("error LP_send\n"); + return(-1); +} + cJSON *LP_peerjson(struct LP_peerinfo *peer) { cJSON *item = cJSON_CreateObject(); @@ -117,7 +139,7 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid) return(utxo); } -struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin) +struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin) { uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; ipbits = (uint32_t)calc_ipbits(ipaddr); @@ -162,12 +184,14 @@ struct LP_peerinfo *LP_addpeer(char *ipaddr,uint16_t port,uint16_t pushport,uint LP_numpeers++; portable_mutex_unlock(&LP_peermutex); printf("_LPaddpeer %s -> numpeers.%d\n",ipaddr,LP_numpeers); + if ( mypubsock >= 0 ) + LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); } } return(peer); } -struct LP_utxoinfo *LP_addutxo(char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) +struct LP_utxoinfo *LP_addutxo(int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) { struct LP_utxoinfo *utxo = 0; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) @@ -205,11 +229,13 @@ struct LP_utxoinfo *LP_addutxo(char *coin,bits256 txid,int32_t vout,int64_t sato LP_numutxos++; portable_mutex_unlock(&LP_utxomutex); printf("%s:%u LP_addutxo.(%.8f %.8f)\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis)); + if ( mypubsock >= 0 ) + LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); } return(utxo); } -int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_peersparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; if ( (array= cJSON_Parse(retstr)) != 0 ) @@ -227,7 +253,7 @@ int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(argipaddr,argport,pushport,subport,jdouble(item,"profit")); + peer = LP_addpeer(mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit")); if ( peer != 0 ) { peer->lasttime = now; @@ -242,7 +268,7 @@ int32_t LP_peersparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n return(n); } -int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; if ( (array= cJSON_Parse(retstr)) != 0 ) @@ -260,11 +286,11 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(argipaddr,argport,pushport,subport,jdouble(item,"profit")); + peer = LP_addpeer(mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit")); if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - utxo = LP_addutxo(jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } @@ -306,7 +332,7 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx return(issue_curl(url)); } -void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) +void LP_peersquery(int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); @@ -315,7 +341,7 @@ void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t my if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers,LP_numutxos)) != 0 ) { now = (uint32_t)time(NULL); - LP_peersparse(destipaddr,destport,retstr,now); + LP_peersparse(mypubsock,destipaddr,destport,retstr,now); free(retstr); HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -333,7 +359,7 @@ void LP_peersquery(char *destipaddr,uint16_t destport,char *myipaddr,uint16_t my peer->errors++; } -void LP_utxosquery(char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) +void LP_utxosquery(int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); @@ -344,7 +370,7 @@ void LP_utxosquery(char *destipaddr,uint16_t destport,char *coin,int32_t lastn,c if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,LP_numpeers,LP_numutxos)) != 0 ) { now = (uint32_t)time(NULL); - LP_utxosparse(destipaddr,destport,retstr,now); + LP_utxosparse(mypubsock,destipaddr,destport,retstr,now); free(retstr); i = 0; if ( lastn >= LP_numutxos ) @@ -397,7 +423,7 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) return(mini); } -uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifstr) +uint64_t LP_privkey_init(int32_t mypubsock,char *coin,uint8_t addrtype,char *passphrase,char *wifstr) { char *retstr,coinaddr[64],*script; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33]; if ( passphrase != 0 ) @@ -451,7 +477,7 @@ uint64_t LP_privkey_init(char *coin,uint8_t addrtype,char *passphrase,char *wifs { value = values[i]; values[i] = 0, used++; - LP_addutxo(coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); + LP_addutxo(mypubsock,coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); total += value; } } @@ -484,7 +510,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) peer->numpeers = otherpeers; if ( (othernumutxos= jint(argjson,"numutxos")) > 0 ) peer->numutxos = othernumutxos; - } else LP_addpeer(ipaddr,argport,pushport,subport,jdouble(argjson,"profit")); + } else LP_addpeer(LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) @@ -494,7 +520,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) else if ( strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); + LP_addutxo(LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } else printf("malformed request.(%s)\n",jprint(argjson,0)); @@ -508,7 +534,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { - char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,i,lastn,pullsock,pubsock; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; + char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); if ( profitmargin == 0. ) @@ -528,7 +554,6 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) n = strlen(myipaddr); if ( myipaddr[n-1] == '\n' ) myipaddr[--n] = 0; - mypeer = LP_addpeer(myipaddr,myport,0,0,profitmargin); pullsock = pubsock = -1; nanomsg_tcpname(pushaddr,myipaddr,mypull); nanomsg_tcpname(subaddr,myipaddr,mypub); @@ -545,16 +570,18 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } if ( pullsock >= 0 ) - nn_close(pullsock); + nn_close(pullsock), pullsock = -1; if ( pubsock >= 0 ) - nn_close(pubsock); + nn_close(pubsock), pubsock = -1; } + LP_mypubsock = pubsock; + mypeer = LP_addpeer(pubsock,myipaddr,myport,0,0,profitmargin); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; i 25 ) continue; - LP_peersquery(default_LPnodes[i],myport,myipaddr,myport,profitmargin); + LP_peersquery(pubsock,default_LPnodes[i],myport,myipaddr,myport,profitmargin); } } } @@ -563,7 +590,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) printf("couldnt get myipaddr\n"); exit(-1); } - LP_privkey_init("KMD",60,"test",""); + LP_privkey_init(pubsock,"KMD",60,"test",""); printf("utxos.(%s)\n",LP_utxos("",10000)); while ( 1 ) { @@ -578,7 +605,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,LP_numpeers); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_peersquery(peer->ipaddr,peer->port,myipaddr,myport,profitmargin); + LP_peersquery(pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } if ( peer->numutxos != LP_numutxos ) { @@ -587,7 +614,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) lastn = LP_PROPAGATION_SLACK * 2; printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,LP_numutxos,lastn); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_utxosquery(peer->ipaddr,peer->port,"",lastn,myipaddr,myport,profitmargin); + LP_utxosquery(pubsock,peer->ipaddr,peer->port,"",lastn,myipaddr,myport,profitmargin); } } sleep(LP_numpeers); From 7cadadf44f0f1ec3ab9440102dfc5b00bba34cdb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 20:53:18 +0300 Subject: [PATCH 0613/2705] Test --- iguana/exchanges/LP_unspents.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 7e0157a6c..52eb7070e 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -534,7 +534,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { - char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; + char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); if ( profitmargin == 0. ) @@ -594,6 +594,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) printf("utxos.(%s)\n",LP_utxos("",10000)); while ( 1 ) { + nonz = 0; if ( mypeer != 0 ) { mypeer->numpeers = LP_numpeers; @@ -616,7 +617,22 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_utxosquery(pubsock,peer->ipaddr,peer->port,"",lastn,myipaddr,myport,profitmargin); } + while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) + { + nonz++; + printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,ptr); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } + } + while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + { + nonz++; + printf("PULL.[%d] %s\n",recvsize,ptr); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; } - sleep(LP_numpeers); + if ( nonz == 0 ) + sleep(LP_numpeers); } } From 6429226e73d148eeb38940f5640a30d7411537dd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 20:56:06 +0300 Subject: [PATCH 0614/2705] Test --- iguana/exchanges/LP_unspents.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 52eb7070e..9a76b6a15 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -54,6 +54,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) len = (int32_t)strlen(msg) + 1; if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); + else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); return(sentbytes); @@ -620,7 +621,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,ptr); + printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } @@ -628,7 +629,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - printf("PULL.[%d] %s\n",recvsize,ptr); + printf("PULL.[%d] %s\n",recvsize,(char *)ptr); if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } From 4fdd34e95f4428cb9dd01cfc15672fdfea4df91d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 20:56:50 +0300 Subject: [PATCH 0615/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 9a76b6a15..2c4051d4f 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -184,7 +184,7 @@ struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer); LP_numpeers++; portable_mutex_unlock(&LP_peermutex); - printf("_LPaddpeer %s -> numpeers.%d\n",ipaddr,LP_numpeers); + printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d\n",ipaddr,LP_numpeers,mypubsock); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); } From 5516d647bbb8b9b2f3ff4c7304eeb99cacb2725b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 20:58:11 +0300 Subject: [PATCH 0616/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 2c4051d4f..cfe9b091f 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -569,7 +569,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) timeout = 1; maxsize = 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - } + } else printf("error binding to (%s).%d (%s).%d\n",pushaddr,pullsock,subaddr,pubsock); if ( pullsock >= 0 ) nn_close(pullsock), pullsock = -1; if ( pubsock >= 0 ) From 6b38dc3684f1625fb0174eb309da35823115ba99 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 20:59:08 +0300 Subject: [PATCH 0617/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index cfe9b091f..781012f21 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -574,7 +574,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) nn_close(pullsock), pullsock = -1; if ( pubsock >= 0 ) nn_close(pubsock), pubsock = -1; - } + } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; mypeer = LP_addpeer(pubsock,myipaddr,myport,0,0,profitmargin); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); From 27acdf104237336cf491a49e607908b52a8809bd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:00:42 +0300 Subject: [PATCH 0618/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 781012f21..2d67a70e8 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -584,8 +584,8 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) continue; LP_peersquery(pubsock,default_LPnodes[i],myport,myipaddr,myport,profitmargin); } - } - } + } else printf("error getting myipaddr\n"); + } else printf("error issuing curl\n"); if ( myipaddr == 0 ) { printf("couldnt get myipaddr\n"); From ea4c652c95fbe4744171bf9f8457c264a980f750 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:01:32 +0300 Subject: [PATCH 0619/2705] Test --- iguana/exchanges/LP_unspents.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 2d67a70e8..148d49ffc 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -558,6 +558,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) pullsock = pubsock = -1; nanomsg_tcpname(pushaddr,myipaddr,mypull); nanomsg_tcpname(subaddr,myipaddr,mypub); + printf(">>>>>>>>> myipaddr.%s (%s %s)\n",myipaddr,pushaddr,subaddr); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) From eeb1b4bf0f9ce4579991499b3e7529d942394393 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:02:01 +0300 Subject: [PATCH 0620/2705] Test --- iguana/exchanges/LP_unspents.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 148d49ffc..91e431023 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -570,11 +570,15 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) timeout = 1; maxsize = 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - } else printf("error binding to (%s).%d (%s).%d\n",pushaddr,pullsock,subaddr,pubsock); - if ( pullsock >= 0 ) - nn_close(pullsock), pullsock = -1; - if ( pubsock >= 0 ) - nn_close(pubsock), pubsock = -1; + } + else + { + printf("error binding to (%s).%d (%s).%d\n",pushaddr,pullsock,subaddr,pubsock); + if ( pullsock >= 0 ) + nn_close(pullsock), pullsock = -1; + if ( pubsock >= 0 ) + nn_close(pubsock), pubsock = -1; + } } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; mypeer = LP_addpeer(pubsock,myipaddr,myport,0,0,profitmargin); From 60230d60ef179ad8bc6e904342134504508626d1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:08:28 +0300 Subject: [PATCH 0621/2705] Test --- iguana/exchanges/LP_unspents.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 91e431023..d7cbfd55d 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -11,7 +11,7 @@ #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; -portable_mutex_t LP_peermutex,LP_utxomutex; +portable_mutex_t LP_peermutex,LP_utxomutex,LP_jsonmutex; int32_t LP_numpeers,LP_numutxos,LP_mypubsock = -1; struct LP_peerinfo @@ -499,6 +499,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) return(clonestr("{\"error\":\"need method in request\"}")); else { + portable_mutex_lock(&LP_jsonmutex); if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { if ( (pushport= juint(argjson,"push")) == 0 ) @@ -525,6 +526,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } else printf("malformed request.(%s)\n",jprint(argjson,0)); + portable_mutex_unlock(&LP_jsonmutex); } if ( retstr != 0 ) return(retstr); @@ -535,9 +537,10 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { - char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; + char *myipaddr=0,*retstr; long filesize,n; int32_t timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); + portable_mutex_init(&LP_jsonmutex); if ( profitmargin == 0. ) { profitmargin = 0.01; @@ -627,6 +630,12 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { nonz++; printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) + { + if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypub)) != 0 ) + free(retstr); + free_json(argjson); + } if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } From 0aba5872664a3c099d4b2fb981a22763c82c62f6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:27:08 +0300 Subject: [PATCH 0622/2705] Test --- iguana/exchanges/LP_unspents.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index d7cbfd55d..0f99afe4e 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -629,13 +629,15 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { - if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypub)) != 0 ) + if ( 0 && (retstr= stats_JSON(argjson,"127.0.0.1",mypub)) != 0 ) + { + printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); + } free_json(argjson); - } + } else printf("error parsing.(%s)\n",(char *)ptr); if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } @@ -651,3 +653,16 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) sleep(LP_numpeers); } } + +#ifdef __APPLE__ +int32_t nn_bind() { return(-1); } +int32_t nn_close() { return(-1); } +int32_t nn_connect() { return(-1); } +int32_t nn_freemsg() { return(-1); } +int32_t nn_poll() { return(-1); } +int32_t nn_recv() { return(-1); } +int32_t nn_send() { return(-1); } +int32_t nn_setsockopt() { return(-1); } +int32_t nn_socket() { return(-1); } + +#endif From 4b9f2c0b3bc2e19d62b1a355a112f0502ba2a898 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:34:38 +0300 Subject: [PATCH 0623/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 0f99afe4e..aa99b3147 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -631,7 +631,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { - if ( 0 && (retstr= stats_JSON(argjson,"127.0.0.1",mypub)) != 0 ) + if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypub)) != 0 ) { printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); From b1f58fa5a47bc036b2895eaf5f240d39119aebfb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:43:14 +0300 Subject: [PATCH 0624/2705] Test --- iguana/exchanges/LP_unspents.c | 47 +++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index aa99b3147..0d02df624 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -65,20 +65,46 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) return(-1); } +struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) +{ + struct LP_peerinfo *peer=0; uint64_t ip_port; + ip_port = ((uint64_t)port << 32) | ipbits; + portable_mutex_lock(&LP_peermutex); + HASH_FIND(hh,LP_peerinfos,&ip_port,sizeof(ip_port),peer); + portable_mutex_unlock(&LP_peermutex); + return(peer); +} + +struct LP_utxoinfo *LP_utxofind(bits256 txid) +{ + struct LP_utxoinfo *utxo=0; + portable_mutex_lock(&LP_utxomutex); + HASH_FIND(hh,LP_utxoinfos,&txid,sizeof(txid),utxo); + portable_mutex_unlock(&LP_utxomutex); + return(utxo); +} + cJSON *LP_peerjson(struct LP_peerinfo *peer) { cJSON *item = cJSON_CreateObject(); jaddstr(item,"ipaddr",peer->ipaddr); jaddnum(item,"port",peer->port); jaddnum(item,"profit",peer->profitmargin); + jaddnum(item,"numpeers",peer->numpeers); + jaddnum(item,"numutxos",peer->numutxos); return(item); } cJSON *LP_utxojson(struct LP_utxoinfo *utxo) { - cJSON *item = cJSON_CreateObject(); + struct LP_peerinfo *peer; cJSON *item = cJSON_CreateObject(); jaddstr(item,"ipaddr",utxo->ipaddr); jaddnum(item,"port",utxo->port); + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(utxo->ipaddr),utxo->port)) != 0 ) + { + jaddnum(item,"numpeers",peer->numpeers); + jaddnum(item,"numutxos",peer->numutxos); + } jaddnum(item,"profit",utxo->profitmargin); jaddstr(item,"coin",utxo->coin); jaddstr(item,"address",utxo->coinaddr); @@ -121,25 +147,6 @@ char *LP_utxos(char *coin,int32_t lastn) return(jprint(utxosjson,1)); } -struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) -{ - struct LP_peerinfo *peer=0; uint64_t ip_port; - ip_port = ((uint64_t)port << 32) | ipbits; - portable_mutex_lock(&LP_peermutex); - HASH_FIND(hh,LP_peerinfos,&ip_port,sizeof(ip_port),peer); - portable_mutex_unlock(&LP_peermutex); - return(peer); -} - -struct LP_utxoinfo *LP_utxofind(bits256 txid) -{ - struct LP_utxoinfo *utxo=0; - portable_mutex_lock(&LP_utxomutex); - HASH_FIND(hh,LP_utxoinfos,&txid,sizeof(txid),utxo); - portable_mutex_unlock(&LP_utxomutex); - return(utxo); -} - struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin) { uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; From d4b50f53649ec536ccf63ae37286db1197b5dde6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:46:03 +0300 Subject: [PATCH 0625/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 0d02df624..ed0ba0726 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -515,9 +515,9 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) subport = argport + 2; if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) { - if ( (otherpeers= jint(argjson,"numpeers")) > 0 ) + if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) peer->numpeers = otherpeers; - if ( (othernumutxos= jint(argjson,"numutxos")) > 0 ) + if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) peer->numutxos = othernumutxos; } else LP_addpeer(LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit")); if ( strcmp(method,"getpeers") == 0 ) From 7ad95b5150f7d91e331b8cf7cee2e3679416a246 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:54:31 +0300 Subject: [PATCH 0626/2705] Test --- iguana/exchanges/LP_unspents.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index ed0ba0726..f81ef3097 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -147,7 +147,7 @@ char *LP_utxos(char *coin,int32_t lastn) return(jprint(utxosjson,1)); } -struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin) +struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) { uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; ipbits = (uint32_t)calc_ipbits(ipaddr); @@ -159,6 +159,10 @@ struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint { if ( peer->profitmargin == 0. ) peer->profitmargin = profitmargin; + if ( numpeers > peer->numpeers ) + peer->numpeers = numpeers; + if ( numutxos > peer->numutxos ) + peer->numutxos = numutxos; } else { @@ -261,7 +265,7 @@ int32_t LP_peersparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit")); + peer = LP_addpeer(mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); if ( peer != 0 ) { peer->lasttime = now; @@ -294,7 +298,7 @@ int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit")); + peer = LP_addpeer(mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); @@ -348,6 +352,7 @@ void LP_peersquery(int32_t mypubsock,char *destipaddr,uint16_t destport,char *my return; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers,LP_numutxos)) != 0 ) { + printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); LP_peersparse(mypubsock,destipaddr,destport,retstr,now); free(retstr); @@ -519,7 +524,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) peer->numpeers = otherpeers; if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) peer->numutxos = othernumutxos; - } else LP_addpeer(LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit")); + } else LP_addpeer(LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) @@ -591,7 +596,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) } } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; - mypeer = LP_addpeer(pubsock,myipaddr,myport,0,0,profitmargin); + mypeer = LP_addpeer(pubsock,myipaddr,myport,0,0,profitmargin,LP_numpeers,LP_numutxos); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; inumpeers = LP_numpeers; + if ( mypeer->numutxos != LP_numutxos ) + printf("numutxos %d -> %d\n",mypeer->numutxos,LP_numutxos); mypeer->numutxos = LP_numutxos; } HASH_ITER(hh,LP_peerinfos,peer,tmp) From 6a979aac65ea9cae6fce3c7dd1ac4a6d0658891f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 21:59:41 +0300 Subject: [PATCH 0627/2705] Test --- iguana/exchanges/LP_unspents.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index f81ef3097..556d8ed10 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -23,7 +23,7 @@ struct LP_peerinfo int32_t pushsock,subsock; uint16_t port; char ipaddr[64]; -} *LP_peerinfos; +} *LP_peerinfos,*LP_mypeer; struct LP_utxoinfo { @@ -203,7 +203,7 @@ struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint return(peer); } -struct LP_utxoinfo *LP_addutxo(int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) +struct LP_utxoinfo *LP_addutxo(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) { struct LP_utxoinfo *utxo = 0; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) @@ -240,9 +240,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t mypubsock,char *coin,bits256 txid,int32_t HASH_ADD(hh,LP_utxoinfos,txid,sizeof(txid),utxo); LP_numutxos++; portable_mutex_unlock(&LP_utxomutex); - printf("%s:%u LP_addutxo.(%.8f %.8f)\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis)); + printf("%s:%u LP_addutxo.(%.8f %.8f) numutxos.%d\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis),LP_numutxos); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); + if ( mypeer != 0 ) + mypeer->numutxos = LP_numutxos; } return(utxo); } @@ -280,7 +282,7 @@ int32_t LP_peersparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char return(n); } -int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; if ( (array= cJSON_Parse(retstr)) != 0 ) @@ -302,7 +304,7 @@ int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - utxo = LP_addutxo(mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } @@ -372,7 +374,7 @@ void LP_peersquery(int32_t mypubsock,char *destipaddr,uint16_t destport,char *my peer->errors++; } -void LP_utxosquery(int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) +void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); @@ -383,7 +385,7 @@ void LP_utxosquery(int32_t mypubsock,char *destipaddr,uint16_t destport,char *co if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,LP_numpeers,LP_numutxos)) != 0 ) { now = (uint32_t)time(NULL); - LP_utxosparse(mypubsock,destipaddr,destport,retstr,now); + LP_utxosparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); i = 0; if ( lastn >= LP_numutxos ) @@ -436,7 +438,7 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) return(mini); } -uint64_t LP_privkey_init(int32_t mypubsock,char *coin,uint8_t addrtype,char *passphrase,char *wifstr) +uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,uint8_t addrtype,char *passphrase,char *wifstr) { char *retstr,coinaddr[64],*script; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33]; if ( passphrase != 0 ) @@ -490,7 +492,7 @@ uint64_t LP_privkey_init(int32_t mypubsock,char *coin,uint8_t addrtype,char *pas { value = values[i]; values[i] = 0, used++; - LP_addutxo(mypubsock,coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); + LP_addutxo(mypeer,mypubsock,coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); total += value; } } @@ -534,7 +536,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) else if ( strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); + LP_addutxo(LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } else printf("malformed request.(%s)\n",jprint(argjson,0)); @@ -596,7 +598,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) } } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; - mypeer = LP_addpeer(pubsock,myipaddr,myport,0,0,profitmargin,LP_numpeers,LP_numutxos); + LP_mypeer = mypeer = LP_addpeer(pubsock,myipaddr,myport,0,0,profitmargin,LP_numpeers,LP_numutxos); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; iipaddr,peer->numutxos,LP_numutxos,lastn); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_utxosquery(pubsock,peer->ipaddr,peer->port,"",lastn,myipaddr,myport,profitmargin); + LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,myipaddr,myport,profitmargin); } while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) { From 0fb0ea6453a699ee87eec464248c7ed3c80e46fe Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:07:10 +0300 Subject: [PATCH 0628/2705] Test --- iguana/exchanges/LP_unspents.c | 81 ++++++++++++++++------------------ 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 556d8ed10..e4de15d98 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -12,7 +12,7 @@ char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; portable_mutex_t LP_peermutex,LP_utxomutex,LP_jsonmutex; -int32_t LP_numpeers,LP_numutxos,LP_mypubsock = -1; +int32_t LP_mypubsock = -1; struct LP_peerinfo { @@ -128,13 +128,13 @@ char *LP_peers() return(jprint(peersjson,1)); } -char *LP_utxos(char *coin,int32_t lastn) +char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) { int32_t i,firsti; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); i = 0; - if ( lastn >= LP_numutxos ) + if ( lastn >= mypeer->numutxos ) firsti = -1; - else firsti = (LP_numutxos - lastn); + else firsti = (mypeer->numutxos - lastn); HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { if ( i++ < firsti ) @@ -147,7 +147,7 @@ char *LP_utxos(char *coin,int32_t lastn) return(jprint(utxosjson,1)); } -struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) +struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) { uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; ipbits = (uint32_t)calc_ipbits(ipaddr); @@ -193,9 +193,12 @@ struct LP_peerinfo *LP_addpeer(int32_t mypubsock,char *ipaddr,uint16_t port,uint peer->ip_port = ((uint64_t)port << 32) | ipbits; portable_mutex_lock(&LP_peermutex); HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer); - LP_numpeers++; + if ( mypeer != 0 ) + { + mypeer->numpeers++; + printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d\n",ipaddr,mypeer->numpeers,mypubsock); + } portable_mutex_unlock(&LP_peermutex); - printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d\n",ipaddr,LP_numpeers,mypubsock); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); } @@ -238,18 +241,19 @@ struct LP_utxoinfo *LP_addutxo(struct LP_peerinfo *mypeer,int32_t mypubsock,char utxo->depositsatoshis = depositsatoshis; portable_mutex_lock(&LP_utxomutex); HASH_ADD(hh,LP_utxoinfos,txid,sizeof(txid),utxo); - LP_numutxos++; + if ( mypeer != 0 ) + { + mypeer->numutxos++; + printf("%s:%u LP_addutxo.(%.8f %.8f) numutxos.%d\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis),mypeer->numutxos); + } portable_mutex_unlock(&LP_utxomutex); - printf("%s:%u LP_addutxo.(%.8f %.8f) numutxos.%d\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis),LP_numutxos); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - if ( mypeer != 0 ) - mypeer->numutxos = LP_numutxos; } return(utxo); } -int32_t LP_peersparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; if ( (array= cJSON_Parse(retstr)) != 0 ) @@ -267,7 +271,7 @@ int32_t LP_peersparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); if ( peer != 0 ) { peer->lasttime = now; @@ -300,7 +304,7 @@ int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); @@ -346,17 +350,17 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx return(issue_curl(url)); } -void LP_peersquery(int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) +void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( peer != 0 && peer->errors > 0 ) return; - if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,LP_numpeers,LP_numutxos)) != 0 ) + if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) { printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); - LP_peersparse(mypubsock,destipaddr,destport,retstr,now); + LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -378,19 +382,19 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr { char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); - if ( peer != 0 && peer->errors > 0 ) + if ( (peer != 0 && peer->errors > 0) || mypeer == 0 ) return; if ( coin == 0 ) coin = ""; - if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,LP_numpeers,LP_numutxos)) != 0 ) + if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) { now = (uint32_t)time(NULL); LP_utxosparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); i = 0; - if ( lastn >= LP_numutxos ) + if ( lastn >= mypeer->numutxos ) firsti = -1; - else firsti = (LP_numutxos - lastn); + else firsti = (mypeer->numutxos - lastn); HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { if ( i++ < firsti ) @@ -526,11 +530,11 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) peer->numpeers = otherpeers; if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) peer->numutxos = othernumutxos; - } else LP_addpeer(LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); + } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) - retstr = LP_utxos(coin,jint(argjson,"lastn")); + retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( strcmp(method,"notifyutxo") == 0 ) @@ -598,47 +602,40 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) } } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; - LP_mypeer = mypeer = LP_addpeer(pubsock,myipaddr,myport,0,0,profitmargin,LP_numpeers,LP_numutxos); + LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,mypeer->numpeers,mypeer->numutxos); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; i 25 ) continue; - LP_peersquery(pubsock,default_LPnodes[i],myport,myipaddr,myport,profitmargin); + LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,myipaddr,myport,profitmargin); } } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); - if ( myipaddr == 0 ) + if ( myipaddr == 0 || mypeer == 0 ) { - printf("couldnt get myipaddr\n"); + printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); exit(-1); } LP_privkey_init(mypeer,pubsock,"KMD",60,"test",""); - printf("utxos.(%s)\n",LP_utxos("",10000)); + printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); while ( 1 ) { nonz = 0; - if ( mypeer != 0 ) - { - mypeer->numpeers = LP_numpeers; - if ( mypeer->numutxos != LP_numutxos ) - printf("numutxos %d -> %d\n",mypeer->numutxos,LP_numutxos); - mypeer->numutxos = LP_numutxos; - } HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers != LP_numpeers ) + if ( peer->numpeers != mypeer->numpeers ) { - printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,LP_numpeers); + printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_peersquery(pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); + LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - if ( peer->numutxos != LP_numutxos ) + if ( peer->numutxos != mypeer->numutxos ) { - lastn = peer->numutxos - LP_numutxos + LP_PROPAGATION_SLACK; + lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; if ( lastn < 0 ) lastn = LP_PROPAGATION_SLACK * 2; - printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,LP_numutxos,lastn); + printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,myipaddr,myport,profitmargin); } @@ -666,7 +663,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) nn_freemsg(ptr), ptr = 0; } if ( nonz == 0 ) - sleep(LP_numpeers); + sleep(mypeer->numpeers + 1); } } From 339f1d1103f1315dc1b7ce095c4e0e9b6bbfa11e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:07:54 +0300 Subject: [PATCH 0629/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index e4de15d98..b6ab7f0d4 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -602,7 +602,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) } } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; - LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,mypeer->numpeers,mypeer->numutxos); + LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; i Date: Wed, 24 May 2017 22:21:07 +0300 Subject: [PATCH 0630/2705] Test --- iguana/exchanges/LP_unspents.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b6ab7f0d4..227a76bfa 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -358,7 +358,7 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr return; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) { - printf("got.(%s)\n",retstr); + //printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); @@ -564,11 +564,6 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) profitmargin = 0.01; printf("default profit margin %f\n",profitmargin); } - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) - { - printf("error launching stats rpcloop for port.%u\n",myport); - exit(-1); - } if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) { if ( (myipaddr= OS_filestr(&filesize,"/tmp/myipaddr")) != 0 && myipaddr[0] != 0 ) @@ -617,6 +612,11 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); exit(-1); } + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",myport); + exit(-1); + } LP_privkey_init(mypeer,pubsock,"KMD",60,"test",""); printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); while ( 1 ) @@ -624,7 +624,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) nonz = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers != mypeer->numpeers ) + //if ( peer->numpeers != mypeer->numpeers ) { printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) From 544fde169359aabd162878110642ecb5c3640420 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:25:38 +0300 Subject: [PATCH 0631/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 227a76bfa..f2dc8caac 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -597,7 +597,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) } } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; - LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); + LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,1,0); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; inumpeers != mypeer->numpeers ) + if ( peer->numpeers != mypeer->numpeers ) { printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) From 6a2b6ff5e51965807564b6c1d962dded80b0dd89 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:27:53 +0300 Subject: [PATCH 0632/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index f2dc8caac..2206b75d6 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -197,7 +197,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char { mypeer->numpeers++; printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d\n",ipaddr,mypeer->numpeers,mypubsock); - } + } else peer->numpeers = 1; portable_mutex_unlock(&LP_peermutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); From 43e0285f6eb90b42ab28903b3900ed00db389731 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:35:03 +0300 Subject: [PATCH 0633/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 2206b75d6..87eace4e9 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -624,7 +624,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) nonz = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers != mypeer->numpeers ) + if ( peer->numpeers != mypeer->numpeers || (rand() % 10) == 0 ) { printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) From 4cecf4e742a25059fbd26e4802833ffb180ea64b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:37:40 +0300 Subject: [PATCH 0634/2705] Test --- iguana/exchanges/LP_unspents.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 87eace4e9..25c290877 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -90,21 +90,14 @@ cJSON *LP_peerjson(struct LP_peerinfo *peer) jaddstr(item,"ipaddr",peer->ipaddr); jaddnum(item,"port",peer->port); jaddnum(item,"profit",peer->profitmargin); - jaddnum(item,"numpeers",peer->numpeers); - jaddnum(item,"numutxos",peer->numutxos); return(item); } cJSON *LP_utxojson(struct LP_utxoinfo *utxo) { - struct LP_peerinfo *peer; cJSON *item = cJSON_CreateObject(); + cJSON *item = cJSON_CreateObject(); jaddstr(item,"ipaddr",utxo->ipaddr); jaddnum(item,"port",utxo->port); - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(utxo->ipaddr),utxo->port)) != 0 ) - { - jaddnum(item,"numpeers",peer->numpeers); - jaddnum(item,"numutxos",peer->numutxos); - } jaddnum(item,"profit",utxo->profitmargin); jaddstr(item,"coin",utxo->coin); jaddstr(item,"address",utxo->coinaddr); From 38b24c7cf21964a1159040d0a121059b58ec1d61 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:43:50 +0300 Subject: [PATCH 0635/2705] Test --- iguana/exchanges/LP_unspents.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 25c290877..5e88a9805 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -317,13 +317,14 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por { char url[512]; sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); + printf("send.(%s)\n",url); return(issue_curl(url)); } -char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) +char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f",destip,destport,coin,lastn,ipaddr,port,profitmargin); return(issue_curl(url)); } @@ -379,7 +380,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr return; if ( coin == 0 ) coin = ""; - if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) + if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit)) != 0 ) { now = (uint32_t)time(NULL); LP_utxosparse(mypeer,mypubsock,destipaddr,destport,retstr,now); From b53513a41bfd01112da0b7079047e7e327518e3b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:47:59 +0300 Subject: [PATCH 0636/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 5e88a9805..e3353fc20 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -523,7 +523,11 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) peer->numpeers = otherpeers; if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) + { + printf("change.(%s) numutxos.%d -> %d\n",peer->ipaddr,peer->numutxos,othernumutxos); peer->numutxos = othernumutxos; + } + printf("peer.(%s) found (%d %d) (%d %d)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos); } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); From c25a0017c7c3e960a44c673e6530b547cfd94b33 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:49:14 +0300 Subject: [PATCH 0637/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index e3353fc20..569c7bf43 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -527,7 +527,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) printf("change.(%s) numutxos.%d -> %d\n",peer->ipaddr,peer->numutxos,othernumutxos); peer->numutxos = othernumutxos; } - printf("peer.(%s) found (%d %d) (%d %d)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos); + printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); From 329d66413f82141e43f0f779f73db099d2a287ab Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:51:40 +0300 Subject: [PATCH 0638/2705] Test --- iguana/exchanges/LP_unspents.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 569c7bf43..8dcd8082b 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -321,10 +321,10 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por return(issue_curl(url)); } -char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin) +char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f",destip,destport,coin,lastn,ipaddr,port,profitmargin); + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); return(issue_curl(url)); } @@ -380,7 +380,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr return; if ( coin == 0 ) coin = ""; - if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit)) != 0 ) + if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) { now = (uint32_t)time(NULL); LP_utxosparse(mypeer,mypubsock,destipaddr,destport,retstr,now); From b16d1faf43bd4070d92c217d663969c9c01dbd9b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 22:58:42 +0300 Subject: [PATCH 0639/2705] Test --- iguana/exchanges/LP_unspents.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 8dcd8082b..54f01ecc0 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -190,7 +190,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char { mypeer->numpeers++; printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d\n",ipaddr,mypeer->numpeers,mypubsock); - } else peer->numpeers = 1; + } else peer->numpeers = 1; // will become mypeer portable_mutex_unlock(&LP_peermutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); @@ -628,7 +628,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - if ( peer->numutxos != mypeer->numutxos ) + if ( 0 && peer->numutxos != mypeer->numutxos ) { lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; if ( lastn < 0 ) From 62bb9b012be13c6137fd70f37feba0882dc2df77 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:01:48 +0300 Subject: [PATCH 0640/2705] Test --- iguana/exchanges/LP_unspents.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 54f01ecc0..2b0909889 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -317,7 +317,7 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por { char url[512]; sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - printf("send.(%s)\n",url); + //printf("send.(%s)\n",url); return(issue_curl(url)); } @@ -527,7 +527,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) printf("change.(%s) numutxos.%d -> %d\n",peer->ipaddr,peer->numutxos,othernumutxos); peer->numutxos = othernumutxos; } - printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); + //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); @@ -624,7 +624,8 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { if ( peer->numpeers != mypeer->numpeers || (rand() % 10) == 0 ) { - printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); + if ( peer->numpeers != mypeer->numpeers ) + printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } From ce080ace44d3dd002f335b22bb3e2651a9344375 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:03:26 +0300 Subject: [PATCH 0641/2705] Test --- iguana/exchanges/LP_unspents.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 2b0909889..0b5621f5e 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -595,7 +595,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) } } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; - LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,1,0); + LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); for (i=0; inumpeers = 1; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); From 23108b13a3b9aa6817eafeb830404fe26460d47c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:07:47 +0300 Subject: [PATCH 0642/2705] Test --- iguana/exchanges/LP_unspents.c | 1 - 1 file changed, 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 0b5621f5e..a1d828af6 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -610,7 +610,6 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); exit(-1); } - mypeer->numpeers = 1; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); From 6495a1c54456705f3220da6ce64ce86def927f9a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:12:38 +0300 Subject: [PATCH 0643/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index a1d828af6..7de38ad1a 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -524,7 +524,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) peer->numpeers = otherpeers; if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) { - printf("change.(%s) numutxos.%d -> %d\n",peer->ipaddr,peer->numutxos,othernumutxos); + printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer->numutxos); peer->numutxos = othernumutxos; } //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); From a0c238c9faf624a6db7f63a448864f3a6fdc9052 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:14:18 +0300 Subject: [PATCH 0644/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 7de38ad1a..27bd29447 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -189,7 +189,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char if ( mypeer != 0 ) { mypeer->numpeers++; - printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d\n",ipaddr,mypeer->numpeers,mypubsock); + printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d other.(%d %d)\n",ipaddr,mypeer->numpeers,mypubsock,numpeers,numutxos); } else peer->numpeers = 1; // will become mypeer portable_mutex_unlock(&LP_peermutex); if ( mypubsock >= 0 ) From 894914a81e29ab8a67ca1f45a6fc37e1a59d19a0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:15:00 +0300 Subject: [PATCH 0645/2705] Test --- iguana/exchanges/LP_unspents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 27bd29447..b0e7c7671 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -629,7 +629,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - if ( 0 && peer->numutxos != mypeer->numutxos ) + if ( peer->numutxos != mypeer->numutxos ) { lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; if ( lastn < 0 ) From 7081569d49f5096ee1a28dd02fb26aa42f3320d5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:35:04 +0300 Subject: [PATCH 0646/2705] Test --- iguana/exchanges/LP_unspents.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index b0e7c7671..06ae07b57 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -281,7 +281,7 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { - struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + struct LP_peerinfo *peer,*destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -307,6 +307,11 @@ int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa } } } + if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) + { + if ( destpeer->numutxos < n ) + destpeer->numutxos = n; + } } free_json(array); } From d7d36a6801223c3d07a97eec0250edb9519e8163 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:37:24 +0300 Subject: [PATCH 0647/2705] Test --- iguana/exchanges/LP_unspents.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 06ae07b57..0469fac13 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -311,6 +311,7 @@ int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa { if ( destpeer->numutxos < n ) destpeer->numutxos = n; + printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); } } free_json(array); From 4eec9b173bcbce5b79cf5aaf178901638bf5f27f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 24 May 2017 23:38:27 +0300 Subject: [PATCH 0648/2705] Test --- iguana/exchanges/LP_unspents.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_unspents.c index 0469fac13..15982d0d3 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_unspents.c @@ -310,8 +310,10 @@ int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) { if ( destpeer->numutxos < n ) + { destpeer->numutxos = n; - printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); + printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); + } } } free_json(array); From 7a2e5995fc02649ad1198bfdcfd6a0c7b149fed4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 26 May 2017 11:15:57 +0300 Subject: [PATCH 0649/2705] Test --- iguana/exchanges/DEXstats.h | 17 +- iguana/exchanges/LP_bitcoin.c | 692 +++++ iguana/exchanges/LP_commands.c | 105 + .../{LP_unspents.c => LP_nativeDEX.c} | 90 +- iguana/exchanges/LP_prices.c | 41 + iguana/exchanges/LP_remember.c | 1168 ++++++++ iguana/exchanges/LP_swap.c | 2379 +++++++++++++++++ iguana/exchanges/mm.c | 16 +- iguana/kmd_lookup.h | 11 +- 9 files changed, 4454 insertions(+), 65 deletions(-) create mode 100644 iguana/exchanges/LP_bitcoin.c create mode 100644 iguana/exchanges/LP_commands.c rename iguana/exchanges/{LP_unspents.c => LP_nativeDEX.c} (88%) create mode 100644 iguana/exchanges/LP_prices.c create mode 100644 iguana/exchanges/LP_remember.c create mode 100644 iguana/exchanges/LP_swap.c diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 5738ab91e..6982cb64d 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -1,10 +1,21 @@ +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ // // DEXstats.h // marketmaker // -// Created by Mac on 5/7/17. -// Copyright © 2017 SuperNET. All rights reserved. -// #ifndef DEXstats_h #define DEXstats_h diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c new file mode 100644 index 000000000..421d889ca --- /dev/null +++ b/iguana/exchanges/LP_bitcoin.c @@ -0,0 +1,692 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_bitcoin.c +// marketmaker +// + +#define IGUANA_MAXSCRIPTSIZE 10001 + +struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }; //PACKEDSTRUCT; + +struct vin_signer { bits256 privkey; char coinaddr[64]; uint8_t siglen,sig[80],rmd160[20],pubkey[66]; }; + +struct vin_info +{ + struct iguana_msgvin vin; uint64_t amount; cJSON *extras; bits256 sigtxid; + int32_t M,N,validmask,spendlen,type,p2shlen,numpubkeys,numsigs,height,hashtype,userdatalen,suppress_pubkeys,ignore_cltverr; + uint32_t sequence,unspentind; struct vin_signer signers[16]; char coinaddr[65]; + uint8_t rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE],userdata[IGUANA_MAXSCRIPTSIZE]; +}; + +#define SIGHASH_ALL 1 +#define SIGHASH_NONE 2 +#define SIGHASH_SINGLE 3 +#define SIGHASH_ANYONECANPAY 0x80 + +#define SCRIPT_OP_NOP 0x00 +#define SCRIPT_OP_TRUE 0x51 +#define SCRIPT_OP_2 0x52 +#define SCRIPT_OP_3 0x53 +#define SCRIPT_OP_4 0x54 +#define SCRIPT_OP_IF 0x63 +#define SCRIPT_OP_ELSE 0x67 +#define SCRIPT_OP_RETURN 0x6a +#define SCRIPT_OP_DUP 0x76 +#define SCRIPT_OP_ENDIF 0x68 +#define SCRIPT_OP_DROP 0x75 +#define SCRIPT_OP_EQUALVERIFY 0x88 +#define SCRIPT_OP_SHA256 0xa8 +#define SCRIPT_OP_HASH160 0xa9 + +#define SCRIPT_OP_EQUAL 0x87 +#define SCRIPT_OP_CHECKSIG 0xac +#define SCRIPT_OP_CHECKMULTISIG 0xae +#define SCRIPT_OP_CHECKSEQUENCEVERIFY 0xb2 +#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 + +void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen) +{ + bits256 hash; + vcalc_sha256(0,hash.bytes,data,datalen); + calc_rmd160(0,rmd160,hash.bytes,sizeof(hash)); +} + +void revcalc_rmd160_sha256(uint8_t rmd160[20],bits256 revhash) +{ + bits256 hash; int32_t i; + for (i=0; i<32; i++) + hash.bytes[i] = revhash.bytes[31-i]; + calc_rmd160_sha256(rmd160,hash.bytes,sizeof(hash)); +} + +bits256 revcalc_sha256(bits256 revhash) +{ + bits256 hash,dest; int32_t i; + for (i=0; i<32; i++) + hash.bytes[i] = revhash.bytes[31-i]; + vcalc_sha256(0,dest.bytes,hash.bytes,sizeof(hash)); + return(dest); +} + +int32_t bitcoin_pubkeylen(const uint8_t *pubkey) +{ + if ( pubkey[0] == 2 || pubkey[0] == 3 ) + return(33); + else if ( pubkey[0] == 4 ) + return(65); + else + { + //printf("illegal pubkey.[%02x] %llx\n",pubkey[0],*(long long *)pubkey); + return(-1); + } +} + +int32_t bitcoin_pubkeyspend(uint8_t *script,int32_t n,uint8_t pubkey[66]) +{ + int32_t plen = bitcoin_pubkeylen(pubkey); + script[n++] = plen; + memcpy(&script[n],pubkey,plen); + n += plen; + script[n++] = SCRIPT_OP_CHECKSIG; + return(n); +} + +int32_t bitcoin_p2shspend(uint8_t *script,int32_t n,uint8_t rmd160[20]) +{ + script[n++] = SCRIPT_OP_HASH160; + script[n++] = 0x14; memcpy(&script[n],rmd160,0x14); n += 0x14; + script[n++] = SCRIPT_OP_EQUAL; + return(n); +} + +int32_t bitcoin_secret160verify(uint8_t *script,int32_t n,uint8_t secret160[20]) +{ + script[n++] = SCRIPT_OP_HASH160; + script[n++] = 0x14; + memcpy(&script[n],secret160,0x14); + n += 0x14; + script[n++] = SCRIPT_OP_EQUALVERIFY; + return(n); +} + +int32_t bitcoin_secret256spend(uint8_t *script,int32_t n,bits256 secret) +{ + script[n++] = SCRIPT_OP_SHA256; + script[n++] = 0x20; + memcpy(&script[n],secret.bytes,0x20); + n += 0x20; + script[n++] = SCRIPT_OP_EQUAL; + return(n); +} + +// OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG +int32_t bitcoin_standardspend(uint8_t *script,int32_t n,uint8_t rmd160[20]) +{ + script[n++] = SCRIPT_OP_DUP; + script[n++] = SCRIPT_OP_HASH160; + script[n++] = 0x14; memcpy(&script[n],rmd160,0x14); n += 0x14; + script[n++] = SCRIPT_OP_EQUALVERIFY; + script[n++] = SCRIPT_OP_CHECKSIG; + return(n); +} + +int32_t bitcoin_checklocktimeverify(uint8_t *script,int32_t n,uint32_t locktime) +{ + script[n++] = 4; + script[n++] = locktime & 0xff, locktime >>= 8; + script[n++] = locktime & 0xff, locktime >>= 8; + script[n++] = locktime & 0xff, locktime >>= 8; + script[n++] = locktime & 0xff; + script[n++] = SCRIPT_OP_CHECKLOCKTIMEVERIFY; + script[n++] = SCRIPT_OP_DROP; + return(n); +} + +int32_t bitcoin_timelockspend(uint8_t *script,int32_t n,uint8_t rmd160[20],uint32_t timestamp) +{ + n = bitcoin_checklocktimeverify(script,n,timestamp); + n = bitcoin_standardspend(script,n,rmd160); + return(n); +} + +int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,const struct vin_info *vp) +{ + int32_t i,plen; + script[n++] = 0x50 + vp->M; + for (i=0; iN; i++) + { + if ( (plen= bitcoin_pubkeylen(vp->signers[i].pubkey)) < 0 ) + return(-1); + script[n++] = plen; + memcpy(&script[n],vp->signers[i].pubkey,plen); + n += plen; + } + script[n++] = 0x50 + vp->N; + script[n++] = SCRIPT_OP_CHECKMULTISIG; + calc_rmd160_sha256(p2sh_rmd160,script,n); + return(n); +} + +int32_t bitcoin_p2shscript(uint8_t *script,int32_t n,const uint8_t *p2shscript,const int32_t p2shlen) +{ + if ( p2shlen >= 0xfd ) + { + script[n++] = 0x4d; + script[n++] = (p2shlen & 0xff); + script[n++] = ((p2shlen >> 8) & 0xff); + } + else if ( p2shlen > 76 ) + { + script[n++] = 0x4c; + script[n++] = p2shlen; + } else script[n++] = p2shlen; + memcpy(&script[n],p2shscript,p2shlen), n += p2shlen; + return(n); +} + +bits256 basilisk_revealkey(bits256 privkey,bits256 pubkey) +{ + bits256 reveal; +#ifdef DISABLE_CHECKSIG + vcalc_sha256(0,reveal.bytes,privkey.bytes,sizeof(privkey)); + //reveal = revcalc_sha256(privkey); + char str[65],str2[65]; printf("priv.(%s) -> reveal.(%s)\n",bits256_str(str,privkey),bits256_str(str2,reveal)); +#else + reveal = pubkey; +#endif + return(reveal); +} + +int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp,uint8_t *redeemscript,uint32_t locktime,bits256 pubA0,bits256 pubB0,bits256 pubB1,bits256 privAm,bits256 privBn,uint8_t *secretAm,uint8_t *secretAm256,uint8_t *secretBn,uint8_t *secretBn256) +{ + int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],secret160[20],secret256[32]; + if ( depositflag != 0 ) + { + pubkeyA[0] = 0x02, cltvpub = pubA0; + pubkeyB[0] = 0x03, destpub = pubB0; + privkey = privBn; + memcpy(secret160,secretBn,20); + memcpy(secret256,secretBn256,32); + } + else + { + pubkeyA[0] = 0x03, cltvpub = pubB1; + pubkeyB[0] = 0x02, destpub = pubA0; + privkey = privAm; + memcpy(secret160,secretAm,20); + memcpy(secret256,secretAm256,32); + } + //for (i=0; i<32; i++) + // printf("%02x",secret256[i]); + //printf(" <- secret256 depositflag.%d nonz.%d\n",depositflag,bits256_nonz(privkey)); + if ( bits256_nonz(cltvpub) == 0 || bits256_nonz(destpub) == 0 ) + return(-1); + for (i=0; i<20; i++) + if ( secret160[i] != 0 ) + break; + if ( i == 20 ) + return(-1); + memcpy(pubkeyA+1,cltvpub.bytes,sizeof(cltvpub)); + memcpy(pubkeyB+1,destpub.bytes,sizeof(destpub)); + redeemscript[n++] = SCRIPT_OP_IF; + n = bitcoin_checklocktimeverify(redeemscript,n,locktime); +#ifdef DISABLE_CHECKSIG + n = bitcoin_secret256spend(redeemscript,n,cltvpub); +#else + n = bitcoin_pubkeyspend(redeemscript,n,pubkeyA); +#endif + redeemscript[n++] = SCRIPT_OP_ELSE; + if ( secretstartp != 0 ) + *secretstartp = n + 2; + if ( 1 ) + { + if ( 1 && bits256_nonz(privkey) != 0 ) + { + uint8_t bufA[20],bufB[20]; + revcalc_rmd160_sha256(bufA,privkey); + calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); + /*if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) + printf("MATCHES BUFA\n"); + else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) + printf("MATCHES BUFB\n"); + else printf("secret160 matches neither\n"); + for (i=0; i<20; i++) + printf("%02x",bufA[i]); + printf(" <- revcalc\n"); + for (i=0; i<20; i++) + printf("%02x",bufB[i]); + printf(" <- calc\n");*/ + memcpy(secret160,bufB,20); + } + n = bitcoin_secret160verify(redeemscript,n,secret160); + } + else + { + redeemscript[n++] = 0xa8;//IGUANA_OP_SHA256; + redeemscript[n++] = 0x20; + memcpy(&redeemscript[n],secret256,0x20), n += 0x20; + redeemscript[n++] = 0x88; //SCRIPT_OP_EQUALVERIFY; + } +#ifdef DISABLE_CHECKSIG + n = bitcoin_secret256spend(redeemscript,n,destpub); +#else + n = bitcoin_pubkeyspend(redeemscript,n,pubkeyB); +#endif + redeemscript[n++] = SCRIPT_OP_ENDIF; + return(n); +} + +int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeemlenp,uint8_t *script,int32_t n,uint32_t *locktimep,int32_t *secretstartp,struct basilisk_swapinfo *swap,int32_t depositflag) +{ + if ( depositflag != 0 ) + *locktimep = swap->started + swap->putduration + swap->callduration; + else *locktimep = swap->started + swap->putduration; + *redeemlenp = n = basilisk_swap_bobredeemscript(depositflag,secretstartp,redeemscript,*locktimep,swap->pubA0,swap->pubB0,swap->pubB1,swap->privAm,swap->privBn,swap->secretAm,swap->secretAm256,swap->secretBn,swap->secretBn256); + if ( n > 0 ) + { + calc_rmd160_sha256(rmd160,redeemscript,n); + n = bitcoin_p2shspend(script,0,rmd160); + //for (i=0; i= 0 ) + { + if ( (scriptlen= iguana_scriptsigextract(myinfo,coin,scriptsig,sizeof(scriptsig),txid,vini)) > 32 ) + { + for (i=0; i<32; i++) + privkey.bytes[i] = scriptsig[scriptlen - 33 + i]; + revcalc_rmd160_sha256(rmd160,privkey);//.bytes,sizeof(privkey)); + if ( memcmp(secret160,rmd160,sizeof(rmd160)) == sizeof(rmd160) ) + { + *destp = privkey; + printf("basilisk_priviextract found privi %s (%s)\n",name,bits256_str(str,privkey)); + return(0); + } + } + } + return(-1); +} + +int32_t basilisk_confirmsobj(cJSON *item) +{ + int32_t height,numconfirms; + height = jint(item,"height"); + numconfirms = jint(item,"numconfirms"); + if ( height > 0 && numconfirms >= 0 ) + return(numconfirms); + printf("basilisk_confirmsobj height.%d numconfirms.%d (%s)\n",height,numconfirms,jprint(item,0)); + return(-1); +} + +int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +{ + cJSON *argjson,*valuearray=0; char *valstr; int32_t i,n,retval = -1; +#ifdef BASILISK_DISABLEWAITTX + return(100); +#endif + argjson = cJSON_CreateObject(); + jaddbits256(argjson,"txid",rawtx->I.actualtxid); + jaddnum(argjson,"vout",0); + jaddstr(argjson,"coin",rawtx->coin->symbol); + if ( (valstr= basilisk_value(myinfo,rawtx->coin,0,0,swap->persistent_pubkey,argjson,0)) != 0 ) + { + char str[65]; printf("basilisk_numconfirms required.%d %s %s valstr.(%s)\n",rawtx->I.numconfirms,rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); + //basilisk_numconfirms required.0 alicespend 29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85 valstr.({"result":"success","numconfirms":0,"address":"1JGvZ67oTdM7kCya4J8kj1uErbSRAoq3wH","satoshis":"1413818","value":0.01413818,"height":462440,"txid":"29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85","vout":0,"coin":"BTC"}) + + if ( (valuearray= cJSON_Parse(valstr)) != 0 ) + { + if ( valstr[0] == '[' && is_cJSON_Array(valuearray) != 0 ) + { + n = cJSON_GetArraySize(valuearray); + for (i=0; i= 0 ) + break; + } + } else retval = basilisk_confirmsobj(valuearray); + free_json(valuearray); + } else printf("parse error\n"); + free(valstr); + } + free_json(argjson); + printf("numconfirms.%d returned\n",retval); + return(retval); +} + +bits256 basilisk_swap_broadcast(char *name,struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,uint8_t *data,int32_t datalen) +{ + bits256 txid; char *signedtx,*retstr; int32_t i; + memset(txid.bytes,0,sizeof(txid)); + if ( data != 0 && datalen != 0 ) + { + char str[65]; +#ifdef BASILISK_DISABLESENDTX + txid = bits256_doublesha256(0,data,datalen); + printf("%s <- dont sendrawtransaction (%s)\n",name,bits256_str(str,txid)); + return(txid); +#endif + signedtx = malloc(datalen*2 + 1); + init_hexbytes_noT(signedtx,data,datalen); + for (i=0; i<3; i++) + { + if ( (retstr= basilisk_sendrawtransaction(myinfo,coin,signedtx)) != 0 ) + { + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + free(retstr); + printf("sendrawtransaction %s.(%s)\n",name,bits256_str(str,txid)); + break; + } + else + { + printf("sendrawtransaction %s error.(%s)\n",name,retstr); + free(retstr); + } + } else printf("sendrawtransaction %s got null return\n",name); + } + free(signedtx); + } + return(txid); +} + +int32_t _basilisk_rawtx_sign(struct supernet_info *myinfo,int32_t height,uint32_t timestamp,uint32_t locktime,uint32_t sequenceid,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) +{ + char *rawtxbytes=0,*signedtx=0,hexstr[999],wifstr[128]; cJSON *txobj,*vins,*item,*sobj,*privkeys; int32_t needsig=1,retval = -1; struct vin_info *V; + V = calloc(256,sizeof(*V)); + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); + privkeys = cJSON_CreateArray(); + bitcoin_priv2wif(wifstr,privkey,rawtx->coin->chain->wiftype); + jaddistr(privkeys,wifstr); + if ( privkey2 != 0 ) + { + V[0].signers[1].privkey = *privkey2; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[1].pubkey,*privkey2); + bitcoin_priv2wif(wifstr,*privkey2,rawtx->coin->chain->wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 2; + //char str[65]; printf("add second privkey.(%s) %s\n",jprint(privkeys,0),bits256_str(str,*privkey2)); + } else V[0].N = V[0].M = 1; + V[0].suppress_pubkeys = dest->I.suppress_pubkeys; + V[0].ignore_cltverr = ignore_cltverr; + if ( dest->I.redeemlen != 0 ) + memcpy(V[0].p2shscript,dest->redeemscript,dest->I.redeemlen), V[0].p2shlen = dest->I.redeemlen; + txobj = bitcoin_txcreate(rawtx->coin->symbol,rawtx->coin->chain->isPoS,locktime,userdata == 0 ? 1 : 1,timestamp);//rawtx->coin->chain->locktime_txversion); + vins = cJSON_CreateArray(); + item = cJSON_CreateObject(); + if ( userdata != 0 && userdatalen > 0 ) + { + memcpy(V[0].userdata,userdata,userdatalen); + V[0].userdatalen = userdatalen; + init_hexbytes_noT(hexstr,userdata,userdatalen); + jaddstr(item,"userdata",hexstr); +#ifdef DISABLE_CHECKSIG + needsig = 0; +#endif + } + //printf("rawtx B\n"); + if ( bits256_nonz(rawtx->I.actualtxid) != 0 ) + jaddbits256(item,"txid",rawtx->I.actualtxid); + else jaddbits256(item,"txid",rawtx->I.signedtxid); + jaddnum(item,"vout",0); + sobj = cJSON_CreateObject(); + init_hexbytes_noT(hexstr,rawtx->spendscript,rawtx->I.spendlen); + jaddstr(sobj,"hex",hexstr); + jadd(item,"scriptPubKey",sobj); + jaddnum(item,"suppress",dest->I.suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); + if ( (dest->I.redeemlen= rawtx->I.redeemlen) != 0 ) + { + init_hexbytes_noT(hexstr,rawtx->redeemscript,rawtx->I.redeemlen); + memcpy(dest->redeemscript,rawtx->redeemscript,rawtx->I.redeemlen); + jaddstr(item,"redeemScript",hexstr); + } + jaddi(vins,item); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + //printf("basilisk_rawtx_sign locktime.%u/%u for %s spendscript.%s -> %s, suppress.%d\n",rawtx->I.locktime,dest->I.locktime,rawtx->name,hexstr,dest->name,dest->I.suppress_pubkeys); + txobj = bitcoin_txoutput(txobj,dest->spendscript,dest->I.spendlen,dest->I.amount); + if ( (rawtxbytes= bitcoin_json2hex(myinfo,rawtx->coin,&dest->I.txid,txobj,V)) != 0 ) + { + //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); + if ( needsig == 0 ) + signedtx = rawtxbytes; + if ( signedtx != 0 || (signedtx= iguana_signrawtx(myinfo,rawtx->coin,height,&dest->I.signedtxid,&dest->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) + { + dest->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( dest->I.datalen <= sizeof(dest->txbytes) ) + decode_hex(dest->txbytes,dest->I.datalen,signedtx); + else printf("DEX tx is too big %d vs %d\n",dest->I.datalen,(int32_t)sizeof(dest->txbytes)); + if ( signedtx != rawtxbytes ) + free(signedtx); + if ( dest->I.completed != 0 ) + retval = 0; + else printf("couldnt complete sign transaction %s\n",rawtx->name); + } else printf("error signing\n"); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(txobj); + free(V); + return(retval); +} + +int32_t basilisk_rawtx_sign(struct supernet_info *myinfo,int32_t height,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) +{ + uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; + timestamp = swap->I.started; + if ( dest == &swap->aliceclaim ) + locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; + else if ( dest == &swap->bobreclaim ) + locktime = swap->bobpayment.I.locktime + 1, sequenceid = 0; + return(_basilisk_rawtx_sign(myinfo,height,timestamp,locktime,sequenceid,dest,rawtx,privkey,privkey2,userdata,userdatalen,ignore_cltverr)); +} + +cJSON *basilisk_privkeyarray(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *vins) +{ + cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],typestr[64],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; double bidasks[2]; + privkeyarray = cJSON_CreateArray(); + //printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr); + if ( (n= cJSON_GetArraySize(vins)) > 0 ) + { + for (i=0; i= 0 ) + { + iguana_txidcategory(myinfo,coin,account,coinaddr,txid,vout); + if ( coinaddr[0] == 0 && (sobj= jobj(item,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 && is_hexstr(hexstr,0) > 0 ) + { + len = (int32_t)strlen(hexstr) >> 1; + if ( len < (sizeof(script) << 1) ) + { + decode_hex(script,len,hexstr); + if ( len == 25 && script[0] == 0x76 && script[1] == 0xa9 && script[2] == 0x14 ) + bitcoin_address(coinaddr,coin->chain->pubtype,script+3,20); + } + } + if ( coinaddr[0] != 0 ) + { + if ( (waddr= iguana_waddresssearch(myinfo,&wacct,coinaddr)) != 0 ) + { + bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype); + jaddistr(privkeyarray,waddr->wifstr); + } + else if ( smartaddress(myinfo,typestr,bidasks,&privkey,coin->symbol,coinaddr) >= 0 ) + { + bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); + jaddistr(privkeyarray,wifstr); + } + else printf("cant find (%s) in wallet\n",coinaddr); + } else printf("cant coinaddr from (%s).v%d\n",bits256_str(str,txid),vout); + } else printf("invalid txid/vout %d of %d\n",i,n); + } + } + return(privkeyarray); +} + +int32_t basilisk_rawtx_return(struct supernet_info *myinfo,int32_t height,struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) +{ + char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; + if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) + { + privkeyarray = basilisk_privkeyarray(myinfo,rawtx->coin,vins); + if ( (signedtx= iguana_signrawtx(myinfo,rawtx->coin,height,&rawtx->I.signedtxid,&rawtx->I.completed,vins,txbytes,privkeyarray,V)) != 0 ) + { + if ( lockinputs != 0 ) + { + //printf("lockinputs\n"); + iguana_RTunspentslock(myinfo,rawtx->coin,vins); + if ( (n= cJSON_GetArraySize(vins)) != 0 ) + { + bits256 txid; int32_t vout; + for (i=0; iI.datalen = (int32_t)strlen(signedtx) >> 1; + //rawtx->txbytes = calloc(1,rawtx->I.datalen); + decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); + //printf("%s SIGNEDTX.(%s)\n",rawtx->name,signedtx); + free(signedtx); + retval = 0; + } else printf("error signrawtx\n"); //do a very short timeout so it finishes via local poll + free_json(privkeyarray); + } + return(retval); +} + +int32_t _basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay) +{ + char *retstr,*jsonstr,scriptstr[1024],coinaddr[64]; uint32_t basilisktag; int32_t flag,i,n,retval = -1; cJSON *addresses,*valsobj,*retarray=0; struct vin_info *V; + //bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,myinfo->persistent_pubkey33,33); + if ( rawtx->coin->changeaddr[0] == 0 ) + { + bitcoin_address(rawtx->coin->changeaddr,rawtx->coin->chain->pubtype,pubkey33,33); + printf("set change address.(%s)\n",rawtx->coin->changeaddr); + } + init_hexbytes_noT(scriptstr,script,scriptlen); + basilisktag = (uint32_t)rand(); + valsobj = cJSON_CreateObject(); + jaddstr(valsobj,"coin",rawtx->coin->symbol); + jaddstr(valsobj,"spendscript",scriptstr); + jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); + jadd64bits(valsobj,"satoshis",rawtx->I.amount); + if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) + txfee = 50000; + jadd64bits(valsobj,"txfee",txfee); + jaddnum(valsobj,"minconf",minconf); + if ( locktime == 0 ) + locktime = (uint32_t)time(NULL) - 777; + jaddnum(valsobj,"locktime",locktime); + jaddnum(valsobj,"timeout",30000); + jaddnum(valsobj,"timestamp",swapstarted+delay); + addresses = cJSON_CreateArray(); + bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,pubkey33,33); + jaddistr(addresses,coinaddr); + jadd(valsobj,"addresses",addresses); + rawtx->I.locktime = locktime; + printf("%s locktime.%u\n",rawtx->name,locktime); + V = calloc(256,sizeof(*V)); + if ( (retstr= basilisk_bitcoinrawtx(myinfo,rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V)) != 0 ) + { + printf("%s %s basilisk_bitcoinrawtx.(%s) txfee %.8f\n",rawtx->name,str,retstr,dstr(txfee)); + flag = 0; + if ( (retarray= cJSON_Parse(retstr)) != 0 ) + { + if ( is_cJSON_Array(retarray) != 0 ) + { + n = cJSON_GetArraySize(retarray); + for (i=0; icoin->longestchain,rawtx,jitem(retarray,i),lockinputs,V)) == 0 ) + { + rawtx->vins = jduplicate(jobj(jitem(retarray,i),"vins")); + jsonstr = jprint(rawtx->vins,0); + safecopy(rawtx->vinstr,jsonstr,sizeof(rawtx->vinstr)); + free(jsonstr); + break; + } + } + } + else + { + retval = basilisk_rawtx_return(myinfo,rawtx->coin->longestchain,rawtx,retarray,lockinputs,V); + rawtx->vins = jduplicate(jobj(retarray,"vins")); + jsonstr = jprint(rawtx->vins,0); + safecopy(rawtx->vinstr,jsonstr,sizeof(rawtx->vinstr)); + free(jsonstr); + } + free(retarray); + } else printf("error parsing.(%s)\n",retstr); + free(retstr); + } else printf("error creating %s %s\n",iambob != 0 ? "BOB" : "ALICE",rawtx->name); + free_json(valsobj); + free(V); + return(retval); +} + +int32_t basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay) +{ + int32_t retval,len; uint64_t newtxfee; struct iguana_info *coin; + if ( (coin= rawtx->coin) == 0 || strcmp(coin->symbol,"BTC") != 0 ) + return(_basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay)); + retval = _basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,0,rawtx,locktime,script,scriptlen,txfee,minconf,delay); + len = rawtx->I.datalen; + if ( coin->estimatedfee == 0 ) + coin->estimatedfee = iguana_getestimatedfee(myinfo,coin); + newtxfee = coin->estimatedfee * len; + if ( newtxfee > txfee ) + { + retval = _basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,newtxfee,minconf,delay); + printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); + } + return(retval); +} diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c new file mode 100644 index 000000000..d15ea3f47 --- /dev/null +++ b/iguana/exchanges/LP_commands.c @@ -0,0 +1,105 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_commands.c +// marketmaker +// + +void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) +{ + char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid; struct LP_utxoinfo *utxo; + if ( (method= jstr(argjson,"method")) != 0 ) + { + if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) + { + txid = jbits256(argjson,"txid"); + if ( (utxo= LP_utxofind(txid)) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && utxo->swappending == 0 ) + { + if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) + { + if ( (price= LP_price(base,rel)) != 0. ) + { + price *= (1. + profitmargin); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"base",base); + jaddstr(retjson,"rel",rel); + jaddnum(retjson,"timestamp",time(NULL)); + jaddnum(retjson,"price",price); + jaddbits256(retjson,"txid",txid); + jadd64bits(retjson,"destsatoshis",price * utxo->satoshis); + if ( strcmp(method,"request") == 0 ) + { + utxo->swappending = (uint32_t)(time(NULL) + 60); + utxo->otherpubkey = jbits256(argjson,"pubkey"); + jaddnum(retjson,"pending",utxo->swappending); + } + retstr = jprint(retjson,1); + LP_send(pubsock,retstr,1); + } + } + } + } + else if ( ) + { + + } + } +} + +char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port +{ + char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; + if ( (method= jstr(argjson,"method")) == 0 ) + return(clonestr("{\"error\":\"need method in request\"}")); + else + { + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + { + if ( (pushport= juint(argjson,"push")) == 0 ) + pushport = argport + 1; + if ( (subport= juint(argjson,"sub")) == 0 ) + subport = argport + 2; + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) + { + if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) + peer->numpeers = otherpeers; + if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) + { + printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer->numutxos); + peer->numutxos = othernumutxos; + } + //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); + } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); + if ( strcmp(method,"getpeers") == 0 ) + retstr = LP_peers(); + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); + else if ( strcmp(method,"notify") == 0 ) + retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); + else if ( strcmp(method,"notifyutxo") == 0 ) + { + printf("utxonotify.(%s)\n",jprint(argjson,0)); + LP_addutxo(LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); + retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); + } + } else printf("malformed request.(%s)\n",jprint(argjson,0)); + } + if ( retstr != 0 ) + return(retstr); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"error","unrecognized command"); + return(clonestr(jprint(retjson,1))); +} diff --git a/iguana/exchanges/LP_unspents.c b/iguana/exchanges/LP_nativeDEX.c similarity index 88% rename from iguana/exchanges/LP_unspents.c rename to iguana/exchanges/LP_nativeDEX.c index 15982d0d3..f139d12ac 100644 --- a/iguana/exchanges/LP_unspents.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -1,17 +1,29 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ // // LP_unspents.c // marketmaker // -// Created by Mac on 5/23/17. -// Copyright © 2017 SuperNET. All rights reserved. -// #include #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; -portable_mutex_t LP_peermutex,LP_utxomutex,LP_jsonmutex; +portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex; int32_t LP_mypubsock = -1; struct LP_peerinfo @@ -28,9 +40,10 @@ struct LP_peerinfo struct LP_utxoinfo { UT_hash_handle hh; - bits256 txid,deposittxid; + bits256 txid,deposittxid,otherpubkey; + void *swap; uint64_t satoshis,depositsatoshis; - int32_t vout,depositvout; uint32_t lasttime,errors; + int32_t vout,depositvout; uint32_t lasttime,errors,swappending; double profitmargin; char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; uint16_t port; @@ -512,59 +525,17 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin return(total); } -char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) -{ - char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; - if ( (method= jstr(argjson,"method")) == 0 ) - return(clonestr("{\"error\":\"need method in request\"}")); - else - { - portable_mutex_lock(&LP_jsonmutex); - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) - { - if ( (pushport= juint(argjson,"push")) == 0 ) - pushport = argport + 1; - if ( (subport= juint(argjson,"sub")) == 0 ) - subport = argport + 2; - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) - { - if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) - peer->numpeers = otherpeers; - if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) - { - printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer->numutxos); - peer->numutxos = othernumutxos; - } - //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); - } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); - if ( strcmp(method,"getpeers") == 0 ) - retstr = LP_peers(); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) - retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - else if ( strcmp(method,"notify") == 0 ) - retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( strcmp(method,"notifyutxo") == 0 ) - { - printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); - retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); - } - } else printf("malformed request.(%s)\n",jprint(argjson,0)); - portable_mutex_unlock(&LP_jsonmutex); - } - if ( retstr != 0 ) - return(retstr); - retjson = cJSON_CreateObject(); - jaddstr(retjson,"error","unrecognized command"); - return(clonestr(jprint(retjson,1))); -} +#include "LP_bitcoin.c" +#include "LP_swap.c" +#include "LP_remember.c" +#include "LP_commands.c" void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { - char *myipaddr=0,*retstr; long filesize,n; int32_t timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; + char *myipaddr=0,*retstr; long filesize,n; int32_t len,timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); - portable_mutex_init(&LP_jsonmutex); + portable_mutex_init(&LP_commandmutex); if ( profitmargin == 0. ) { profitmargin = 0.01; @@ -651,11 +622,13 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { + portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypub)) != 0 ) { printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } + portable_mutex_unlock(&LP_commandmutex); free_json(argjson); } else printf("error parsing.(%s)\n",(char *)ptr); if ( ptr != 0 ) @@ -665,7 +638,14 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - printf("PULL.[%d] %s\n",recvsize,(char *)ptr); + if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) + { + len = (int32_t)strlen((char *)ptr) + 1; + portable_mutex_lock(&LP_commandmutex); + LP_command(mypeer,mypub,argjson,&ptr[len],recvsize - len,profitmargin); + portable_mutex_unlock(&LP_commandmutex); + free_json(argjson); + } if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c new file mode 100644 index 000000000..691325cc4 --- /dev/null +++ b/iguana/exchanges/LP_prices.c @@ -0,0 +1,41 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_prices.c +// marketmaker +// + +double LP_kmdbtc; + +// very, very simple for now + +void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]) +{ + if ( avebid > SMALLVAL && aveask > SMALLVAL && strcmp(base,"KMD") == 0 && strcmp(rel,"BTC") == 0 ) + LP_kmdbtc = (avebid + aveask) * 0.5; +} + +double LP_price(char *base,char *rel) +{ + if ( LP_kmdbtc != 0. ) + { + if ( strcmp(base,"KMD") == 0 && strcmp(rel,"BTC") == 0 ) + return(LP_kmdbtc); + else if ( strcmp(rel,"KMD") == 0 && strcmp(base,"BTC") == 0 ) + return(1. / LP_kmdbtc); + } + return(0.); +} diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c new file mode 100644 index 000000000..22ec7d53a --- /dev/null +++ b/iguana/exchanges/LP_remember.c @@ -0,0 +1,1168 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_remember.c +// marketmaker +// + + +cJSON *basilisk_nullretjson(cJSON *retjson) +{ + char *outstr; + if ( retjson != 0 ) + { + outstr = jprint(retjson,0); + if ( strcmp(outstr,"{}") == 0 ) + { + free_json(retjson); + retjson = 0; + } + free(outstr); + } + return(retjson); +} + +cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 trigger,int32_t vout) +{ + char *retstr; cJSON *retjson=0; struct iguana_info *coin; + if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + { + if ( (retstr= dex_gettxout(myinfo,0,0,0,trigger,symbol,vout)) != 0 ) + { + //printf("dexgettxout.(%s)\n",retstr); + retjson = cJSON_Parse(retstr); + free(retstr); + } + if ( 0 && strcmp("BTC",symbol) == 0 ) + printf("%s gettxout.(%s)\n",symbol,jprint(retjson,0)); + } + else + { + retjson = dpow_gettxout(myinfo,coin,trigger,vout); + //printf("need to verify passthru has this info\n"); + //printf("dpowgettxout.(%s)\n",jprint(retjson,0)); + } + return(basilisk_nullretjson(retjson)); +} + +cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid) +{ + char *retstr; cJSON *retjson=0; struct iguana_info *coin; + if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + { + if ( (retstr= dex_gettransaction(myinfo,0,0,0,txid,symbol)) != 0 ) + { + retjson = cJSON_Parse(retstr); + free(retstr); + } + //if ( strcmp("BTC",symbol) == 0 ) + // printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); + } else retjson = dpow_gettransaction(myinfo,coin,txid); + return(basilisk_nullretjson(retjson)); +} + +int32_t basilisk_swap_txdestaddr(char *destaddr,bits256 txid,int32_t vout,cJSON *txobj) +{ + int32_t n,m,retval = -1; cJSON *vouts,*item,*addresses,*skey; char *addr; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && vout < n ) + { + item = jitem(vouts,vout); + if ( (skey= jobj(item,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + { + item = jitem(addresses,0); + if ( (addr= jstr(item,0)) != 0 ) + { + safecopy(destaddr,addr,64); + retval = 0; + } + //printf("item.(%s) -> dest.(%s)\n",jprint(item,0),destaddr); + } + } + return(retval); +} + +int32_t basilisk_swap_getcoinaddr(struct supernet_info *myinfo,char *symbol,char *coinaddr,bits256 txid,int32_t vout) +{ + cJSON *retjson; + coinaddr[0] = 0; + if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + basilisk_swap_txdestaddr(coinaddr,txid,vout,retjson); + free_json(retjson); + } + return(coinaddr[0] != 0); +} + +int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uint8_t *script,int32_t maxlen,bits256 txid,int32_t vini) +{ + cJSON *retjson,*vins,*item,*skey; int32_t n,scriptlen = 0; char *hexstr; + if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + if ( (vins= jarray(&n,retjson,"vin")) != 0 && vini < n ) + { + item = jitem(vins,vini); + if ( (skey= jobj(item,"scriptSig")) != 0 && (hexstr= jstr(skey,"hex")) != 0 && (scriptlen= (int32_t)strlen(hexstr)) < maxlen*2 ) + { + scriptlen >>= 1; + decode_hex(script,scriptlen,hexstr); + //char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); + } + } + free_json(retjson); + } + return(scriptlen); +} + +int64_t basilisk_txvalue(struct supernet_info *myinfo,char *symbol,bits256 txid,int32_t vout) +{ + cJSON *txobj,*vouts,*item; int32_t n; int64_t value = 0; + //char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid)); + if ( (txobj= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + { + //printf("txobj.(%s)\n",jprint(txobj,0)); + if ( (vouts= jarray(&n,txobj,"vout")) != 0 ) + { + item = jitem(vouts,vout); + if ( (value= jdouble(item,"amount") * SATOSHIDEN) == 0 ) + value = jdouble(item,"value") * SATOSHIDEN; + } + free_json(txobj); + } + return(value); +} + +bits256 dex_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,char *coinaddr,bits256 utxotxid,int32_t vout) +{ + char *retstr,*addr; cJSON *array,*item,*array2; int32_t i,n,m; bits256 spendtxid,txid; + memset(&spendtxid,0,sizeof(spendtxid)); + if ( (retstr= dex_listtransactions(myinfo,0,0,0,symbol,coinaddr,100,0)) != 0 ) + { + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i %s\n",bits256_str(str,spendtxid),destaddr); + break; + } + } + } + } + free_json(array); + } + free(retstr); + } + return(spendtxid); +} + +bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) +{ + bits256 spendtxid,txid; char *catstr,*addr; cJSON *array,*item,*item2,*txobj,*vins; int32_t i,n,m; char coinaddr[64],str[65]; struct iguana_info *coin = iguana_coinfind(symbol); + // listtransactions or listspents + destaddr[0] = 0; + coinaddr[0] = 0; + memset(&spendtxid,0,sizeof(spendtxid)); + //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); + if ( (coin == 0 || coin->FULLNODE >= 0) && iguana_isnotarychain(symbol) >= 0 ) + { + //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] + basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + if ( coinaddr[0] != 0 ) + spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); + } + else if ( coin != 0 ) + { + if ( (array= dpow_listtransactions(myinfo,coin,destaddr,1000,0)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i 0 ) + { + for (i=0; i jint(item,"vout") ) + { + item2 = jitem(vins,jint(item,"vout")); + if ( bits256_cmp(utxotxid,jbits256(item2,"txid")) == 0 && vout == jint(item2,"vout") ) + { + spendtxid = txid; + break; + } + } + } + } + } + if ( i == n ) + printf("dpowlist: native couldnt find spendtxid for %s\n",bits256_str(str,utxotxid)); + } + free_json(array); + } + if ( bits256_nonz(spendtxid) != 0 ) + return(spendtxid); + } + if ( iguana_isnotarychain(symbol) >= 0 ) + { + basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); + printf("fallback use DEX for native (%s) (%s)\n",coinaddr,bits256_str(str,utxotxid)); + if ( coinaddr[0] != 0 ) + { + spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); + printf("spendtxid.(%s)\n",bits256_str(str,spendtxid)); + } + } + } + return(spendtxid); +} + +bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname,char *symbol,char *txbytes) +{ + char *retstr; bits256 txid; int32_t i,sentflag = 0; + memset(&txid,0,sizeof(txid)); + for (i=0; i<3; i++) + { + if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) + { + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + sentflag = 1; + } + char str[65]; printf("[%s] %s RETSTR.(%s) %s.%s\n",txname,txbytes,retstr,symbol,bits256_str(str,txid)); + free(retstr); + } + if ( sentflag != 0 ) + break; + } + return(txid); +} + +char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp) +{ + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; + *destamountp = 0; + if ( finalseqid == 0 ) + locktime = expiration; + //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) + return(0); + if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) + { + printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); + return(0); + } + if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + { + printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); + free_json(utxoobj); + return(0); + } else free_json(utxoobj); + *destamountp = destamount; + if ( destamount > 10000 ) + destamount -= 10000; + if ( strcmp(symbol,"BTC") == 0 ) + { + if ( destamount > 40000 ) + destamount -= 40000; + } + height = coin->longestchain; + timestamp = (uint32_t)time(NULL); + V = calloc(256,sizeof(*V)); + privkeys = cJSON_CreateArray(); + if ( privkey2p != 0 ) + { + V[0].signers[1].privkey = *privkey2p; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[1].pubkey,*privkey2p); + bitcoin_priv2wif(wifstr,*privkey2p,coin->chain->wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 2; + } else V[0].N = V[0].M = 1; + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); + bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); + jaddistr(privkeys,wifstr); + V[0].suppress_pubkeys = suppress_pubkeys; + V[0].ignore_cltverr = ignore_cltverr; + if ( redeemlen != 0 ) + memcpy(V[0].p2shscript,redeemscript,redeemlen), V[0].p2shlen = redeemlen; + txobj = bitcoin_txcreate(coin->symbol,coin->chain->isPoS,locktime,1,timestamp); + vins = cJSON_CreateArray(); + item = cJSON_CreateObject(); + if ( userdata != 0 && userdatalen > 0 ) + { + memcpy(V[0].userdata,userdata,userdatalen); + V[0].userdatalen = userdatalen; + init_hexbytes_noT(hexstr,userdata,userdatalen); + jaddstr(item,"userdata",hexstr); + } + jaddbits256(item,"txid",utxotxid); + jaddnum(item,"vout",vout); + sobj = cJSON_CreateObject(); + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); + /*int32_t i; + for (i=0; i<33; i++) + printf("%02x",pubkey33[i]); + printf(" pubkey33 ->\n"); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" destaddr.(%s)\n",destaddr); + calc_rmd160_sha256(rmd160,pubkey33,33); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- vs direct calc\n");*/ + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + init_hexbytes_noT(hexstr,spendscript,spendlen); + jaddstr(sobj,"hex",hexstr); + jadd(item,"scriptPubKey",sobj); + jaddnum(item,"suppress",suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); + if ( redeemlen != 0 ) + { + init_hexbytes_noT(hexstr,redeemscript,redeemlen); + jaddstr(item,"redeemScript",hexstr); + } + jaddi(vins,item); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); + if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) + { + //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); + if ( (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) + printf("couldnt sign transaction\n"); + else if ( completed == 0 ) + printf("incomplete signing\n"); + else printf("%s -> %s\n",name,bits256_str(str,signedtxid)); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(txobj); + free(V); + return(signedtx); +} + +char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp) +{ + char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); + if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + pubAm = bitcoin_pubkey33(myinfo->ctx,tmp33,privAm); + pubBn = bitcoin_pubkey33(myinfo->ctx,tmp33,privBn); + //char str[65]; + //printf("pubAm.(%s)\n",bits256_str(str,pubAm)); + //printf("pubBn.(%s)\n",bits256_str(str,pubBn)); + spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); + //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); + /*rev = privAm; + for (i=0; i<32; i++) + privAm.bytes[i] = rev.bytes[31 - i]; + rev = privBn; + for (i=0; i<32; i++) + privBn.bytes[i] = rev.bytes[31 - i];*/ + signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration,destamountp); + } + return(signedtx); +} + +bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol,bits256 spendtxid,int32_t vini,int32_t revflag) +{ + bits256 privkey; int32_t i,scriptlen,siglen; uint8_t script[1024]; // from Bob refund of Bob deposit + memset(&privkey,0,sizeof(privkey)); + if ( (scriptlen= basilisk_swap_getsigscript(myinfo,symbol,script,(int32_t)sizeof(script),spendtxid,vini)) > 0 ) + { + siglen = script[0]; + for (i=0; i<32; i++) + { + if ( revflag != 0 ) + privkey.bytes[31 - i] = script[siglen+2+i]; + else privkey.bytes[i] = script[siglen+2+i]; + } + char str[65]; printf("extracted privbob.(%s)\n",bits256_str(str,privkey)); + } + return(privkey); +} + +bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,bits256 *bobrefundp,char *bobcoin,bits256 bobdeposit,bits256 privBn) +{ + char destaddr[64]; + if ( bits256_nonz(privBn) == 0 ) + { + if ( bits256_nonz(bobdeposit) != 0 ) + *bobrefundp = basilisk_swap_spendtxid(myinfo,bobcoin,destaddr,bobdeposit,0); + if ( bits256_nonz(*bobrefundp) != 0 ) + privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,*bobrefundp,0,0); + } + return(privBn); +} + +bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int32_t *sentflags,bits256 *txids,int32_t utxoind,int32_t alicespent,int32_t bobspent,int32_t vout,char *aliceaddr,char *bobaddr) +{ + bits256 spendtxid,txid; char destaddr[64]; + txid = txids[utxoind]; + memset(&spendtxid,0,sizeof(spendtxid)); + /*if ( aliceaddr != 0 ) + printf("aliceaddr.(%s)\n",aliceaddr); + if ( bobaddr != 0 ) + printf("bobaddr.(%s)\n",bobaddr);*/ + if ( bits256_nonz(txid) != 0 ) + { + //char str[65]; + spendtxid = basilisk_swap_spendtxid(myinfo,symbol,destaddr,txid,vout); + if ( bits256_nonz(spendtxid) != 0 ) + { + sentflags[utxoind] = 1; + if ( aliceaddr != 0 && strcmp(destaddr,aliceaddr) == 0 ) + { + //printf("ALICE spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + sentflags[alicespent] = 1; + txids[alicespent] = spendtxid; + } + else if ( bobaddr != 0 && strcmp(destaddr,bobaddr) == 0 ) + { + //printf("BOB spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + sentflags[bobspent] = 1; + txids[bobspent] = spendtxid; + } + else + { + //printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr); + if ( aliceaddr != 0 ) + { + sentflags[bobspent] = 1; + txids[bobspent] = spendtxid; + } + else if ( bobaddr != 0 ) + { + sentflags[alicespent] = 1; + txids[alicespent] = spendtxid; + } + } + } + } else printf("utxoind.%d null txid\n",utxoind); + return(spendtxid); +} + +#define BASILISK_ALICESPEND 0 +#define BASILISK_BOBSPEND 1 +#define BASILISK_BOBPAYMENT 2 +#define BASILISK_ALICEPAYMENT 3 +#define BASILISK_BOBDEPOSIT 4 +#define BASILISK_OTHERFEE 5 +#define BASILISK_MYFEE 6 +#define BASILISK_BOBREFUND 7 +#define BASILISK_BOBRECLAIM 8 +#define BASILISK_ALICERECLAIM 9 +#define BASILISK_ALICECLAIM 10 +//0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0 +char *txnames[] = { "alicespend", "bobspend", "bobpayment", "alicepayment", "bobdeposit", "otherfee", "myfee", "bobrefund", "bobreclaim", "alicereclaim", "aliceclaim" }; + +int32_t basilisk_isbobcoin(int32_t iambob,int32_t ind) +{ + switch ( ind ) + { + case BASILISK_MYFEE: return(iambob); break; + case BASILISK_OTHERFEE: return(!iambob); break; + case BASILISK_BOBSPEND: + case BASILISK_ALICEPAYMENT: + case BASILISK_ALICERECLAIM: + case BASILISK_ALICECLAIM: return(0); + break; + case BASILISK_BOBDEPOSIT: + case BASILISK_ALICESPEND: + case BASILISK_BOBPAYMENT: + case BASILISK_BOBREFUND: + case BASILISK_BOBRECLAIM: return(1); + break; + default: return(-1); break; + } +} + +// add blocktrail presence requirement for BTC +int32_t basilisk_swap_isfinished(int32_t iambob,bits256 *txids,int32_t *sentflags,bits256 paymentspent,bits256 Apaymentspent,bits256 depositspent) +{ + int32_t i,n = 0; + for (i=0; i (%s)\n",fname,fstr); + if ( (txobj= cJSON_Parse(fstr)) != 0 ) + { + paymentspent = jbits256(txobj,"paymentspent"); + Apaymentspent = jbits256(txobj,"Apaymentspent"); + depositspent = jbits256(txobj,"depositspent"); + if ( (array= jarray(&n,txobj,"values")) != 0 ) + for (i=0; i (%s)\n",fname,fstr); + if ( (txobj= cJSON_Parse(fstr)) != 0 ) + { + //printf("TXOBJ.(%s)\n",jprint(txobj,0)); + iambob = jint(txobj,"iambob"); + txid = jbits256(txobj,"txid"); + if ( bits256_nonz(txid) == 0 ) + continue; + txids[i] = txid; + if ( jobj(txobj,"tx") != 0 ) + { + txbytes[i] = clonestr(jstr(txobj,"tx")); + //printf("[%s] TX.(%s)\n",txnames[i],txbytes[i]); + } + if ( (value= jdouble(txobj,"amount") * SATOSHIDEN) == 0 ) + value = jdouble(txobj,"value") * SATOSHIDEN; + values[i] = value; + if ( (symbol= jstr(txobj,"coin")) != 0 ) + { + if ( i == BASILISK_ALICESPEND || i == BASILISK_BOBPAYMENT || i == BASILISK_BOBDEPOSIT || i == BASILISK_BOBREFUND || i == BASILISK_BOBRECLAIM || i == BASILISK_ALICECLAIM ) + safecopy(bobcoin,symbol,sizeof(bobcoin)); + else if ( i == BASILISK_BOBSPEND || i == BASILISK_ALICEPAYMENT || i == BASILISK_ALICERECLAIM ) + safecopy(alicecoin,symbol,sizeof(alicecoin)); + if ( finishedflag == 0 ) + { + if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + { + //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + } + else + { + checktxid = jbits256(sentobj,"txid"); + if ( bits256_nonz(checktxid) == 0 ) + checktxid = jbits256(sentobj,"hash"); + if ( bits256_cmp(checktxid,txid) == 0 ) + { + //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid)); + sentflags[i] = 1; + } + free_json(sentobj); + } + printf("%s %s %.8f\n",txnames[i],bits256_str(str,txid),dstr(value)); + } + } + } //else printf("no symbol\n"); + free(fstr); + } else if ( finishedflag == 0 ) + printf("%s not finished\n",fname); + } + //printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); + Adestaddr[0] = destaddr[0] = 0; + Adest = Bdest = AAdest = ABdest = 0; + if ( bobcoin[0] == 0 || alicecoin[0] == 0 ) + return(0); + //printf("privAm.(%s) %p/%p\n",bits256_str(str,privAm),Adest,AAdest); + //printf("privBn.(%s) %p/%p\n",bits256_str(str,privBn),Bdest,ABdest); + if ( finishedflag == 0 && bobcoin[0] != 0 && alicecoin[0] != 0 ) + { + if ( iambob == 0 ) + { + if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + AAdest = Adestaddr; + } + if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + { + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + Adest = destaddr; + } + } + else + { + if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + { + bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + Bdest = destaddr; + } + if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + { + bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + ABdest = Adestaddr; + } + } + if ( sentflags[BASILISK_ALICEPAYMENT] == 0 && bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 ) + { + printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); + if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) + sentflags[BASILISK_ALICEPAYMENT] = 1; + else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) + { + sentflags[BASILISK_ALICEPAYMENT] = 1; + free_json(sentobj); + } + } + paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBPAYMENT,BASILISK_ALICESPEND,BASILISK_BOBRECLAIM,0,Adest,Bdest); + Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,sentflags,txids,BASILISK_ALICEPAYMENT,BASILISK_ALICERECLAIM,BASILISK_BOBSPEND,0,AAdest,ABdest); + depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBDEPOSIT,BASILISK_ALICECLAIM,BASILISK_BOBREFUND,0,Adest,Bdest); + finishedflag = basilisk_swap_isfinished(iambob,txids,sentflags,paymentspent,Apaymentspent,depositspent); + if ( iambob == 0 ) + { + if ( sentflags[BASILISK_ALICESPEND] == 0 ) + { + if ( sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(paymentspent) == 0 ) + { + //if ( txbytes[BASILISK_ALICESPEND] == 0 ) + { + if ( bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 ) + { + // alicespend + for (j=0; j<32; j++) + rev.bytes[j] = privAm.bytes[31 - j]; + revcalc_rmd160_sha256(secretAm,rev);//privAm); + vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + printf("alicespend len.%d redeemlen.%d\n",len,redeemlen); + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND])) != 0 ) + printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); + } + } + if ( txbytes[BASILISK_ALICESPEND] != 0 ) + { + txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction(myinfo,"alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested + { + sentflags[BASILISK_ALICESPEND] = 1; + paymentspent = txids[BASILISK_ALICESPEND]; + } + } + } + } + if ( sentflags[BASILISK_ALICECLAIM] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 && bits256_nonz(depositspent) == 0 ) + { + if ( time(NULL) > expiration ) + { + //if ( txbytes[BASILISK_ALICECLAIM] == 0 ) + { + redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,zero,secretAm,secretAm256,secretBn,secretBn256); + if ( redeemlen > 0 ) + { + len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM])) != 0 ) + printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); + } + } + if ( txbytes[BASILISK_ALICECLAIM] != 0 ) + { + txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); + if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // tested + { + sentflags[BASILISK_ALICECLAIM] = 1; + depositspent = txids[BASILISK_ALICECLAIM]; + } + } + } else printf("now %u before expiration %u\n",(uint32_t)time(NULL),expiration); + } + if ( sentflags[BASILISK_ALICEPAYMENT] != 0 && bits256_nonz(Apaymentspent) == 0 && sentflags[BASILISK_ALICECLAIM] == 0 ) + { + //if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) + { + privBn = basilisk_swap_privBn_extract(myinfo,&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); + if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM])) != 0 ) + printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); + } + } + if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) + { + txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); + if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // tested + { + sentflags[BASILISK_ALICERECLAIM] = 1; + Apaymentspent = txids[BASILISK_ALICERECLAIM]; + } + } + } + } + else if ( iambob == 1 ) + { + if ( sentflags[BASILISK_BOBSPEND] == 0 && bits256_nonz(Apaymentspent) == 0 ) + { + printf("try to bobspend aspend.%s have privAm.%d\n",bits256_str(str,txids[BASILISK_ALICESPEND]),bits256_nonz(privAm)); + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 || bits256_nonz(privAm) != 0 ) + { + //if ( txbytes[BASILISK_BOBSPEND] == 0 ) + { + if ( bits256_nonz(privAm) == 0 ) + { + privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0,1); + } + if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND])) != 0 ) + printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); + } + } + if ( txbytes[BASILISK_BOBSPEND] != 0 ) + { + txids[BASILISK_BOBSPEND] = basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); + if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) // tested + { + sentflags[BASILISK_BOBSPEND] = 1; + Apaymentspent = txids[BASILISK_BOBSPEND]; + } + } + } + } + if ( sentflags[BASILISK_BOBRECLAIM] == 0 && sentflags[BASILISK_BOBPAYMENT] != 0 && bits256_nonz(txids[BASILISK_BOBPAYMENT]) != 0 && time(NULL) > expiration && bits256_nonz(paymentspent) == 0 ) + { + //if ( txbytes[BASILISK_BOBRECLAIM] == 0 ) + { + // bobreclaim + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,zero,privBn,secretAm,secretAm256,secretBn,secretBn256); + if ( redeemlen > 0 ) + { + len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM])) != 0 ) + { + int32_t z; + for (z=0; z<20; z++) + printf("%02x",secretAm[z]); + printf(" secretAm, myprivs[1].(%s) bobreclaim.(%s)\n",bits256_str(str,myprivs[1]),txbytes[BASILISK_BOBRECLAIM]); + } + } + } + if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) + { + txids[BASILISK_BOBRECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); + if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) // tested + { + sentflags[BASILISK_BOBRECLAIM] = 1; + paymentspent = txids[BASILISK_BOBRECLAIM]; + } + } + } + if ( sentflags[BASILISK_BOBREFUND] == 0 && sentflags[BASILISK_BOBDEPOSIT] != 0 && bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0 && bits256_nonz(depositspent) == 0 ) + { + if ( bits256_nonz(paymentspent) != 0 || time(NULL) > expiration ) + { + printf("do the refund!\n"); + //if ( txbytes[BASILISK_BOBREFUND] == 0 ) + { + revcalc_rmd160_sha256(secretBn,privBn); + vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); + redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND])) != 0 ) + printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); + } + if ( txbytes[BASILISK_BOBREFUND] != 0 ) + { + txids[BASILISK_BOBREFUND] = basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); + if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) // tested + { + sentflags[BASILISK_BOBREFUND] = 1; + depositspent = txids[BASILISK_BOBREFUND]; + } + } + } else printf("time %u vs expiration %u\n",(uint32_t)time(NULL),expiration); + } + } + } + //printf("finish.%d iambob.%d REFUND %d %d %d %d\n",finishedflag,iambob,sentflags[BASILISK_BOBREFUND] == 0,sentflags[BASILISK_BOBDEPOSIT] != 0,bits256_nonz(txids[BASILISK_BOBDEPOSIT]) != 0,bits256_nonz(depositspent) == 0); + if ( sentflags[BASILISK_ALICESPEND] != 0 || sentflags[BASILISK_BOBRECLAIM] != 0 ) + sentflags[BASILISK_BOBPAYMENT] = 1; + if ( sentflags[BASILISK_ALICERECLAIM] != 0 || sentflags[BASILISK_BOBSPEND] != 0 ) + sentflags[BASILISK_ALICEPAYMENT] = 1; + if ( sentflags[BASILISK_ALICECLAIM] != 0 || sentflags[BASILISK_BOBREFUND] != 0 ) + sentflags[BASILISK_BOBDEPOSIT] = 1; + for (i=0; inumswaps; i++) + if ( (swap= myinfo->swaps[i]) != 0 && swap->I.req.requestid == requestid && swap->I.req.quoteid == quoteid ) + { + jaddi(array,basilisk_swapjson(myinfo,swap)); + flag = 1; + break; + } + if ( flag == 0 ) + { + if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) + { + jaddi(array,item); + if ( 1 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + break; + } + } + } + fclose(fp); + } + jaddstr(retjson,"result","success"); + jadd(retjson,"swaps",array); + if ( cJSON_GetArraySize(array) > 0 ) + { + totalsobj = cJSON_CreateObject(); + for (Btotal=i=0; i 0 && Btotal < 0 ) + jaddnum(retjson,"avebuy",(double)-Btotal/Ktotal); + else if ( Ktotal < 0 && Btotal > 0 ) + jaddnum(retjson,"avesell",(double)-Btotal/Ktotal); + } + array = cJSON_CreateArray(); + for (i=0; ilinfos)/sizeof(*myinfo->linfos); i++) + { + if ( myinfo->linfos[i].base[0] != 0 && myinfo->linfos[i].rel[0] != 0 ) + jaddi(array,linfo_json(&myinfo->linfos[i])); + } + jadd(retjson,"quotes",array); + return(jprint(retjson,1)); +} + diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c new file mode 100644 index 000000000..5df4a6b86 --- /dev/null +++ b/iguana/exchanges/LP_swap.c @@ -0,0 +1,2379 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_swap.c +// marketmaker +// +/* + resume handling: list of tx broadcast, tx pending + required items, reconnect state machine or have statemachine assume off by one or state/otherstate specific handling + make sure to broadcast deposit before claiming refund, or to just skip it if neither is done + */ + +#define DEX_SLEEP 10 +#define BASILISK_DEFAULT_NUMCONFIRMS 5 + +// Todo: monitor blockchains, ie complete extracting scriptsig +// mode to autocreate required outputs +// more better LP commands + +// depends on just three external functions: +// - basilisk_sendrawtransaction(myinfo,coin,signedtx); +// - basilisk_value(myinfo,rawtx->coin,0,0,myinfo->myaddr.persistent,argjson,0) +// basilisk_bitcoinrawtx(myinfo,rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V) + + +// included from basilisk.c +/* https://bitcointalk.org/index.php?topic=1340621.msg13828271#msg13828271 + https://bitcointalk.org/index.php?topic=1364951 + Tier Nolan's approach is followed with the following changes: + a) instead of cutting 1000 keypairs, only INSTANTDEX_DECKSIZE are a + b) instead of sending the entire 256 bits, it is truncated to 64 bits. With odds of collision being so low, it is dwarfed by the ~0.1% insurance factor. + c) D is set to ~100x the insurance rate of 1/777 12.87% + BTC amount + d) insurance is added to Bob's payment, which is after the deposit and bailin + e) BEFORE Bob broadcasts deposit, Alice broadcasts BTC denominated fee in cltv so if trade isnt done fee is reclaimed + */ + +//#define DISABLE_CHECKSIG // unsolved MITM (evil peer) + +/* + both fees are standard payments: OP_DUP OP_HASH160 FEE_RMD160 OP_EQUALVERIFY OP_CHECKSIG + + Alice altpayment: OP_2 OP_2 OP_CHECKMULTISIG + + Bob deposit: + #ifndef DISABLE_CHECKSIG + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF + #else + OP_IF + OP_CLTV OP_DROP OP_SHA256 OP_EQUAL + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_SHA256 OP_EQUAL + OP_ENDIF + #endif + + Bob paytx: + #ifndef DISABLE_CHECKSIG + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF + #else + OP_IF + OP_CLTV OP_DROP OP_SHA256 OP_EQUAL + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_SHA256 OP_EQUAL + OP_ENDIF + #endif + + Naming convention are pubAi are alice's pubkeys (seems only pubA0 and not pubA1) + pubBi are Bob's pubkeys + + privN is Bob's privkey from the cut and choose deck as selected by Alice + privM is Alice's counterpart + pubN and pubM are the corresponding pubkeys for these chosen privkeys + + Alice timeout event is triggered if INSTANTDEX_LOCKTIME elapses from the start of a FSM instance. Bob timeout event is triggered after INSTANTDEX_LOCKTIME*2 + */ + +/* + Bob sends bobdeposit and waits for alicepayment to confirm before sending bobpayment + Alice waits for bobdeposit to confirm and sends alicepayment + + Alice spends bobpayment immediately divulging privAm + Bob spends alicepayment immediately after getting privAm and divulges privBn + + Bob will spend bobdeposit after end of trade or INSTANTDEX_LOCKTIME, divulging privBn + Alice spends alicepayment as soon as privBn is seen + + Bob will spend bobpayment after INSTANTDEX_LOCKTIME + Alice spends bobdeposit in 2*INSTANTDEX_LOCKTIME + */ + +//Bobdeposit includes a covered put option for alicecoin, duration INSTANTDEX_LOCKTIME +//alicepayment includes a covered call option for alicecoin, duration (2*INSTANTDEX_LOCKTIME - elapsed) + + +/* in case of following states, some funds remain unclaimable, but all identified cases are due to one or both sides not spending when they were the only eligible party: + + Bob failed to claim deposit during exclusive period and since alice put in the claim, the alicepayment is unspendable. if alice is nice, she can send privAm to Bob. + Apaymentspent.(0000000000000000000000000000000000000000000000000000000000000000) alice.0 bob.0 + paymentspent.(f91da4e001360b95276448e7b01904d9ee4d15862c5af7f5c7a918df26030315) alice.0 bob.1 + depositspent.(f34e04ad74e290f63f3d0bccb7d0d50abfa54eea58de38816fdc596a19767add) alice.1 bob.0 + + */ + +int32_t basilisk_istrustedbob(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + // for BTC and if trusted LP + return(0); +} + +struct basilisk_rawtx *basilisk_swapdata_rawtx(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx) +{ + if ( rawtx->I.datalen != 0 && rawtx->I.datalen <= maxlen ) + { + memcpy(data,rawtx->txbytes,rawtx->I.datalen); + return(rawtx); + } + return(0); +} + +int32_t basilisk_verify_otherfee(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + struct basilisk_swap *swap = ptr; + // add verification and broadcast + //swap->otherfee.txbytes = calloc(1,datalen); + memcpy(swap->otherfee.txbytes,data,datalen); + swap->otherfee.I.datalen = datalen; + swap->otherfee.I.actualtxid = swap->otherfee.I.signedtxid = bits256_doublesha256(0,data,datalen); + basilisk_txlog(myinfo,swap,&swap->otherfee,-1); + return(0); +} + +int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) +{ + int32_t datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; bits256 txid; + datalen = recvbuf[0]; + datalen += (int32_t)recvbuf[1] << 8; + if ( datalen > 65536 ) + return(-1); + rawtx->I.redeemlen = recvbuf[2]; + data = &recvbuf[3]; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); + //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); + if ( rawtx->I.datalen == 0 ) + { + //rawtx->txbytes = calloc(1,datalen); + memcpy(rawtx->txbytes,data,datalen); + rawtx->I.datalen = datalen; + } + else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) + { + int32_t i; for (i=0; iI.datalen; i++) + printf("%02x",rawtx->txbytes[i]); + printf(" <- rawtx\n"); + printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); + return(-1); + } + txid = bits256_doublesha256(0,data,datalen); + char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); + if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + rawtx->I.actualtxid = txid; + if ( (txobj= bitcoin_data2json(rawtx->coin,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + rawtx->I.actualtxid = rawtx->I.signedtxid; + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,rawtx->signedtxid),jprint(txobj,0)); + rawtx->I.locktime = rawtx->msgtx.lock_time; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) + { + vout = jitem(vouts,v); + if ( j64bits(vout,"satoshis") == rawtx->I.amount && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) + { + if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) + { + decode_hex(rawtx->spendscript,hexlen,hexstr); + rawtx->I.spendlen = hexlen; + bitcoin_address(rawtx->p2shaddr,rawtx->coin->chain->p2shtype,rawtx->spendscript,hexlen); + if ( swap != 0 ) + basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment + retval = 0; + } + } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); + } + free_json(txobj); + } + return(retval); +} + +void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) +{ + cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; + if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) + { + vout = jitem(vouts,0); + //printf("VOUT.(%s)\n",jprint(vout,0)); + if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + { + item = jitem(addresses,0); + //printf("item.(%s)\n",jprint(item,0)); + if ( (addr= jstr(item,0)) != 0 ) + { + safecopy(coinaddr,addr,64); + //printf("extracted.(%s)\n",coinaddr); + } + } + } + free_json(txobj); + } +} + +int32_t basilisk_swapuserdata(uint8_t *userdata,bits256 privkey,int32_t ifpath,bits256 signpriv,uint8_t *redeemscript,int32_t redeemlen) +{ + int32_t i,len = 0; +#ifdef DISABLE_CHECKSIG + userdata[len++] = sizeof(signpriv); + for (i=0; i if path, 0 -> else path + return(len); +} + +/* Bob deposit: + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF*/ + +void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,int32_t scriptlen) +{ + int32_t i; char scriptstr[513]; + if ( scriptlen != 0 ) + { + for (i=0; iI.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); + coinaddr[0] = secretAmstr[0] = secretAm256str[0] = secretBnstr[0] = secretBn256str[0] = 0; + memset(zeroes,0,sizeof(zeroes)); + if ( rawtx != 0 && (fp= fopen(fname,"wb")) != 0 ) + { + fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); + if ( rawtx->I.datalen > 0 ) + { + fprintf(fp,",\"tx\":\""); + for (i=0; iI.datalen; i++) + fprintf(fp,"%02x",rawtx->txbytes[i]); + fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); + if ( rawtx == &swap->bobdeposit || rawtx == &swap->bobpayment ) + { + basilisk_swap_coinaddr(myinfo,swap,swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); + if ( coinaddr[0] != 0 ) + { + if ( swap->bobcoin != 0 && swap->bobcoin->FULLNODE < 0 ) + { + if ( (tmp= dpow_importaddress(myinfo,swap->bobcoin,coinaddr)) != 0 ) + free(tmp); + } + if ( rawtx == &swap->bobdeposit ) + safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); + else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); + } + } + } + if ( swap->Bdeposit[0] != 0 ) + fprintf(fp,",\"%s\":\"%s\"","Bdeposit",swap->Bdeposit); + if ( swap->Bpayment[0] != 0 ) + fprintf(fp,",\"%s\":\"%s\"","Bpayment",swap->Bpayment); + fprintf(fp,",\"expiration\":%u",swap->I.expiration); + fprintf(fp,",\"iambob\":%d",swap->I.iambob); + fprintf(fp,",\"bobcoin\":\"%s\"",swap->bobcoin->symbol); + fprintf(fp,",\"alicecoin\":\"%s\"",swap->alicecoin->symbol); + fprintf(fp,",\"lock\":%u",locktime); + fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); + if ( bits256_nonz(triggertxid) != 0 ) + fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); + if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) + { + basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicecoin != 0 && swap->alicecoin->FULLNODE < 0 ) + { + if ( (tmp= dpow_importaddress(myinfo,swap->alicecoin,coinaddr)) != 0 ) + free(tmp); + } + fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); + } + /*basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); + basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); + basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); + basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); + basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); + basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen);*/ + fprintf(fp,"}\n"); + fclose(fp); + } + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%u,\"otherstate\":%u,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); + if ( memcmp(zeroes,swap->I.secretAm,20) != 0 ) + { + init_hexbytes_noT(secretAmstr,swap->I.secretAm,20); + fprintf(fp,",\"secretAm\":\"%s\"",secretAmstr); + } + if ( memcmp(zeroes,swap->I.secretAm256,32) != 0 ) + { + init_hexbytes_noT(secretAm256str,swap->I.secretAm256,32); + fprintf(fp,",\"secretAm256\":\"%s\"",secretAm256str); + } + if ( memcmp(zeroes,swap->I.secretBn,20) != 0 ) + { + init_hexbytes_noT(secretBnstr,swap->I.secretBn,20); + fprintf(fp,",\"secretBn\":\"%s\"",secretBnstr); + } + if ( memcmp(zeroes,swap->I.secretBn256,32) != 0 ) + { + init_hexbytes_noT(secretBn256str,swap->I.secretBn256,32); + fprintf(fp,",\"secretBn256\":\"%s\"",secretBn256str); + } + for (i=0; i<2; i++) + if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) + fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); + if ( bits256_nonz(swap->I.privAm) != 0 ) + fprintf(fp,",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); + if ( bits256_nonz(swap->I.privBn) != 0 ) + fprintf(fp,",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); + if ( bits256_nonz(swap->I.pubA0) != 0 ) + fprintf(fp,",\"pubA0\":\"%s\"",bits256_str(str,swap->I.pubA0)); + if ( bits256_nonz(swap->I.pubB0) != 0 ) + fprintf(fp,",\"pubB0\":\"%s\"",bits256_str(str,swap->I.pubB0)); + if ( bits256_nonz(swap->I.pubB1) != 0 ) + fprintf(fp,",\"pubB1\":\"%s\"",bits256_str(str,swap->I.pubB1)); + if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + fprintf(fp,",\"Bdeposit\":\"%s\"",bits256_str(str,swap->bobdeposit.I.actualtxid)); + if ( bits256_nonz(swap->bobrefund.I.actualtxid) != 0 ) + fprintf(fp,",\"Brefund\":\"%s\"",bits256_str(str,swap->bobrefund.I.actualtxid)); + if ( bits256_nonz(swap->aliceclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Aclaim\":\"%s\"",bits256_str(str,swap->aliceclaim.I.actualtxid)); + + if ( bits256_nonz(swap->bobpayment.I.actualtxid) != 0 ) + fprintf(fp,",\"Bpayment\":\"%s\"",bits256_str(str,swap->bobpayment.I.actualtxid)); + if ( bits256_nonz(swap->alicespend.I.actualtxid) != 0 ) + fprintf(fp,",\"Aspend\":\"%s\"",bits256_str(str,swap->alicespend.I.actualtxid)); + if ( bits256_nonz(swap->bobreclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Breclaim\":\"%s\"",bits256_str(str,swap->bobreclaim.I.actualtxid)); + + if ( bits256_nonz(swap->alicepayment.I.actualtxid) != 0 ) + fprintf(fp,",\"Apayment\":\"%s\"",bits256_str(str,swap->alicepayment.I.actualtxid)); + if ( bits256_nonz(swap->bobspend.I.actualtxid) != 0 ) + fprintf(fp,",\"Bspend\":\"%s\"",bits256_str(str,swap->bobspend.I.actualtxid)); + if ( bits256_nonz(swap->alicereclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Areclaim\":\"%s\"",bits256_str(str,swap->alicereclaim.I.actualtxid)); + + if ( bits256_nonz(swap->otherfee.I.actualtxid) != 0 ) + fprintf(fp,",\"otherfee\":\"%s\"",bits256_str(str,swap->otherfee.I.actualtxid)); + if ( bits256_nonz(swap->myfee.I.actualtxid) != 0 ) + fprintf(fp,",\"myfee\":\"%s\"",bits256_str(str,swap->myfee.I.actualtxid)); + fprintf(fp,",\"dest33\":\""); + for (i=0; i<33; i++) + fprintf(fp,"%02x",swap->persistent_pubkey33[i]); + fprintf(fp,"\"}\n"); + fclose(fp); + } +} + +void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +{ + bits256 triggertxid; + memset(triggertxid.bytes,0,sizeof(triggertxid)); + if ( rawtx == 0 ) + { + basilisk_dontforget(myinfo,swap,0,0,triggertxid); + return; + } + if ( rawtx == &swap->myfee ) + basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); + else if ( rawtx == &swap->otherfee ) + basilisk_dontforget(myinfo,swap,&swap->otherfee,0,triggertxid); + else if ( rawtx == &swap->bobdeposit ) + { + basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + } + else if ( rawtx == &swap->bobrefund ) + basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + else if ( rawtx == &swap->aliceclaim ) + { + basilisk_dontforget(myinfo,swap,&swap->bobrefund,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->aliceclaim,0,swap->bobrefund.I.actualtxid); + } + else if ( rawtx == &swap->alicepayment ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + } + else if ( rawtx == &swap->bobspend ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); + } + else if ( rawtx == &swap->alicereclaim ) + { + basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); + } + else if ( rawtx == &swap->bobpayment ) + { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); + } + else if ( rawtx == &swap->alicespend ) + { + basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); + } + else if ( rawtx == &swap->bobreclaim ) + basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); +} + +int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; + if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) + { + swap->bobdeposit.I.signedtxid = basilisk_swap_broadcast(swap->bobdeposit.name,myinfo,swap,swap->bobdeposit.coin,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) + swap->depositunconf = 1; + basilisk_dontforget_update(myinfo,swap,&swap->bobdeposit); + len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_aliceclaim,userdata,len); + swap->I.userdata_aliceclaimlen = len; + if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobdeposit.I.datalen; i++) + printf("%02x",swap->bobdeposit.txbytes[i]); + printf(" <- bobdeposit\n"); + for (i=0; ialiceclaim.I.datalen; i++) + printf("%02x",swap->aliceclaim.txbytes[i]); + printf(" <- aliceclaim\n"); + basilisk_txlog(myinfo,swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); + return(retval); + } + } + printf("error with bobdeposit\n"); + return(-1); +} + +int32_t basilisk_bobdeposit_refund(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t delay) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; char str[65]; + len = basilisk_swapuserdata(userdata,swap->I.privBn,0,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_bobrefund,userdata,len); + swap->I.userdata_bobrefundlen = len; + if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0)) == 0 ) + { + for (i=0; ibobrefund.I.datalen; i++) + printf("%02x",swap->bobrefund.txbytes[i]); + printf(" <- bobrefund.(%s)\n",bits256_str(str,swap->bobrefund.I.txid)); + basilisk_txlog(myinfo,swap,&swap->bobrefund,delay); + return(retval); + } + return(-1); +} + +/*Bob paytx: + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF*/ + +int32_t basilisk_bobpayment_reclaim(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t delay) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; + printf("basilisk_bobpayment_reclaim\n"); + len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_bobreclaim,userdata,len); + swap->I.userdata_bobreclaimlen = len; + if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobreclaim.I.datalen; i++) + printf("%02x",swap->bobreclaim.txbytes[i]); + printf(" <- bobreclaim\n"); + basilisk_txlog(myinfo,swap,&swap->bobreclaim,delay); + return(retval); + } + return(-1); +} + +int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; bits256 revAm; struct basilisk_swap *swap = ptr; + memset(revAm.bytes,0,sizeof(revAm)); + if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) + { + swap->bobpayment.I.signedtxid = basilisk_swap_broadcast(swap->bobpayment.name,myinfo,swap,swap->bobpayment.coin,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) + swap->paymentunconf = 1; + basilisk_dontforget_update(myinfo,swap,&swap->bobpayment); + for (i=0; i<32; i++) + revAm.bytes[i] = swap->I.privAm.bytes[31-i]; + len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_alicespend,userdata,len); + swap->I.userdata_alicespendlen = len; + char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); + if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobpayment.I.datalen; i++) + printf("%02x",swap->bobpayment.txbytes[i]); + printf(" <- bobpayment\n"); + for (i=0; ialicespend.I.datalen; i++) + printf("%02x",swap->alicespend.txbytes[i]); + printf(" <- alicespend\n\n"); + swap->I.alicespent = 1; + basilisk_txlog(myinfo,swap,&swap->alicespend,-1); + return(retval); + } + } + return(-1); +} + +void basilisk_alicepayment(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) +{ + alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->chain->p2shtype,pubAm,pubBn); + basilisk_rawtx_gen("alicepayment",myinfo,swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->chain->txfee,1,0); +} + +int32_t basilisk_alicepayment_spend(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *dest) +{ + int32_t i,retval; + printf("alicepayment_spend\n"); + swap->alicepayment.I.spendlen = basilisk_alicescript(swap->alicepayment.redeemscript,&swap->alicepayment.I.redeemlen,swap->alicepayment.spendscript,0,swap->alicepayment.I.destaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); + printf("alicepayment_spend len.%d\n",swap->alicepayment.I.spendlen); + if ( swap->I.iambob == 0 ) + { + memcpy(swap->I.userdata_alicereclaim,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); + swap->I.userdata_alicereclaimlen = swap->alicepayment.I.spendlen; + } + else + { + memcpy(swap->I.userdata_bobspend,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); + swap->I.userdata_bobspendlen = swap->alicepayment.I.spendlen; + } + if ( (retval= basilisk_rawtx_sign(myinfo,swap->alicecoin->longestchain,swap,dest,&swap->alicepayment,swap->I.privAm,&swap->I.privBn,0,0,1)) == 0 ) + { + for (i=0; iI.datalen; i++) + printf("%02x",dest->txbytes[i]); + printf(" <- msigspend\n\n"); + if ( dest == &swap->bobspend ) + swap->I.bobspent = 1; + basilisk_txlog(myinfo,swap,dest,0); // bobspend or alicereclaim + return(retval); + } + return(-1); +} + +int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + struct basilisk_swap *swap = ptr; + if ( basilisk_rawtx_spendscript(swap,swap->alicecoin->longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) + { + swap->alicepayment.I.signedtxid = basilisk_swap_broadcast(swap->alicepayment.name,myinfo,swap,swap->alicepayment.coin,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) + swap->aliceunconf = 1; + basilisk_dontforget_update(myinfo,swap,&swap->alicepayment); + return(0); + } + else return(-1); +} + +int32_t basilisk_verify_pubpair(int32_t *wrongfirstbytep,struct basilisk_swap *swap,int32_t ind,uint8_t pub0,bits256 pubi,uint64_t txid) +{ + if ( pub0 != (swap->I.iambob ^ 1) + 0x02 ) + { + (*wrongfirstbytep)++; + printf("wrongfirstbyte[%d] %02x\n",ind,pub0); + return(-1); + } + else if ( swap->otherdeck[ind][1] != pubi.txid ) + { + printf("otherdeck[%d] priv ->pub mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][1],(long long)pubi.txid); + return(-1); + } + else if ( swap->otherdeck[ind][0] != txid ) + { + printf("otherdeck[%d] priv mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][0],(long long)txid); + return(-1); + } + return(0); +} + +int32_t basilisk_bobscripts_set(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) +{ + int32_t i,j; //char str[65]; + if ( genflag != 0 && swap->I.iambob == 0 ) + printf("basilisk_bobscripts_set WARNING: alice generating BOB tx\n"); + if ( depositflag == 0 ) + { + swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); + bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + //for (i=0; ibobpayment.redeemlen; i++) + // printf("%02x",swap->bobpayment.redeemscript[i]); + //printf(" <- bobpayment.%d\n",i); + if ( genflag != 0 && bits256_nonz(*(bits256 *)swap->I.secretBn256) != 0 && swap->bobpayment.I.datalen == 0 ) + { + for (i=0; i<3; i++) + { + //if ( swap->bobpayment.txbytes != 0 && swap->bobpayment.I.spendlen != 0 ) + // break; + basilisk_rawtx_gen("payment",myinfo,swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->chain->txfee,1,0); + if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) + { + printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); + sleep(DEX_SLEEP); + } + else + { + for (j=0; jbobpayment.I.datalen; j++) + printf("%02x",swap->bobpayment.txbytes[j]); + //printf(" <- bobpayment.%d\n",swap->bobpayment.datalen); + //for (j=0; jbobpayment.redeemlen; j++) + // printf("%02x",swap->bobpayment.redeemscript[j]); + //printf(" <- redeem.%d\n",swap->bobpayment.redeemlen); + printf(" <- GENERATED BOB PAYMENT.%d\n",swap->bobpayment.I.datalen); + iguana_unspents_mark(myinfo,swap->bobcoin,swap->bobpayment.vins); + basilisk_bobpayment_reclaim(myinfo,swap,swap->I.callduration); + printf("bobscripts set completed\n"); + return(0); + } + } + } + } + else + { + swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); + bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) + { + for (i=0; i<3; i++) + { + //if ( swap->bobdeposit.txbytes != 0 && swap->bobdeposit.I.spendlen != 0 ) + // break; + basilisk_rawtx_gen("deposit",myinfo,swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->chain->txfee,1,0); + if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) + { + printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); + sleep(DEX_SLEEP); + } + else + { + for (j=0; jbobdeposit.I.datalen; j++) + printf("%02x",swap->bobdeposit.txbytes[j]); + printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); + //for (j=0; jbobdeposit.redeemlen; j++) + // printf("%02x",swap->bobdeposit.redeemscript[j]); + //printf(" <- redeem.%d\n",swap->bobdeposit.redeemlen); + //printf("GENERATED BOB DEPOSIT\n"); + iguana_unspents_mark(myinfo,swap->bobcoin,swap->bobdeposit.vins); + basilisk_bobdeposit_refund(myinfo,swap,swap->I.putduration); + printf("bobscripts set completed\n"); + return(0); + } + } + } + //for (i=0; ibobdeposit.redeemlen; i++) + // printf("%02x",swap->bobdeposit.redeemscript[i]); + //printf(" <- bobdeposit.%d\n",i); + } + return(0); +} + +int32_t basilisk_verify_privi(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t j,wrongfirstbyte,len = 0; bits256 privkey,pubi; char str[65],str2[65]; uint8_t secret160[20],pubkey33[33]; uint64_t txid; struct basilisk_swap *swap = ptr; + memset(privkey.bytes,0,sizeof(privkey)); + if ( datalen == sizeof(bits256) ) + { + for (j=0; j<32; j++) + privkey.bytes[j] = data[len++]; + revcalc_rmd160_sha256(secret160,privkey);//.bytes,sizeof(privkey)); + memcpy(&txid,secret160,sizeof(txid)); + pubi = bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); + if ( basilisk_verify_pubpair(&wrongfirstbyte,swap,swap->I.choosei,pubkey33[0],pubi,txid) == 0 ) + { + if ( swap->I.iambob != 0 ) + { + swap->I.privAm = privkey; + vcalc_sha256(0,swap->I.secretAm256,privkey.bytes,sizeof(privkey)); + printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); + basilisk_bobscripts_set(myinfo,swap,0,1); + } + else + { + swap->I.privBn = privkey; + vcalc_sha256(0,swap->I.secretBn256,privkey.bytes,sizeof(privkey)); + printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); + } + basilisk_dontforget_update(myinfo,swap,0); + char str[65]; printf("privi verified.(%s)\n",bits256_str(str,privkey)); + return(0); + } + } + return(-1); +} + +int32_t basilisk_process_swapverify(struct supernet_info *myinfo,void *ptr,int32_t (*internal_func)(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen),uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen,uint32_t expiration,uint32_t duration) +{ + struct basilisk_swap *swap = ptr; + if ( internal_func != 0 ) + return((*internal_func)(myinfo,swap,data,datalen)); + else return(0); +} + +void basilisk_swapgotdata(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t crc32,bits256 srchash,bits256 desthash,uint32_t quoteid,uint32_t msgbits,uint8_t *data,int32_t datalen,int32_t reinit) +{ + int32_t i; struct basilisk_swapmessage *mp; + for (i=0; inummessages; i++) + if ( crc32 == swap->messages[i].crc32 && msgbits == swap->messages[i].msgbits && bits256_cmp(srchash,swap->messages[i].srchash) == 0 && bits256_cmp(desthash,swap->messages[i].desthash) == 0 ) + return; + //printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); + swap->messages = realloc(swap->messages,sizeof(*swap->messages) * (swap->nummessages + 1)); + mp = &swap->messages[swap->nummessages++]; + mp->crc32 = crc32; + mp->srchash = srchash; + mp->desthash = desthash; + mp->msgbits = msgbits; + mp->quoteid = quoteid; + mp->data = malloc(datalen); + mp->datalen = datalen; + memcpy(mp->data,data,datalen); + if ( reinit == 0 && swap->fp != 0 ) + { + fwrite(mp,1,sizeof(*mp),swap->fp); + fwrite(data,1,datalen,swap->fp); + fflush(swap->fp); + } +} + +FILE *basilisk_swap_save(struct supernet_info *myinfo,struct basilisk_swap *swap,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) +{ + FILE *fp=0; /*char fname[512]; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,rp->requestid,rp->quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) == 0 ) + { + if ( (fp= fopen(fname,"wb+")) != 0 ) + { + fwrite(privkey.bytes,1,sizeof(privkey),fp); + fwrite(rp,1,sizeof(*rp),fp); + fwrite(&statebits,1,sizeof(statebits),fp); + fwrite(&optionduration,1,sizeof(optionduration),fp); + fflush(fp); + } + } + else if ( reinit != 0 ) + { + }*/ + return(fp); +} + +int32_t basilisk_swap_load(uint32_t requestid,uint32_t quoteid,bits256 *privkeyp,struct basilisk_request *rp,uint32_t *statebitsp,int32_t *optiondurationp) +{ + FILE *fp=0; char fname[512]; int32_t retval = -1; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) + { + if ( fread(privkeyp,1,sizeof(*privkeyp),fp) == sizeof(*privkeyp) && + fread(rp,1,sizeof(*rp),fp) == sizeof(*rp) && + fread(statebitsp,1,sizeof(*statebitsp),fp) == sizeof(*statebitsp) && + fread(optiondurationp,1,sizeof(*optiondurationp),fp) == sizeof(*optiondurationp) ) + retval = 0; + fclose(fp); + } + return(retval); +} + +struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit); + +void basilisk_swaps_init(struct supernet_info *myinfo) +{ + char fname[512]; uint32_t iter,swapcompleted,requestid,quoteid,optionduration,statebits; FILE *fp; bits256 privkey;struct basilisk_request R; struct basilisk_swapmessage M; struct basilisk_swap *swap = 0; + sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); + if ( (myinfo->swapsfp= fopen(fname,"rb+")) != 0 ) + { + while ( fread(&requestid,1,sizeof(requestid),myinfo->swapsfp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),myinfo->swapsfp) == sizeof(quoteid) ) + { + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + printf("%s\n",fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) // check to see if completed + { + memset(&M,0,sizeof(M)); + swapcompleted = 1; + for (iter=0; iter<2; iter++) + { + if ( fread(privkey.bytes,1,sizeof(privkey),fp) == sizeof(privkey) && + fread(&R,1,sizeof(R),fp) == sizeof(R) && + fread(&statebits,1,sizeof(statebits),fp) == sizeof(statebits) && + fread(&optionduration,1,sizeof(optionduration),fp) == sizeof(optionduration) ) + { + while ( 0 && fread(&M,1,sizeof(M),fp) == sizeof(M) ) + { + M.data = 0; + //printf("entry iter.%d crc32.%x datalen.%d\n",iter,M.crc32,M.datalen); + if ( M.datalen < 100000 ) + { + M.data = malloc(M.datalen); + if ( fread(M.data,1,M.datalen,fp) == M.datalen ) + { + if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) + { + if ( iter == 1 ) + { + if ( swap == 0 ) + { + swap = basilisk_thread_start(myinfo,privkey,&R,statebits,optionduration,1); + swap->I.choosei = swap->I.otherchoosei = -1; + } + if ( swap != 0 ) + basilisk_swapgotdata(myinfo,swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); + } + } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); + } else printf("error reading M.datalen %d\n",M.datalen); + free(M.data), M.data = 0; + } + } + } + if ( swapcompleted != 0 ) + break; + rewind(fp); + } + } + } + } else myinfo->swapsfp = fopen(fname,"wb+"); +} + +void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t amlp); + +int32_t basilisk_swapget(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen)) +{ + uint8_t *ptr; bits256 srchash,desthash; uint32_t crc32,_msgbits,quoteid; int32_t i,size,offset,retval = -1; struct basilisk_swapmessage *mp = 0; + while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,0)) >= 0 ) + { + swap->lasttime = (uint32_t)time(NULL); + memset(srchash.bytes,0,sizeof(srchash)); + memset(desthash.bytes,0,sizeof(desthash)); + //printf("gotmsg.[%d] crc.%x\n",size,crc32); + offset = 0; + for (i=0; i<32; i++) + srchash.bytes[i] = ptr[offset++]; + for (i=0; i<32; i++) + desthash.bytes[i] = ptr[offset++]; + offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),"eid); + offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),&_msgbits); + if ( size > offset ) + { + crc32 = calc_crc32(0,&ptr[offset],size-offset); + if ( size > offset ) + { + //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); + basilisk_swapgotdata(myinfo,swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); + } + } + else if ( bits256_nonz(srchash) == 0 && bits256_nonz(desthash) == 0 ) + { + if ( swap->aborted == 0 ) + { + swap->aborted = (uint32_t)time(NULL); + printf("got abort signal from other side\n"); + } + } else printf("basilisk_swapget: got strange packet\n"); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } + //char str[65],str2[65]; + for (i=0; inummessages; i++) + { + //printf("%d: %s vs %s\n",i,bits256_str(str,swap->messages[i].srchash),bits256_str(str2,swap->messages[i].desthash)); + if ( bits256_cmp(swap->messages[i].desthash,swap->I.myhash) == 0 ) + { + if ( swap->messages[i].msgbits == msgbits ) + { + if ( swap->I.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) + { + printf("nothing received for a while from Bob, try new sockets\n"); + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + } + mp = &swap->messages[i]; + if ( msgbits != 0x80000000 ) + break; + } + } + } + if ( mp != 0 ) + retval = (*basilisk_verify_func)(myinfo,swap,mp->data,mp->datalen); + //printf("mine/other %s vs %s\n",bits256_str(str,swap->I.myhash),bits256_str(str2,swap->I.otherhash)); + return(retval); +} + +uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits,uint32_t crcs[2]) +{ + uint8_t *buf; int32_t sentbytes,offset=0,i; + buf = malloc(datalen + sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2); + for (i=0; i<32; i++) + buf[offset++] = swap->I.myhash.bytes[i]; + for (i=0; i<32; i++) + buf[offset++] = swap->I.otherhash.bytes[i]; + offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); + offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); + if ( datalen > 0 ) + memcpy(&buf[offset],data,datalen), offset += datalen; + if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) + { + printf("sentbytes.%d vs offset.%d\n",sentbytes,offset); + if ( sentbytes < 0 ) + { + if ( swap->pushsock >= 0 ) + nn_close(swap->pushsock), swap->pushsock = -1; //, + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = swap->I.iambob != 0 ? -1 : 0; + swap->aborted = (uint32_t)time(NULL); + } + } + //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); + free(buf); + return(nextbits); +} + +void basilisk_swap_sendabort(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + uint32_t msgbits = 0; uint8_t buf[sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2]; int32_t sentbytes,offset=0; + memset(buf,0,sizeof(buf)); + offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); + offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); + if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) + { + if ( sentbytes < 0 ) + { + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; + } + } else printf("basilisk_swap_sendabort\n"); +} + +int32_t basilisk_privBn_extract(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + if ( basilisk_priviextract(myinfo,swap->bobcoin,"privBn",&swap->I.privBn,swap->I.secretBn,swap->bobrefund.I.actualtxid,0) == 0 ) + { + printf("extracted privBn from blockchain\n"); + } + else if ( basilisk_swapget(myinfo,swap,0x40000000,data,maxlen,basilisk_verify_privi) == 0 ) + { + } + if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) + { + char str[65]; printf("got privBn.%s\n",bits256_str(str,swap->I.privBn)); + return(basilisk_alicepayment_spend(myinfo,swap,&swap->alicereclaim)); + } + return(-1); +} + +int32_t basilisk_privAm_extract(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + if ( basilisk_priviextract(myinfo,swap->bobcoin,"privAm",&swap->I.privAm,swap->I.secretAm,swap->bobpayment.I.actualtxid,0) == 0 ) + { + printf("extracted privAm from blockchain\n"); + } + if ( bits256_nonz(swap->I.privAm) != 0 && swap->bobspend.I.datalen == 0 ) + { + char str[65]; printf("got privAm.%s\n",bits256_str(str,swap->I.privAm)); + return(basilisk_alicepayment_spend(myinfo,swap,&swap->bobspend)); + } + return(-1); +} + +bits256 instantdex_derivekeypair(void *ctx,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash) +{ + bits256 sharedsecret; + sharedsecret = curve25519_shared(privkey,orderhash); + vcalc_sha256cat(newprivp->bytes,orderhash.bytes,sizeof(orderhash),sharedsecret.bytes,sizeof(sharedsecret)); + return(bitcoin_pubkey33(ctx,pubkey,*newprivp)); +} + +int32_t instantdex_pubkeyargs(void *ctx,struct basilisk_swap *swap,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte) +{ + char buf[3]; int32_t i,n,m,len=0; bits256 pubi,reveal; uint64_t txid; uint8_t secret160[20],pubkey[33]; + sprintf(buf,"%c0",'A' - 0x02 + firstbyte); + if ( numpubs > 2 ) + { + if ( swap->I.numpubs+2 >= numpubs ) + return(numpubs); + //fprintf(stderr,">>>>>> start generating %s\n",buf); + } + for (i=n=m=0; iI.mypubs[n]) == 0 ) + { + swap->I.myprivs[n] = privkey; + memcpy(swap->I.mypubs[n].bytes,pubkey+1,sizeof(bits256)); + reveal = basilisk_revealkey(privkey,swap->I.mypubs[n]); + if ( swap->I.iambob != 0 ) + { + if ( n == 0 ) + swap->I.pubB0 = reveal; + else if ( n == 1 ) + swap->I.pubB1 = reveal; + } + else if ( swap->I.iambob == 0 ) + { + if ( n == 0 ) + swap->I.pubA0 = reveal; + else if ( n == 1 ) + swap->I.pubA1 = reveal; + } + } + } + if ( m < INSTANTDEX_DECKSIZE ) + { + swap->privkeys[m] = privkey; + revcalc_rmd160_sha256(secret160,privkey);//.bytes,sizeof(privkey)); + memcpy(&txid,secret160,sizeof(txid)); + len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][0],sizeof(txid),&txid); + len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][1],sizeof(pubi.txid),&pubi.txid); + m++; + if ( m > swap->I.numpubs ) + swap->I.numpubs = m; + } + n++; + } + if ( n > 2 || m > 2 ) + printf("n.%d m.%d len.%d numpubs.%d\n",n,m,len,swap->I.numpubs); + return(n); +} + +void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx *rawtx,struct iguana_info *coin,int32_t numconfirms,int32_t vintype,uint64_t satoshis,int32_t vouttype,uint8_t *pubkey33,int32_t jumblrflag) +{ + strcpy(rawtx->name,name); + rawtx->coin = coin; + strcpy(rawtx->I.coinstr,coin->symbol); + rawtx->I.numconfirms = numconfirms; + if ( (rawtx->I.amount= satoshis) < 50000 ) + rawtx->I.amount = 50000; + rawtx->I.vintype = vintype; // 0 -> std, 2 -> 2of2, 3 -> spend bobpayment, 4 -> spend bobdeposit + rawtx->I.vouttype = vouttype; // 0 -> fee, 1 -> std, 2 -> 2of2, 3 -> bobpayment, 4 -> bobdeposit + if ( rawtx->I.vouttype == 0 ) + { + if ( strcmp(coin->symbol,"BTC") == 0 && (quoteid % 10) == 0 ) + decode_hex(rawtx->I.rmd160,20,TIERNOLAN_RMD160); + else decode_hex(rawtx->I.rmd160,20,INSTANTDEX_RMD160); + bitcoin_address(rawtx->I.destaddr,rawtx->coin->chain->pubtype,rawtx->I.rmd160,20); + } + if ( pubkey33 != 0 ) + { + memcpy(rawtx->I.pubkey33,pubkey33,33); + bitcoin_address(rawtx->I.destaddr,rawtx->coin->chain->pubtype,rawtx->I.pubkey33,33); + bitcoin_addr2rmd160(&rawtx->I.addrtype,rawtx->I.rmd160,rawtx->I.destaddr); + } + if ( rawtx->I.vouttype <= 1 && rawtx->I.destaddr[0] != 0 ) + { + rawtx->I.spendlen = bitcoin_standardspend(rawtx->spendscript,0,rawtx->I.rmd160); + printf("%s spendlen.%d %s <- %.8f\n",name,rawtx->I.spendlen,rawtx->I.destaddr,dstr(rawtx->I.amount)); + } else printf("%s vouttype.%d destaddr.(%s)\n",name,rawtx->I.vouttype,rawtx->I.destaddr); +} + +int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct iguana_info **alicecoinp,char *src,char *dest,bits256 srchash,bits256 desthash) +{ + struct iguana_info *coin = iguana_coinfind(src); + if ( coin == 0 || iguana_coinfind(dest) == 0 ) + return(0); + *bobcoinp = *alicecoinp = 0; + *bobcoinp = iguana_coinfind(dest); + *alicecoinp = iguana_coinfind(src); + if ( bits256_cmp(pubkey,srchash) == 0 ) + { + if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) + return(1); + else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) + return(-1); + else return(0); + } + else if ( bits256_cmp(pubkey,desthash) == 0 ) + { + if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) + return(-1); + else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) + return(1); + else return(0); + } + return(0); +} + +void basilisk_swap_saveupdate(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + FILE *fp; char fname[512]; + sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fwrite(&swap->I,1,sizeof(swap->I),fp); + /*fwrite(&swap->bobdeposit,1,sizeof(swap->bobdeposit),fp); + fwrite(&swap->bobpayment,1,sizeof(swap->bobpayment),fp); + fwrite(&swap->alicepayment,1,sizeof(swap->alicepayment),fp); + fwrite(&swap->myfee,1,sizeof(swap->myfee),fp); + fwrite(&swap->otherfee,1,sizeof(swap->otherfee),fp); + fwrite(&swap->aliceclaim,1,sizeof(swap->aliceclaim),fp); + fwrite(&swap->alicespend,1,sizeof(swap->alicespend),fp); + fwrite(&swap->bobreclaim,1,sizeof(swap->bobreclaim),fp); + fwrite(&swap->bobspend,1,sizeof(swap->bobspend),fp); + fwrite(&swap->bobrefund,1,sizeof(swap->bobrefund),fp); + fwrite(&swap->alicereclaim,1,sizeof(swap->alicereclaim),fp);*/ + fwrite(swap->privkeys,1,sizeof(swap->privkeys),fp); + fwrite(swap->otherdeck,1,sizeof(swap->otherdeck),fp); + fwrite(swap->deck,1,sizeof(swap->deck),fp); + fclose(fp); + } +} + +int32_t basilisk_swap_loadtx(struct basilisk_rawtx *rawtx,FILE *fp,char *bobcoinstr,char *alicecoinstr) +{ + if ( fread(rawtx,1,sizeof(*rawtx),fp) == sizeof(*rawtx) ) + { + rawtx->coin = 0; + rawtx->vins = 0; + if ( strcmp(rawtx->I.coinstr,bobcoinstr) == 0 || strcmp(rawtx->I.coinstr,alicecoinstr) == 0 ) + { + rawtx->coin = iguana_coinfind(rawtx->I.coinstr); + if ( rawtx->vinstr[0] != 0 ) + rawtx->vins = cJSON_Parse(rawtx->vinstr); + printf("loaded.%s len.%d\n",rawtx->name,rawtx->I.datalen); + return(0); + } + } + return(-1); +} + +struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 privkey,uint8_t *pubkey33,bits256 pubkey25519,struct basilisk_swap *swap,int32_t optionduration,uint32_t statebits,int32_t reinit) +{ + FILE *fp; char fname[512]; uint8_t *alicepub33=0,*bobpub33=0; int32_t errs=0,jumblrflag,x = -1; + if ( reinit != 0 ) + { + sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + printf("reinit.(%s)\n",fname); + if ( (fp= fopen(fname,"rb")) != 0 ) + { + if ( fread(&swap->I,1,sizeof(swap->I),fp) != sizeof(swap->I) ) + errs++; + if ( swap->bobcoin == 0 ) + swap->bobcoin = iguana_coinfind(swap->I.req.dest); + if ( swap->alicecoin == 0 ) + swap->alicecoin = iguana_coinfind(swap->I.req.src); + if ( swap->alicecoin != 0 && swap->bobcoin != 0 ) + { + /*basilisk_swap_loadtx(&swap->bobdeposit,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->bobpayment,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->alicepayment,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->myfee,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->otherfee,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->aliceclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->alicespend,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->bobreclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->bobspend,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->bobrefund,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); + basilisk_swap_loadtx(&swap->alicereclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol);*/ + } else printf("missing coins (%p %p)\n",swap->bobcoin,swap->alicecoin); + if ( fread(swap->privkeys,1,sizeof(swap->privkeys),fp) != sizeof(swap->privkeys) ) + errs++; + if ( fread(swap->otherdeck,1,sizeof(swap->otherdeck),fp) != sizeof(swap->otherdeck) ) + errs++; + if ( fread(swap->deck,1,sizeof(swap->deck),fp) != sizeof(swap->deck) ) + errs++; + fclose(fp); + } else printf("cant find.(%s)\n",fname); + } + else + { + swap->I.putduration = swap->I.callduration = INSTANTDEX_LOCKTIME; + if ( optionduration < 0 ) + swap->I.putduration -= optionduration; + else if ( optionduration > 0 ) + swap->I.callduration += optionduration; + swap->I.bobsatoshis = swap->I.req.destamount; + swap->I.alicesatoshis = swap->I.req.srcamount; + if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) + swap->I.bobinsurance = 50000; + if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) + swap->I.aliceinsurance = 50000; + strcpy(swap->I.bobstr,swap->I.req.dest); + strcpy(swap->I.alicestr,swap->I.req.src); + swap->I.started = (uint32_t)time(NULL); + swap->I.expiration = swap->I.req.timestamp + swap->I.putduration + swap->I.callduration; + OS_randombytes((uint8_t *)&swap->I.choosei,sizeof(swap->I.choosei)); + if ( swap->I.choosei < 0 ) + swap->I.choosei = -swap->I.choosei; + swap->I.choosei %= INSTANTDEX_DECKSIZE; + swap->I.otherchoosei = -1; + swap->I.myhash = pubkey25519; + if ( statebits != 0 ) + { + swap->I.iambob = 0; + swap->I.otherhash = swap->I.req.desthash; + } + else + { + swap->I.iambob = 1; + swap->I.otherhash = swap->I.req.srchash; + } + if ( bits256_nonz(privkey) == 0 || (x= instantdex_pubkeyargs(myinfo->ctx,swap,2 + INSTANTDEX_DECKSIZE,privkey,swap->I.orderhash,0x02+swap->I.iambob)) != 2 + INSTANTDEX_DECKSIZE ) + { + char str[65]; printf("couldnt generate privkeys %d %s\n",x,bits256_str(str,privkey)); + return(0); + } + } + swap->bobcoin = iguana_coinfind(swap->I.req.dest); + swap->alicecoin = iguana_coinfind(swap->I.req.src); + if ( swap->bobcoin == 0 || swap->alicecoin == 0 ) + { + printf("missing bobcoin.%p or missing alicecoin.%p src.%p dest.%p\n",swap->bobcoin,swap->alicecoin,iguana_coinfind(swap->I.req.src),iguana_coinfind(swap->I.req.dest)); + free(swap); + return(0); + } + if ( strcmp("BTC",swap->bobcoin->symbol) == 0 ) + { + swap->I.bobconfirms = (1*0 + sqrt(dstr(swap->I.bobsatoshis) * .1)); + swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); + } + else if ( strcmp("BTC",swap->alicecoin->symbol) == 0 ) + { + swap->I.aliceconfirms = (1*0 + sqrt(dstr(swap->I.alicesatoshis) * .1)); + swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); + } + else + { + swap->I.bobconfirms = BASILISK_DEFAULT_NUMCONFIRMS; + swap->I.aliceconfirms = BASILISK_DEFAULT_NUMCONFIRMS; + } + /*if ( swap->I.bobconfirms == 0 ) + swap->I.bobconfirms = swap->bobcoin->chain->minconfirms; + if ( swap->I.aliceconfirms == 0 ) + swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms;*/ + jumblrflag = (bits256_cmp(pubkey25519,myinfo->jumblr_pubkey) == 0 || bits256_cmp(pubkey25519,myinfo->jumblr_depositkey) == 0); + printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); + if ( swap->I.iambob != 0 ) + { + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + bobpub33 = pubkey33; + } + else + { + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + alicepub33 = pubkey33; + } + basilisk_rawtx_setparms("bobdeposit",swap->I.req.quoteid,&swap->bobdeposit,swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3) + swap->bobcoin->txfee,4,0,jumblrflag); + basilisk_rawtx_setparms("bobrefund",swap->I.req.quoteid,&swap->bobrefund,swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,bobpub33,jumblrflag); + swap->bobrefund.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("aliceclaim",swap->I.req.quoteid,&swap->aliceclaim,swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,alicepub33,jumblrflag); + swap->aliceclaim.I.suppress_pubkeys = 1; + swap->aliceclaim.I.locktime = swap->I.started + swap->I.putduration+swap->I.callduration + 1; + + basilisk_rawtx_setparms("bobpayment",swap->I.req.quoteid,&swap->bobpayment,swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + swap->bobcoin->txfee,3,0,jumblrflag); + basilisk_rawtx_setparms("alicespend",swap->I.req.quoteid,&swap->alicespend,swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,alicepub33,jumblrflag); + swap->alicespend.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("bobreclaim",swap->I.req.quoteid,&swap->bobreclaim,swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,bobpub33,jumblrflag); + swap->bobreclaim.I.suppress_pubkeys = 1; + swap->bobreclaim.I.locktime = swap->I.started + swap->I.putduration + 1; + basilisk_rawtx_setparms("alicepayment",swap->I.req.quoteid,&swap->alicepayment,swap->alicecoin,swap->I.aliceconfirms,0,swap->I.alicesatoshis+swap->alicecoin->txfee,2,0,jumblrflag); + basilisk_rawtx_setparms("bobspend",swap->I.req.quoteid,&swap->bobspend,swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,bobpub33,jumblrflag); + swap->bobspend.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("alicereclaim",swap->I.req.quoteid,&swap->alicereclaim,swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,alicepub33,jumblrflag); + swap->alicereclaim.I.suppress_pubkeys = 1; + printf("IAMBOB.%d\n",swap->I.iambob); + + return(swap); +} +// end of alice/bob code + +void basilisk_rawtx_purge(struct basilisk_rawtx *rawtx) +{ + if ( rawtx->vins != 0 ) + free_json(rawtx->vins); + //if ( rawtx->txbytes != 0 ) + // free(rawtx->txbytes), rawtx->txbytes = 0; +} + +void basilisk_swap_finished(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + int32_t i; + swap->I.finished = (uint32_t)time(NULL); + // save to permanent storage + basilisk_rawtx_purge(&swap->bobdeposit); + basilisk_rawtx_purge(&swap->bobpayment); + basilisk_rawtx_purge(&swap->alicepayment); + basilisk_rawtx_purge(&swap->myfee); + basilisk_rawtx_purge(&swap->otherfee); + basilisk_rawtx_purge(&swap->aliceclaim); + basilisk_rawtx_purge(&swap->alicespend); + basilisk_rawtx_purge(&swap->bobreclaim); + basilisk_rawtx_purge(&swap->bobspend); + basilisk_rawtx_purge(&swap->bobrefund); + basilisk_rawtx_purge(&swap->alicereclaim); + for (i=0; inummessages; i++) + if ( swap->messages[i].data != 0 ) + free(swap->messages[i].data), swap->messages[i].data = 0; + free(swap->messages), swap->messages = 0; + swap->nummessages = 0; +} + +void basilisk_swap_purge(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + int32_t i,n; + // while still in orderbook, wait + //return; + portable_mutex_lock(&myinfo->DEX_swapmutex); + n = myinfo->numswaps; + for (i=0; iswaps[i] == swap ) + { + myinfo->swaps[i] = myinfo->swaps[--myinfo->numswaps]; + myinfo->swaps[myinfo->numswaps] = 0; + basilisk_swap_finished(myinfo,swap); + break; + } + portable_mutex_unlock(&myinfo->DEX_swapmutex); +} + +int32_t basilisk_verify_otherstatebits(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t retval; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(swap->I.otherstatebits) ) + { + retval = iguana_rwnum(0,data,sizeof(swap->I.otherstatebits),&swap->I.otherstatebits); + return(retval); + } else return(-1); +} + +int32_t basilisk_verify_statebits(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t retval = -1; uint32_t statebits; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(swap->I.statebits) ) + { + retval = iguana_rwnum(0,data,sizeof(swap->I.statebits),&statebits); + if ( statebits != swap->I.statebits ) + { + printf("statebits.%x != %x\n",statebits,swap->I.statebits); + return(-1); + } + } + return(retval); +} + +int32_t basilisk_verify_choosei(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t otherchoosei=-1,i,len = 0; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(otherchoosei)+sizeof(bits256)*2 ) + { + len += iguana_rwnum(0,data,sizeof(otherchoosei),&otherchoosei); + if ( otherchoosei >= 0 && otherchoosei < INSTANTDEX_DECKSIZE ) + { + //printf("otherchoosei.%d\n",otherchoosei); + swap->I.otherchoosei = otherchoosei; + if ( swap->I.iambob != 0 ) + { + for (i=0; i<32; i++) + swap->I.pubA0.bytes[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.pubA1.bytes[i] = data[len++]; + char str[65]; printf("GOT pubA0/1 %s\n",bits256_str(str,swap->I.pubA0)); + } + else + { + for (i=0; i<32; i++) + swap->I.pubB0.bytes[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.pubB1.bytes[i] = data[len++]; + } + return(0); + } + } + printf("illegal otherchoosei.%d datalen.%d vs %d\n",otherchoosei,datalen,(int32_t)(sizeof(otherchoosei)+sizeof(bits256)*2)); + return(-1); +} + +int32_t basilisk_swapdata_deck(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,datalen = 0; + for (i=0; ideck)/sizeof(swap->deck[0][0]); i++) + datalen += iguana_rwnum(1,&data[datalen],sizeof(swap->deck[i>>1][i&1]),&swap->deck[i>>1][i&1]); + return(datalen); +} + +int32_t basilisk_verify_otherdeck(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t i,len = 0; struct basilisk_swap *swap = ptr; + for (i=0; iotherdeck)/sizeof(swap->otherdeck[0][0]); i++) + len += iguana_rwnum(0,&data[len],sizeof(swap->otherdeck[i>>1][i&1]),&swap->otherdeck[i>>1][i&1]); + return(0); +} + +int32_t basilisk_verify_privkeys(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t i,j,wrongfirstbyte=0,errs=0,len = 0; bits256 otherpriv,pubi; uint8_t secret160[20],otherpubkey[33]; uint64_t txid; struct basilisk_swap *swap = ptr; + //printf("verify privkeys choosei.%d otherchoosei.%d datalen.%d vs %d\n",swap->choosei,swap->otherchoosei,datalen,(int32_t)sizeof(swap->privkeys)+20+32); + memset(otherpriv.bytes,0,sizeof(otherpriv)); + if ( swap->I.cutverified == 0 && swap->I.otherchoosei >= 0 && datalen == sizeof(swap->privkeys)+20+2*32 ) + { + for (i=errs=0; iprivkeys)/sizeof(*swap->privkeys); i++) + { + for (j=0; j<32; j++) + otherpriv.bytes[j] = data[len++]; + if ( i != swap->I.choosei ) + { + pubi = bitcoin_pubkey33(myinfo->ctx,otherpubkey,otherpriv); + revcalc_rmd160_sha256(secret160,otherpriv);//.bytes,sizeof(otherpriv)); + memcpy(&txid,secret160,sizeof(txid)); + errs += basilisk_verify_pubpair(&wrongfirstbyte,swap,i,otherpubkey[0],pubi,txid); + } + } + if ( errs == 0 && wrongfirstbyte == 0 ) + { + swap->I.cutverified = 1, printf("CUT VERIFIED\n"); + if ( swap->I.iambob != 0 ) + { + for (i=0; i<32; i++) + swap->I.pubAm.bytes[i] = data[len++]; + for (i=0; i<20; i++) + swap->I.secretAm[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.secretAm256[i] = data[len++]; + basilisk_bobscripts_set(myinfo,swap,1,1); + } + else + { + for (i=0; i<32; i++) + swap->I.pubBn.bytes[i] = data[len++]; + for (i=0; i<20; i++) + swap->I.secretBn[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.secretBn256[i] = data[len++]; + //basilisk_bobscripts_set(myinfo,swap,0); + } + } else printf("failed verification: wrong firstbyte.%d errs.%d\n",wrongfirstbyte,errs); + } + //printf("privkeys errs.%d wrongfirstbyte.%d\n",errs,wrongfirstbyte); + return(errs); +} + +uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) +{ + uint8_t sendbuf[32768]; int32_t sendlen; + if ( basilisk_swapdata_rawtx(myinfo,swap,data,maxlen,rawtx) != 0 ) + { + if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + { + char str[65],str2[65]; + rawtx->I.actualtxid = basilisk_swap_broadcast(rawtx->name,myinfo,swap,rawtx->coin,rawtx->txbytes,rawtx->I.datalen); + if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) + { + printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); + rawtx->I.actualtxid = rawtx->I.signedtxid; + } + if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) + { + sendlen = 0; + sendbuf[sendlen++] = rawtx->I.datalen & 0xff; + sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; + sendbuf[sendlen++] = rawtx->I.redeemlen; + memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + { + memcpy(&sendbuf[sendlen],rawtx->redeemscript,rawtx->I.redeemlen); + sendlen += rawtx->I.redeemlen; + } + basilisk_dontforget_update(myinfo,swap,rawtx); + //printf("sendlen.%d datalen.%d redeemlen.%d\n",sendlen,rawtx->datalen,rawtx->redeemlen); + if ( suppress_swapsend == 0 ) + return(basilisk_swapsend(myinfo,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs)); + else + { + printf("suppress swapsend %x\n",msgbits); + return(0); + } + } + } + return(nextbits); + } else if ( swap->I.iambob == 0 ) + printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); + return(0); +} + +void basilisk_sendpubkeys(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t datalen; + datalen = basilisk_swapdata_deck(myinfo,swap,data,maxlen); + printf("send deck.%d\n",datalen); + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x02,data,datalen,0x01,swap->I.crcs_mypub); +} + +int32_t basilisk_checkdeck(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + if ( (swap->I.statebits & 0x02) == 0 ) + { + //printf("check for other deck\n"); + if ( basilisk_swapget(myinfo,swap,0x02,data,maxlen,basilisk_verify_otherdeck) == 0 ) + swap->I.statebits |= 0x02; + else return(-1); + } + return(0); +} + +void basilisk_sendstate(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t datalen=0; + datalen = iguana_rwnum(1,data,sizeof(swap->I.statebits),&swap->I.statebits); + basilisk_swapsend(myinfo,swap,0x80000000,data,datalen,0,0); +} + +void basilisk_sendchoosei(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,datalen; char str[65]; + datalen = iguana_rwnum(1,data,sizeof(swap->I.choosei),&swap->I.choosei); + if ( swap->I.iambob != 0 ) + { + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubB0.bytes[i]; + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubB1.bytes[i]; + printf("SEND pubB0/1 %s\n",bits256_str(str,swap->I.pubB0)); + } + else + { + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubA0.bytes[i]; + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubA1.bytes[i]; + printf("SEND pubA0/1 %s\n",bits256_str(str,swap->I.pubA0)); + } + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x08,data,datalen,0x04,swap->I.crcs_mychoosei); +} + +void basilisk_waitchoosei(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + uint8_t pubkey33[33]; char str[65],str2[65]; + //printf("check otherchoosei\n"); + if ( basilisk_swapget(myinfo,swap,0x08,data,maxlen,basilisk_verify_choosei) == 0 ) + { + if ( swap->I.iambob != 0 ) + { + if ( bits256_nonz(swap->I.privBn) == 0 ) + { + swap->I.privBn = swap->privkeys[swap->I.otherchoosei]; + memset(&swap->privkeys[swap->I.otherchoosei],0,sizeof(swap->privkeys[swap->I.otherchoosei])); + revcalc_rmd160_sha256(swap->I.secretBn,swap->I.privBn);//.bytes,sizeof(swap->privBn)); + vcalc_sha256(0,swap->I.secretBn256,swap->I.privBn.bytes,sizeof(swap->I.privBn)); + swap->I.pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,swap->I.privBn); + printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); + basilisk_bobscripts_set(myinfo,swap,1,1); + } + } + else + { + if ( bits256_nonz(swap->I.privAm) == 0 ) + { + swap->I.privAm = swap->privkeys[swap->I.otherchoosei]; + memset(&swap->privkeys[swap->I.otherchoosei],0,sizeof(swap->privkeys[swap->I.otherchoosei])); + revcalc_rmd160_sha256(swap->I.secretAm,swap->I.privAm);//.bytes,sizeof(swap->privAm)); + vcalc_sha256(0,swap->I.secretAm256,swap->I.privAm.bytes,sizeof(swap->I.privAm)); + swap->I.pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,swap->I.privAm); + char str[65],str2[65]; printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); + //basilisk_bobscripts_set(myinfo,swap,0); + } + } + swap->I.statebits |= 0x08; + } +} + +void basilisk_sendmostprivs(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,j,datalen; + datalen = 0; + for (i=0; iprivkeys)/sizeof(*swap->privkeys); i++) + { + for (j=0; j<32; j++) + data[datalen++] = (i == swap->I.otherchoosei) ? 0 : swap->privkeys[i].bytes[j]; + } + if ( swap->I.iambob != 0 ) + { + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubBn.bytes[i]; + for (i=0; i<20; i++) + data[datalen++] = swap->I.secretBn[i]; + for (i=0; i<32; i++) + data[datalen++] = swap->I.secretBn256[i]; + } + else + { + for (i=0; i<32; i++) + data[datalen++] = swap->I.pubAm.bytes[i]; + for (i=0; i<20; i++) + data[datalen++] = swap->I.secretAm[i]; + for (i=0; i<32; i++) + data[datalen++] = swap->I.secretAm256[i]; + } + //printf("send privkeys.%d\n",datalen); + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x20,data,datalen,0x10,swap->I.crcs_myprivs); +} + +int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t j,datalen,retval = 0; uint32_t savestatebits=0,saveotherbits=0; + if ( swap->I.iambob != 0 ) + swap->I.statebits |= 0x80; + while ( swap->aborted == 0 && ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) + { + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + printf("D r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); + if ( swap->I.iambob != 0 && (swap->I.statebits & 0x80) == 0 ) // wait for fee + { + if ( basilisk_swapget(myinfo,swap,0x80,data,maxlen,basilisk_verify_otherfee) == 0 ) + { + // verify and submit otherfee + swap->I.statebits |= 0x80; + basilisk_sendstate(myinfo,swap,data,maxlen); + } + } + else if ( swap->I.iambob == 0 ) + swap->I.statebits |= 0x80; + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + if ( (swap->I.otherstatebits & 0x80) != 0 && (swap->I.statebits & 0x80) != 0 ) + break; + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + basilisk_sendstate(myinfo,swap,data,maxlen); + if ( (swap->I.otherstatebits & 0x80) == 0 ) + basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); + } + basilisk_swap_saveupdate(myinfo,swap); + while ( swap->aborted == 0 && retval == 0 && time(NULL) < swap->I.expiration ) // both sides have setup required data and paid txfee + { + basilisk_swap_saveupdate(myinfo,swap); + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + //if ( (rand() % 30) == 0 ) + printf("E r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); + if ( swap->I.iambob != 0 ) + { + //printf("BOB\n"); + if ( (swap->I.statebits & 0x100) == 0 ) + { + printf("send bobdeposit\n"); + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0); + } + // [BLOCKING: altfound] make sure altpayment is confirmed and send payment + else if ( (swap->I.statebits & 0x1000) == 0 ) + { + printf("check alicepayment\n"); + if ( basilisk_swapget(myinfo,swap,0x1000,data,maxlen,basilisk_verify_alicepaid) == 0 ) + { + swap->I.statebits |= 0x1000; + printf("got alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); + } + } + else if ( (swap->I.statebits & 0x2000) == 0 ) + { + if ( (swap->I.aliceconfirms == 0 && swap->aliceunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->alicepayment) >= swap->I.aliceconfirms ) + { + swap->I.statebits |= 0x2000; + printf("alicepayment confirmed\n"); + } + } + else if ( (swap->I.statebits & 0x4000) == 0 ) + { + basilisk_bobscripts_set(myinfo,swap,0,1); + printf("send bobpayment\n"); + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0); + } + // [BLOCKING: privM] Bob waits for privAm either from Alice or alice blockchain + else if ( (swap->I.statebits & 0xc0000) != 0xc0000 ) + { + if ( basilisk_swapget(myinfo,swap,0x40000,data,maxlen,basilisk_verify_privi) == 0 || basilisk_privAm_extract(myinfo,swap) == 0 ) // divulges privAm + { + //printf("got privi spend alicepayment, dont divulge privBn until bobspend propagated\n"); + basilisk_alicepayment_spend(myinfo,swap,&swap->bobspend); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobspend,0x40000,1) == 0 ) + printf("Bob error spending alice payment\n"); + else + { + tradebot_swap_balancingtrade(myinfo,swap,1); + printf("Bob spends alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); + swap->I.statebits |= 0x40000; + if ( basilisk_numconfirms(myinfo,swap,&swap->bobspend) >= swap->I.aliceconfirms ) + { + printf("bobspend confirmed\n"); + swap->I.statebits |= 0x80000; + printf("Bob confirming spend of Alice's payment\n"); + sleep(DEX_SLEEP); + } + retval = 1; + } + } + } + if ( swap->bobpayment.I.locktime != 0 && time(NULL) > swap->bobpayment.I.locktime ) + { + // submit reclaim of payment + printf("bob reclaims bobpayment\n"); + swap->I.statebits |= (0x40000 | 0x80000); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobreclaim,0,0) == 0 ) + printf("Bob error reclaiming own payment after alice timed out\n"); + else + { + printf("Bob reclaimed own payment\n"); + while ( 0 && (swap->I.statebits & 0x100000) == 0 ) // why wait for own tx? + { + if ( basilisk_numconfirms(myinfo,swap,&swap->bobreclaim) >= 1 ) + { + printf("bobreclaim confirmed\n"); + swap->I.statebits |= 0x100000; + printf("Bob confirms reclain of payment\n"); + break; + } + } + retval = 1; + } + } + } + else + { + //printf("ALICE\n"); + // [BLOCKING: depfound] Alice waits for deposit to confirm and sends altpayment + if ( (swap->I.statebits & 0x200) == 0 ) + { + printf("checkfor deposit\n"); + if ( basilisk_swapget(myinfo,swap,0x200,data,maxlen,basilisk_verify_bobdeposit) == 0 ) + { + // verify deposit and submit, set confirmed height + printf("got bobdeposit\n"); + swap->I.statebits |= 0x200; + } else printf("no valid deposit\n"); + } + else if ( (swap->I.statebits & 0x400) == 0 ) + { + if ( basilisk_istrustedbob(myinfo,swap) != 0 || (swap->I.bobconfirms == 0 && swap->depositunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobdeposit) >= swap->I.bobconfirms ) + { + printf("bobdeposit confirmed\n"); + swap->I.statebits |= 0x400; + } + } + else if ( (swap->I.statebits & 0x800) == 0 ) + { + printf("send alicepayment\n"); + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0); + } + // [BLOCKING: payfound] make sure payment is confrmed and send in spend or see bob's reclaim and claim + else if ( (swap->I.statebits & 0x8000) == 0 ) + { + if ( basilisk_swapget(myinfo,swap,0x8000,data,maxlen,basilisk_verify_bobpaid) == 0 ) + { + printf("got bobpayment\n"); + tradebot_swap_balancingtrade(myinfo,swap,0); + // verify payment and submit, set confirmed height + swap->I.statebits |= 0x8000; + } + } + else if ( (swap->I.statebits & 0x10000) == 0 ) + { + if ( basilisk_istrustedbob(myinfo,swap) != 0 || (swap->I.bobconfirms == 0 && swap->paymentunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobpayment) >= swap->I.bobconfirms ) + { + printf("bobpayment confirmed\n"); + swap->I.statebits |= 0x10000; + } + } + else if ( (swap->I.statebits & 0x20000) == 0 ) + { + printf("alicespend bobpayment\n"); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicespend,0x20000,0) != 0 )//&& (swap->aliceunconf != 0 || basilisk_numconfirms(myinfo,swap,&swap->alicespend) > 0) ) + { + swap->I.statebits |= 0x20000; + } + } + else if ( (swap->I.statebits & 0x40000) == 0 ) + { + int32_t numconfs; + if ( (numconfs= basilisk_numconfirms(myinfo,swap,&swap->alicespend)) >= swap->I.bobconfirms ) + { + for (j=datalen=0; j<32; j++) + data[datalen++] = swap->I.privAm.bytes[j]; + printf("send privAm %x\n",swap->I.statebits); + swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x40000,data,datalen,0x20000,swap->I.crcs_mypriv); + printf("Alice confirms spend of Bob's payment\n"); + retval = 1; + } else printf("alicespend numconfs.%d < %d\n",numconfs,swap->I.bobconfirms); + } + if ( swap->bobdeposit.I.locktime != 0 && time(NULL) > swap->bobdeposit.I.locktime ) + { + printf("Alice claims deposit\n"); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->aliceclaim,0,0) == 0 ) + printf("Alice couldnt claim deposit\n"); + else + { + printf("Alice claimed deposit\n"); + retval = 1; + } + } + else if ( swap->aborted != 0 || basilisk_privBn_extract(myinfo,swap,data,maxlen) == 0 ) + { + printf("Alice reclaims her payment\n"); + swap->I.statebits |= 0x40000000; + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicereclaim,0x40000000,0) == 0 ) + printf("Alice error sending alicereclaim\n"); + else + { + printf("Alice reclaimed her payment\n"); + retval = 1; + } + } + } + if ( (rand() % 30) == 0 ) + printf("finished swapstate.%x other.%x\n",swap->I.statebits,swap->I.otherstatebits); + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + } + return(retval); +} + +int32_t swapcompleted(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + if ( swap->I.iambob != 0 ) + return(swap->I.bobspent); + else return(swap->I.alicespent); +} + +cJSON *swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + cJSON *retjson = cJSON_CreateObject(); + return(retjson); +} + +void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t amlp) +{ + char keystr[64],databuf[1024],pubkeystr[128],*retstr,*retstr2,*datastr,*pushaddr=0,*subaddr=0; cJSON *retjson,*addrjson; uint8_t data[512]; int32_t datalen,timeout,pushsock = -1,subsock = -1; + if ( swap->connected == 1 ) + return; + if ( swap->pushsock < 0 && swap->subsock < 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + { + timeout = 1000; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + swap->pushsock = pushsock; + swap->subsock = subsock; + } + if ( (subsock= swap->subsock) < 0 || (pushsock= swap->pushsock) < 0 ) + { + printf("error getting nn_sockets\n"); + return; + } + sprintf(keystr,"%08x-%08x",swap->I.req.requestid,swap->I.req.quoteid); + if ( swap->connected == 0 && (retstr= _dex_kvsearch(myinfo,"KV",keystr)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (datastr= jstr(retjson,"value")) != 0 ) + { + datalen = (int32_t)strlen(datastr) >> 1; + decode_hex((uint8_t *)databuf,datalen,datastr); + if ( (addrjson= cJSON_Parse(databuf)) != 0 ) + { + pushaddr = jstr(addrjson,"push"); + subaddr = jstr(addrjson,"sub"); + if ( pushaddr != 0 && subaddr != 0 ) + { + printf("KV decoded (%s and %s) %d %d\n",pushaddr,subaddr,swap->pushsock,swap->subsock); + if ( nn_connect(swap->pushsock,pushaddr) >= 0 && nn_connect(swap->subsock,subaddr) >= 0 ) + swap->connected = 1; + } + free_json(addrjson); + } + } + free_json(retjson); + } + printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d) amlp.%d\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock,amlp); + free(retstr); + } + printf("connected.%d amlp.%d subsock.%d pushsock.%d\n",swap->connected,amlp,subsock,pushsock); + if ( swap->connected <= 0 && amlp != 0 && subsock >= 0 && pushsock >= 0 ) + { + if ( (retstr= _dex_psock(myinfo,"{}")) != 0 ) + { + printf("psock returns.(%s)\n",retstr); + // {"result":"success","pushaddr":"tcp://5.9.102.210:30002","subaddr":"tcp://5.9.102.210:30003","randipbits":3606291758,"coin":"KMD","tag":"6952562460568228137"} + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + pushaddr = jstr(retjson,"pushaddr"); + subaddr = jstr(retjson,"subaddr"); + if ( pushaddr != 0 && subaddr != 0 ) + { + if ( nn_connect(pushsock,pushaddr) >= 0 ) + { + printf("connected to %d pushaddr.(%s)\n",pushsock,pushaddr); + if ( nn_connect(subsock,subaddr) >= 0 ) + { + swap->connected = 1; + init_hexbytes_noT(pubkeystr,myinfo->persistent_pubkey33,33); + sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f],\"pub\":\"%s\"}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),pubkeystr); + datalen = (int32_t)strlen((char *)data) + 1; + printf("datalen.%d (%s)\n",datalen,(char *)data); + init_hexbytes_noT(databuf,data,datalen); + printf("%s -> %s\n",keystr,databuf); + if ( (retstr2= _dex_kvupdate(myinfo,"KV",keystr,databuf,1)) != 0 ) + { + printf("KVupdate.(%s)\n",retstr2); + free(retstr2); + } + } else printf("nn_connect error to %d subaddr.(%s)\n",subsock,subaddr); + } else printf("nn_connect error to %d pushaddr.(%s)\n",pushsock,pushaddr); + } + else printf("missing addr (%p) (%p) (%s)\n",pushaddr,subaddr,jprint(retjson,0)); + free_json(retjson); + } else printf("Error parsing psock.(%s)\n",retstr); + free(retstr); + } else printf("error issuing _dex_psock\n"); + } +} + +int32_t basilisk_alicetxs(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,retval = -1; + printf("alicetxs\n"); + for (i=0; i<3; i++) + { + if ( swap->alicepayment.I.datalen == 0 ) + basilisk_alicepayment(myinfo,swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) + { + printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); + sleep(20); + } + else + { + retval = 0; + for (i=0; ialicepayment.I.datalen; i++) + printf("%02x",swap->alicepayment.txbytes[i]); + printf(" ALICE PAYMENT created\n"); + iguana_unspents_mark(myinfo,swap->alicecoin,swap->alicepayment.vins); + basilisk_txlog(myinfo,swap,&swap->alicepayment,-1); + break; + } + } + if ( swap->myfee.I.datalen == 0 ) + { + printf("generate fee\n"); + if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) + { + swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); + iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); + basilisk_txlog(myinfo,swap,&swap->myfee,-1); + for (i=0; imyfee.I.spendlen; i++) + printf("%02x",swap->myfee.txbytes[i]); + printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); + swap->I.statebits |= 0x40; + } + else + { + printf("error creating myfee\n"); + return(-2); + } + } + if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 && swap->myfee.I.datalen != 0 && swap->myfee.I.spendlen > 0 ) + return(0); + return(-1); +} + +void basilisk_swaploop(void *_swap) +{ + uint8_t *data; uint32_t expiration,savestatebits=0,saveotherbits=0; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct supernet_info *myinfo; struct basilisk_swap *swap = _swap; + myinfo = swap->myinfoptr; + fprintf(stderr,"start swap\n"); + maxlen = 1024*1024 + sizeof(*swap); + data = malloc(maxlen); + expiration = (uint32_t)time(NULL) + 300; + myinfo->DEXactive = expiration; + channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); + while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) + { + dex_channelsend(myinfo,swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + if ( swap->connected > 0 ) + { + printf("A r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_sendpubkeys(myinfo,swap,data,maxlen); // send pubkeys + if ( basilisk_checkdeck(myinfo,swap,data,maxlen) == 0) // check for other deck 0x02 + basilisk_sendchoosei(myinfo,swap,data,maxlen); + basilisk_waitchoosei(myinfo,swap,data,maxlen); // wait for choosei 0x08 + if ( (swap->I.statebits & (0x08|0x02)) == (0x08|0x02) ) + break; + } + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + } + if ( swap->connected == 0 ) + { + printf("couldnt establish connection\n"); + retval = -1; + } + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 ) + { + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + printf("B r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_sendchoosei(myinfo,swap,data,maxlen); + basilisk_sendmostprivs(myinfo,swap,data,maxlen); + if ( basilisk_swapget(myinfo,swap,0x20,data,maxlen,basilisk_verify_privkeys) == 0 ) + { + swap->I.statebits |= 0x20; + break; + } + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + if ( time(NULL) > expiration ) + break; + } + myinfo->DEXactive = swap->I.expiration; + if ( time(NULL) >= expiration ) + { + retval = -1; + myinfo->DEXactive = 0; + } + if ( swap->aborted != 0 ) + { + printf("swap aborted before tx sent\n"); + retval = -1; + } + printf("C r%u/q%u swapstate.%x retval.%d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,retval); + iters = 0; + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x40) == 0 && iters++ < 10 ) // send fee + { + if ( swap->connected == 0 ) + basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + //printf("sendstate.%x\n",swap->I.statebits); + basilisk_sendstate(myinfo,swap,data,maxlen); + //printf("swapget\n"); + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + //printf("after swapget\n"); + if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) + { + printf("bobscripts set\n"); + if ( basilisk_bobscripts_set(myinfo,swap,1,1) < 0 ) + { + sleep(DEX_SLEEP); + printf("bobscripts set error\n"); + continue; + } + } + if ( swap->I.iambob == 0 ) + { + /*for (i=0; i<20; i++) + printf("%02x",swap->secretAm[i]); + printf(" <- secretAm\n"); + for (i=0; i<32; i++) + printf("%02x",swap->secretAm256[i]); + printf(" <- secretAm256\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubAm.bytes[i]); + printf(" <- pubAm\n"); + for (i=0; i<20; i++) + printf("%02x",swap->secretBn[i]); + printf(" <- secretBn\n"); + for (i=0; i<32; i++) + printf("%02x",swap->secretBn256[i]); + printf(" <- secretBn256\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubBn.bytes[i]); + printf(" <- pubBn\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubA0.bytes[i]); + printf(" <- pubA0\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubA1.bytes[i]); + printf(" <- pubA1\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubB0.bytes[i]); + printf(" <- pubB0\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubB1.bytes[i]); + printf(" <- pubB1\n");*/ + if ( (retval= basilisk_alicetxs(myinfo,swap,data,maxlen)) != 0 ) + { + printf("basilisk_alicetxs error\n"); + break; + } + } + } + if ( swap->I.iambob == 0 && (swap->I.statebits & 0x40) == 0 ) + { + printf("couldnt send fee\n"); + retval = -8; + } + if ( retval == 0 ) + { + if ( swap->I.iambob == 0 && (swap->myfee.I.datalen == 0 || swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.datalen == 0) ) + { + printf("ALICE's error %d %d %d\n",swap->myfee.I.datalen,swap->alicepayment.I.datalen,swap->alicepayment.I.datalen); + retval = -7; + } + else if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) //swap->bobpayment.I.datalen == 0 + { + printf("BOB's error %d %d %d\n",swap->myfee.I.datalen,swap->bobpayment.I.datalen,swap->bobdeposit.I.datalen); + retval = -7; + } + } + while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(myinfo,swap,data,maxlen) == 0 ) + { + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + basilisk_swap_saveupdate(myinfo,swap); + if ( time(NULL) > swap->I.expiration ) + break; + } + if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen != 0 && bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + { + printf("BOB waiting for confirm state.%x\n",swap->I.statebits); + sleep(60); // wait for confirm/propagation of msig + printf("BOB reclaims refund\n"); + basilisk_bobdeposit_refund(myinfo,swap,0); + if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobrefund,0x40000000,0) == 0 ) // use secretBn + { + printf("Bob submit error getting refund of deposit\n"); + } + else + { + // maybe wait for bobrefund to be confirmed + for (j=datalen=0; j<32; j++) + data[datalen++] = swap->I.privBn.bytes[j]; + basilisk_swapsend(myinfo,swap,0x40000000,data,datalen,0x40000000,swap->I.crcs_mypriv); + } + basilisk_swap_saveupdate(myinfo,swap); + } + if ( retval != 0 ) + basilisk_swap_sendabort(myinfo,swap); + printf("end of atomic swap\n"); + if ( swapcompleted(myinfo,swap) > 0 ) // only if swap completed + { + if ( swap->I.iambob != 0 ) + tradebot_pendingadd(myinfo,swapjson(myinfo,swap),swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); + else tradebot_pendingadd(myinfo,swapjson(myinfo,swap),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.src,dstr(swap->I.req.srcamount)); + } + printf("%s swap finished statebits %x\n",swap->I.iambob!=0?"BOB":"ALICE",swap->I.statebits); + basilisk_swap_purge(myinfo,swap); + free(data); +} + +cJSON *basilisk_swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap) +{ + cJSON *item = cJSON_CreateObject(); + jaddnum(item,"requestid",swap->I.req.requestid); + jaddnum(item,"quoteid",swap->I.req.quoteid); + jaddnum(item,"state",swap->I.statebits); + jaddnum(item,"otherstate",swap->I.otherstatebits); + jadd(item,"request",basilisk_requestjson(&swap->I.req)); + return(item); +} + +struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) +{ + int32_t i,m,n,iter; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; + // statebits 1 -> client, 0 -> LP + if ( myinfo->numswaps > 0 ) + { + if ( (coin= iguana_coinfind(rp->src)) == 0 || coin->FULLNODE >= 0 ) + { + printf("dont have SRC coin.%s or not native and already swap pending\n",rp->src); + return(0); + } + if ( (coin= iguana_coinfind(rp->dest)) == 0 || coin->FULLNODE >= 0 ) + { + printf("dont have DEST coin.%s or not native and already swap pending\n",rp->dest); + return(0); + } + } + portable_mutex_lock(&myinfo->DEX_swapmutex); + for (i=0; inumswaps; i++) + if ( myinfo->swaps[i]->I.req.requestid == rp->requestid ) + { + printf("basilisk_thread_start error trying to start requestid.%u which is already started\n",rp->requestid); + break; + } + if ( i == myinfo->numswaps && i < sizeof(myinfo->swaps)/sizeof(*myinfo->swaps) ) + { + swap = calloc(1,sizeof(*swap)); + swap->subsock = swap->pushsock = -1; + vcalc_sha256(0,swap->I.orderhash.bytes,(uint8_t *)rp,sizeof(*rp)); + swap->I.req = *rp; + swap->myinfoptr = myinfo; + printf("basilisk_thread_start request.%u statebits.%d (%s/%s) reinit.%d\n",rp->requestid,statebits,rp->src,rp->dest,reinit); + bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); + pubkey25519 = curve25519(privkey,curve25519_basepoint9()); + swap->persistent_pubkey = pubkey25519; + swap->persistent_privkey = privkey; + memcpy(swap->persistent_pubkey33,pubkey33,33); + m = n = 0; + if ( bitcoin_swapinit(myinfo,privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) + { + for (iter=0; iter<16; iter++) + { + basilisk_psockinit(myinfo,swap,statebits == 0); + sleep(3); + if ( swap->connected > 0 ) + break; + sleep(10); + /*basilisk_sendstate(myinfo,swap,data,sizeof(data)); + basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); + if ( swap->connected > 0 ) + break; + printf("loopback didntwork with %d %d\n",swap->pushsock,swap->subsock);*/ + } + if ( reinit != 0 ) + { + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) + { + + } + myinfo->swaps[myinfo->numswaps++] = swap; + } + else + { + starttime = (uint32_t)time(NULL); + printf("statebits.%x m.%d n.%d\n",statebits,m,n); + while ( statebits == 0 && m <= n/2 && time(NULL) < starttime+7*BASILISK_MSGDURATION ) + { + uint32_t msgid; uint8_t data[1024]; int32_t datalen; + m = n = 0; + sleep(DEX_SLEEP); + printf("waiting for offer to be accepted\n"); + channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); + datalen = basilisk_rwDEXquote(1,data,rp); + msgid = (uint32_t)time(NULL); + printf("other req.%d >>>>>>>>>>> send response (%llx -> %llx) last.%u r.%u quoteid.%u\n",i,(long long)rp->desthash.txid,(long long)rp->srchash.txid,myinfo->lastdexrequestid,rp->requestid,rp->quoteid); + dex_channelsend(myinfo,rp->desthash,rp->srchash,channel,msgid,data,datalen); + if ( (retarray= basilisk_channelget(myinfo,rp->srchash,rp->desthash,channel,0x4000000,30)) != 0 ) + { + if ( is_cJSON_Array(retarray) != 0 && (n= cJSON_GetArraySize(retarray)) > 0 ) + { + for (i=0; i 0 ) + { + item = jitem(msgobj,0); + if ( jobj(item,"data") != 0 && jobj(item,"key") != 0 ) + m++; + else printf("(%s)\n",jprint(item,0)); + } //else printf("msgobj.%p m.%d n.%d\n",msgobj,m,n); + } + } + } else printf("no retarray\n"); + } + printf("LAUNCH check.%d m.%d\n",statebits,m); + if ( statebits != 0 || m > 0 )//n/2 ) + { + //for (i=0; iI.req); i++) + // fprintf(stderr,"%02x",((uint8_t *)&swap->I.req)[i]); + fprintf(stderr," M.%d N.%d launch.%d %d %p reinit.%d\n",m,n,myinfo->numswaps,(int32_t)(sizeof(myinfo->swaps)/sizeof(*myinfo->swaps)),&swap->I.req,reinit); + if ( (swap->fp= basilisk_swap_save(myinfo,swap,privkey,rp,statebits,optionduration,reinit)) != 0 ) + { + } + if ( reinit == 0 ) + { + if ( myinfo->swapsfp == 0 ) + { + char fname[512]; + sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); + if ( (myinfo->swapsfp= fopen(fname,"rb+")) == 0 ) + myinfo->swapsfp = fopen(fname,"wb+"); + else fseek(myinfo->swapsfp,0,SEEK_END); + printf("LIST fp.%p\n",myinfo->swapsfp); + } + if ( myinfo->swapsfp != 0 ) + { + fwrite(&rp->requestid,1,sizeof(rp->requestid),myinfo->swapsfp); + fwrite(&rp->quoteid,1,sizeof(rp->quoteid),myinfo->swapsfp); + fflush(myinfo->swapsfp); + } + } + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) + { + + } + myinfo->swaps[myinfo->numswaps++] = swap; + } + else + { + if ( statebits != 0 ) + { + if ( (coin= iguana_coinfind(rp->src)) != 0 ) + { + + } + } + printf("%u/%u offer wasnt accepted statebits.%d m.%d n.%d pending %.8f\n",rp->requestid,rp->quoteid,statebits,m,n,pending); + } + } + } + } + portable_mutex_unlock(&myinfo->DEX_swapmutex); + return(swap); +} + +/////////////// remember functions + diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 7ea3b1f63..04f20f410 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -26,6 +26,7 @@ #define MAX(a,b) ((a) > (b) ? (a) : (b)) char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port); #include "stats.c" +#include "LP_prices.c" #if defined(__APPLE__) || defined(WIN32) || defined(USE_STATIC_NANOMSG) #include "../../crypto777/nanosrc/nn.h" @@ -716,6 +717,7 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double } } } + LP_priceupdate(base,rel,theoretical,avebid,aveask,highbid,lowask,PAXPRICES); } if ( strcmp(exchange,"bittrex") == 0 ) { @@ -790,7 +792,13 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double } } -#include "LP_unspents.c" +#include "LP_nativeDEX.c" + +void LP_main(void *ptr) +{ + double profitmargin = *(double *)ptr; + LPinit(7779,7780,7781,profitmargin); +} int main(int argc, const char * argv[]) { @@ -802,7 +810,11 @@ int main(int argc, const char * argv[]) minask = jdouble(retjson,"minask"); maxbid = jdouble(retjson,"maxbid"); profitmargin = jdouble(retjson,"profitmargin"); - LPinit(7779,7780,7781,profitmargin); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_main,(void *)&profitmargin) != 0 ) + { + printf("error launching LP_main %f\n",profitmargin); + exit(-1); + } getchar(); maxexposure = jdouble(retjson,"maxexposure"); incrratio = jdouble(retjson,"lotratio"); start_base = jdouble(retjson,"start_base"); diff --git a/iguana/kmd_lookup.h b/iguana/kmd_lookup.h index 8403f91d7..61f7f60b0 100755 --- a/iguana/kmd_lookup.h +++ b/iguana/kmd_lookup.h @@ -638,9 +638,10 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) } height = kmd_height(coin); loadheight = coin->kmd_height+1; - if ( strcmp(coin->symbol,"LTC") == 0 ) - lag = 3; - else lag = (strcmp(coin->symbol,"KMD") == 0 ? KMD_EXPLORER_LAG : 2); + //if ( strcmp(coin->symbol,"LTC") == 0 ) + // lag = 3; + //else + lag = (strcmp(coin->symbol,"KMD") == 0 ? KMD_EXPLORER_LAG : 2); while ( loadheight < height-lag ) { flag = 0; @@ -749,7 +750,7 @@ int32_t _kmd_bitcoinscan(struct iguana_info *coin) } free_json(blockjson); } - if ( flag != 0 || num > 500 ) + if ( flag != 0 || num > 100 ) break; coin->kmd_height = loadheight++; } @@ -771,7 +772,7 @@ void kmd_bitcoinscan() { //if ( strcmp("KMD",coin->symbol) == 0 ) _kmd_bitcoinscan(coin); - usleep(250000); + sleep(1); } } } From 3ee5c2f19ad60b98412321ba2c16fec09b02cc0e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 28 May 2017 11:58:53 +0300 Subject: [PATCH 0650/2705] Test --- crypto777/OS_portable.h | 2 +- iguana/dpow/dpow_network.c | 51 +- iguana/exchanges/LP_bitcoin.c | 2357 +++++++++++++++++++++------ iguana/exchanges/LP_commands.c | 101 +- iguana/exchanges/LP_include.h | 469 ++++++ iguana/exchanges/LP_nativeDEX.c | 97 +- iguana/exchanges/LP_network.c | 307 ++++ iguana/exchanges/LP_remember.c | 718 ++++----- iguana/exchanges/LP_rpc.c | 505 ++++++ iguana/exchanges/LP_secp.c | 186 +++ iguana/exchanges/LP_statemachine.c | 558 +++++++ iguana/exchanges/LP_swap.c | 2405 +++++++--------------------- iguana/exchanges/LP_transaction.c | 1657 +++++++++++++++++++ iguana/m_mm | 3 +- 14 files changed, 6649 insertions(+), 2767 deletions(-) create mode 100644 iguana/exchanges/LP_include.h create mode 100644 iguana/exchanges/LP_network.c create mode 100644 iguana/exchanges/LP_rpc.c create mode 100644 iguana/exchanges/LP_secp.c create mode 100644 iguana/exchanges/LP_statemachine.c create mode 100644 iguana/exchanges/LP_transaction.c diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index f986b5216..a90889279 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -347,7 +347,7 @@ char *hmac_tiger_str(char *dest,char *key,int32_t key_size,char *message); char *hmac_whirlpool_str(char *dest,char *key,int32_t key_size,char *message); int nn_base64_encode(const uint8_t *in,size_t in_len,char *out,size_t out_len); int nn_base64_decode(const char *in,size_t in_len,uint8_t *out,size_t out_len); - +void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen); void sha256_sha256(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); void rmd160ofsha256(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); void calc_md5str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 9eafc39be..2a98ed265 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -145,10 +145,10 @@ int32_t signed_nn_send(struct supernet_info *myinfo,void *ctx,bits256 privkey,in int32_t signed_nn_recv(void **freeptrp,struct supernet_info *myinfo,uint8_t notaries[64][33],int32_t n,int32_t sock,void *packetp) { - int32_t i,recvbytes; uint8_t pubkey33[33],pubkey0[33]; bits256 packethash; struct signed_nnpacket *sigpacket=0; + int32_t i=0,recvbytes; uint8_t pubkey33[33],pubkey0[33]; bits256 packethash; struct signed_nnpacket *sigpacket=0; *(void **)packetp = 0; *freeptrp = 0; - for (i=0; i<100; i++) + /*for (i=0; i<100; i++) { struct nn_pollfd pfd; pfd.fd = myinfo->reqsock; @@ -159,11 +159,11 @@ int32_t signed_nn_recv(void **freeptrp,struct supernet_info *myinfo,uint8_t nota } if ( i == 100 ) recvbytes = 0; - else if ( (recvbytes= nn_recv(sock,&sigpacket,NN_MSG,0)) > 0 ) + else*/ if ( (recvbytes= nn_recv(sock,&sigpacket,NN_MSG,0)) > 0 ) { //for (i=0; ipacketlen == recvbytes-sizeof(*sigpacket)); + printf(" <- [%d] RECV.%d crc.%08x cmp.%d\n",i,recvbytes,calc_crc32(0,(void *)sigpacket,recvbytes),sigpacket->packetlen == recvbytes-sizeof(*sigpacket)); } if ( sigpacket != 0 && recvbytes > sizeof(*sigpacket) && sigpacket->packetlen == recvbytes-sizeof(*sigpacket) ) { @@ -199,9 +199,9 @@ int32_t signed_nn_recv(void **freeptrp,struct supernet_info *myinfo,uint8_t nota printf(" pubkey[%d]\n",i); } } - //for (i=0; i<33; i++) - // printf("%02x",pubkey33[i]); - //printf(" invalid pubkey33 n.%d\n",n); + for (i=0; i<33; i++) + printf("%02x",pubkey33[i]); + printf(" invalid pubkey33 n.%d\n",n); } else printf("recoververify error nonce.%u packetlen.%d\n",sigpacket->nonce,sigpacket->packetlen); } else printf("hash mismatch or bad nonce.%u packetlen.%d\n",sigpacket->nonce,sigpacket->packetlen); } else if ( recvbytes > 0 ) @@ -390,7 +390,7 @@ void dex_packet(struct supernet_info *myinfo,struct dex_nanomsghdr *dexp,int32_t char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32_t keylen,uint8_t *data,int32_t datalen) { - struct dex_nanomsghdr *dexp; cJSON *retjson; char ipaddr[64],str[128]; int32_t timeout,i,n,size,recvbytes,sentbytes = 0,reqsock,subsock; uint32_t *retptr,ipbits; void *freeptr; char *retstr = 0; + struct dex_nanomsghdr *dexp; cJSON *retjson; char ipaddr[64],str[128]; int32_t prio,timeout,i,n,size,recvbytes,sentbytes = 0,reqsock,subsock; uint32_t *retptr,ipbits; void *freeptr; char *retstr = 0; portable_mutex_lock(&myinfo->dexmutex); subsock = myinfo->subsock; reqsock = myinfo->reqsock; @@ -400,15 +400,15 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 { timeout = 1000; nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - //timeout = 1500; - //nn_setsockopt(reqsock,NN_TCP,NN_RECONNECT_IVL,&timeout,sizeof(timeout)); - timeout = 3000; + timeout = 1000; + nn_setsockopt(reqsock,NN_TCP,NN_RECONNECT_IVL,&timeout,sizeof(timeout)); + timeout = 10000; nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - //prio = 1; - //nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_SNDPRIO,&prio,sizeof(prio)); - //nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_RCVPRIO,&prio,sizeof(prio)); for (i=0; idexseed_ipaddrs)/sizeof(*myinfo->dexseed_ipaddrs); i++) { + prio = (i/2) + 1; + nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_SNDPRIO,&prio,sizeof(prio)); + nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_RCVPRIO,&prio,sizeof(prio)); if ( nn_connect(reqsock,nanomsg_tcpname(0,str,myinfo->dexseed_ipaddrs[i],REP_SOCK)) < 0 ) { nn_close(reqsock); @@ -416,9 +416,6 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 break; } } - //prio = 8; - //nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_SNDPRIO,&prio,sizeof(prio)); - //nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_RCVPRIO,&prio,sizeof(prio)); } if ( reqsock >= 0 ) { @@ -435,14 +432,14 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 } if ( reqsock >= 0 && subsock >= 0 ) { - timeout = 100; + timeout = 1; nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); printf("CLIENT sockets req.%d sub.%d\n",reqsock,subsock); //timeout = 5000; //nn_setsockopt(reqsock,NN_TCP,NN_RECONNECT_IVL,&timeout,sizeof(timeout)); - timeout = 10000; - nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + //timeout = 10000; + //nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); } } } @@ -481,7 +478,7 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 if ( nn_poll(&pfd,1,100) > 0 ) { sentbytes = nn_send(myinfo->reqsock,dexp,size,0); - //printf(" sent.%d:%d datalen.%d crc.%08x\n",sentbytes,size,datalen,calc_crc32(0,(void *)dexp,size)); + printf(" [%d] sent.%d:%d datalen.%d crc.%08x\n",i,sentbytes,size,datalen,calc_crc32(0,(void *)dexp,size)); break; } usleep(1000); @@ -490,7 +487,7 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 // printf("%02x",((uint8_t *)data)[i]); if ( (recvbytes= signed_nn_recv(&freeptr,myinfo,myinfo->notaries,myinfo->numnotaries,myinfo->reqsock,&retptr)) >= 0 ) { - //printf("req returned.[%d]\n",recvbytes); + printf("req returned.[%d]\n",recvbytes); portable_mutex_lock(&myinfo->dexmutex); ipbits = 0; if ( strcmp(handler,"DEX") == 0 ) @@ -2163,11 +2160,11 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo) if ( (flags & 4) == 0 && (size= nn_recv(myinfo->repsock,&dexp,NN_MSG,0)) > 0 ) { num2++; - //printf("REP got %d crc.%08x\n",size,calc_crc32(0,(void *)dexp,size)); + printf("REP got %d crc.%08x\n",size,calc_crc32(0,(void *)dexp,size)); if ( (retstr= dex_response(&broadcastflag,myinfo,dexp)) != 0 ) { signed_nn_send(myinfo,myinfo->ctx,myinfo->persistent_priv,myinfo->repsock,retstr,(int32_t)strlen(retstr)+1); - //printf("send back[%ld]\n",strlen(retstr)+1); + printf("send back[%ld]\n",strlen(retstr)+1); free(retstr); if ( broadcastflag != 0 ) { @@ -2182,11 +2179,11 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo) { r = myinfo->dpowipbits[rand() % m]; signed_nn_send(myinfo,myinfo->ctx,myinfo->persistent_priv,myinfo->repsock,&r,sizeof(r)); - //printf("REP.%08x <- rand ip m.%d %x\n",dexp->crc32,m,r); + printf("REP.%08x <- rand ip m.%d %x\n",dexp->crc32,m,r); } else printf("illegal state without dpowipbits?\n"); if ( dex_packetcheck(myinfo,dexp,size) == 0 ) { - signed_nn_send(myinfo,myinfo->ctx,myinfo->persistent_priv,myinfo->dexsock,dexp,size); + //signed_nn_send(myinfo,myinfo->ctx,myinfo->persistent_priv,myinfo->dexsock,dexp,size); //signed_nn_send(myinfo,myinfo->ctx,myinfo->persistent_priv,myinfo->pubsock,dexp,size); //printf("REP.%08x -> dexbus and pub, t.%d lag.%d\n",dexp->crc32,dexp->timestamp,(int32_t)(time(NULL)-dexp->timestamp)); dex_packet(myinfo,dexp,size); @@ -2208,7 +2205,7 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo) } else break; } portable_mutex_unlock(&myinfo->dpowmutex); - return(num); + return(num+n+num2); } #else diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 421d889ca..078bc1d3f 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -18,52 +18,435 @@ // marketmaker // -#define IGUANA_MAXSCRIPTSIZE 10001 - -struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }; //PACKEDSTRUCT; - -struct vin_signer { bits256 privkey; char coinaddr[64]; uint8_t siglen,sig[80],rmd160[20],pubkey[66]; }; - -struct vin_info -{ - struct iguana_msgvin vin; uint64_t amount; cJSON *extras; bits256 sigtxid; - int32_t M,N,validmask,spendlen,type,p2shlen,numpubkeys,numsigs,height,hashtype,userdatalen,suppress_pubkeys,ignore_cltverr; - uint32_t sequence,unspentind; struct vin_signer signers[16]; char coinaddr[65]; - uint8_t rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE],userdata[IGUANA_MAXSCRIPTSIZE]; -}; - -#define SIGHASH_ALL 1 -#define SIGHASH_NONE 2 -#define SIGHASH_SINGLE 3 -#define SIGHASH_ANYONECANPAY 0x80 - -#define SCRIPT_OP_NOP 0x00 -#define SCRIPT_OP_TRUE 0x51 -#define SCRIPT_OP_2 0x52 -#define SCRIPT_OP_3 0x53 -#define SCRIPT_OP_4 0x54 -#define SCRIPT_OP_IF 0x63 -#define SCRIPT_OP_ELSE 0x67 -#define SCRIPT_OP_RETURN 0x6a -#define SCRIPT_OP_DUP 0x76 -#define SCRIPT_OP_ENDIF 0x68 -#define SCRIPT_OP_DROP 0x75 -#define SCRIPT_OP_EQUALVERIFY 0x88 -#define SCRIPT_OP_SHA256 0xa8 -#define SCRIPT_OP_HASH160 0xa9 - -#define SCRIPT_OP_EQUAL 0x87 -#define SCRIPT_OP_CHECKSIG 0xac -#define SCRIPT_OP_CHECKMULTISIG 0xae -#define SCRIPT_OP_CHECKSEQUENCEVERIFY 0xb2 -#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 - -void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen) +int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp) +{ + int32_t i; uint64_t x; + if ( rwflag == 0 ) + { + x = 0; + for (i=len-1; i>=0; i--) + { + x <<= 8; + x |= serialized[i]; + } + switch ( len ) + { + case 1: *(uint8_t *)endianedp = (uint8_t)x; break; + case 2: *(uint16_t *)endianedp = (uint16_t)x; break; + case 4: *(uint32_t *)endianedp = (uint32_t)x; break; + case 8: *(uint64_t *)endianedp = (uint64_t)x; break; + } + } + else + { + x = 0; + switch ( len ) + { + case 1: x = *(uint8_t *)endianedp; break; + case 2: x = *(uint16_t *)endianedp; break; + case 4: x = *(uint32_t *)endianedp; break; + case 8: x = *(uint64_t *)endianedp; break; + } + for (i=0; i>= 8) + serialized[i] = (uint8_t)(x & 0xff); + } + return(len); +} + +int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp) +{ + int32_t i; + if ( rwflag == 0 ) + { + for (i=0; i> 8) & 0xff; + } + return(serialized); +} + +uint8_t *iguana_varint32(int32_t rwflag,uint8_t *serialized,uint16_t *varint16p) +{ + serialized = iguana_varint16(rwflag,serialized,varint16p); + serialized = iguana_varint16(rwflag,serialized,&varint16p[1]); + return(serialized); +} + +uint8_t *iguana_varint64(int32_t rwflag,uint8_t *serialized,uint32_t *varint32p) +{ + serialized = iguana_varint32(rwflag,serialized,(uint16_t *)varint32p); + serialized = iguana_varint32(rwflag,serialized,(uint16_t *)&varint32p[1]); + return(serialized); +} + +int32_t iguana_rwvarint(int32_t rwflag,uint8_t *serialized,uint64_t *varint64p) +{ + uint64_t n; int32_t vlen = 1; + if ( rwflag == 0 ) + { + *varint64p = 0; + if ( (n= *serialized++) >= 0xfd ) + { + if ( n == 0xfd ) + { + n = 0; + iguana_varint16(rwflag,serialized,(uint16_t *)&n); + vlen += 2; + } + else if ( n == 0xfe ) + { + n = 0; + iguana_varint32(rwflag,serialized,(uint16_t *)&n); + vlen += 4; + } + else if ( n == 0xff ) + { + n = 0; + iguana_varint64(rwflag,serialized,(uint32_t *)&n); + vlen += 8; + } + } + *varint64p = n; + } + else + { + n = *varint64p; + if ( n < 0xfd ) + *serialized++ = (uint8_t)n; + else if ( n <= 0xffff ) + { + *serialized++ = 0xfd; + iguana_varint16(rwflag,serialized,(uint16_t *)varint64p); + vlen += 2; + } + else if ( n <= 0xffffffff ) + { + *serialized++ = 0xfe; + iguana_varint32(rwflag,serialized,(uint16_t *)varint64p); + vlen += 4; + } + else + { + *serialized++ = 0xff; + iguana_varint64(rwflag,serialized,(uint32_t *)varint64p); + vlen += 8; + } + } + return(vlen); +} + +int32_t iguana_rwvarint32(int32_t rwflag,uint8_t *serialized,uint32_t *int32p) +{ + int32_t len; uint64_t x = 0; + if ( rwflag != 0 ) + x = *int32p; + len = iguana_rwvarint(rwflag,serialized,&x); + if ( rwflag == 0 ) + *int32p = (int32_t)x; + return(len); +} + +int32_t iguana_rwvarstr(int32_t rwflag,uint8_t *serialized,int32_t maxlen,char *endianedp) +{ + int32_t vlen; uint64_t n; + if ( rwflag == 0 ) + { + vlen = iguana_rwvarint(rwflag,serialized,&n); + memcpy(endianedp,&serialized[vlen],n); + ((uint8_t *)endianedp)[n] = 0; + } + else + { + n = strlen(endianedp); + if ( n > maxlen ) + n = maxlen; + vlen = iguana_rwvarint(rwflag,serialized,&n); + memcpy(&serialized[vlen],endianedp,n); + } + return((int32_t)(n + vlen)); +} + +int32_t iguana_rwmem(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp) +{ + if ( rwflag == 0 ) + memcpy(endianedp,serialized,len); + else memcpy(serialized,endianedp,len); + return(len); +} + +const char *get_opname(uint8_t *stackitemsp,uint8_t *flagsp,int32_t *extralenp,enum opcodetype opcode) +{ + *extralenp = 0; + switch ( opcode ) + { + // push value + case OP_0 : return "0"; + case OP_PUSHDATA1 : *extralenp = 1; return "OP_PUSHDATA1"; + case OP_PUSHDATA2 : *extralenp = 2; return "OP_PUSHDATA2"; + case OP_PUSHDATA4 : *flagsp = IGUANA_EXECUTIONILLEGAL; return "OP_PUSHDATA4"; + case OP_1NEGATE : return "-1"; + case OP_RESERVED : *flagsp = IGUANA_EXECUTIONILLEGAL; return "OP_RESERVED"; + case OP_1 : return "1"; + case OP_2 : return "2"; + case OP_3 : return "3"; + case OP_4 : return "4"; + case OP_5 : return "5"; + case OP_6 : return "6"; + case OP_7 : return "7"; + case OP_8 : return "8"; + case OP_9 : return "9"; + case OP_10 : return "10"; + case OP_11 : return "11"; + case OP_12 : return "12"; + case OP_13 : return "13"; + case OP_14 : return "14"; + case OP_15 : return "15"; + case OP_16 : return "16"; + + // control + case OP_NOP : *flagsp = IGUANA_NOPFLAG; return "OP_NOP"; + case OP_VER : *flagsp = IGUANA_EXECUTIONILLEGAL; return "OP_VER"; + case OP_IF : *flagsp = IGUANA_CONTROLFLAG; *stackitemsp = 1; return "OP_IF"; + case OP_NOTIF : *flagsp = IGUANA_CONTROLFLAG; *stackitemsp = 1; return "OP_NOTIF"; + case OP_VERIF : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_VERIF"; + case OP_VERNOTIF : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_VERNOTIF"; + case OP_ELSE : *flagsp = IGUANA_CONTROLFLAG; return "OP_ELSE"; + case OP_ENDIF : *flagsp = IGUANA_CONTROLFLAG; return "OP_ENDIF"; + case OP_VERIFY : *flagsp = IGUANA_POSTVERIFY; return "OP_VERIFY"; + case OP_RETURN : *flagsp = IGUANA_CONTROLFLAG; return "OP_RETURN"; + + // stack ops + case OP_TOALTSTACK : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 1; return "OP_TOALTSTACK"; + case OP_FROMALTSTACK : *flagsp = IGUANA_STACKFLAG; return "OP_FROMALTSTACK"; + case OP_2DROP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 2; return "OP_2DROP"; + case OP_2DUP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 2; return "OP_2DUP"; + case OP_3DUP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 3; return "OP_3DUP"; + case OP_2OVER : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 4; return "OP_2OVER"; + case OP_2ROT : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 6; return "OP_2ROT"; + case OP_2SWAP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 4; return "OP_2SWAP"; + case OP_IFDUP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 1; return "OP_IFDUP"; + case OP_DEPTH : *flagsp = IGUANA_STACKFLAG; return "OP_DEPTH"; + case OP_DROP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 1; return "OP_DROP"; + case OP_DUP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 1; return "OP_DUP"; + case OP_NIP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 2; return "OP_NIP"; + case OP_OVER : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 2; return "OP_OVER"; + case OP_PICK : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 1; return "OP_PICK"; + case OP_ROLL : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 1; return "OP_ROLL"; + case OP_ROT : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 3; return "OP_ROT"; + case OP_SWAP : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 2; return "OP_SWAP"; + case OP_TUCK : *flagsp = IGUANA_STACKFLAG; *stackitemsp = 2; return "OP_TUCK"; + + // splice ops + case OP_CAT : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_CAT"; + case OP_SUBSTR : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_SUBSTR"; + case OP_LEFT : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_LEFT"; + case OP_RIGHT : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_RIGHT"; + case OP_SIZE : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_SIZE"; + + // bit logic + case OP_INVERT : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_INVERT"; + case OP_AND : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_AND"; + case OP_OR : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_OR"; + case OP_XOR : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_XOR"; + case OP_EQUAL : *stackitemsp = 2; return "OP_EQUAL"; + case OP_EQUALVERIFY : *stackitemsp = 2; *flagsp = IGUANA_POSTVERIFY; return "OP_EQUALVERIFY"; + case OP_RESERVED1 : *flagsp = IGUANA_EXECUTIONILLEGAL; return "OP_RESERVED1"; + case OP_RESERVED2 : *flagsp = IGUANA_EXECUTIONILLEGAL; return "OP_RESERVED2"; + + // numeric + case OP_1ADD : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 1; return "OP_1ADD"; + case OP_1SUB : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 1; return "OP_1SUB"; + case OP_2MUL : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_2MUL"; + case OP_2DIV : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_2DIV"; + case OP_NEGATE : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 1; return "OP_NEGATE"; + case OP_ABS : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 1; return "OP_ABS"; + case OP_NOT : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 1; return "OP_NOT"; + case OP_0NOTEQUAL : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 1; return "OP_0NOTEQUAL"; + case OP_ADD : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_ADD"; + case OP_SUB : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_SUB"; + case OP_MUL : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_MUL"; + case OP_DIV : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_DIV"; + case OP_MOD : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_MOD"; + case OP_LSHIFT : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_LSHIFT"; + case OP_RSHIFT : *flagsp = IGUANA_ALWAYSILLEGAL; return "OP_RSHIFT"; + case OP_BOOLAND : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_BOOLAND"; + case OP_BOOLOR : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_BOOLOR"; + case OP_NUMEQUAL : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_NUMEQUAL"; + case OP_NUMEQUALVERIFY: *flagsp = IGUANA_MATHFLAG | IGUANA_POSTVERIFY; *stackitemsp = 2; return "OP_NUMEQUALVERIFY"; + case OP_NUMNOTEQUAL : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_NUMNOTEQUAL"; + case OP_LESSTHAN : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_LESSTHAN"; + case OP_GREATERTHAN : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_GREATERTHAN"; + case OP_LESSTHANOREQUAL: *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_LESSTHANOREQUAL"; + case OP_GREATERTHANOREQUAL: *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_GREATERTHANOREQUAL"; + case OP_MIN : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_MIN"; + case OP_MAX : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 2; return "OP_MAX"; + case OP_WITHIN : *flagsp = IGUANA_MATHFLAG; *stackitemsp = 3; return "OP_WITHIN"; + + // crypto + case OP_RIPEMD160 : *stackitemsp = 1; *flagsp = IGUANA_CRYPTOFLAG; return "OP_RIPEMD160"; + case OP_SHA1 : *stackitemsp = 1; *flagsp = IGUANA_CRYPTOFLAG; return "OP_SHA1"; + case OP_SHA256 : *stackitemsp = 1; *flagsp = IGUANA_CRYPTOFLAG; return "OP_SHA256"; + case OP_HASH160 : *stackitemsp = 1; *flagsp = IGUANA_CRYPTOFLAG; return "OP_HASH160"; + case OP_HASH256 : *stackitemsp = 1; *flagsp = IGUANA_CRYPTOFLAG; return "OP_HASH256"; + case OP_CODESEPARATOR: return "OP_CODESEPARATOR"; + case OP_CHECKSIG : *stackitemsp = 2; *flagsp = IGUANA_CRYPTOFLAG; return "OP_CHECKSIG"; + case OP_CHECKSIGVERIFY: *stackitemsp = 2; *flagsp = IGUANA_CRYPTOFLAG | IGUANA_POSTVERIFY; return "OP_CHECKSIGVERIFY"; + case OP_CHECKMULTISIG: *flagsp = IGUANA_CRYPTOFLAG; return "OP_CHECKMULTISIG"; + case OP_CHECKMULTISIGVERIFY: *flagsp = IGUANA_CRYPTOFLAG | IGUANA_POSTVERIFY; return "OP_CHECKMULTISIGVERIFY"; + case OP_COMBINEPUBKEYS: *flagsp = IGUANA_CRYPTOFLAG; return "OP_COMBINEPUBKEYS"; + case OP_CHECKSCHNORR: *stackitemsp = 3; *flagsp = IGUANA_CRYPTOFLAG; return "OP_CHECKSCHNORR"; + case OP_CHECKSCHNORRVERIFY: *stackitemsp = 3; *flagsp = IGUANA_CRYPTOFLAG | IGUANA_POSTVERIFY; return "OP_CHECKSCHNORRVERIFY"; + case OP_CHECKPRIVATEKEY: *stackitemsp = 2; *flagsp = IGUANA_CRYPTOFLAG; return "OP_CHECKPRIVATEKEY"; + case OP_CHECKPRIVATEKEYVERIFY: *stackitemsp = 2; *flagsp = IGUANA_CRYPTOFLAG | IGUANA_POSTVERIFY; return "OP_CHECKPRIVATEKEYVERIFY"; + + // expanson + case OP_NOP1 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP1"; + case OP_CHECKLOCKTIMEVERIFY: *stackitemsp = 1; return "OP_CHECKLOCKTIMEVERIFY"; + case OP_CHECKSEQUENCEVERIFY: *stackitemsp = 1; return "OP_CHECKSEQUENCEVERIFY"; + case OP_NOP4 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP4"; + case OP_NOP5 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP5"; + case OP_NOP6 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP6"; + case OP_NOP7 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP7"; + case OP_NOP8 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP8"; + case OP_NOP9 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP9"; + case OP_NOP10 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP10"; + + case OP_INVALIDOPCODE: return "OP_INVALIDOPCODE"; + default: return "OP_UNKNOWN"; + } +} + +void iguana_optableinit() +{ + int32_t i,extralen; uint8_t stackitems,flags; char *opname; struct bitcoin_opcode *op; + if ( OPTABLE == 0 ) + { + for (i=0; i<0x100; i++) + OPCODES[i] = "OP_UNKNOWN"; + for (i=0; i<0x100; i++) + { + extralen = stackitems = flags = 0; + opname = (char *)get_opname(&stackitems,&flags,&extralen,i); + if ( strcmp("OP_UNKNOWN",opname) != 0 ) + { + op = calloc(1,sizeof(*op)); + HASH_ADD_KEYPTR(hh,OPTABLE,opname,strlen(opname),op); + //printf("{%-16s %02x} ",opname,i); + op->opcode = i; + op->flags = flags; + op->stackitems = stackitems; + op->extralen = extralen; + OPCODES[i] = (char *)op->hh.key; + OPCODELENS[i] = (int32_t)strlen(OPCODES[i]); + } + } + //printf("bitcoin opcodes\n"); + } +} + +int32_t iguana_expandscript(char *asmstr,int32_t maxlen,uint8_t *script,int32_t scriptlen) +{ + int32_t len,n,j,i = 0; uint8_t opcode; uint32_t val,extraflag; + iguana_optableinit(); + asmstr[0] = len = 0; + while ( i < scriptlen ) + { + val = extraflag = 0; + opcode = script[i++]; + if ( opcode > 0 && opcode < 76 ) + { + for (j=0; j= IGUANA_OP_1 && opcode <= IGUANA_OP_16 ) + { + sprintf(&asmstr[len],"%d",opcode - IGUANA_OP_1 + 1); + len += strlen(&asmstr[len]); + } + else if ( opcode == IGUANA_OP_0 ) + { + strcpy(&asmstr[len],"OP_FALSE"); + len += 8; + } + else if ( opcode == IGUANA_OP_1NEGATE ) + { + asmstr[len++] = '-'; + asmstr[len++] = '1'; + } + else + { + //printf("dest.%p <- %p %02x\n",&asmstr[len],OPCODES[opcode],opcode); + strcpy(&asmstr[len],OPCODES[opcode]); + len += OPCODELENS[opcode]; + } + if ( i < scriptlen ) + asmstr[len++] = ' '; + if ( opcode == IGUANA_OP_PUSHDATA1 ) + { + n = script[i++]; + for (j=0; j reveal.(%s)\n",bits256_str(str,privkey),bits256_str(str2,reveal)); -#else - reveal = pubkey; -#endif - return(reveal); + return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params)); } -int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp,uint8_t *redeemscript,uint32_t locktime,bits256 pubA0,bits256 pubB0,bits256 pubB1,bits256 privAm,bits256 privBn,uint8_t *secretAm,uint8_t *secretAm256,uint8_t *secretBn,uint8_t *secretBn256) +int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr) { - int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],secret160[20],secret256[32]; - if ( depositflag != 0 ) + bits256 hash; uint8_t *buf,_buf[25]; int32_t len; + memset(rmd160,0,20); + *addrtypep = 0; + buf = _buf; + if ( (len= bitcoin_base58decode(buf,coinaddr)) >= 4 ) { - pubkeyA[0] = 0x02, cltvpub = pubA0; - pubkeyB[0] = 0x03, destpub = pubB0; - privkey = privBn; - memcpy(secret160,secretBn,20); - memcpy(secret256,secretBn256,32); + // validate with trailing hash, then remove hash + hash = bits256_doublesha256(0,buf,21); + *addrtypep = *buf; + memcpy(rmd160,buf+1,20); + if ( (buf[21]&0xff) == hash.bytes[31] && (buf[22]&0xff) == hash.bytes[30] &&(buf[23]&0xff) == hash.bytes[29] && (buf[24]&0xff) == hash.bytes[28] ) + { + //printf("coinaddr.(%s) valid checksum addrtype.%02x\n",coinaddr,*addrtypep); + return(20); + } + else + { + int32_t i; + if ( len > 20 ) + { + hash = bits256_doublesha256(0,buf,len); + } + for (i=0; istarted + swap->putduration + swap->callduration; - else *locktimep = swap->started + swap->putduration; - *redeemlenp = n = basilisk_swap_bobredeemscript(depositflag,secretstartp,redeemscript,*locktimep,swap->pubA0,swap->pubB0,swap->pubB1,swap->privAm,swap->privBn,swap->secretAm,swap->secretAm256,swap->secretBn,swap->secretBn256); - if ( n > 0 ) + uint8_t i; bits256 hash; + data[0] = addrtype; + //for (i=0; i "); + hash = bits256_doublesha256(0,data,(int32_t)data_len+1); + //for (i=0; i<32; i++) + // printf("%02x",hash.bytes[i]); + //printf(" checkhash\n"); + for (i=0; i<4; i++) + data[data_len+i+1] = hash.bytes[31-i]; + return(data_len + 5); +} + +int32_t bitcoin_wif2priv(uint8_t *addrtypep,bits256 *privkeyp,char *wifstr) +{ + int32_t len = -1; bits256 hash; uint8_t buf[256]; + memset(buf,0,sizeof(buf)); + if ( (len= bitcoin_base58decode(buf,wifstr)) >= 4 ) { - calc_rmd160_sha256(rmd160,redeemscript,n); - n = bitcoin_p2shspend(script,0,rmd160); - //for (i=0; i wif.(%s) addrtype.%02x -> %02x (%s)\n",bits256_str(str,privkey),wifstr,addrtype,checktype,bits256_str(str2,checkpriv)); + } + } + return((int32_t)strlen(wifstr)); } -int32_t basilisk_priviextract(struct supernet_info *myinfo,struct iguana_info *coin,char *name,bits256 *destp,uint8_t secret160[20],bits256 srctxid,int32_t srcvout) +int32_t bitcoin_priv2wiflong(char *wifstr,bits256 privkey,uint8_t addrtype) { - bits256 txid,privkey; char str[65]; int32_t i,vini,scriptlen; uint8_t rmd160[20],scriptsig[IGUANA_MAXSCRIPTSIZE]; - memset(privkey.bytes,0,sizeof(privkey)); - // use dex_listtransactions! - if ( (vini= iguana_vinifind(myinfo,coin,&txid,srctxid,srcvout)) >= 0 ) + uint8_t data[128]; int32_t len = 32; + memcpy(data+1,privkey.bytes,sizeof(privkey)); + len = base58encode_checkbuf(addrtype,data,len); + if ( bitcoin_base58encode(wifstr,data,len) == 0 ) + return(-1); + if ( 1 ) { - if ( (scriptlen= iguana_scriptsigextract(myinfo,coin,scriptsig,sizeof(scriptsig),txid,vini)) > 32 ) + uint8_t checktype; bits256 checkpriv; char str[65],str2[65]; + if ( bitcoin_wif2priv(&checktype,&checkpriv,wifstr) == sizeof(bits256) ) { - for (i=0; i<32; i++) - privkey.bytes[i] = scriptsig[scriptlen - 33 + i]; - revcalc_rmd160_sha256(rmd160,privkey);//.bytes,sizeof(privkey)); - if ( memcmp(secret160,rmd160,sizeof(rmd160)) == sizeof(rmd160) ) - { - *destp = privkey; - printf("basilisk_priviextract found privi %s (%s)\n",name,bits256_str(str,privkey)); - return(0); - } + if ( checktype != addrtype || bits256_cmp(checkpriv,privkey) != 0 ) + printf("(%s) -> wif.(%s) addrtype.%02x -> %02x (%s)\n",bits256_str(str,privkey),wifstr,addrtype,checktype,bits256_str(str2,checkpriv)); } } - return(-1); + return((int32_t)strlen(wifstr)); } -int32_t basilisk_confirmsobj(cJSON *item) +char *_setVsigner(uint8_t pubtype,struct vin_info *V,int32_t ind,char *pubstr,char *wifstr) { - int32_t height,numconfirms; - height = jint(item,"height"); - numconfirms = jint(item,"numconfirms"); - if ( height > 0 && numconfirms >= 0 ) - return(numconfirms); - printf("basilisk_confirmsobj height.%d numconfirms.%d (%s)\n",height,numconfirms,jprint(item,0)); - return(-1); + uint8_t addrtype; + decode_hex(V->signers[ind].pubkey,(int32_t)strlen(pubstr)/2,pubstr); + bitcoin_wif2priv(&addrtype,&V->signers[ind].privkey,wifstr); + if ( addrtype != pubtype ) + return(clonestr("{\"error\":\"invalid wifA\"}")); + else return(0); } -int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +uint8_t iguana_addrtype(uint8_t pubtype,uint8_t p2shtype,uint8_t script_type) { - cJSON *argjson,*valuearray=0; char *valstr; int32_t i,n,retval = -1; -#ifdef BASILISK_DISABLEWAITTX - return(100); -#endif - argjson = cJSON_CreateObject(); - jaddbits256(argjson,"txid",rawtx->I.actualtxid); - jaddnum(argjson,"vout",0); - jaddstr(argjson,"coin",rawtx->coin->symbol); - if ( (valstr= basilisk_value(myinfo,rawtx->coin,0,0,swap->persistent_pubkey,argjson,0)) != 0 ) - { - char str[65]; printf("basilisk_numconfirms required.%d %s %s valstr.(%s)\n",rawtx->I.numconfirms,rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); - //basilisk_numconfirms required.0 alicespend 29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85 valstr.({"result":"success","numconfirms":0,"address":"1JGvZ67oTdM7kCya4J8kj1uErbSRAoq3wH","satoshis":"1413818","value":0.01413818,"height":462440,"txid":"29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85","vout":0,"coin":"BTC"}) - - if ( (valuearray= cJSON_Parse(valstr)) != 0 ) - { - if ( valstr[0] == '[' && is_cJSON_Array(valuearray) != 0 ) - { - n = cJSON_GetArraySize(valuearray); - for (i=0; i= 0 ) - break; - } - } else retval = basilisk_confirmsobj(valuearray); - free_json(valuearray); - } else printf("parse error\n"); - free(valstr); + if ( script_type == IGUANA_SCRIPT_76A988AC || script_type == IGUANA_SCRIPT_AC || script_type == IGUANA_SCRIPT_76AC ) + return(pubtype); + else + { + //printf("P2SH type.%d\n",script_type); + return(p2shtype); } - free_json(argjson); - printf("numconfirms.%d returned\n",retval); - return(retval); } -bits256 basilisk_swap_broadcast(char *name,struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,uint8_t *data,int32_t datalen) +int32_t iguana_scriptgen(uint8_t pubtype,uint8_t p2shtype,int32_t *Mp,int32_t *nump,char *coinaddr,uint8_t *script,char *asmstr,uint8_t rmd160[20],uint8_t type,const struct vin_info *vp,int32_t txi) { - bits256 txid; char *signedtx,*retstr; int32_t i; - memset(txid.bytes,0,sizeof(txid)); - if ( data != 0 && datalen != 0 ) + uint8_t addrtype; char rmd160str[41],pubkeystr[256]; int32_t plen,i,m,n,flag = 0,scriptlen = 0; + m = n = 0; + if ( asmstr != 0 ) + asmstr[0] = 0; + addrtype = iguana_addrtype(pubtype,p2shtype,type); + if ( type == IGUANA_SCRIPT_76A988AC || type == IGUANA_SCRIPT_AC || type == IGUANA_SCRIPT_76AC || type == IGUANA_SCRIPT_P2SH ) { - char str[65]; -#ifdef BASILISK_DISABLESENDTX - txid = bits256_doublesha256(0,data,datalen); - printf("%s <- dont sendrawtransaction (%s)\n",name,bits256_str(str,txid)); - return(txid); -#endif - signedtx = malloc(datalen*2 + 1); - init_hexbytes_noT(signedtx,data,datalen); - for (i=0; i<3; i++) + init_hexbytes_noT(rmd160str,rmd160,20); + bitcoin_address(coinaddr,addrtype,rmd160,20); + } + switch ( type ) + { + case IGUANA_SCRIPT_NULL: + if ( asmstr != 0 ) + strcpy(asmstr,txi == 0 ? "coinbase " : "PoSbase "); + flag++; + coinaddr[0] = 0; + break; + case IGUANA_SCRIPT_76AC: + case IGUANA_SCRIPT_AC: + if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) < 0 ) + return(0); + init_hexbytes_noT(pubkeystr,(uint8_t *)vp->signers[0].pubkey,plen); + if ( asmstr != 0 ) + { + if ( type == IGUANA_SCRIPT_76AC ) + strcpy(asmstr,"OP_DUP "); + sprintf(asmstr + strlen(asmstr),"%s OP_CHECKSIG // %s",pubkeystr,coinaddr); + } + if ( type == IGUANA_SCRIPT_76AC ) + script[scriptlen++] = 0x76; + scriptlen = bitcoin_pubkeyspend(script,scriptlen,(uint8_t *)vp->signers[0].pubkey); + //printf("[%02x] type.%d scriptlen.%d\n",vp->signers[0].pubkey[0],type,scriptlen); + break; + case IGUANA_SCRIPT_76A988AC: + if ( asmstr != 0 ) + sprintf(asmstr,"OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG // %s",rmd160str,coinaddr); + scriptlen = bitcoin_standardspend(script,0,rmd160); + break; + case IGUANA_SCRIPT_P2SH: + if ( asmstr != 0 ) + sprintf(asmstr,"OP_HASH160 %s OP_EQUAL // %s",rmd160str,coinaddr); + scriptlen = bitcoin_p2shspend(script,0,rmd160); + break; + case IGUANA_SCRIPT_OPRETURN: + if ( asmstr != 0 ) + strcpy(asmstr,"OP_RETURN "); + bitcoin_address(coinaddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); + flag++; + break; + case IGUANA_SCRIPT_3of3: m = 3, n = 3; break; + case IGUANA_SCRIPT_2of3: m = 2, n = 3; break; + case IGUANA_SCRIPT_1of3: m = 1, n = 3; break; + case IGUANA_SCRIPT_2of2: m = 2, n = 2; break; + case IGUANA_SCRIPT_1of2: m = 1, n = 2; break; + case IGUANA_SCRIPT_1of1: m = 1, n = 1; break; + case IGUANA_SCRIPT_MSIG: m = vp->M, n = vp->N; break; + case IGUANA_SCRIPT_DATA: + if ( asmstr != 0 ) + strcpy(asmstr,"DATA ONLY"); + bitcoin_address(coinaddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); + flag++; + break; + case IGUANA_SCRIPT_STRANGE: + if ( asmstr != 0 ) + strcpy(asmstr,"STRANGE SCRIPT "); + bitcoin_address(coinaddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); + flag++; + break; + default: break;//printf("unexpected script type.%d\n",type); break; + } + if ( n > 0 ) + { + scriptlen = bitcoin_MofNspendscript(rmd160,script,0,vp); + bitcoin_address(coinaddr,p2shtype,script,scriptlen); + if ( asmstr != 0 ) { - if ( (retstr= basilisk_sendrawtransaction(myinfo,coin,signedtx)) != 0 ) + sprintf(asmstr,"%d ",m); + for (i=0; isigners[i].pubkey)) > 0 ) { - printf("sendrawtransaction %s error.(%s)\n",name,retstr); - free(retstr); + init_hexbytes_noT(asmstr + strlen(asmstr),(uint8_t *)vp->signers[i].pubkey,plen); + if ( asmstr != 0 ) + strcat(asmstr," "); } - } else printf("sendrawtransaction %s got null return\n",name); + else if ( asmstr != 0 ) + strcat(asmstr,"NOPUBKEY "); + sprintf(asmstr + strlen(asmstr),"%d // M.%d of N.%d [",n,m,n); + for (i=0; isigners[i].coinaddr,ispendlen > 0 ) + init_hexbytes_noT(asmstr + strlen(asmstr),(uint8_t *)vp->spendscript,vp->spendlen); + *Mp = m, *nump = n; + return(scriptlen); } -int32_t _basilisk_rawtx_sign(struct supernet_info *myinfo,int32_t height,uint32_t timestamp,uint32_t locktime,uint32_t sequenceid,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) -{ - char *rawtxbytes=0,*signedtx=0,hexstr[999],wifstr[128]; cJSON *txobj,*vins,*item,*sobj,*privkeys; int32_t needsig=1,retval = -1; struct vin_info *V; - V = calloc(256,sizeof(*V)); - V[0].signers[0].privkey = privkey; - bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); - privkeys = cJSON_CreateArray(); - bitcoin_priv2wif(wifstr,privkey,rawtx->coin->chain->wiftype); - jaddistr(privkeys,wifstr); - if ( privkey2 != 0 ) - { - V[0].signers[1].privkey = *privkey2; - bitcoin_pubkey33(myinfo->ctx,V[0].signers[1].pubkey,*privkey2); - bitcoin_priv2wif(wifstr,*privkey2,rawtx->coin->chain->wiftype); - jaddistr(privkeys,wifstr); - V[0].N = V[0].M = 2; - //char str[65]; printf("add second privkey.(%s) %s\n",jprint(privkeys,0),bits256_str(str,*privkey2)); - } else V[0].N = V[0].M = 1; - V[0].suppress_pubkeys = dest->I.suppress_pubkeys; - V[0].ignore_cltverr = ignore_cltverr; - if ( dest->I.redeemlen != 0 ) - memcpy(V[0].p2shscript,dest->redeemscript,dest->I.redeemlen), V[0].p2shlen = dest->I.redeemlen; - txobj = bitcoin_txcreate(rawtx->coin->symbol,rawtx->coin->chain->isPoS,locktime,userdata == 0 ? 1 : 1,timestamp);//rawtx->coin->chain->locktime_txversion); - vins = cJSON_CreateArray(); - item = cJSON_CreateObject(); - if ( userdata != 0 && userdatalen > 0 ) - { - memcpy(V[0].userdata,userdata,userdatalen); - V[0].userdatalen = userdatalen; - init_hexbytes_noT(hexstr,userdata,userdatalen); - jaddstr(item,"userdata",hexstr); -#ifdef DISABLE_CHECKSIG - needsig = 0; -#endif +int32_t bitcoin_scriptget(uint8_t pubtype,uint8_t p2shtype,int32_t *hashtypep,uint32_t *sigsizep,uint32_t *pubkeysizep,uint8_t **userdatap,uint32_t *userdatalenp,struct vin_info *vp,uint8_t *scriptsig,int32_t len,int32_t spendtype) +{ + int32_t j,n,siglen,plen; uint8_t *p2shscript; + j = n = 0; + *userdatap = 0; + *userdatalenp = *pubkeysizep = *sigsizep = 0; + *hashtypep = SIGHASH_ALL; + while ( (siglen= scriptsig[n]) >= 70 && siglen <= 73 && n+siglen < len && j < 16 ) + { + vp->signers[j].siglen = siglen; + memcpy(vp->signers[j].sig,&scriptsig[n+1],siglen); + if ( j == 0 ) + *hashtypep = vp->signers[j].sig[siglen-1]; + else if ( vp->signers[j].sig[siglen-1] != *hashtypep ) + { + //printf("SIGHASH.%d mismatch %d vs %d\n",j,vp->signers[j].sig[siglen-1],*hashtypep); + break; + } + (*sigsizep) += siglen; + //printf("sigsize %d [%02x]\n",*sigsizep,vp->signers[j].sig[siglen-1]); + n += (siglen + 1); + j++; + if ( spendtype == 0 && j > 1 ) + spendtype = IGUANA_SCRIPT_MSIG; } - //printf("rawtx B\n"); - if ( bits256_nonz(rawtx->I.actualtxid) != 0 ) - jaddbits256(item,"txid",rawtx->I.actualtxid); - else jaddbits256(item,"txid",rawtx->I.signedtxid); - jaddnum(item,"vout",0); - sobj = cJSON_CreateObject(); - init_hexbytes_noT(hexstr,rawtx->spendscript,rawtx->I.spendlen); - jaddstr(sobj,"hex",hexstr); - jadd(item,"scriptPubKey",sobj); - jaddnum(item,"suppress",dest->I.suppress_pubkeys); - jaddnum(item,"sequence",sequenceid); - if ( (dest->I.redeemlen= rawtx->I.redeemlen) != 0 ) + vp->numsigs = j; + vp->type = spendtype; + if ( j == 0 ) { - init_hexbytes_noT(hexstr,rawtx->redeemscript,rawtx->I.redeemlen); - memcpy(dest->redeemscript,rawtx->redeemscript,rawtx->I.redeemlen); - jaddstr(item,"redeemScript",hexstr); + //*userdatalenp = len; + vp->spendlen = len; + return(vp->spendlen); } - jaddi(vins,item); - jdelete(txobj,"vin"); - jadd(txobj,"vin",vins); - //printf("basilisk_rawtx_sign locktime.%u/%u for %s spendscript.%s -> %s, suppress.%d\n",rawtx->I.locktime,dest->I.locktime,rawtx->name,hexstr,dest->name,dest->I.suppress_pubkeys); - txobj = bitcoin_txoutput(txobj,dest->spendscript,dest->I.spendlen,dest->I.amount); - if ( (rawtxbytes= bitcoin_json2hex(myinfo,rawtx->coin,&dest->I.txid,txobj,V)) != 0 ) - { - //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); - if ( needsig == 0 ) - signedtx = rawtxbytes; - if ( signedtx != 0 || (signedtx= iguana_signrawtx(myinfo,rawtx->coin,height,&dest->I.signedtxid,&dest->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) - { - dest->I.datalen = (int32_t)strlen(signedtx) >> 1; - if ( dest->I.datalen <= sizeof(dest->txbytes) ) - decode_hex(dest->txbytes,dest->I.datalen,signedtx); - else printf("DEX tx is too big %d vs %d\n",dest->I.datalen,(int32_t)sizeof(dest->txbytes)); - if ( signedtx != rawtxbytes ) - free(signedtx); - if ( dest->I.completed != 0 ) - retval = 0; - else printf("couldnt complete sign transaction %s\n",rawtx->name); - } else printf("error signing\n"); - free(rawtxbytes); - } else printf("error making rawtx\n"); - free_json(privkeys); - free_json(txobj); - free(V); - return(retval); -} - -int32_t basilisk_rawtx_sign(struct supernet_info *myinfo,int32_t height,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) -{ - uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; - timestamp = swap->I.started; - if ( dest == &swap->aliceclaim ) - locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; - else if ( dest == &swap->bobreclaim ) - locktime = swap->bobpayment.I.locktime + 1, sequenceid = 0; - return(_basilisk_rawtx_sign(myinfo,height,timestamp,locktime,sequenceid,dest,rawtx,privkey,privkey2,userdata,userdatalen,ignore_cltverr)); -} - -cJSON *basilisk_privkeyarray(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *vins) -{ - cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],typestr[64],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; double bidasks[2]; - privkeyarray = cJSON_CreateArray(); - //printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr); - if ( (n= cJSON_GetArraySize(vins)) > 0 ) + j = 0; + while ( ((plen= scriptsig[n]) == 33 || plen == 65) && j < 16 && plen+n <= len ) { - for (i=0; isigners[j].pubkey,&scriptsig[n+1],plen); + calc_rmd160_sha256(vp->signers[j].rmd160,vp->signers[j].pubkey,plen); + if ( j == 0 ) + memcpy(vp->rmd160,vp->signers[j].rmd160,20); + n += (plen + 1); + (*pubkeysizep) += plen; + j++; + } + vp->numpubkeys = j; + *userdatap = &scriptsig[n]; + if ( len > n ) + *userdatalenp = (len - n); + p2shscript = 0; + while ( n < len ) + { + if ( n+2 < len && (scriptsig[n] == 0x4c || scriptsig[n] == 0x4d) ) { - item = jitem(vins,i); - txid = jbits256(item,"txid"); - vout = jint(item,"vout"); - if ( bits256_nonz(txid) != 0 && vout >= 0 ) + if ( scriptsig[n] == 0x4c ) + vp->p2shlen = scriptsig[n+1], n += 2; + else vp->p2shlen = ((uint32_t)scriptsig[n+1] + ((uint32_t)scriptsig[n+2] << 8)), n += 3; + //printf("p2sh opcode.%02x %02x %02x scriptlen.%d\n",scriptsig[n],scriptsig[n+1],scriptsig[n+2],vp->p2shlen); + if ( vp->p2shlen < IGUANA_MAXSCRIPTSIZE && n+vp->p2shlen <= len ) { - iguana_txidcategory(myinfo,coin,account,coinaddr,txid,vout); - if ( coinaddr[0] == 0 && (sobj= jobj(item,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 && is_hexstr(hexstr,0) > 0 ) - { - len = (int32_t)strlen(hexstr) >> 1; - if ( len < (sizeof(script) << 1) ) - { - decode_hex(script,len,hexstr); - if ( len == 25 && script[0] == 0x76 && script[1] == 0xa9 && script[2] == 0x14 ) - bitcoin_address(coinaddr,coin->chain->pubtype,script+3,20); - } - } - if ( coinaddr[0] != 0 ) - { - if ( (waddr= iguana_waddresssearch(myinfo,&wacct,coinaddr)) != 0 ) - { - bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype); - jaddistr(privkeyarray,waddr->wifstr); - } - else if ( smartaddress(myinfo,typestr,bidasks,&privkey,coin->symbol,coinaddr) >= 0 ) - { - bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); - jaddistr(privkeyarray,wifstr); - } - else printf("cant find (%s) in wallet\n",coinaddr); - } else printf("cant coinaddr from (%s).v%d\n",bits256_str(str,txid),vout); - } else printf("invalid txid/vout %d of %d\n",i,n); + p2shscript = &scriptsig[n]; + memcpy(vp->p2shscript,&scriptsig[n],vp->p2shlen); + n += vp->p2shlen; + vp->type = IGUANA_SCRIPT_P2SH; + } else vp->p2shlen = 0; } } - return(privkeyarray); + if ( *userdatap == p2shscript ) + *userdatap = 0; + /*if ( len == 0 ) + { + // txid.(eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2).v1 + decode_hex(vp->rmd160,20,"010966776006953d5567439e5e39f86a0d273bee");//3564a74f9ddb4372301c49154605573d7d1a88fe"); + vp->type = IGUANA_SCRIPT_76A988AC; + }*/ + vp->spendlen = iguana_scriptgen(pubtype,p2shtype,&vp->M,&vp->N,vp->coinaddr,vp->spendscript,0,vp->rmd160,vp->type,(const struct vin_info *)vp,vp->vin.prev_vout); + //printf("type.%d asmstr.(%s) spendlen.%d\n",vp->type,asmstr,vp->spendlen); + return(vp->spendlen); } -int32_t basilisk_rawtx_return(struct supernet_info *myinfo,int32_t height,struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) +int32_t _iguana_calcrmd160(uint8_t pubtype,uint8_t p2shtype,struct vin_info *vp) { - char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; - if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) + static uint8_t zero_rmd160[20]; + char hexstr[8192]; uint8_t *script,type; int32_t i,n,m,plen; + if ( vp->N == 0 ) + vp->N = 1; + if ( vp->M == 0 ) + vp->M = 1; + type = IGUANA_SCRIPT_STRANGE; + init_hexbytes_noT(hexstr,vp->spendscript,vp->spendlen); + //char str[65]; printf("script.(%s).%d in %s len.%d plen.%d spendlen.%d cmp.%d\n",hexstr,vp->spendlen,bits256_str(str,vp->vin.prev_hash),vp->spendlen,bitcoin_pubkeylen(&vp->spendscript[1]),vp->spendlen,vp->spendscript[vp->spendlen-1] == SCRIPT_OP_CHECKSIG); + if ( vp->spendlen == 0 ) + { + if ( zero_rmd160[0] == 0 ) + { + calc_rmd160_sha256(zero_rmd160,vp->spendscript,vp->spendlen); + //vcalc_sha256(0,sha256,vp->spendscript,vp->spendlen); // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + //calc_rmd160(0,zero_rmd160,sha256,sizeof(sha256)); // b472a266d0bd89c13706a4132ccfb16f7c3b9fcb + init_hexbytes_noT(hexstr,zero_rmd160,20); + } + memcpy(vp->rmd160,zero_rmd160,sizeof(zero_rmd160)); + return(IGUANA_SCRIPT_NULL); + } + else if ( vp->spendscript[0] == SCRIPT_OP_RETURN ) + type = IGUANA_SCRIPT_OPRETURN; + else if ( vp->spendscript[0] == SCRIPT_OP_DUP && vp->spendscript[1] == SCRIPT_OP_HASH160 && vp->spendscript[2] == 20 && vp->spendscript[vp->spendscript[2]+3] == SCRIPT_OP_EQUALVERIFY && vp->spendscript[vp->spendscript[2]+4] == SCRIPT_OP_CHECKSIG ) + { + //printf("IGUANA_SCRIPT_76A988AC plen.%d vs %d vp->spendlen\n",vp->spendscript[2]+4,vp->spendlen); + // 76a9145f69cb73016264270dae9f65c51f60d0e4d6fd4488ac + memcpy(vp->rmd160,&vp->spendscript[3],20); + if ( (plen= vp->spendscript[2]+5) != vp->spendlen ) + { + return(IGUANA_SCRIPT_STRANGE); + /*while ( plen < vp->spendlen ) + if ( vp->spendscript[plen++] != 0x61 ) // nop + return(IGUANA_SCRIPT_STRANGE);*/ + } + return(IGUANA_SCRIPT_76A988AC); + } + // 21035f1321ed17d387e4433b2fa229c53616057964af065f98bfcae2233c5108055eac + else if ( vp->spendscript[0] == SCRIPT_OP_DUP && (plen= bitcoin_pubkeylen(&vp->spendscript[2])) > 0 && vp->spendscript[vp->spendlen-1] == SCRIPT_OP_CHECKSIG && vp->spendscript[0] == plen && vp->spendlen == plen+3 ) + { + memcpy(vp->signers[0].pubkey,&vp->spendscript[2],plen); + calc_rmd160_sha256(vp->rmd160,vp->signers[0].pubkey,plen); + //printf("found IGUANA_SCRIPT_76AC\n"); + return(IGUANA_SCRIPT_76AC); + } + else if ( (plen= bitcoin_pubkeylen(&vp->spendscript[1])) > 0 && vp->spendscript[vp->spendlen-1] == SCRIPT_OP_CHECKSIG && vp->spendscript[0] == plen && vp->spendlen == plen+2 ) { - privkeyarray = basilisk_privkeyarray(myinfo,rawtx->coin,vins); - if ( (signedtx= iguana_signrawtx(myinfo,rawtx->coin,height,&rawtx->I.signedtxid,&rawtx->I.completed,vins,txbytes,privkeyarray,V)) != 0 ) + memcpy(vp->signers[0].pubkey,&vp->spendscript[1],plen); + calc_rmd160_sha256(vp->rmd160,vp->signers[0].pubkey,plen); + //printf("found IGUANA_SCRIPT_AC\n"); + return(IGUANA_SCRIPT_AC); + } + else if ( vp->spendscript[0] == SCRIPT_OP_HASH160 && vp->spendscript[1] == 0x14 && vp->spendlen == 23 && vp->spendscript[22] == SCRIPT_OP_EQUAL ) + { + memcpy(vp->rmd160,vp->spendscript+2,20); + return(IGUANA_SCRIPT_P2SH); + } + else if ( vp->spendlen > 34 && vp->spendscript[vp->spendlen-1] == SCRIPT_OP_CHECKMULTISIG && (n= vp->spendscript[vp->spendlen-2]) >= 0x51 && n <= 0x60 && (m= vp->spendscript[0]) >= 0x51 && m <= n ) // m of n multisig + { + m -= 0x50, n -= 0x50; + script = vp->spendscript+1; + for (i=0; icoin,vins); - if ( (n= cJSON_GetArraySize(vins)) != 0 ) - { - bits256 txid; int32_t vout; - for (i=0; iI.datalen = (int32_t)strlen(signedtx) >> 1; - //rawtx->txbytes = calloc(1,rawtx->I.datalen); - decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); - //printf("%s SIGNEDTX.(%s)\n",rawtx->name,signedtx); - free(signedtx); - retval = 0; - } else printf("error signrawtx\n"); //do a very short timeout so it finishes via local poll - free_json(privkeyarray); + memcpy(vp->signers[i].pubkey,script,plen); + calc_rmd160_sha256(vp->signers[i].rmd160,vp->signers[i].pubkey,plen); + bitcoin_address(vp->signers[i].coinaddr,pubtype,vp->signers[i].pubkey,plen); + } + if ( (int32_t)((long)script - (long)vp->spendscript) == vp->spendlen-2 ) + { + vp->N = n; + vp->M = m; + //printf("M.%d N.%d\n",m,n); + } + calc_rmd160_sha256(vp->rmd160,vp->spendscript,vp->spendlen); + if ( n == 3 ) + { + if ( m == 3 ) + return(IGUANA_SCRIPT_3of3); + else if ( m == 2 ) + return(IGUANA_SCRIPT_2of3); + else if ( m == 1 ) + return(IGUANA_SCRIPT_1of3); + } + else if ( n == 2 ) + { + if ( m == 2 ) + return(IGUANA_SCRIPT_2of2); + else if ( m == 1 ) + return(IGUANA_SCRIPT_1of2); + } + else if ( m == 1 && n == 1 ) + return(IGUANA_SCRIPT_1of1); + //printf("strange msig M.%d of N.%d\n",m,n); + return(IGUANA_SCRIPT_MSIG); + } + else if ( vp->spendlen == vp->spendscript[0]+1 ) + { + //printf("just data.%d\n",vp->spendlen); + memcpy(vp->rmd160,zero_rmd160,sizeof(zero_rmd160)); + return(IGUANA_SCRIPT_DATA); + } + if ( type != IGUANA_SCRIPT_OPRETURN && type != IGUANA_SCRIPT_DATA ) + { + if ( vp->spendlen > 0 && vp->spendlen < sizeof(hexstr)/2-1 ) + { + static FILE *fp; + init_hexbytes_noT(hexstr,vp->spendscript,vp->spendlen); + //char str[65]; printf("unparsed script.(%s).%d in %s len.%d\n",hexstr,vp->spendlen,bits256_str(str,vp->vin.prev_hash),vp->spendlen); + if ( 1 && fp == 0 ) + fp = fopen("unparsed.txt","w"); + if ( fp != 0 ) + fprintf(fp,"%s\n",hexstr), fflush(fp); + } else sprintf(hexstr,"pkscript overflowed %ld\n",(long)sizeof(hexstr)); } - return(retval); + calc_rmd160_sha256(vp->rmd160,vp->spendscript,vp->spendlen); + return(type); } -int32_t _basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay) +int32_t iguana_calcrmd160(uint8_t pubtype,uint8_t p2shtype,char *asmstr,struct vin_info *vp,uint8_t *pk_script,int32_t pk_scriptlen,bits256 debugtxid,int32_t vout,uint32_t sequence) { - char *retstr,*jsonstr,scriptstr[1024],coinaddr[64]; uint32_t basilisktag; int32_t flag,i,n,retval = -1; cJSON *addresses,*valsobj,*retarray=0; struct vin_info *V; - //bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,myinfo->persistent_pubkey33,33); - if ( rawtx->coin->changeaddr[0] == 0 ) + int32_t scriptlen; uint8_t script[IGUANA_MAXSCRIPTSIZE]; + memset(vp,0,sizeof(*vp)); + vp->vin.prev_hash = debugtxid, vp->vin.prev_vout = vout; + vp->spendlen = pk_scriptlen; + vp->vin.sequence = sequence; + memcpy(vp->spendscript,pk_script,pk_scriptlen); + if ( (vp->type= _iguana_calcrmd160(pubtype,p2shtype,vp)) >= 0 ) { - bitcoin_address(rawtx->coin->changeaddr,rawtx->coin->chain->pubtype,pubkey33,33); - printf("set change address.(%s)\n",rawtx->coin->changeaddr); - } - init_hexbytes_noT(scriptstr,script,scriptlen); - basilisktag = (uint32_t)rand(); - valsobj = cJSON_CreateObject(); - jaddstr(valsobj,"coin",rawtx->coin->symbol); - jaddstr(valsobj,"spendscript",scriptstr); - jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); - jadd64bits(valsobj,"satoshis",rawtx->I.amount); - if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) - txfee = 50000; - jadd64bits(valsobj,"txfee",txfee); - jaddnum(valsobj,"minconf",minconf); - if ( locktime == 0 ) - locktime = (uint32_t)time(NULL) - 777; - jaddnum(valsobj,"locktime",locktime); - jaddnum(valsobj,"timeout",30000); - jaddnum(valsobj,"timestamp",swapstarted+delay); - addresses = cJSON_CreateArray(); - bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,pubkey33,33); - jaddistr(addresses,coinaddr); - jadd(valsobj,"addresses",addresses); - rawtx->I.locktime = locktime; - printf("%s locktime.%u\n",rawtx->name,locktime); - V = calloc(256,sizeof(*V)); - if ( (retstr= basilisk_bitcoinrawtx(myinfo,rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V)) != 0 ) - { - printf("%s %s basilisk_bitcoinrawtx.(%s) txfee %.8f\n",rawtx->name,str,retstr,dstr(txfee)); - flag = 0; - if ( (retarray= cJSON_Parse(retstr)) != 0 ) - { - if ( is_cJSON_Array(retarray) != 0 ) + scriptlen = iguana_scriptgen(pubtype,p2shtype,&vp->M,&vp->N,vp->coinaddr,script,asmstr,vp->rmd160,vp->type,(const struct vin_info *)vp,vout); + if ( vp->M == 0 && vp->N == 0 ) + { + vp->M = vp->N = 1; + strcpy(vp->signers[0].coinaddr,vp->coinaddr); + memcpy(vp->signers[0].rmd160,vp->rmd160,20); + } + if ( scriptlen != pk_scriptlen || (scriptlen != 0 && memcmp(script,pk_script,scriptlen) != 0) ) + { + if ( vp->type != IGUANA_SCRIPT_OPRETURN && vp->type != IGUANA_SCRIPT_DATA && vp->type != IGUANA_SCRIPT_STRANGE ) { - n = cJSON_GetArraySize(retarray); - for (i=0; icoin->longestchain,rawtx,jitem(retarray,i),lockinputs,V)) == 0 ) - { - rawtx->vins = jduplicate(jobj(jitem(retarray,i),"vins")); - jsonstr = jprint(rawtx->vins,0); - safecopy(rawtx->vinstr,jsonstr,sizeof(rawtx->vinstr)); - free(jsonstr); - break; - } - } + int32_t i; + printf("\n--------------------\n"); + for (i=0; itype,scriptlen,pk_scriptlen); } - else - { - retval = basilisk_rawtx_return(myinfo,rawtx->coin->longestchain,rawtx,retarray,lockinputs,V); - rawtx->vins = jduplicate(jobj(retarray,"vins")); - jsonstr = jprint(rawtx->vins,0); - safecopy(rawtx->vinstr,jsonstr,sizeof(rawtx->vinstr)); - free(jsonstr); + } + } + return(vp->type); +} + +cJSON *bitcoin_txscript(char *asmstr,char **vardata,int32_t numvars) +{ + int32_t i; cJSON *scriptjson,*array; + scriptjson = cJSON_CreateObject(); + jaddstr(scriptjson,"asm",asmstr); + jaddnum(scriptjson,"numvars",numvars); + if ( numvars > 0 ) + { + array = cJSON_CreateArray(); + for (i=0; i= 0 ) + { + if ( (n= V.N) == 0 ) + n = 1; + for (i=0; i 0 ) + init_hexbytes_noT(pubkeystr,V.signers[i].pubkey,plen); + else pubkeystr[0] = 0; + jaddistr(pubkeys,pubkeystr); + } + } + return(pubkeys); +} + +void iguana_addscript(cJSON *dest,uint8_t *script,int32_t scriptlen,char *fieldname) +{ + char *scriptstr,scriptbuf[8192+256]; int32_t maxlen; cJSON *scriptobj; + if ( scriptlen < 0 || scriptlen > IGUANA_MAXSCRIPTSIZE || scriptlen > sizeof(scriptbuf) ) + return; + scriptstr = scriptbuf, maxlen = sizeof(scriptbuf); + init_hexbytes_noT(scriptstr,script,scriptlen); + //if ( strcmp(fieldname,"userdata") == 0 ) + // printf("SCRIPT_USERDATA.(%s)\n",scriptstr); + if ( strcmp(fieldname,"coinbase") == 0 ) + jaddstr(dest,"coinbase",scriptstr); + else + { + scriptobj = cJSON_CreateObject(); + jaddstr(scriptobj,"hex",scriptstr); + iguana_expandscript(scriptstr,maxlen,script,scriptlen); + if ( scriptstr[0] != 0 ) + jaddstr(scriptobj,"asm",scriptstr); + if ( scriptstr != scriptbuf ) + free(scriptstr); + jadd(dest,fieldname,scriptobj); + } +} + +cJSON *iguana_pubkeysjson(uint8_t *pubkeyptrs[],int32_t numpubkeys) +{ + int32_t i,plen; char pubkeystr[256]; cJSON *pubkeysjson = cJSON_CreateArray(); + for (i=0; i 0 ) + init_hexbytes_noT(pubkeystr,pubkeyptrs[i],plen); + else pubkeystr[0] = 0; + jaddistr(pubkeysjson,pubkeystr); + } + return(pubkeysjson); +} + +cJSON *bitcoin_txinput(uint8_t pubtype,uint8_t p2shtype,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequenceid,uint8_t *spendscript,int32_t spendlen,uint8_t *redeemscript,int32_t p2shlen,uint8_t *pubkeys[],int32_t numpubkeys,uint8_t *sig,int32_t siglen) +{ + cJSON *item,*vins; char p2shscriptstr[IGUANA_MAXSCRIPTSIZE*2+1]; uint8_t *script,len=0; + vins = jduplicate(jobj(txobj,"vin")); + jdelete(txobj,"vin"); + item = cJSON_CreateObject(); + if ( sig != 0 && siglen > 0 ) + iguana_addscript(item,sig,siglen,"scriptSig"); + if ( spendscript != 0 && spendscript > 0 ) + { + iguana_addscript(item,spendscript,spendlen,"scriptPubKey"); + script = spendscript, len = spendlen; + } + else if ( redeemscript != 0 && p2shlen > 0 ) + { + init_hexbytes_noT(p2shscriptstr,redeemscript,p2shlen); + jaddstr(item,"redeemScript",p2shscriptstr); + script = redeemscript, len = p2shlen; + } else script = 0; + if ( script != 0 && numpubkeys == 0 ) + jadd(item,"pubkeys",iguana_scriptpubkeys(pubtype,p2shtype,script,len,txid,vout,sequenceid)); + else if ( pubkeys != 0 && numpubkeys > 0 ) + jadd(item,"pubkeys",iguana_pubkeysjson(pubkeys,numpubkeys)); + jaddbits256(item,"txid",txid); + jaddnum(item,"vout",vout); + jaddnum(item,"sequence",sequenceid); + jaddi(vins,item); + jadd(txobj,"vin",vins); + //printf("addvin -> (%s)\n",jprint(txobj,0)); + return(txobj); +} + +cJSON *bitcoin_txcreate(char *symbol,int32_t isPoS,int64_t locktime,uint32_t txversion,uint32_t timestamp) +{ + cJSON *json = cJSON_CreateObject(); + jaddnum(json,"version",txversion); + if ( locktime == 0 && strcmp(symbol,"KMD") == 0 ) + locktime = (uint32_t)time(NULL); + jaddnum(json,"locktime",locktime); + if ( isPoS != 0 ) + jaddnum(json,"timestamp",timestamp == 0 ? time(NULL) : timestamp); + jadd(json,"vin",cJSON_CreateArray()); + jadd(json,"vout",cJSON_CreateArray()); + return(json); +} + +cJSON *bitcoin_txoutput(cJSON *txobj,uint8_t *paymentscript,int32_t len,uint64_t satoshis) +{ + char *hexstr; cJSON *item,*skey,*vouts = jduplicate(jobj(txobj,"vout")); + jdelete(txobj,"vout"); + item = cJSON_CreateObject(); + jadd64bits(item,"satoshis",satoshis); + skey = cJSON_CreateObject(); + hexstr = malloc(len*2 + 1); + init_hexbytes_noT(hexstr,paymentscript,len); + jaddstr(skey,"hex",hexstr); + //printf("addoutput.(%s %s)\n",hexstr,jprint(skey,0)); + free(hexstr); + jadd(item,"scriptPubkey",skey); + jaddi(vouts,item); + jadd(txobj,"vout",vouts); + return(txobj); +} + +int32_t bitcoin_txaddspend(uint8_t pubtype,uint8_t p2shtype,cJSON *txobj,char *destaddress,uint64_t satoshis) +{ + uint8_t outputscript[128],addrtype,rmd160[20]; int32_t scriptlen; + if ( bitcoin_validaddress(pubtype,p2shtype,destaddress) == 0 && satoshis != 0 ) + { + bitcoin_addr2rmd160(&addrtype,rmd160,destaddress); + scriptlen = bitcoin_standardspend(outputscript,0,rmd160); + bitcoin_txoutput(txobj,outputscript,scriptlen,satoshis); + return(0); + } else return(-1); +} + +int32_t iguana_vinparse(int32_t rwflag,uint8_t *serialized,struct iguana_msgvin *msg) +{ + int32_t p2shlen,len = 0; uint32_t tmp; + len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->prev_hash),msg->prev_hash.bytes); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->prev_vout),&msg->prev_vout); + //char str[65]; printf("prev_hash.(%s) v%d\n",bits256_str(str,msg->prev_hash),msg->prev_vout); + if ( rwflag == 1 ) + { + tmp = msg->scriptlen + msg->userdatalen + msg->p2shlen; + if ( msg->p2shlen != 0 ) + { + if ( msg->p2shlen < 76 ) + tmp++; + else if ( msg->p2shlen < 0x100 ) + tmp += 2; + else tmp += 3; + } + } + len += iguana_rwvarint32(rwflag,&serialized[len],&tmp); + if ( rwflag == 0 ) + { + /*if ( msg->p2shlen != 0 ) + { + if ( msg->p2shlen < 76 ) + tmp++; + else if ( msg->p2shlen < 0x100 ) + tmp += 2; + else tmp += 3; + }*/ + msg->scriptlen = tmp; + } + if ( msg->scriptlen > IGUANA_MAXSCRIPTSIZE ) + { + printf("iguana_vinparse illegal scriptlen.%d\n",msg->scriptlen); + return(-1); + } + //printf("len.%d scriptlen.%d user.%d p2sh.%d\n",len,msg->scriptlen,msg->userdatalen,msg->p2shlen); + if ( rwflag == 0 ) + { + msg->vinscript = &serialized[len]; + len += msg->scriptlen; + } + else + { + if ( msg->vinscript != 0 && msg->scriptlen > 0 ) + memcpy(&serialized[len],msg->vinscript,msg->scriptlen), len += msg->scriptlen; // pubkeys here + if ( msg->userdatalen > 0 && msg->userdata != 0 ) + { + //printf("userdata.%d scriptlen.%d\n",msg->userdatalen,msg->scriptlen); + memcpy(&serialized[len],msg->userdata,msg->userdatalen); + len += msg->userdatalen; + } + if ( (p2shlen= msg->p2shlen) > 0 && msg->redeemscript != 0 ) + { + if ( p2shlen < 76 ) + serialized[len++] = p2shlen; + else if ( p2shlen <= 0xff ) + { + serialized[len++] = 0x4c; + serialized[len++] = p2shlen; + } + else if ( p2shlen <= 0xffff ) + { + serialized[len++] = 0x4d; + serialized[len++] = (p2shlen & 0xff); + serialized[len++] = ((p2shlen >> 8) & 0xff); + } else return(-1); + memcpy(&serialized[len],msg->redeemscript,p2shlen), len += p2shlen; + if ( (0) ) + { + int32_t j; + for (j=0; jredeemscript[j]); + printf(" p2shlen.%d %x\n",p2shlen,p2shlen); + } + } + } + //printf("sequence starts.%d %08x\n",len,*(int32_t *)&serialized[len]); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->sequence),&msg->sequence); + if ( (0) ) + { + int32_t i; char str[65]; + for (i=0; isequence,bits256_str(str,msg->prev_hash),msg->prev_vout,msg->vinscript,msg->scriptlen,rwflag); + } + return(len); +} + +int32_t iguana_voutparse(int32_t rwflag,uint8_t *serialized,struct iguana_msgvout *msg) +{ + int32_t len = 0; + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->value),&msg->value); + len += iguana_rwvarint32(rwflag,&serialized[len],&msg->pk_scriptlen); + if ( msg->pk_scriptlen > IGUANA_MAXSCRIPTSIZE ) + { + printf("iguana_voutparse illegal scriptlen.%d\n",msg->pk_scriptlen); + return(-1); + } + if ( rwflag == 0 ) + msg->pk_script = &serialized[len]; + else if ( msg->pk_scriptlen > 0 ) + { + memcpy(&serialized[len],msg->pk_script,msg->pk_scriptlen); + if ( (0) ) + { + int32_t i; + for (i=0; ipk_scriptlen; i++) + printf("%02x",msg->pk_script[i]); + printf(" [%p] scriptlen.%d rwflag.%d %.8f\n",msg->pk_script,msg->pk_scriptlen,rwflag,dstr(msg->value)); + } + } // else serialized[len++] = 0; + len += msg->pk_scriptlen; + return(len); +} + +cJSON *iguana_vinjson(struct iguana_msgvin *vin,bits256 sigtxid) +{ + char str[65]; int32_t vout; cJSON *json = cJSON_CreateObject(); + vout = vin->prev_vout; + jaddnum(json,"sequence",vin->sequence); + if ( vout < 0 && bits256_nonz(vin->prev_hash) == 0 ) + iguana_addscript(json,vin->vinscript,vin->scriptlen,"coinbase"); + else + { + jaddstr(json,"txid",bits256_str(str,vin->prev_hash)); + jaddnum(json,"vout",vout); + if ( bits256_nonz(sigtxid) != 0 ) + jaddbits256(json,"sigtxid",sigtxid); + if ( vin->scriptlen > 0 && vin->vinscript != 0 ) // sigs + iguana_addscript(json,vin->vinscript,vin->scriptlen,"scriptSig"); + if ( vin->userdatalen > 0 && vin->userdata != 0 ) + iguana_addscript(json,vin->userdata,vin->userdatalen,"userdata"); + if ( vin->p2shlen > 0 && vin->redeemscript != 0 ) + iguana_addscript(json,vin->redeemscript,vin->p2shlen,"redeemScript"); + if ( vin->spendlen > 0 && vin->spendscript != 0 ) + iguana_addscript(json,vin->spendscript,vin->spendlen,"scriptPubKey"); + } + return(json); +} + +int32_t iguana_parsehexstr(uint8_t **destp,uint16_t *lenp,uint8_t *dest2,int32_t *len2p,uint8_t *serialized,char *hexstr) +{ + int32_t n; + n = (int32_t)strlen(hexstr) >> 1; + //printf("addhex.(%s) %d\n",hexstr,n); + if ( serialized == 0 ) + { + if ( (serialized= *destp) == 0 ) + printf("iguana_parsehexstr null serialized and destp\n"); + } + if ( serialized != 0 ) + { + decode_hex(serialized,n,hexstr); + *destp = serialized; + *lenp = n; + if ( dest2 != 0 && len2p != 0 ) + { + *len2p = n; + memcpy(dest2,serialized,n); + } + } + return(n); +} + +int32_t iguana_scriptnum(uint8_t opcode) +{ + if ( opcode == 0x00 ) + return(0); + else if ( opcode >= 0x51 && opcode < 0x60 ) + return(opcode - 0x50); + else return(-1); +} + +int32_t iguana_parsevinobj(uint8_t *serialized,int32_t maxsize,struct iguana_msgvin *vin,cJSON *vinobj,struct vin_info *V) +{ + //struct iguana_outpoint outpt; struct iguana_waddress *waddr; struct iguana_waccount *wacct; + uint8_t lastbyte; uint32_t tmp=0; int32_t i,n,starti,suppress_pubkeys,siglen,plen,m,endi,rwflag=1,len = 0; char *userdata=0,*pubkeystr,*hexstr = 0,*redeemstr = 0,*spendstr = 0; cJSON *scriptjson = 0,*obj,*pubkeysjson = 0; + //printf("PARSEVIN.(%s) vin.%p\n",jprint(vinobj,0),vin); + if ( V == 0 ) + memset(vin,0,sizeof(*vin)); + vin->prev_vout = -1; + suppress_pubkeys = juint(vinobj,"suppress"); + if ( jobj(vinobj,"sequence") != 0 ) + vin->sequence = juint(vinobj,"sequence"); + else vin->sequence = 0xffffffff; + if ( (hexstr= jstr(vinobj,"coinbase")) == 0 ) + { + vin->prev_hash = jbits256(vinobj,"txid"); + //char str[65]; printf("vin->prev_hash.(%s)\n",bits256_str(str,vin->prev_hash)); + vin->prev_vout = jint(vinobj,"vout"); + if ( (scriptjson= jobj(vinobj,"scriptSig")) != 0 ) + hexstr = jstr(scriptjson,"hex"); + if ( ((spendstr= jstr(vinobj,"scriptPub")) == 0 && (spendstr= jstr(vinobj,"scriptPubKey")) == 0) || is_hexstr(spendstr,(int32_t)strlen(spendstr)) <= 0 ) + { + if ( (obj= jobj(vinobj,"scriptPub")) != 0 || (obj= jobj(vinobj,"scriptPubKey")) != 0 ) + { + spendstr = jstr(obj,"hex"); + if ( spendstr[0] != 0 ) + { + lastbyte = _decode_hex(&spendstr[strlen(spendstr)-2]); + //if ( lastbyte == SCRIPT_OP_CHECKMULTISIG ) + // need_op0 = 1; + if ( V != 0 ) + { + V->spendlen = (int32_t)strlen(spendstr) >> 1; + decode_hex(V->spendscript,V->spendlen,spendstr); + } + } + } + } + if ( (redeemstr= jstr(vinobj,"redeemScript")) == 0 || is_hexstr(redeemstr,(int32_t)strlen(redeemstr)) <= 0 ) + { + if ( (obj= jobj(vinobj,"redeemScript")) != 0 ) + { + redeemstr = jstr(obj,"hex"); + lastbyte = _decode_hex(&redeemstr[strlen(redeemstr)-2]); + //if ( lastbyte == SCRIPT_OP_CHECKMULTISIG ) + // need_op0 = 1; + } + } + if ( (userdata= jstr(vinobj,"userdata")) == 0 || is_hexstr(userdata,(int32_t)strlen(userdata)) <= 0 ) + { + if ( (obj= jobj(vinobj,"userdata")) != 0 ) + userdata = jstr(obj,"hex"); + } + } + //char str[65]; printf("rw.%d prevhash.(%s)\n",rwflag,bits256_str(str,vin->prev_hash)); + len += iguana_rwbignum(rwflag,&serialized[len],sizeof(vin->prev_hash),vin->prev_hash.bytes); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(vin->prev_vout),&vin->prev_vout); + if ( V != 0 ) + { + V->suppress_pubkeys = suppress_pubkeys; + if ( vin->vinscript == 0 && V->spendlen == 0 ) + { + /*if ( iguana_RTunspentindfind(coin,&outpt,V->coinaddr,spendscript,&spendlen,&V->amount,&V->height,vin->prev_hash,vin->prev_vout,coin->bundlescount-1,0) == 0 ) + { + V->unspentind = outpt.unspentind; + if ( V->coinaddr[0] != 0 && (waddr= iguana_waddresssearch(&wacct,V->coinaddr)) != 0 ) + { + plen = bitcoin_pubkeylen(waddr->pubkey); + for (z=0; zsigners[0].pubkey[z] = waddr->pubkey[z]; + } + //printf("V %.8f (%s) spendscript.[%d]\n",dstr(V->amount),V->coinaddr,V->spendlen); } - free(retarray); - } else printf("error parsing.(%s)\n",retstr); - free(retstr); - } else printf("error creating %s %s\n",iambob != 0 ? "BOB" : "ALICE",rawtx->name); - free_json(valsobj); - free(V); - return(retval); -} - -int32_t basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay) -{ - int32_t retval,len; uint64_t newtxfee; struct iguana_info *coin; - if ( (coin= rawtx->coin) == 0 || strcmp(coin->symbol,"BTC") != 0 ) - return(_basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay)); - retval = _basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,0,rawtx,locktime,script,scriptlen,txfee,minconf,delay); - len = rawtx->I.datalen; - if ( coin->estimatedfee == 0 ) - coin->estimatedfee = iguana_getestimatedfee(myinfo,coin); - newtxfee = coin->estimatedfee * len; - if ( newtxfee > txfee ) - { - retval = _basilisk_rawtx_gen(str,myinfo,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,newtxfee,minconf,delay); - printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); - } - return(retval); + if ( spendlen != 0 && V->spendlen == 0 ) + { + V->spendlen = spendlen; + memcpy(V->spendscript,spendscript,spendlen); + }*/ + } + } + tmp = IGUANA_MAXSCRIPTSIZE; + starti = len; + len += iguana_rwvarint32(rwflag,&serialized[len],&tmp); + endi = len; + //printf("rwflag.%d len.%d tmp.%d\n",rwflag,len,tmp); + //if ( need_op0 != 0 ) + // serialized[len++] = 0; // hack for bug for bug backward compatibility + if ( hexstr != 0 ) + { + n = (int32_t)strlen(hexstr) >> 1; + //printf("add.(%s) offset.%d\n",hexstr,len); + vin->vinscript = &serialized[len]; + decode_hex(&serialized[len],n,hexstr); + vin->scriptlen = n;// + need_op0; + if ( V != 0 ) + { + i = m = 0; + while ( m < n ) + { + siglen = serialized[len + m++]; + //if ( i == 0 && m == 1 && siglen == 0 ) // multisig backward compatible + // continue; + if ( serialized[len + m + siglen - 1] == SIGHASH_ALL ) + memcpy(V->signers[i++].sig,&serialized[len + m],siglen); + if ( (0) ) + { + int32_t j; + for (j=0; jvinscript != 0 ) + { + /*if ( vin->vinscript == 0 ) + { + vin->vinscript = serialized; + vin->vinscript[0] = 0; + vin->scriptlen = 1; + }*/ + for (i=0; i> 1) > 0 ) + { + if ( V != 0 ) + { + memcpy(V->signers[i].pubkey,&vin->vinscript[vin->scriptlen],plen); + if ( V->spendlen == 35 && V->spendscript[0] == 33 && V->spendscript[34] == 0xac ) + suppress_pubkeys = 1; + } + if ( suppress_pubkeys == 0 ) + { + printf("addpub.(%s)\n",pubkeystr); + vin->vinscript[vin->scriptlen++] = plen; + decode_hex(&vin->vinscript[vin->scriptlen],plen,pubkeystr); + vin->scriptlen += plen; + serialized[len++] = plen; + memcpy(&serialized[len],&vin->vinscript[vin->scriptlen],plen), len += plen; + } + } + } + } + //printf("userdata len.%d: ",len); + if ( userdata != 0 ) + { + n = iguana_parsehexstr(&vin->userdata,&vin->userdatalen,V!=0?V->userdata:0,V!=0?&V->userdatalen:0,&serialized[len],userdata); + //printf("parsed userdata.%d\n",n); + len += n; + } + //printf("redeemlen.%d: ",len); + if ( redeemstr != 0 ) + { + n = (int32_t)strlen(redeemstr) >> 1; + if ( n < 76 ) + serialized[len++] = n; + else if ( n <= 0xff ) + { + serialized[len++] = 0x4c; + serialized[len++] = n; + } + else + { + serialized[len++] = 0x4d; + serialized[len++] = n & 0xff; + serialized[len++] = (n >> 8) & 0xff; + } + n = iguana_parsehexstr(&vin->redeemscript,&vin->p2shlen,V!=0?V->p2shscript:0,V!=0?&V->p2shlen:0,&serialized[len],redeemstr); + len += n; + if ( vin->redeemscript[vin->p2shlen-1] == SCRIPT_OP_CHECKMULTISIG ) + { + V->M = iguana_scriptnum(vin->redeemscript[0]); + V->N = iguana_scriptnum(vin->redeemscript[vin->p2shlen-2]); + } + } + tmp = (len - endi); + if ( tmp < 0xfd ) + { + serialized[starti] = tmp; + for (i=starti+1; i> 8) & 0xff); + } + //printf("len.%d tmp.%d output sequence.[%d] <- %x\n",len,tmp,len,vin->sequence); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(vin->sequence),&vin->sequence); + if ( spendstr != 0 ) + { + if ( V != 0 ) + { + if ( V->spendlen == 0 ) + { + V->spendlen = (int32_t)strlen(spendstr) >> 1; + decode_hex(V->spendscript,V->spendlen,spendstr); + } + if ( vin->spendscript == 0 ) + vin->spendscript = V->spendscript; + } + if ( vin->spendlen == 0 && vin->spendscript != 0 ) + { + vin->spendlen = (int32_t)strlen(spendstr) >> 1; + decode_hex(vin->spendscript,vin->spendlen,spendstr); + } + //printf("serialized.%p len.%d\n",serialized,len); + //n = iguana_parsehexstr(&vin->spendscript,&vin->spendlen,V!=0?V->spendscript:0,V!=0?&V->spendlen:0,&serialized[len],spendstr); + //len += n; + } + return(len); +} + +int32_t iguana_parsevoutobj(uint8_t *serialized,int32_t maxsize,struct iguana_msgvout *vout,cJSON *voutobj) +{ + int32_t n,len = 0,rwflag = 1; cJSON *skey; char *hexstr; + memset(vout,0,sizeof(*vout)); + if ( jobj(voutobj,"satoshis") != 0 ) + vout->value = j64bits(voutobj,"satoshis"); + else vout->value = jdouble(voutobj,"value") * SATOSHIDEN; + len += iguana_rwnum(rwflag,&serialized[len],sizeof(vout->value),&vout->value); + if ( (skey= jobj(voutobj,"scriptPubKey")) != 0 ) + { + if ( (hexstr= jstr(skey,"hex")) != 0 ) + { + n = (int32_t)strlen(hexstr) >> 1; + vout->pk_scriptlen = n; + len += iguana_rwvarint32(rwflag,&serialized[len],&vout->pk_scriptlen); + decode_hex(&serialized[len],n,hexstr); + vout->pk_script = &serialized[len]; + len += n; + } // else serialized[len++] = 0; + } //else serialized[len++] = 0; + return(len); +} + +cJSON *iguana_voutjson(uint8_t pubtype,uint8_t p2shtype,struct iguana_msgvout *vout,int32_t txi,bits256 txid) +{ + // 035f1321ed17d387e4433b2fa229c53616057964af065f98bfcae2233c5108055e OP_CHECKSIG + char scriptstr[IGUANA_MAXSCRIPTSIZE+1],asmstr[2*IGUANA_MAXSCRIPTSIZE+1]; int32_t i,m,n,scriptlen,asmtype; struct vin_info *vp; + uint8_t space[8192]; cJSON *addrs,*skey,*json = cJSON_CreateObject(); + vp = calloc(1,sizeof(*vp)); + jadd64bits(json,"satoshis",vout->value); + jaddnum(json,"value",dstr(vout->value)); + jaddnum(json,"n",txi); + //"scriptPubKey":{"asm":"OP_DUP OP_HASH160 5f69cb73016264270dae9f65c51f60d0e4d6fd44 OP_EQUALVERIFY OP_CHECKSIG","reqSigs":1,"type":"pubkeyhash","addresses":["RHyh1V9syARTf2pyxibz7v27D5paBeWza5"]} + if ( vout->pk_script != 0 && vout->pk_scriptlen*2+1 < sizeof(scriptstr) ) + { + memset(vp,0,sizeof(*vp)); + if ( (asmtype= iguana_calcrmd160(pubtype,p2shtype,asmstr,vp,vout->pk_script,vout->pk_scriptlen,txid,txi,0xffffffff)) >= 0 ) + { + skey = cJSON_CreateObject(); + scriptlen = iguana_scriptgen(pubtype,p2shtype,&m,&n,vp->coinaddr,space,asmstr,vp->rmd160,asmtype,vp,txi); + if ( asmstr[0] != 0 ) + jaddstr(skey,"asm",asmstr); + addrs = cJSON_CreateArray(); + if ( vp->N == 1 ) + { + if ( asmtype == 2 ) + { + jaddnum(skey,"reqSigs",1); + jaddstr(skey,"type","pubkeyhash"); + } + if ( vp->coinaddr[0] != 0 ) + jaddistr(addrs,vp->coinaddr); + } + else + { + jaddnum(skey,"reqSigs",vp->M); + for (i=0; iN; i++) + { + //btc_convrmd160(coinaddr,coin->chain->pubtype,V.signers[i].pubkey); + jaddistr(addrs,vp->signers[i].coinaddr); + } + } + jadd(skey,"addresses",addrs); + init_hexbytes_noT(scriptstr,vout->pk_script,vout->pk_scriptlen); + if ( scriptstr[0] != 0 ) + jaddstr(skey,"hex",scriptstr); + jadd(json,"scriptPubKey",skey); + } + } + return(json); +} + +void iguana_vinobjset(struct iguana_msgvin *vin,cJSON *item,uint8_t *spendscript,int32_t maxsize) +{ + char *redeemstr,*hexstr=0; cJSON *sobj; + if ( (redeemstr= jstr(item,"redeemScript")) != 0 && is_hexstr(redeemstr,0) > 0 ) + { + vin->p2shlen = (int32_t)strlen(redeemstr) >> 1; + vin->spendlen = vin->p2shlen; + vin->redeemscript = calloc(1,vin->p2shlen); + decode_hex(vin->redeemscript,vin->p2shlen,redeemstr); + hexstr = redeemstr; + //printf("VINOBJSET.(%s)\n",redeemstr); + } + else if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 && is_hexstr(hexstr,0) > 0 && (vin->spendlen == 0 || vin->spendscript == 0) ) + { + vin->spendlen = (int32_t)strlen(hexstr) >> 1; + } + if ( hexstr != 0 && vin->spendlen != 0 ) + { + if ( vin->spendlen < maxsize ) + { + if ( vin->spendscript == 0 ) + vin->spendscript = spendscript; + decode_hex(vin->spendscript,vin->spendlen,hexstr); + } + } +} + +int32_t iguana_vinarray_check(cJSON *vinarray,bits256 txid,int32_t vout) +{ + bits256 array_txid; cJSON *item; int32_t array_vout,i,n = cJSON_GetArraySize(vinarray); + for (i=0; ivins,dest.tx_in * sizeof(*dest.vins)); + memcpy(dest.vouts,msgtx->vouts,dest.tx_out * sizeof(*dest.vouts)); + memset(sigtxid.bytes,0,sizeof(sigtxid)); + if ( hashtype != SIGHASH_ALL ) + { + printf("currently only SIGHASH_ALL supported, not %d\n",hashtype); + return(sigtxid); + } + for (i=0; i 0 ) // (dest.tx_in != 1 || bits256_nonz(dest.vins[0].prev_hash) != 0) && dest.vins[0].scriptlen > 0 && + { +#ifdef BTC2_VERSION + if ( height >= BTC2_HARDFORK_HEIGHT ) + hashtype |= (0x777 << 20); +#endif + len += iguana_rwnum(1,&serialized[len],sizeof(hashtype),&hashtype); + revsigtxid = bits256_doublesha256(0,serialized,len); + for (i=0; iversion),&msg->version); + if ( json != 0 ) + { + jaddnum(json,"version",msg->version); + vinarray = cJSON_CreateArray(); + voutarray = cJSON_CreateArray(); + if ( rwflag == 0 ) + sigser = calloc(1,maxsize*2); + //printf("json.%p array.%p sigser.%p\n",json,vinarray,sigser); + } + //printf("version.%d\n",msg->version); + if ( isPoS != 0 ) + { + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->timestamp),&msg->timestamp); + //char str[65]; printf("version.%d timestamp.%08x %u %s\n",msg->version,msg->timestamp,msg->timestamp,utc_str(str,msg->timestamp)); + if ( json != 0 ) + jaddnum(json,"timestamp",msg->timestamp); + } + len += iguana_rwvarint32(rwflag,&serialized[len],&msg->tx_in); + if ( rwflag == 0 ) + { + if ( msg->vins == 0 ) + { + if ( sizeof(struct iguana_msgvin)*msg->tx_in > extralen ) + { + printf("(size.%d * tx_in.%d) > extralen.%d\n",(int32_t)sizeof(struct iguana_msgvin),msg->tx_in,extralen); + return(-1); + } + msg->vins = (struct iguana_msgvin *)extraspace; + extraused += (sizeof(struct iguana_msgvin) * msg->tx_in); + } else printf("unexpected non-null msg->vins.%p\n",msg->vins); + memset(msg->vins,0,sizeof(struct iguana_msgvin) * msg->tx_in); + } + for (i=0; itx_in; i++) + { + //printf("vin.%d starts offset.%d\n",i,len); + if ( vins != 0 && jitem(vins,i) != 0 ) + iguana_vinobjset(&msg->vins[i],jitem(vins,i),spendscript,sizeof(spendscript)); + if ( (n= iguana_vinparse(rwflag,&serialized[len],&msg->vins[i])) < 0 ) + return(-1); + //printf("serialized vin.[%02x %02x %02x]\n",serialized[len],serialized[len+1],serialized[len+2]); + if ( msg->vins[i].spendscript == spendscript ) + msg->vins[i].spendscript = 0; + //printf("vin.%d n.%d len.%d\n",i,n,len); + len += n; + if ( len > maxsize ) + { + printf("invalid tx_in.%d len.%d vs maxsize.%d\n",msg->tx_in,len,maxsize); + return(-1); + } + } + //for (i=-3; i<7; i++) + // printf("%02x",serialized[len+i]); + //printf(" prev 3 bytes before tx_out rw.%d\n",rwflag); + len += iguana_rwvarint32(rwflag,&serialized[len],&msg->tx_out); + if ( rwflag == 0 ) + { + if ( msg->vouts == 0 ) + { + if ( (extraused & 0xf) != 0 ) + extraused += 0xf - (extraused & 0xf); + if ( extraused + sizeof(struct iguana_msgvout)*msg->tx_out > extralen ) + { + printf("extraused.%d + tx_out.%d > extralen.%d\n",extraused,msg->tx_out,extralen); + return(-1); + } + msg->vouts = (struct iguana_msgvout *)&extraspace[extraused]; + extraused += (sizeof(struct iguana_msgvout) * msg->tx_out); + } else printf("unexpected non-null msg->vouts %p\n",msg->vouts); + memset(msg->vouts,0,sizeof(struct iguana_msgvout) * msg->tx_out); + } + for (i=0; itx_out; i++) + { + //printf("rwflag.%d vout.%d starts %d\n",rwflag,i,len); + if ( (n= iguana_voutparse(rwflag,&serialized[len],&msg->vouts[i])) < 0 ) + return(-1); + len += n; + if ( len > maxsize ) + { + printf("invalidC tx_out.%d of %d len.%d vs maxsize.%d n.%d\n",i,msg->tx_out,len,maxsize,n); + return(-1); + } + if ( voutarray != 0 ) + jaddi(voutarray,iguana_voutjson(pubtype,p2shtype,&msg->vouts[i],i,*txidp)); + } + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->lock_time),&msg->lock_time); + //printf("lock_time.%08x len.%d\n",msg->lock_time,len); + /*if ( strcmp(coin->symbol,"VPN") == 0 ) + { + uint16_t ddosflag = 0; + len += iguana_rwnum(rwflag,&serialized[len],sizeof(ddosflag),&ddosflag); + for (i=0; serialized[len]!=0&&lentx_in; i++) + { + memset(sigtxid.bytes,0,sizeof(sigtxid)); + if ( vins != 0 && jitem(vins,i) != 0 ) + { + iguana_vinobjset(&msg->vins[i],jitem(vins,i),spendscript,sizeof(spendscript)); + sigtxid = bitcoin_sigtxid(pubtype,p2shtype,isPoS,height,sigser,maxsize*2,msg,i,msg->vins[i].spendscript,msg->vins[i].spendlen,SIGHASH_ALL,vpnstr,suppress_pubkeys); + //printf("after vini.%d vinscript.%p spendscript.%p spendlen.%d (%s)\n",i,msg->vins[i].vinscript,msg->vins[i].spendscript,msg->vins[i].spendlen,jprint(jitem(vins,i),0)); + if ( iguana_vinarray_check(vinarray,msg->vins[i].prev_hash,msg->vins[i].prev_vout) < 0 ) + jaddi(vinarray,iguana_vinjson(&msg->vins[i],sigtxid)); + if ( msg->vins[i].spendscript == spendscript ) + msg->vins[i].spendscript = 0; + } else if ( iguana_vinarray_check(vinarray,msg->vins[i].prev_hash,msg->vins[i].prev_vout) < 0 ) + jaddi(vinarray,iguana_vinjson(&msg->vins[i],sigtxid)); + } + free(sigser); + jadd(json,"vin",vinarray); + msg->tx_in = cJSON_GetArraySize(vinarray); + jaddnum(json,"numvins",msg->tx_in); + } + if ( voutarray != 0 ) + { + jadd(json,"vout",voutarray); + jaddnum(json,"numvouts",msg->tx_out); + } + *txidp = bits256_doublesha256(txidstr,txstart,len); + if ( json != 0 ) + { + jaddnum(json,"locktime",msg->lock_time); + jaddnum(json,"size",len); + jaddbits256(json,"txid",*txidp); + //printf("TX.(%s) %p\n",jprint(json,0),json); + } + msg->allocsize = len; + return(len); +} + +bits256 iguana_parsetxobj(uint8_t isPoS,int32_t *txstartp,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,cJSON *txobj,struct vin_info *V) +{ + int32_t i,n,numvins,numvouts,len = 0,rwflag=1; cJSON *array=0; bits256 txid; char vpnstr[64]; + memset(&txid,0,sizeof(txid)); + memset(msg,0,sizeof(*msg)); + *txstartp = 0; + if ( txobj == 0 ) + return(txid); + vpnstr[0] = 0; + if ( (msg->version= juint(txobj,"version")) == 0 ) + msg->version = 1; + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->version),&msg->version); + if ( isPoS != 0 ) + { + if ( (msg->timestamp= juint(txobj,"timestamp")) == 0 ) + msg->timestamp = (uint32_t)time(NULL); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->timestamp),&msg->timestamp); + } + if ( (array= jarray(&numvins,txobj,"vin")) != 0 ) + { + msg->tx_in = numvins; + len += iguana_rwvarint32(rwflag,&serialized[len],&msg->tx_in); + if ( len + sizeof(struct iguana_msgvin)*msg->tx_in > maxsize ) + return(txid); + maxsize -= (sizeof(struct iguana_msgvin) * msg->tx_in); + msg->vins = (struct iguana_msgvin *)&serialized[maxsize]; + memset(msg->vins,0,sizeof(struct iguana_msgvin) * msg->tx_in); + if ( msg->tx_in > 0 && msg->tx_in*sizeof(struct iguana_msgvin) < maxsize ) + { + for (i=0; itx_in; i++) + { + n = iguana_parsevinobj(&serialized[len],maxsize,&msg->vins[i],jitem(array,i),V!=0?&V[i]:0); + //for (j=0; j<8; j++) + // printf("%02x",serialized[len+j]); + //char str[65]; printf(" <- vinobj.%d starts offset.%d %s\n",i,len,bits256_str(str,msg->vins[i].prev_hash)); + len += n; + } + } + } + if ( (array= jarray(&numvouts,txobj,"vout")) != 0 ) + { + msg->tx_out = numvouts; + len += iguana_rwvarint32(rwflag,&serialized[len],&msg->tx_out); + if ( len + sizeof(struct iguana_msgvout)*msg->tx_out > maxsize ) + return(txid); + maxsize -= (sizeof(struct iguana_msgvout) * msg->tx_out); + msg->vouts = (struct iguana_msgvout *)&serialized[maxsize]; + memset(msg->vouts,0,sizeof(struct iguana_msgvout) * msg->tx_out); + if ( msg->tx_out > 0 && msg->tx_out*sizeof(struct iguana_msgvout) < maxsize ) + { + for (i=0; itx_out; i++) + { + //printf("parsetxobj parsevout.%d starts %d\n",i,len); + len += iguana_parsevoutobj(&serialized[len],maxsize,&msg->vouts[i],jitem(array,i)); + } + } + } + msg->lock_time = jint(txobj,"locktime"); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->lock_time),&msg->lock_time); + //msg->txid = jbits256(txobj,"txid"); + *txstartp = 0; + msg->allocsize = len; + msg->txid = txid = bits256_doublesha256(0,serialized,len); + return(txid); +} + +char *iguana_rawtxbytes(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,cJSON *json,struct iguana_msgtx *msgtx,int32_t suppress_pubkeys) +{ + int32_t n; char *txbytes = 0,vpnstr[64]; uint8_t *serialized; + serialized = malloc(IGUANA_MAXPACKETSIZE); + vpnstr[0] = 0; + //char str[65]; printf("%d of %d: %s\n",i,msg.txn_count,bits256_str(str,tx.txid)); + if ( (n= iguana_rwmsgtx(pubtype,p2shtype,isPoS,height,1,json,serialized,IGUANA_MAXPACKETSIZE,msgtx,&msgtx->txid,vpnstr,0,0,0,suppress_pubkeys)) > 0 ) + { + txbytes = malloc(n*2+1); + init_hexbytes_noT(txbytes,serialized,n); + } + free(serialized); + return(txbytes); +} + +char *bitcoin_json2hex(uint8_t isPoS,bits256 *txidp,cJSON *txjson,struct vin_info *V) +{ + int32_t txstart; uint8_t *serialized; struct iguana_msgtx msgtx; char *txbytes = 0; + if ( txjson == 0 ) + { + memset(txidp,0,sizeof(*txidp)); + return(0); + } + serialized = malloc(IGUANA_MAXPACKETSIZE*1.5); + *txidp = iguana_parsetxobj(isPoS,&txstart,serialized,IGUANA_MAXPACKETSIZE*1.5,&msgtx,txjson,V); + if ( msgtx.allocsize > 0 ) + { + txbytes = malloc(msgtx.allocsize*2 + 1); + init_hexbytes_noT(txbytes,&serialized[txstart],msgtx.allocsize); + } else printf("bitcoin_txtest: zero msgtx allocsize.(%s)\n",jprint(txjson,0)); + free(serialized); + return(txbytes); +} + +cJSON *bitcoin_data2json(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *txidp,struct iguana_msgtx *msgtx,uint8_t *extraspace,int32_t extralen,uint8_t *serialized,int32_t len,cJSON *vins,int32_t suppress_pubkeys) +{ + int32_t n; char vpnstr[64]; struct iguana_msgtx M; cJSON *txobj; + if ( serialized == 0 ) + return(0); + txobj = cJSON_CreateObject(); + if ( msgtx == 0 ) + msgtx = &M; + memset(msgtx,0,sizeof(M)); + vpnstr[0] = 0; + memset(txidp,0,sizeof(*txidp)); + if ( (n= iguana_rwmsgtx(pubtype,p2shtype,isPoS,height,0,txobj,serialized,len,msgtx,txidp,vpnstr,extraspace,extralen,vins,suppress_pubkeys)) <= 0 ) + { + printf("errortxobj.(%s)\n",jprint(txobj,0)); + free_json(txobj); + txobj = cJSON_CreateObject(); + jaddstr(txobj,"error","couldnt decode transaction"); + } + //printf("msgtx.(%s)\n",jprint(txobj,0)); + if ( n != len ) + { + int32_t i; + for (i=0; i<=len; i++) + printf("%02x",serialized[i]); + printf(" data2json n.%d vs len.%d\n",n,len); + } + return(txobj); +} + +cJSON *bitcoin_hex2json(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *txidp,struct iguana_msgtx *msgtx,char *txbytes,uint8_t *extraspace,int32_t extralen,uint8_t *origserialized,cJSON *vins,int32_t suppress_pubkeys) +{ + int32_t len; uint8_t *serialized; cJSON *txobj; + if ( txbytes == 0 ) + return(0); + len = (int32_t)strlen(txbytes) >> 1; + if ( (serialized= origserialized) == 0 ) + serialized = calloc(1,len+4096); + decode_hex(serialized,len,txbytes); + txobj = bitcoin_data2json(pubtype,p2shtype,isPoS,height,txidp,msgtx,extraspace,extralen,serialized,len,vins,suppress_pubkeys); + if ( serialized != origserialized ) + free(serialized); + return(txobj); } diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index d15ea3f47..7db343df6 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -18,18 +18,39 @@ // marketmaker // +struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srchash,bits256 desthash,char *src,uint64_t srcsatoshis,char *dest,uint64_t destsatoshis,uint32_t timestamp,uint32_t quotetime,int32_t DEXselector) +{ + memset(rp,0,sizeof(*rp)); + rp->srchash = srchash; + rp->desthash = desthash; + rp->srcamount = srcsatoshis; + rp->destamount = destsatoshis; + rp->timestamp = timestamp; + rp->quotetime = quotetime; + rp->DEXselector = DEXselector; + safecopy(rp->src,src,sizeof(rp->src)); + safecopy(rp->dest,dest,sizeof(rp->dest)); + rp->quoteid = basilisk_quoteid(rp); + rp->requestid = basilisk_requestid(rp); + return(rp); +} + void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid; struct LP_utxoinfo *utxo; + char *method,*base,*rel,*retstr,*pairstr; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; if ( (method= jstr(argjson,"method")) != 0 ) { - if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) + txid = jbits256(argjson,"txid"); + if ( (utxo= LP_utxofind(txid,jint(argjson,"vout"))) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { - txid = jbits256(argjson,"txid"); - if ( (utxo= LP_utxofind(txid)) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && utxo->swappending == 0 ) + if ( time(NULL) > utxo->swappending ) + utxo->swappending = 0; + if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) { - if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) + if ( utxo->swappending == 0 && utxo->pair < 0 ) { + if ( utxo->pair >= 0 ) + nn_close(utxo->pair), utxo->pair = -1; if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); @@ -39,11 +60,17 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ jaddnum(retjson,"timestamp",time(NULL)); jaddnum(retjson,"price",price); jaddbits256(retjson,"txid",txid); - jadd64bits(retjson,"destsatoshis",price * utxo->satoshis); + pubkey = LP_pubkey(LP_privkey(utxo->coinaddr)); + jaddbits256(retjson,"srchash",pubkey); + txfee = LP_txfee(base); + jadd64bits(retjson,"txfee",txfee); + jadd64bits(retjson,"satoshis",utxo->satoshis - txfee); + jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee)); if ( strcmp(method,"request") == 0 ) { utxo->swappending = (uint32_t)(time(NULL) + 60); utxo->otherpubkey = jbits256(argjson,"pubkey"); + jaddstr(retjson,"result","reserved"); jaddnum(retjson,"pending",utxo->swappending); } retstr = jprint(retjson,1); @@ -51,10 +78,64 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ } } } - } - else if ( ) - { - + else if ( strcmp(method,"connect") == 0 ) + { + if ( utxo->pair < 0 ) + { + if ( (price= LP_price(base,rel)) != 0. ) + { + price *= (1. + profitmargin); + txfee = LP_txfee(base); + satoshis = j64bits(argjson,"satoshis"); + desttxfee = LP_txfee(rel); + desttxid = jbits256(argjson,"desttxid"); + destvout = jint(argjson,"destvout"); + timestamp = juint(argjson,"timestamp"); + quotetime = juint(argjson,"quotetime"); + privkey = LP_privkey(utxo->coinaddr); + pubkey = LP_pubkey(privkey); + srchash = jbits256(argjson,"srchash"); + value = j64bits(argjson,"destsatoshis"); + if ( timestamp == utxo->swappending-60 && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) + { + destsatoshis = value; + if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) + printf("error creating utxo->pair\n"); + else if ( (pairstr= jstr(argjson,"pair")) != 0 && nn_connect(utxo->pair,pairstr) >= 0 ) + { + desthash = jbits256(argjson,"desthash"); + LP_requestinit(&R,srchash,desthash,base,satoshis,rel,destsatoshis,timestamp,quotetime,DEXselector); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) != 0 ) + { + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","connected"); + jaddnum(retjson,"requestid",R.requestid); + jaddnum(retjson,"quoteid",R.quoteid); + retstr = jprint(retjson,1); + LP_send(pubsock,retstr,1); + utxo->swap = LP_swapinit(1,0,privkey,&R); + } + else + { + printf("error launching swaploop\n"); + free(utxo->swap); + utxo->swap = 0; + nn_close(utxo->pair); + utxo->pair = -1; + } + } + else + { + if ( pairstr != 0 ) + printf("printf error nn_connect to %s\n",pairstr); + else printf("(%s) missing pair\n",jprint(argjson,0)); + nn_close(utxo->pair); + utxo->pair = -1; + } + } else printf("dest %.8f < required %.8f\n",dstr(value),dstr(price*(utxo->satoshis-txfee))); + } else printf("no price for %s/%s\n",base,rel); + } else printf("utxo->pair.%d when connect came in (%s)\n",utxo->pair,jprint(argjson,0)); + } } } } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h new file mode 100644 index 000000000..965b2a7ae --- /dev/null +++ b/iguana/exchanges/LP_include.h @@ -0,0 +1,469 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_include.h +// marketmaker +// + +#ifndef LP_INCLUDE_H +#define LP_INCLUDE_H + +#define BASILISK_DISABLEWAITTX +#define BASILISK_DISABLESENDTX + +#define BASILISK_DEFAULT_NUMCONFIRMS 5 +#define DEX_SLEEP 3 +#define BASILISK_DEXDURATION 300 +#define BASILISK_MSGDURATION 30 +#define BASILISK_AUCTION_DURATION 5 + +#define BASILISK_MAXFUTUREBLOCK 60 +#define BASILISK_KEYSIZE ((int32_t)(2*sizeof(bits256)+sizeof(uint32_t)*2)) + +extern char GLOBAL_DBDIR[]; + +void *bitcoin_ctx(); +int32_t bitcoin_verify(void *ctx,uint8_t *sig,int32_t siglen,bits256 txhash2,uint8_t *pubkey,int32_t plen); +int32_t bitcoin_recoververify(void *ctx,char *symbol,uint8_t *sig,bits256 messagehash2,uint8_t *pubkey,size_t plen); +int32_t bitcoin_sign(void *ctx,char *symbol,uint8_t *sig,bits256 txhash2,bits256 privkey,int32_t recoverflag); +bits256 bitcoin_pubkey33(void *ctx,uint8_t *data,bits256 privkey); +bits256 bitcoin_pub256(void *ctx,bits256 *privkeyp,uint8_t odd_even); + +char *bitcoin_base58encode(char *coinaddr,uint8_t *data,int32_t datalen); +int32_t bitcoin_base58decode(uint8_t *data,char *coinaddr); + +#define IGUANA_MAXSCRIPTSIZE 10001 +#define IGUANA_SEQUENCEID_FINAL 0xfffffffe + +#define IGUANA_SCRIPT_NULL 0 +#define IGUANA_SCRIPT_76AC 1 +#define IGUANA_SCRIPT_76A988AC 2 +#define IGUANA_SCRIPT_P2SH 3 +#define IGUANA_SCRIPT_OPRETURN 4 +#define IGUANA_SCRIPT_3of3 5 +#define IGUANA_SCRIPT_2of3 6 +#define IGUANA_SCRIPT_1of3 7 +#define IGUANA_SCRIPT_2of2 8 +#define IGUANA_SCRIPT_1of2 9 +#define IGUANA_SCRIPT_MSIG 10 +#define IGUANA_SCRIPT_DATA 11 +#define IGUANA_SCRIPT_AC 12 +#define IGUANA_SCRIPT_1of1 13 +#define IGUANA_SCRIPT_STRANGE 15 + +#define BASILISK_TIMEOUT 3000 +#define BASILISK_MINFANOUT 8 +#define BASILISK_MAXFANOUT 64 +#define BASILISK_DEFAULTDIFF 0x1effffff +#define BASILISK_HDROFFSET ((int32_t)(sizeof(bits256)+sizeof(struct iguana_msghdr)+sizeof(uint32_t))) + +#define INSTANTDEX_DECKSIZE 1000 +#define INSTANTDEX_LOCKTIME (3600*2 + 300*2) +#define INSTANTDEX_INSURANCEDIV 777 +#define INSTANTDEX_PUBKEY "03bc2c7ba671bae4a6fc835244c9762b41647b9827d4780a89a949b984a8ddcc06" +#define INSTANTDEX_RMD160 "ca1e04745e8ca0c60d8c5881531d51bec470743f" +#define JUMBLR_RMD160 "5177f8b427e5f47342a4b8ab5dac770815d4389e" +#define TIERNOLAN_RMD160 "daedddd8dbe7a2439841ced40ba9c3d375f98146" +#define INSTANTDEX_BTC "1KRhTPvoxyJmVALwHFXZdeeWFbcJSbkFPu" +#define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" + +struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }; + +struct iguana_msgvout { uint64_t value; uint32_t pk_scriptlen; uint8_t *pk_script; }; + +struct iguana_msgtx +{ + uint32_t version,tx_in,tx_out,lock_time; + struct iguana_msgvin *vins; + struct iguana_msgvout *vouts; + bits256 txid; + int32_t allocsize,timestamp,numinputs,numoutputs; + int64_t inputsum,outputsum,txfee; + uint8_t *serialized; +}; + +struct vin_signer { bits256 privkey; char coinaddr[64]; uint8_t siglen,sig[80],rmd160[20],pubkey[66]; }; + +struct vin_info +{ + struct iguana_msgvin vin; uint64_t amount; cJSON *extras; bits256 sigtxid; + int32_t M,N,validmask,spendlen,type,p2shlen,numpubkeys,numsigs,height,hashtype,userdatalen,suppress_pubkeys,ignore_cltverr; + uint32_t sequence,unspentind; struct vin_signer signers[16]; char coinaddr[65]; + uint8_t rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE],userdata[IGUANA_MAXSCRIPTSIZE]; +}; + +struct basilisk_swapmessage +{ + bits256 srchash,desthash; + uint32_t crc32,msgbits,quoteid,datalen; + uint8_t *data; +}; + +struct basilisk_swap; + +struct basilisk_rawtxinfo +{ + char destaddr[64],coinstr[16]; + bits256 txid,signedtxid,actualtxid; + uint64_t amount,change,inputsum; + int32_t redeemlen,datalen,completed,vintype,vouttype,numconfirms,spendlen,secretstart,suppress_pubkeys; + uint32_t locktime,crcs[2]; + uint8_t addrtype,pubkey33[33],rmd160[20]; +}; + +struct basilisk_request +{ + uint32_t requestid,timestamp,quoteid,quotetime; // 0 to 15 + uint64_t srcamount,unused; // 16 to 31 + bits256 srchash; // 32 to 63 + bits256 desthash; + char src[8],dest[8]; + uint64_t destamount; + int32_t optionhours,DEXselector; +}; + +struct basilisk_rawtx +{ + char name[32]; + struct iguana_msgtx msgtx; + struct basilisk_rawtxinfo I; + struct iguana_info *coin; + char vinstr[8192],p2shaddr[64]; + cJSON *vins; + bits256 utxotxid; int32_t utxovout; + uint8_t txbytes[16384],spendscript[512],redeemscript[1024],extraspace[4096],pubkey33[33]; +}; + +struct basilisk_swapinfo +{ + struct basilisk_request req; + char bobstr[64],alicestr[64]; + bits256 myhash,otherhash,orderhash; + uint32_t statebits,otherstatebits,started,expiration,finished,dead,reftime,putduration,callduration; + int32_t bobconfirms,aliceconfirms,iambob,reclaimed,bobspent,alicespent,pad; + uint64_t alicesatoshis,bobsatoshis,bobinsurance,aliceinsurance; + + bits256 myprivs[2],mypubs[2],otherpubs[2],pubA0,pubA1,pubB0,pubB1,privAm,pubAm,privBn,pubBn; + uint32_t crcs_mypub[2],crcs_mychoosei[2],crcs_myprivs[2],crcs_mypriv[2]; + int32_t choosei,otherchoosei,cutverified,otherverifiedcut,numpubs,havestate,otherhavestate,pad2; + uint8_t secretAm[20],secretBn[20]; + uint8_t secretAm256[32],secretBn256[32]; + uint8_t userdata_aliceclaim[256],userdata_aliceclaimlen; + uint8_t userdata_alicereclaim[256],userdata_alicereclaimlen; + uint8_t userdata_alicespend[256],userdata_alicespendlen; + uint8_t userdata_bobspend[256],userdata_bobspendlen; + uint8_t userdata_bobreclaim[256],userdata_bobreclaimlen; + uint8_t userdata_bobrefund[256],userdata_bobrefundlen; +}; + +struct iguana_info +{ + uint64_t txfee,estimatedfee; + int32_t longestchain; + uint8_t pubtype,p2shtype,isPoS,wiftype; + char symbol[16],changeaddr[64]; +}; + +struct basilisk_swap +{ + void *ctx; struct iguana_info bobcoin,alicecoin; + void (*balancingtrade)(struct basilisk_swap *swap,int32_t iambob); + int32_t subsock,pushsock,connected,aliceunconf,depositunconf,paymentunconf; uint32_t lasttime,aborted; + FILE *fp; + bits256 persistent_privkey,persistent_pubkey; + struct basilisk_swapinfo I; + struct basilisk_rawtx bobdeposit,bobpayment,alicepayment,myfee,otherfee,aliceclaim,alicespend,bobreclaim,bobspend,bobrefund,alicereclaim; + bits256 privkeys[INSTANTDEX_DECKSIZE]; + struct basilisk_swapmessage *messages; int32_t nummessages; + char Bdeposit[64],Bpayment[64]; + uint64_t otherdeck[INSTANTDEX_DECKSIZE][2],deck[INSTANTDEX_DECKSIZE][2]; + uint8_t persistent_pubkey33[33],pad[15],verifybuf[65536]; + +}; + +static struct bitcoin_opcode { UT_hash_handle hh; uint8_t opcode,flags,stackitems; int8_t extralen; } *OPTABLE; static char *OPCODES[0x100]; static int32_t OPCODELENS[0x100]; + +#define SIGHASH_ALL 1 +#define SIGHASH_NONE 2 +#define SIGHASH_SINGLE 3 +#define SIGHASH_ANYONECANPAY 0x80 + +#define SCRIPT_OP_NOP 0x00 +#define SCRIPT_OP_TRUE 0x51 +#define SCRIPT_OP_2 0x52 +#define SCRIPT_OP_3 0x53 +#define SCRIPT_OP_4 0x54 +#define SCRIPT_OP_IF 0x63 +#define SCRIPT_OP_ELSE 0x67 +#define SCRIPT_OP_RETURN 0x6a +#define SCRIPT_OP_DUP 0x76 +#define SCRIPT_OP_ENDIF 0x68 +#define SCRIPT_OP_DROP 0x75 +#define SCRIPT_OP_EQUALVERIFY 0x88 +#define SCRIPT_OP_SHA256 0xa8 +#define SCRIPT_OP_HASH160 0xa9 + +#define SCRIPT_OP_EQUAL 0x87 +#define SCRIPT_OP_CHECKSIG 0xac +#define SCRIPT_OP_CHECKMULTISIG 0xae +#define SCRIPT_OP_CHECKSEQUENCEVERIFY 0xb2 +#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 +#define IGUANA_OP_0 0x00 +#define IGUANA_OP_PUSHDATA1 0x4c +#define IGUANA_OP_PUSHDATA2 0x4d +#define IGUANA_OP_PUSHDATA4 0x4e +#define IGUANA_OP_1NEGATE 0x4f +#define IGUANA_OP_1 0x51 +#define IGUANA_OP_16 0x60 +#define IGUANA_OP_NOP 0x61 +#define IGUANA_OP_IF 0x63 +#define IGUANA_OP_NOTIF 0x64 +#define IGUANA_OP_ELSE 0x67 +#define IGUANA_OP_ENDIF 0x68 +#define IGUANA_OP_VERIFY 0x69 +#define IGUANA_OP_RETURN 0x6a + +#define IGUANA_OP_TOALTSTACK 0x6b +#define IGUANA_OP_FROMALTSTACK 0x6c +#define IGUANA_OP_2DROP 0x6d +#define IGUANA_OP_2DUP 0x6e +#define IGUANA_OP_3DUP 0x6f +#define IGUANA_OP_2OVER 0x70 +#define IGUANA_OP_2ROT 0x71 +#define IGUANA_OP_2SWAP 0x72 +#define IGUANA_OP_IFDUP 0x73 +#define IGUANA_OP_DEPTH 0x74 +#define IGUANA_OP_DROP 0x75 +#define IGUANA_OP_DUP 0x76 +#define IGUANA_OP_NIP 0x77 +#define IGUANA_OP_OVER 0x78 +#define IGUANA_OP_PICK 0x79 +#define IGUANA_OP_ROLL 0x7a +#define IGUANA_OP_ROT 0x7b +#define IGUANA_OP_SWAP 0x7c +#define IGUANA_OP_TUCK 0x7d + +#define IGUANA_OP_EQUAL 0x87 +#define IGUANA_OP_EQUALVERIFY 0x88 + +#define IGUANA_OP_1ADD 0x8b +#define IGUANA_OP_1SUB 0x8c +#define IGUANA_OP_NEGATE 0x8f +#define IGUANA_OP_ABS 0x90 +#define IGUANA_OP_NOT 0x91 +#define IGUANA_OP_0NOTEQUAL 0x92 +#define IGUANA_OP_ADD 0x93 +#define IGUANA_OP_SUB 0x94 + +#define IGUANA_OP_BOOLAND 0x9a +#define IGUANA_OP_BOOLOR 0x9b +#define IGUANA_OP_NUMEQUAL 0x9c +#define IGUANA_OP_NUMEQUALVERIFY 0x9d +#define IGUANA_OP_NUMNOTEQUAL 0x9e +#define IGUANA_OP_LESSTHAN 0x9f +#define IGUANA_OP_GREATERTHAN 0xa0 +#define IGUANA_OP_LESSTHANOREQUAL 0xa1 +#define IGUANA_OP_GREATERTHANOREQUAL 0xa2 +#define IGUANA_OP_MIN 0xa3 +#define IGUANA_OP_MAX 0xa4 +#define IGUANA_OP_WITHIN 0xa5 + +#define IGUANA_OP_RIPEMD160 0xa6 +#define IGUANA_OP_SHA1 0xa7 +#define IGUANA_OP_SHA256 0xa8 +#define IGUANA_OP_HASH160 0xa9 +#define IGUANA_OP_HASH256 0xaa +#define IGUANA_OP_CODESEPARATOR 0xab +#define IGUANA_OP_CHECKSIG 0xac +#define IGUANA_OP_CHECKSIGVERIFY 0xad +#define IGUANA_OP_CHECKMULTISIG 0xae +#define IGUANA_OP_CHECKMULTISIGVERIFY 0xaf + +#define IGUANA_OP_NOP1 0xb0 +#define IGUANA_OP_CHECKLOCKTIMEVERIFY 0xb1 +#define IGUANA_OP_CHECKSEQUENCEVERIFY 0xb2 +#define IGUANA_OP_NOP10 0xb9 + +#define IGUANA_OP_COMBINEPUBKEYS 0xc0 +#define IGUANA_OP_CHECKSCHNORR 0xc1 +#define IGUANA_OP_CHECKSCHNORRVERIFY 0xc2 + +// https://github.com/TierNolan/bips/blob/cpkv/bip-cprkv.mediawiki +#define IGUANA_OP_CHECKPRIVATEKEY 0xc3 +#define IGUANA_OP_CHECKPRIVATEKEYVERIFY 0xc4 + +#define IGUANA_NOPFLAG 1 +#define IGUANA_ALWAYSILLEGAL 2 +#define IGUANA_EXECUTIONILLEGAL 4 +#define IGUANA_POSTVERIFY 8 +#define IGUANA_CRYPTOFLAG 16 +#define IGUANA_MATHFLAG 32 +#define IGUANA_CONTROLFLAG 64 +#define IGUANA_STACKFLAG 128 + +enum opcodetype +{ + // push value + OP_0 = 0x00, + OP_FALSE = OP_0, + OP_PUSHDATA1 = 0x4c, + OP_PUSHDATA2 = 0x4d, + OP_PUSHDATA4 = 0x4e, + OP_1NEGATE = 0x4f, + OP_RESERVED = 0x50, + OP_1 = 0x51, + OP_TRUE=OP_1, + OP_2 = 0x52, + OP_3 = 0x53, + OP_4 = 0x54, + OP_5 = 0x55, + OP_6 = 0x56, + OP_7 = 0x57, + OP_8 = 0x58, + OP_9 = 0x59, + OP_10 = 0x5a, + OP_11 = 0x5b, + OP_12 = 0x5c, + OP_13 = 0x5d, + OP_14 = 0x5e, + OP_15 = 0x5f, + OP_16 = 0x60, + + // control + OP_NOP = 0x61, + OP_VER = 0x62, + OP_IF = 0x63, + OP_NOTIF = 0x64, + OP_VERIF = 0x65, + OP_VERNOTIF = 0x66, + OP_ELSE = 0x67, + OP_ENDIF = 0x68, + OP_VERIFY = 0x69, + OP_RETURN = 0x6a, + + // stack ops + OP_TOALTSTACK = 0x6b, + OP_FROMALTSTACK = 0x6c, + OP_2DROP = 0x6d, + OP_2DUP = 0x6e, + OP_3DUP = 0x6f, + OP_2OVER = 0x70, + OP_2ROT = 0x71, + OP_2SWAP = 0x72, + OP_IFDUP = 0x73, + OP_DEPTH = 0x74, + OP_DROP = 0x75, + OP_DUP = 0x76, + OP_NIP = 0x77, + OP_OVER = 0x78, + OP_PICK = 0x79, + OP_ROLL = 0x7a, + OP_ROT = 0x7b, + OP_SWAP = 0x7c, + OP_TUCK = 0x7d, + + // splice ops + OP_CAT = 0x7e, + OP_SUBSTR = 0x7f, + OP_LEFT = 0x80, + OP_RIGHT = 0x81, + OP_SIZE = 0x82, + + // bit logic + OP_INVERT = 0x83, + OP_AND = 0x84, + OP_OR = 0x85, + OP_XOR = 0x86, + OP_EQUAL = 0x87, + OP_EQUALVERIFY = 0x88, + OP_RESERVED1 = 0x89, + OP_RESERVED2 = 0x8a, + + // numeric + OP_1ADD = 0x8b, + OP_1SUB = 0x8c, + OP_2MUL = 0x8d, + OP_2DIV = 0x8e, + OP_NEGATE = 0x8f, + OP_ABS = 0x90, + OP_NOT = 0x91, + OP_0NOTEQUAL = 0x92, + + OP_ADD = 0x93, + OP_SUB = 0x94, + OP_MUL = 0x95, + OP_DIV = 0x96, + OP_MOD = 0x97, + OP_LSHIFT = 0x98, + OP_RSHIFT = 0x99, + + OP_BOOLAND = 0x9a, + OP_BOOLOR = 0x9b, + OP_NUMEQUAL = 0x9c, + OP_NUMEQUALVERIFY = 0x9d, + OP_NUMNOTEQUAL = 0x9e, + OP_LESSTHAN = 0x9f, + OP_GREATERTHAN = 0xa0, + OP_LESSTHANOREQUAL = 0xa1, + OP_GREATERTHANOREQUAL = 0xa2, + OP_MIN = 0xa3, + OP_MAX = 0xa4, + + OP_WITHIN = 0xa5, + + // crypto + OP_RIPEMD160 = 0xa6, + OP_SHA1 = 0xa7, + OP_SHA256 = 0xa8, + OP_HASH160 = 0xa9, + OP_HASH256 = 0xaa, + OP_CODESEPARATOR = 0xab, + OP_CHECKSIG = 0xac, + OP_CHECKSIGVERIFY = 0xad, + OP_CHECKMULTISIG = 0xae, + OP_CHECKMULTISIGVERIFY = 0xaf, + + // expansion + OP_NOP1 = 0xb0, + OP_CHECKLOCKTIMEVERIFY = 0xb1, + OP_CHECKSEQUENCEVERIFY = 0xb2, + OP_NOP4 = 0xb3, + OP_NOP5 = 0xb4, + OP_NOP6 = 0xb5, + OP_NOP7 = 0xb6, + OP_NOP8 = 0xb7, + OP_NOP9 = 0xb8, + OP_NOP10 = 0xb9, + + OP_COMBINEPUBKEYS = 0xc0, + OP_CHECKSCHNORR = 0xc1, + OP_CHECKSCHNORRVERIFY = 0xc2, + OP_CHECKPRIVATEKEY = 0xc3, + OP_CHECKPRIVATEKEYVERIFY = 0xc4, + + // template matching params + //OP_SMALLINTEGER = 0xfa, + //OP_PUBKEYS = 0xfb, + //OP_PUBKEYHASH = 0xfd, + //OP_PUBKEY = 0xfe, + + OP_INVALIDOPCODE = 0xff, +}; +void basilisk_dontforget_update(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx); +uint32_t basilisk_requestid(struct basilisk_request *rp); +uint32_t basilisk_quoteid(struct basilisk_request *rp); + +#endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f139d12ac..0c2ecb51d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -14,11 +14,13 @@ * * ******************************************************************************/ // -// LP_unspents.c +// LP_nativeDEX.c // marketmaker // #include +#include "LP_include.h" +#include "LP_network.c" #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid @@ -43,41 +45,13 @@ struct LP_utxoinfo bits256 txid,deposittxid,otherpubkey; void *swap; uint64_t satoshis,depositsatoshis; - int32_t vout,depositvout; uint32_t lasttime,errors,swappending; + uint8_t key[sizeof(bits256) + sizeof(int32_t)]; + int32_t vout,depositvout,pair; uint32_t lasttime,errors,swappending; double profitmargin; char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; uint16_t port; } *LP_utxoinfos; -char *nanomsg_tcpname(char *str,char *ipaddr,uint16_t port) -{ - sprintf(str,"tcp://%s:%u",ipaddr,port); - return(str); -} - -int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) -{ - int32_t sentbytes,len,i; struct nn_pollfd pfd; - for (i=0; i<100; i++) - { - pfd.fd = sock; - pfd.events = NN_POLLOUT; - if ( nn_poll(&pfd,1,100) > 0 ) - { - len = (int32_t)strlen(msg) + 1; - if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) - printf("LP_send sent %d instead of %d\n",sentbytes,len); - else printf("SENT.(%s)\n",msg); - if ( freeflag != 0 ) - free(msg); - return(sentbytes); - } - usleep(1000); - } - printf("error LP_send\n"); - return(-1); -} - struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) { struct LP_peerinfo *peer=0; uint64_t ip_port; @@ -88,11 +62,13 @@ struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) return(peer); } -struct LP_utxoinfo *LP_utxofind(bits256 txid) +struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) { - struct LP_utxoinfo *utxo=0; + struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; + memcpy(key,txid.bytes,sizeof(txid)); + memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); portable_mutex_lock(&LP_utxomutex); - HASH_FIND(hh,LP_utxoinfos,&txid,sizeof(txid),utxo); + HASH_FIND(hh,LP_utxoinfos,key,sizeof(key),utxo); portable_mutex_unlock(&LP_utxomutex); return(utxo); } @@ -214,13 +190,13 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char struct LP_utxoinfo *LP_addutxo(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) { - struct LP_utxoinfo *utxo = 0; + struct LP_utxoinfo *utxo = 0; uint8_t key[sizeof(txid) + sizeof(vout)]; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d %d %d %d\n", coin == 0,coin[0] == 0,spendscript == 0,spendscript[0] == 0,coinaddr == 0,coinaddr[0] == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); return(0); } - if ( (utxo= LP_utxofind(txid)) != 0 ) + if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->deposittxid) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->depositvout || depositsatoshis != utxo->depositsatoshis || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) { @@ -233,6 +209,7 @@ struct LP_utxoinfo *LP_addutxo(struct LP_peerinfo *mypeer,int32_t mypubsock,char else { utxo = calloc(1,sizeof(*utxo)); + utxo->pair = -1; utxo->profitmargin = profitmargin; strcpy(utxo->ipaddr,ipaddr); utxo->port = port; @@ -245,8 +222,11 @@ struct LP_utxoinfo *LP_addutxo(struct LP_peerinfo *mypeer,int32_t mypubsock,char utxo->deposittxid = deposittxid; utxo->depositvout = depositvout; utxo->depositsatoshis = depositsatoshis; + memcpy(key,txid.bytes,sizeof(txid)); + memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); + memcpy(utxo->key,key,sizeof(key)); portable_mutex_lock(&LP_utxomutex); - HASH_ADD(hh,LP_utxoinfos,txid,sizeof(txid),utxo); + HASH_ADD(hh,LP_utxoinfos,key,sizeof(key),utxo); if ( mypeer != 0 ) { mypeer->numutxos++; @@ -525,9 +505,50 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin return(total); } + +int32_t basilisk_istrustedbob(struct basilisk_swap *swap) +{ + // for BTC and if trusted LP + return(0); +} + +struct iguana_info KMDcoin,BTCcoin,LTCcoin; + +struct iguana_info *LP_coinfind(char *symbol) +{ + struct iguana_info *coin; + if ( strcmp(symbol,"BTC") == 0 ) + return(&BTCcoin); + else if ( strcmp(symbol,"LTC") == 0 ) + return(<Ccoin); + else //if ( strcmp(symbol,"KMD") == 0 ) + { + coin = calloc(1,sizeof(*coin)); + *coin = KMDcoin; + strcpy(coin->symbol,symbol); + return(coin); + } +} + +void tradebot_swap_balancingtrade(struct basilisk_swap *swap,int32_t iambob) +{ + +} + +void tradebot_pendingadd(cJSON *tradejson,char *base,double basevolume,char *rel,double relvolume) +{ + // add to trades +} + +char GLOBAL_DBDIR[] = "."; + +#include "LP_secp.c" +#include "LP_rpc.c" #include "LP_bitcoin.c" -#include "LP_swap.c" +#include "LP_transaction.c" #include "LP_remember.c" +#include "LP_statemachine.c" +#include "LP_swap.c" #include "LP_commands.c" void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c new file mode 100644 index 000000000..c32ded7f4 --- /dev/null +++ b/iguana/exchanges/LP_network.c @@ -0,0 +1,307 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_network.c +// marketmaker +// + +void basilisk_psockinit(struct basilisk_swap *swap,int32_t amlp) +{ +/* char keystr[64],databuf[1024],pubkeystr[128],*retstr,*retstr2,*datastr,*pushaddr=0,*subaddr=0; cJSON *retjson,*addrjson; uint8_t data[512]; int32_t datalen,timeout,pushsock = -1,subsock = -1; + if ( swap->connected == 1 ) + return; + if ( swap->pushsock < 0 && swap->subsock < 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + { + timeout = 1000; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + swap->pushsock = pushsock; + swap->subsock = subsock; + } + if ( (subsock= swap->subsock) < 0 || (pushsock= swap->pushsock) < 0 ) + { + printf("error getting nn_sockets\n"); + return; + } + sprintf(keystr,"%08x-%08x",swap->I.req.requestid,swap->I.req.quoteid); + if ( swap->connected == 0 && (retstr= _dex_kvsearch("KV",keystr)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (datastr= jstr(retjson,"value")) != 0 ) + { + datalen = (int32_t)strlen(datastr) >> 1; + decode_hex((uint8_t *)databuf,datalen,datastr); + if ( (addrjson= cJSON_Parse(databuf)) != 0 ) + { + pushaddr = jstr(addrjson,"push"); + subaddr = jstr(addrjson,"sub"); + if ( pushaddr != 0 && subaddr != 0 ) + { + printf("KV decoded (%s and %s) %d %d\n",pushaddr,subaddr,swap->pushsock,swap->subsock); + if ( nn_connect(swap->pushsock,pushaddr) >= 0 && nn_connect(swap->subsock,subaddr) >= 0 ) + swap->connected = 1; + } + free_json(addrjson); + } + } + free_json(retjson); + } + printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d) amlp.%d\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock,amlp); + free(retstr); + } + printf("connected.%d amlp.%d subsock.%d pushsock.%d\n",swap->connected,amlp,subsock,pushsock); + if ( swap->connected <= 0 && amlp != 0 && subsock >= 0 && pushsock >= 0 ) + { + if ( (retstr= _dex_psock("{}")) != 0 ) + { + printf("psock returns.(%s)\n",retstr); + // {"result":"success","pushaddr":"tcp://5.9.102.210:30002","subaddr":"tcp://5.9.102.210:30003","randipbits":3606291758,"coin":"KMD","tag":"6952562460568228137"} + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + pushaddr = jstr(retjson,"pushaddr"); + subaddr = jstr(retjson,"subaddr"); + if ( pushaddr != 0 && subaddr != 0 ) + { + if ( nn_connect(pushsock,pushaddr) >= 0 ) + { + printf("connected to %d pushaddr.(%s)\n",pushsock,pushaddr); + if ( nn_connect(subsock,subaddr) >= 0 ) + { + swap->connected = 1; + init_hexbytes_noT(pubkeystr,myinfo->persistent_pubkey33,33); + sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f],\"pub\":\"%s\"}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),pubkeystr); + datalen = (int32_t)strlen((char *)data) + 1; + printf("datalen.%d (%s)\n",datalen,(char *)data); + init_hexbytes_noT(databuf,data,datalen); + printf("%s -> %s\n",keystr,databuf); + if ( (retstr2= _dex_kvupdate("KV",keystr,databuf,1)) != 0 ) + { + printf("KVupdate.(%s)\n",retstr2); + free(retstr2); + } + } else printf("nn_connect error to %d subaddr.(%s)\n",subsock,subaddr); + } else printf("nn_connect error to %d pushaddr.(%s)\n",pushsock,pushaddr); + } + else printf("missing addr (%p) (%p) (%s)\n",pushaddr,subaddr,jprint(retjson,0)); + free_json(retjson); + } else printf("Error parsing psock.(%s)\n",retstr); + free(retstr); + } else printf("error issuing _dex_psock\n"); + }*/ +} + +char *nanomsg_tcpname(char *str,char *ipaddr,uint16_t port) +{ + sprintf(str,"tcp://%s:%u",ipaddr,port); + return(str); +} + +int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) +{ + int32_t sentbytes,len,i; struct nn_pollfd pfd; + for (i=0; i<100; i++) + { + pfd.fd = sock; + pfd.events = NN_POLLOUT; + if ( nn_poll(&pfd,1,100) > 0 ) + { + len = (int32_t)strlen(msg) + 1; + if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) + printf("LP_send sent %d instead of %d\n",sentbytes,len); + else printf("SENT.(%s)\n",msg); + if ( freeflag != 0 ) + free(msg); + return(sentbytes); + } + usleep(1000); + } + printf("error LP_send\n"); + return(-1); +} + +uint32_t LP_swapsend(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits,uint32_t crcs[2]) +{ + uint8_t *buf; int32_t sentbytes,offset=0,i; + buf = malloc(datalen + sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2); + for (i=0; i<32; i++) + buf[offset++] = swap->I.myhash.bytes[i]; + for (i=0; i<32; i++) + buf[offset++] = swap->I.otherhash.bytes[i]; + offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); + offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); + if ( datalen > 0 ) + memcpy(&buf[offset],data,datalen), offset += datalen; + if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) + { + printf("sentbytes.%d vs offset.%d\n",sentbytes,offset); + if ( sentbytes < 0 ) + { + if ( swap->pushsock >= 0 ) + nn_close(swap->pushsock), swap->pushsock = -1; //, + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = swap->I.iambob != 0 ? -1 : 0; + swap->aborted = (uint32_t)time(NULL); + } + } + //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); + free(buf); + return(nextbits); +} + +void basilisk_swap_sendabort(struct basilisk_swap *swap) +{ + uint32_t msgbits = 0; uint8_t buf[sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2]; int32_t sentbytes,offset=0; + memset(buf,0,sizeof(buf)); + offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); + offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); + if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) + { + if ( sentbytes < 0 ) + { + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; + } + } else printf("basilisk_swap_sendabort\n"); +} + +void basilisk_psockinit(struct basilisk_swap *swap,int32_t amlp); + +void basilisk_swapgotdata(struct basilisk_swap *swap,uint32_t crc32,bits256 srchash,bits256 desthash,uint32_t quoteid,uint32_t msgbits,uint8_t *data,int32_t datalen,int32_t reinit) +{ + int32_t i; struct basilisk_swapmessage *mp; + for (i=0; inummessages; i++) + if ( crc32 == swap->messages[i].crc32 && msgbits == swap->messages[i].msgbits && bits256_cmp(srchash,swap->messages[i].srchash) == 0 && bits256_cmp(desthash,swap->messages[i].desthash) == 0 ) + return; + //printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); + swap->messages = realloc(swap->messages,sizeof(*swap->messages) * (swap->nummessages + 1)); + mp = &swap->messages[swap->nummessages++]; + mp->crc32 = crc32; + mp->srchash = srchash; + mp->desthash = desthash; + mp->msgbits = msgbits; + mp->quoteid = quoteid; + mp->data = malloc(datalen); + mp->datalen = datalen; + memcpy(mp->data,data,datalen); + if ( reinit == 0 && swap->fp != 0 ) + { + fwrite(mp,1,sizeof(*mp),swap->fp); + fwrite(data,1,datalen,swap->fp); + fflush(swap->fp); + } +} + +int32_t basilisk_swapget(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(void *ptr,uint8_t *data,int32_t datalen)) +{ + uint8_t *ptr; bits256 srchash,desthash; uint32_t crc32,_msgbits,quoteid; int32_t i,size,offset,retval = -1; struct basilisk_swapmessage *mp = 0; + while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,0)) >= 0 ) + { + swap->lasttime = (uint32_t)time(NULL); + memset(srchash.bytes,0,sizeof(srchash)); + memset(desthash.bytes,0,sizeof(desthash)); + //printf("gotmsg.[%d] crc.%x\n",size,crc32); + offset = 0; + for (i=0; i<32; i++) + srchash.bytes[i] = ptr[offset++]; + for (i=0; i<32; i++) + desthash.bytes[i] = ptr[offset++]; + offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),"eid); + offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),&_msgbits); + if ( size > offset ) + { + crc32 = calc_crc32(0,&ptr[offset],size-offset); + if ( size > offset ) + { + //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); + basilisk_swapgotdata(swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); + } + } + else if ( bits256_nonz(srchash) == 0 && bits256_nonz(desthash) == 0 ) + { + if ( swap->aborted == 0 ) + { + swap->aborted = (uint32_t)time(NULL); + printf("got abort signal from other side\n"); + } + } else printf("basilisk_swapget: got strange packet\n"); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } + //char str[65],str2[65]; + for (i=0; inummessages; i++) + { + //printf("%d: %s vs %s\n",i,bits256_str(str,swap->messages[i].srchash),bits256_str(str2,swap->messages[i].desthash)); + if ( bits256_cmp(swap->messages[i].desthash,swap->I.myhash) == 0 ) + { + if ( swap->messages[i].msgbits == msgbits ) + { + if ( swap->I.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) + { + printf("nothing received for a while from Bob, try new sockets\n"); + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; + basilisk_psockinit(swap,swap->I.iambob != 0); + } + mp = &swap->messages[i]; + if ( msgbits != 0x80000000 ) + break; + } + } + } + if ( mp != 0 ) + retval = (*basilisk_verify_func)(swap,mp->data,mp->datalen); + //printf("mine/other %s vs %s\n",bits256_str(str,swap->I.myhash),bits256_str(str2,swap->I.otherhash)); + return(retval); +} + +int32_t basilisk_messagekeyread(uint8_t *key,uint32_t *channelp,uint32_t *msgidp,bits256 *srchashp,bits256 *desthashp) +{ + int32_t keylen = 0; + keylen += iguana_rwnum(0,&key[keylen],sizeof(uint32_t),channelp); + keylen += iguana_rwnum(0,&key[keylen],sizeof(uint32_t),msgidp); + keylen += iguana_rwbignum(0,&key[keylen],sizeof(*srchashp),srchashp->bytes); + keylen += iguana_rwbignum(0,&key[keylen],sizeof(*desthashp),desthashp->bytes); + return(keylen); +} + +int32_t basilisk_messagekey(uint8_t *key,uint32_t channel,uint32_t msgid,bits256 srchash,bits256 desthash) +{ + int32_t keylen = 0; + keylen += iguana_rwnum(1,&key[keylen],sizeof(uint32_t),&channel); + keylen += iguana_rwnum(1,&key[keylen],sizeof(uint32_t),&msgid); + keylen += iguana_rwbignum(1,&key[keylen],sizeof(srchash),srchash.bytes); + keylen += iguana_rwbignum(1,&key[keylen],sizeof(desthash),desthash.bytes); + return(keylen); +} + +void LP_channelsend(bits256 srchash,bits256 desthash,uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen) +{ + int32_t keylen; uint8_t key[BASILISK_KEYSIZE]; //char *retstr; + keylen = basilisk_messagekey(key,channel,msgid,srchash,desthash); + //if ( (retstr= _dex_reqsend(myinfo,"DEX",key,keylen,data,datalen)) != 0 ) + // free(retstr); +} + diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 22ec7d53a..547f8ab9c 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -18,439 +18,341 @@ // marketmaker // - -cJSON *basilisk_nullretjson(cJSON *retjson) -{ - char *outstr; - if ( retjson != 0 ) - { - outstr = jprint(retjson,0); - if ( strcmp(outstr,"{}") == 0 ) - { - free_json(retjson); - retjson = 0; - } - free(outstr); - } - return(retjson); -} - -cJSON *basilisk_swapgettxout(struct supernet_info *myinfo,char *symbol,bits256 trigger,int32_t vout) +/*void basilisk_swaps_init(struct supernet_info *myinfo) { - char *retstr; cJSON *retjson=0; struct iguana_info *coin; - if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + char fname[512]; uint32_t iter,swapcompleted,requestid,quoteid,optionduration,statebits; FILE *fp; bits256 privkey;struct basilisk_request R; struct basilisk_swapmessage M; struct basilisk_swap *swap = 0; + sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); + if ( (myinfo->swapsfp= fopen(fname,"rb+")) != 0 ) { - if ( (retstr= dex_gettxout(myinfo,0,0,0,trigger,symbol,vout)) != 0 ) + while ( fread(&requestid,1,sizeof(requestid),myinfo->swapsfp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),myinfo->swapsfp) == sizeof(quoteid) ) { - //printf("dexgettxout.(%s)\n",retstr); - retjson = cJSON_Parse(retstr); - free(retstr); + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + printf("%s\n",fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) // check to see if completed + { + memset(&M,0,sizeof(M)); + swapcompleted = 1; + for (iter=0; iter<2; iter++) + { + if ( fread(privkey.bytes,1,sizeof(privkey),fp) == sizeof(privkey) && + fread(&R,1,sizeof(R),fp) == sizeof(R) && + fread(&statebits,1,sizeof(statebits),fp) == sizeof(statebits) && + fread(&optionduration,1,sizeof(optionduration),fp) == sizeof(optionduration) ) + { + while ( 0 && fread(&M,1,sizeof(M),fp) == sizeof(M) ) + { + M.data = 0; + //printf("entry iter.%d crc32.%x datalen.%d\n",iter,M.crc32,M.datalen); + if ( M.datalen < 100000 ) + { + M.data = malloc(M.datalen); + if ( fread(M.data,1,M.datalen,fp) == M.datalen ) + { + if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) + { + if ( iter == 1 ) + { + if ( swap == 0 ) + { + swap = basilisk_thread_start(privkey,&R,statebits,optionduration,1); + swap->I.choosei = swap->I.otherchoosei = -1; + } + if ( swap != 0 ) + basilisk_swapgotdata(swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); + } + } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); + } else printf("error reading M.datalen %d\n",M.datalen); + free(M.data), M.data = 0; + } + } + } + if ( swapcompleted != 0 ) + break; + rewind(fp); + } + } } - if ( 0 && strcmp("BTC",symbol) == 0 ) - printf("%s gettxout.(%s)\n",symbol,jprint(retjson,0)); - } - else - { - retjson = dpow_gettxout(myinfo,coin,trigger,vout); - //printf("need to verify passthru has this info\n"); - //printf("dpowgettxout.(%s)\n",jprint(retjson,0)); - } - return(basilisk_nullretjson(retjson)); -} + } else myinfo->swapsfp = fopen(fname,"wb+"); +}*/ -cJSON *basilisk_swapgettx(struct supernet_info *myinfo,char *symbol,bits256 txid) +FILE *basilisk_swap_save(struct basilisk_swap *swap,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { - char *retstr; cJSON *retjson=0; struct iguana_info *coin; - if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) - { - if ( (retstr= dex_gettransaction(myinfo,0,0,0,txid,symbol)) != 0 ) - { - retjson = cJSON_Parse(retstr); - free(retstr); - } - //if ( strcmp("BTC",symbol) == 0 ) - // printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); - } else retjson = dpow_gettransaction(myinfo,coin,txid); - return(basilisk_nullretjson(retjson)); + FILE *fp=0; /*char fname[512]; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,rp->requestid,rp->quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) == 0 ) + { + if ( (fp= fopen(fname,"wb+")) != 0 ) + { + fwrite(privkey.bytes,1,sizeof(privkey),fp); + fwrite(rp,1,sizeof(*rp),fp); + fwrite(&statebits,1,sizeof(statebits),fp); + fwrite(&optionduration,1,sizeof(optionduration),fp); + fflush(fp); + } + } + else if ( reinit != 0 ) + { + }*/ + return(fp); } -int32_t basilisk_swap_txdestaddr(char *destaddr,bits256 txid,int32_t vout,cJSON *txobj) +int32_t basilisk_swap_load(uint32_t requestid,uint32_t quoteid,bits256 *privkeyp,struct basilisk_request *rp,uint32_t *statebitsp,int32_t *optiondurationp) { - int32_t n,m,retval = -1; cJSON *vouts,*item,*addresses,*skey; char *addr; - if ( (vouts= jarray(&n,txobj,"vout")) != 0 && vout < n ) + FILE *fp=0; char fname[512]; int32_t retval = -1; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) { - item = jitem(vouts,vout); - if ( (skey= jobj(item,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) - { - item = jitem(addresses,0); - if ( (addr= jstr(item,0)) != 0 ) - { - safecopy(destaddr,addr,64); - retval = 0; - } - //printf("item.(%s) -> dest.(%s)\n",jprint(item,0),destaddr); - } + if ( fread(privkeyp,1,sizeof(*privkeyp),fp) == sizeof(*privkeyp) && + fread(rp,1,sizeof(*rp),fp) == sizeof(*rp) && + fread(statebitsp,1,sizeof(*statebitsp),fp) == sizeof(*statebitsp) && + fread(optiondurationp,1,sizeof(*optiondurationp),fp) == sizeof(*optiondurationp) ) + retval = 0; + fclose(fp); } return(retval); } -int32_t basilisk_swap_getcoinaddr(struct supernet_info *myinfo,char *symbol,char *coinaddr,bits256 txid,int32_t vout) +void basilisk_swap_saveupdate(struct basilisk_swap *swap) { - cJSON *retjson; - coinaddr[0] = 0; - if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + FILE *fp; char fname[512]; + sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) { - basilisk_swap_txdestaddr(coinaddr,txid,vout,retjson); - free_json(retjson); + fwrite(&swap->I,1,sizeof(swap->I),fp); + /*fwrite(&swap->bobdeposit,1,sizeof(swap->bobdeposit),fp); + fwrite(&swap->bobpayment,1,sizeof(swap->bobpayment),fp); + fwrite(&swap->alicepayment,1,sizeof(swap->alicepayment),fp); + fwrite(&swap->myfee,1,sizeof(swap->myfee),fp); + fwrite(&swap->otherfee,1,sizeof(swap->otherfee),fp); + fwrite(&swap->aliceclaim,1,sizeof(swap->aliceclaim),fp); + fwrite(&swap->alicespend,1,sizeof(swap->alicespend),fp); + fwrite(&swap->bobreclaim,1,sizeof(swap->bobreclaim),fp); + fwrite(&swap->bobspend,1,sizeof(swap->bobspend),fp); + fwrite(&swap->bobrefund,1,sizeof(swap->bobrefund),fp); + fwrite(&swap->alicereclaim,1,sizeof(swap->alicereclaim),fp);*/ + fwrite(swap->privkeys,1,sizeof(swap->privkeys),fp); + fwrite(swap->otherdeck,1,sizeof(swap->otherdeck),fp); + fwrite(swap->deck,1,sizeof(swap->deck),fp); + fclose(fp); } - return(coinaddr[0] != 0); } -int32_t basilisk_swap_getsigscript(struct supernet_info *myinfo,char *symbol,uint8_t *script,int32_t maxlen,bits256 txid,int32_t vini) +/*int32_t basilisk_swap_loadtx(struct basilisk_rawtx *rawtx,FILE *fp,char *bobcoinstr,char *alicecoinstr) { - cJSON *retjson,*vins,*item,*skey; int32_t n,scriptlen = 0; char *hexstr; - if ( (retjson= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + if ( fread(rawtx,1,sizeof(*rawtx),fp) == sizeof(*rawtx) ) { - if ( (vins= jarray(&n,retjson,"vin")) != 0 && vini < n ) + rawtx->coin = 0; + rawtx->vins = 0; + if ( strcmp(rawtx->I.coinstr,bobcoinstr) == 0 || strcmp(rawtx->I.coinstr,alicecoinstr) == 0 ) { - item = jitem(vins,vini); - if ( (skey= jobj(item,"scriptSig")) != 0 && (hexstr= jstr(skey,"hex")) != 0 && (scriptlen= (int32_t)strlen(hexstr)) < maxlen*2 ) - { - scriptlen >>= 1; - decode_hex(script,scriptlen,hexstr); - //char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); - } + rawtx->coin = LP_coinfind(rawtx->I.coinstr); + if ( rawtx->vinstr[0] != 0 ) + rawtx->vins = cJSON_Parse(rawtx->vinstr); + printf("loaded.%s len.%d\n",rawtx->name,rawtx->I.datalen); + return(0); } - free_json(retjson); } - return(scriptlen); -} + return(-1); +}*/ -int64_t basilisk_txvalue(struct supernet_info *myinfo,char *symbol,bits256 txid,int32_t vout) +void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,int32_t scriptlen) { - cJSON *txobj,*vouts,*item; int32_t n; int64_t value = 0; - //char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid)); - if ( (txobj= basilisk_swapgettx(myinfo,symbol,txid)) != 0 ) + int32_t i; char scriptstr[513]; + if ( scriptlen != 0 ) { - //printf("txobj.(%s)\n",jprint(txobj,0)); - if ( (vouts= jarray(&n,txobj,"vout")) != 0 ) - { - item = jitem(vouts,vout); - if ( (value= jdouble(item,"amount") * SATOSHIDEN) == 0 ) - value = jdouble(item,"value") * SATOSHIDEN; - } - free_json(txobj); + for (i=0; iI.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); + coinaddr[0] = secretAmstr[0] = secretAm256str[0] = secretBnstr[0] = secretBn256str[0] = 0; + memset(zeroes,0,sizeof(zeroes)); + if ( rawtx != 0 && (fp= fopen(fname,"wb")) != 0 ) { - if ( (array= cJSON_Parse(retstr)) != 0 ) + fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); + if ( rawtx->I.datalen > 0 ) { - if ( (n= cJSON_GetArraySize(array)) > 0 ) + fprintf(fp,",\"tx\":\""); + for (i=0; iI.datalen; i++) + fprintf(fp,"%02x",rawtx->txbytes[i]); + fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); + if ( rawtx == &swap->bobdeposit || rawtx == &swap->bobpayment ) { - for (i=0; ibobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); + if ( coinaddr[0] != 0 ) { - if ( (item= jitem(array,i)) == 0 ) - continue; - txid = jbits256(item,"txid"); - if ( bits256_nonz(txid) == 0 ) - { - if ( (array2= jarray(&m,item,"inputs")) != 0 && m == 1 ) - { - //printf("found inputs with %s\n",bits256_str(str,spendtxid)); - txid = jbits256(jitem(array2,0),"output_hash"); - if ( bits256_cmp(txid,utxotxid) == 0 ) - { - //printf("matched %s\n",bits256_str(str,txid)); - if ( (array2= jarray(&m,item,"outputs")) != 0 && m == 1 && (addr= jstr(jitem(array2,0),"address")) != 0 ) - { - spendtxid = jbits256(item,"hash"); - strcpy(destaddr,addr); - //printf("set spend addr.(%s) <- %s\n",addr,jprint(item,0)); - break; - } - } - } - } - else if ( bits256_cmp(txid,utxotxid) == 0 ) - { - spendtxid = jbits256(item,"spendtxid"); - if ( bits256_nonz(spendtxid) != 0 ) - { - basilisk_swap_getcoinaddr(myinfo,symbol,destaddr,spendtxid,0); - //char str[65]; printf("found spendtxid.(%s) -> %s\n",bits256_str(str,spendtxid),destaddr); - break; - } - } + if ( (tmp= LP_importaddress(swap->bobcoin.symbol,coinaddr)) != 0 ) + free(tmp); + if ( rawtx == &swap->bobdeposit ) + safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); + else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); } } - free_json(array); } - free(retstr); - } - return(spendtxid); -} - -bits256 basilisk_swap_spendtxid(struct supernet_info *myinfo,char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) -{ - bits256 spendtxid,txid; char *catstr,*addr; cJSON *array,*item,*item2,*txobj,*vins; int32_t i,n,m; char coinaddr[64],str[65]; struct iguana_info *coin = iguana_coinfind(symbol); - // listtransactions or listspents - destaddr[0] = 0; - coinaddr[0] = 0; - memset(&spendtxid,0,sizeof(spendtxid)); - //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); - if ( (coin == 0 || coin->FULLNODE >= 0) && iguana_isnotarychain(symbol) >= 0 ) - { - //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] - basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); - if ( coinaddr[0] != 0 ) - spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); + if ( swap->Bdeposit[0] != 0 ) + fprintf(fp,",\"%s\":\"%s\"","Bdeposit",swap->Bdeposit); + if ( swap->Bpayment[0] != 0 ) + fprintf(fp,",\"%s\":\"%s\"","Bpayment",swap->Bpayment); + fprintf(fp,",\"expiration\":%u",swap->I.expiration); + fprintf(fp,",\"iambob\":%d",swap->I.iambob); + fprintf(fp,",\"bobcoin\":\"%s\"",swap->bobcoin.symbol); + fprintf(fp,",\"alicecoin\":\"%s\"",swap->alicecoin.symbol); + fprintf(fp,",\"lock\":%u",locktime); + fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); + if ( bits256_nonz(triggertxid) != 0 ) + fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); + if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) + { + basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin.p2shtype,swap->I.pubAm,swap->I.pubBn); + if ( (tmp= LP_importaddress(swap->alicecoin.symbol,coinaddr)) != 0 ) + free(tmp); + fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); + } + /*basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); + basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); + basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); + basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); + basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); + basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen);*/ + fprintf(fp,"}\n"); + fclose(fp); } - else if ( coin != 0 ) + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) { - if ( (array= dpow_listtransactions(myinfo,coin,destaddr,1000,0)) != 0 ) + fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%u,\"otherstate\":%u,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); + if ( memcmp(zeroes,swap->I.secretAm,20) != 0 ) { - if ( (n= cJSON_GetArraySize(array)) > 0 ) - { - for (i=0; iI.secretAm,20); + fprintf(fp,",\"secretAm\":\"%s\"",secretAmstr); } - if ( destaddr[0] != 0 ) + if ( memcmp(zeroes,swap->I.secretAm256,32) != 0 ) { - if ( (array= dpow_listtransactions(myinfo,coin,destaddr,1000,0)) != 0 ) - { - if ( (n= cJSON_GetArraySize(array)) > 0 ) - { - for (i=0; i jint(item,"vout") ) - { - item2 = jitem(vins,jint(item,"vout")); - if ( bits256_cmp(utxotxid,jbits256(item2,"txid")) == 0 && vout == jint(item2,"vout") ) - { - spendtxid = txid; - break; - } - } - } - } - } - if ( i == n ) - printf("dpowlist: native couldnt find spendtxid for %s\n",bits256_str(str,utxotxid)); - } - free_json(array); - } - if ( bits256_nonz(spendtxid) != 0 ) - return(spendtxid); + init_hexbytes_noT(secretAm256str,swap->I.secretAm256,32); + fprintf(fp,",\"secretAm256\":\"%s\"",secretAm256str); } - if ( iguana_isnotarychain(symbol) >= 0 ) + if ( memcmp(zeroes,swap->I.secretBn,20) != 0 ) { - basilisk_swap_getcoinaddr(myinfo,symbol,coinaddr,utxotxid,vout); - printf("fallback use DEX for native (%s) (%s)\n",coinaddr,bits256_str(str,utxotxid)); - if ( coinaddr[0] != 0 ) - { - spendtxid = dex_swap_spendtxid(myinfo,symbol,destaddr,coinaddr,utxotxid,vout); - printf("spendtxid.(%s)\n",bits256_str(str,spendtxid)); - } + init_hexbytes_noT(secretBnstr,swap->I.secretBn,20); + fprintf(fp,",\"secretBn\":\"%s\"",secretBnstr); } - } - return(spendtxid); -} - -bits256 basilisk_swap_sendrawtransaction(struct supernet_info *myinfo,char *txname,char *symbol,char *txbytes) -{ - char *retstr; bits256 txid; int32_t i,sentflag = 0; - memset(&txid,0,sizeof(txid)); - for (i=0; i<3; i++) - { - if ( (retstr= _dex_sendrawtransaction(myinfo,symbol,txbytes)) != 0 ) + if ( memcmp(zeroes,swap->I.secretBn256,32) != 0 ) { - if ( is_hexstr(retstr,0) == 64 ) - { - decode_hex(txid.bytes,32,retstr); - sentflag = 1; - } - char str[65]; printf("[%s] %s RETSTR.(%s) %s.%s\n",txname,txbytes,retstr,symbol,bits256_str(str,txid)); - free(retstr); + init_hexbytes_noT(secretBn256str,swap->I.secretBn256,32); + fprintf(fp,",\"secretBn256\":\"%s\"",secretBn256str); } - if ( sentflag != 0 ) - break; + for (i=0; i<2; i++) + if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) + fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); + if ( bits256_nonz(swap->I.privAm) != 0 ) + fprintf(fp,",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); + if ( bits256_nonz(swap->I.privBn) != 0 ) + fprintf(fp,",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); + if ( bits256_nonz(swap->I.pubA0) != 0 ) + fprintf(fp,",\"pubA0\":\"%s\"",bits256_str(str,swap->I.pubA0)); + if ( bits256_nonz(swap->I.pubB0) != 0 ) + fprintf(fp,",\"pubB0\":\"%s\"",bits256_str(str,swap->I.pubB0)); + if ( bits256_nonz(swap->I.pubB1) != 0 ) + fprintf(fp,",\"pubB1\":\"%s\"",bits256_str(str,swap->I.pubB1)); + if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + fprintf(fp,",\"Bdeposit\":\"%s\"",bits256_str(str,swap->bobdeposit.I.actualtxid)); + if ( bits256_nonz(swap->bobrefund.I.actualtxid) != 0 ) + fprintf(fp,",\"Brefund\":\"%s\"",bits256_str(str,swap->bobrefund.I.actualtxid)); + if ( bits256_nonz(swap->aliceclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Aclaim\":\"%s\"",bits256_str(str,swap->aliceclaim.I.actualtxid)); + + if ( bits256_nonz(swap->bobpayment.I.actualtxid) != 0 ) + fprintf(fp,",\"Bpayment\":\"%s\"",bits256_str(str,swap->bobpayment.I.actualtxid)); + if ( bits256_nonz(swap->alicespend.I.actualtxid) != 0 ) + fprintf(fp,",\"Aspend\":\"%s\"",bits256_str(str,swap->alicespend.I.actualtxid)); + if ( bits256_nonz(swap->bobreclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Breclaim\":\"%s\"",bits256_str(str,swap->bobreclaim.I.actualtxid)); + + if ( bits256_nonz(swap->alicepayment.I.actualtxid) != 0 ) + fprintf(fp,",\"Apayment\":\"%s\"",bits256_str(str,swap->alicepayment.I.actualtxid)); + if ( bits256_nonz(swap->bobspend.I.actualtxid) != 0 ) + fprintf(fp,",\"Bspend\":\"%s\"",bits256_str(str,swap->bobspend.I.actualtxid)); + if ( bits256_nonz(swap->alicereclaim.I.actualtxid) != 0 ) + fprintf(fp,",\"Areclaim\":\"%s\"",bits256_str(str,swap->alicereclaim.I.actualtxid)); + + if ( bits256_nonz(swap->otherfee.I.actualtxid) != 0 ) + fprintf(fp,",\"otherfee\":\"%s\"",bits256_str(str,swap->otherfee.I.actualtxid)); + if ( bits256_nonz(swap->myfee.I.actualtxid) != 0 ) + fprintf(fp,",\"myfee\":\"%s\"",bits256_str(str,swap->myfee.I.actualtxid)); + fprintf(fp,",\"dest33\":\""); + for (i=0; i<33; i++) + fprintf(fp,"%02x",swap->persistent_pubkey33[i]); + fprintf(fp,"\"}\n"); + fclose(fp); } - return(txid); } -char *basilisk_swap_bobtxspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp) +void basilisk_dontforget_update(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t height,completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; struct iguana_info *coin; bits256 txid,signedtxid; uint64_t destamount; - *destamountp = 0; - if ( finalseqid == 0 ) - locktime = expiration; - //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); - if ( redeemlen < 0 || (coin= iguana_coinfind(symbol)) == 0 ) - return(0); - if ( (utxoobj= basilisk_swapgettxout(myinfo,symbol,utxotxid,vout)) == 0 ) + bits256 triggertxid; + memset(triggertxid.bytes,0,sizeof(triggertxid)); + if ( rawtx == 0 ) { - printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); - return(0); + basilisk_dontforget(swap,0,0,triggertxid); + return; } - if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + if ( rawtx == &swap->myfee ) + basilisk_dontforget(swap,&swap->myfee,0,triggertxid); + else if ( rawtx == &swap->otherfee ) + basilisk_dontforget(swap,&swap->otherfee,0,triggertxid); + else if ( rawtx == &swap->bobdeposit ) { - printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); - free_json(utxoobj); - return(0); - } else free_json(utxoobj); - *destamountp = destamount; - if ( destamount > 10000 ) - destamount -= 10000; - if ( strcmp(symbol,"BTC") == 0 ) + basilisk_dontforget(swap,&swap->bobdeposit,0,triggertxid); + basilisk_dontforget(swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + } + else if ( rawtx == &swap->bobrefund ) + basilisk_dontforget(swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); + else if ( rawtx == &swap->aliceclaim ) { - if ( destamount > 40000 ) - destamount -= 40000; + basilisk_dontforget(swap,&swap->bobrefund,0,triggertxid); + basilisk_dontforget(swap,&swap->aliceclaim,0,swap->bobrefund.I.actualtxid); } - height = coin->longestchain; - timestamp = (uint32_t)time(NULL); - V = calloc(256,sizeof(*V)); - privkeys = cJSON_CreateArray(); - if ( privkey2p != 0 ) + else if ( rawtx == &swap->alicepayment ) { - V[0].signers[1].privkey = *privkey2p; - bitcoin_pubkey33(myinfo->ctx,V[0].signers[1].pubkey,*privkey2p); - bitcoin_priv2wif(wifstr,*privkey2p,coin->chain->wiftype); - jaddistr(privkeys,wifstr); - V[0].N = V[0].M = 2; - } else V[0].N = V[0].M = 1; - V[0].signers[0].privkey = privkey; - bitcoin_pubkey33(myinfo->ctx,V[0].signers[0].pubkey,privkey); - bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); - jaddistr(privkeys,wifstr); - V[0].suppress_pubkeys = suppress_pubkeys; - V[0].ignore_cltverr = ignore_cltverr; - if ( redeemlen != 0 ) - memcpy(V[0].p2shscript,redeemscript,redeemlen), V[0].p2shlen = redeemlen; - txobj = bitcoin_txcreate(coin->symbol,coin->chain->isPoS,locktime,1,timestamp); - vins = cJSON_CreateArray(); - item = cJSON_CreateObject(); - if ( userdata != 0 && userdatalen > 0 ) + basilisk_dontforget(swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + } + else if ( rawtx == &swap->bobspend ) { - memcpy(V[0].userdata,userdata,userdatalen); - V[0].userdatalen = userdatalen; - init_hexbytes_noT(hexstr,userdata,userdatalen); - jaddstr(item,"userdata",hexstr); + basilisk_dontforget(swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); } - jaddbits256(item,"txid",utxotxid); - jaddnum(item,"vout",vout); - sobj = cJSON_CreateObject(); - bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); - bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); - /*int32_t i; - for (i=0; i<33; i++) - printf("%02x",pubkey33[i]); - printf(" pubkey33 ->\n"); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" destaddr.(%s)\n",destaddr); - calc_rmd160_sha256(rmd160,pubkey33,33); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" <- vs direct calc\n");*/ - spendlen = bitcoin_standardspend(spendscript,0,rmd160); - init_hexbytes_noT(hexstr,spendscript,spendlen); - jaddstr(sobj,"hex",hexstr); - jadd(item,"scriptPubKey",sobj); - jaddnum(item,"suppress",suppress_pubkeys); - jaddnum(item,"sequence",sequenceid); - if ( redeemlen != 0 ) + else if ( rawtx == &swap->alicereclaim ) { - init_hexbytes_noT(hexstr,redeemscript,redeemlen); - jaddstr(item,"redeemScript",hexstr); + basilisk_dontforget(swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); + basilisk_dontforget(swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); } - jaddi(vins,item); - jdelete(txobj,"vin"); - jadd(txobj,"vin",vins); - txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); - if ( (rawtxbytes= bitcoin_json2hex(myinfo,coin,&txid,txobj,V)) != 0 ) + else if ( rawtx == &swap->bobpayment ) { - //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); - if ( (signedtx= iguana_signrawtx(myinfo,coin,height,&signedtxid,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) - printf("couldnt sign transaction\n"); - else if ( completed == 0 ) - printf("incomplete signing\n"); - else printf("%s -> %s\n",name,bits256_str(str,signedtxid)); - free(rawtxbytes); - } else printf("error making rawtx\n"); - free_json(privkeys); - free_json(txobj); - free(V); - return(signedtx); -} - -char *basilisk_swap_Aspend(char *name,struct supernet_info *myinfo,char *symbol,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp) -{ - char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn; struct iguana_info *coin = iguana_coinfind(symbol); - if ( coin != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + basilisk_dontforget(swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); + } + else if ( rawtx == &swap->alicespend ) { - pubAm = bitcoin_pubkey33(myinfo->ctx,tmp33,privAm); - pubBn = bitcoin_pubkey33(myinfo->ctx,tmp33,privBn); - //char str[65]; - //printf("pubAm.(%s)\n",bits256_str(str,pubAm)); - //printf("pubBn.(%s)\n",bits256_str(str,pubBn)); - spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,coin->chain->p2shtype,pubAm,pubBn); - //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); - /*rev = privAm; - for (i=0; i<32; i++) - privAm.bytes[i] = rev.bytes[31 - i]; - rev = privBn; - for (i=0; i<32; i++) - privBn.bytes[i] = rev.bytes[31 - i];*/ - signedtx = basilisk_swap_bobtxspend(name,myinfo,symbol,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration,destamountp); + basilisk_dontforget(swap,&swap->bobpayment,0,triggertxid); + basilisk_dontforget(swap,&swap->alicespend,0,triggertxid); } - return(signedtx); + else if ( rawtx == &swap->bobreclaim ) + basilisk_dontforget(swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); } -bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol,bits256 spendtxid,int32_t vini,int32_t revflag) + + +bits256 basilisk_swap_privbob_extract(char *symbol,bits256 spendtxid,int32_t vini,int32_t revflag) { bits256 privkey; int32_t i,scriptlen,siglen; uint8_t script[1024]; // from Bob refund of Bob deposit memset(&privkey,0,sizeof(privkey)); - if ( (scriptlen= basilisk_swap_getsigscript(myinfo,symbol,script,(int32_t)sizeof(script),spendtxid,vini)) > 0 ) + if ( (scriptlen= basilisk_swap_getsigscript(symbol,script,(int32_t)sizeof(script),spendtxid,vini)) > 0 ) { siglen = script[0]; for (i=0; i<32; i++) @@ -464,20 +366,20 @@ bits256 basilisk_swap_privbob_extract(struct supernet_info *myinfo,char *symbol, return(privkey); } -bits256 basilisk_swap_privBn_extract(struct supernet_info *myinfo,bits256 *bobrefundp,char *bobcoin,bits256 bobdeposit,bits256 privBn) +bits256 basilisk_swap_privBn_extract(bits256 *bobrefundp,char *bobcoin,bits256 bobdeposit,bits256 privBn) { char destaddr[64]; if ( bits256_nonz(privBn) == 0 ) { if ( bits256_nonz(bobdeposit) != 0 ) - *bobrefundp = basilisk_swap_spendtxid(myinfo,bobcoin,destaddr,bobdeposit,0); + *bobrefundp = LP_swap_spendtxid(bobcoin,destaddr,bobdeposit,0); if ( bits256_nonz(*bobrefundp) != 0 ) - privBn = basilisk_swap_privbob_extract(myinfo,bobcoin,*bobrefundp,0,0); + privBn = basilisk_swap_privbob_extract(bobcoin,*bobrefundp,0,0); } return(privBn); } -bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int32_t *sentflags,bits256 *txids,int32_t utxoind,int32_t alicespent,int32_t bobspent,int32_t vout,char *aliceaddr,char *bobaddr) +bits256 basilisk_swap_spendupdate(char *symbol,int32_t *sentflags,bits256 *txids,int32_t utxoind,int32_t alicespent,int32_t bobspent,int32_t vout,char *aliceaddr,char *bobaddr) { bits256 spendtxid,txid; char destaddr[64]; txid = txids[utxoind]; @@ -489,7 +391,7 @@ bits256 basilisk_swap_spendupdate(struct supernet_info *myinfo,char *symbol,int3 if ( bits256_nonz(txid) != 0 ) { //char str[65]; - spendtxid = basilisk_swap_spendtxid(myinfo,symbol,destaddr,txid,vout); + spendtxid = LP_swap_spendtxid(symbol,destaddr,txid,vout); if ( bits256_nonz(spendtxid) != 0 ) { sentflags[utxoind] = 1; @@ -598,9 +500,12 @@ int32_t basilisk_swap_isfinished(int32_t iambob,bits256 *txids,int32_t *sentflag return(0); } -cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) +cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { - FILE *fp; struct iguana_info *coin; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,n,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[1024],userdata[1024]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*txname,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; + static void *ctx; + FILE *fp; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,n,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[1024],userdata[1024]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*txname,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)],signedtxid; struct iguana_info *bob=0,*alice=0; uint64_t txfee = 10000; + if ( ctx == 0 ) + ctx = bitcoin_ctx(); memset(values,0,sizeof(values)); memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); @@ -753,7 +658,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t safecopy(alicecoin,symbol,sizeof(alicecoin)); if ( finishedflag == 0 ) { - if ( (sentobj= basilisk_swapgettx(myinfo,symbol,txid)) == 0 ) + if ( (sentobj= LP_swapgettx(symbol,txid)) == 0 ) { //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); } @@ -788,27 +693,27 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { if ( iambob == 0 ) { - if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + if ( (alice= LP_coinfind(alicecoin)) != 0 ) { - bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + bitcoin_address(Adestaddr,alice->pubtype,pubkey33,33); AAdest = Adestaddr; } - if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + if ( (bob= LP_coinfind(bobcoin)) != 0 ) { - bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + bitcoin_address(destaddr,bob->pubtype,pubkey33,33); Adest = destaddr; } } else { - if ( (coin= iguana_coinfind(bobcoin)) != 0 ) + if ( (bob= LP_coinfind(bobcoin)) != 0 ) { - bitcoin_address(destaddr,coin->chain->pubtype,pubkey33,33); + bitcoin_address(destaddr,bob->pubtype,pubkey33,33); Bdest = destaddr; } - if ( (coin= iguana_coinfind(alicecoin)) != 0 ) + if ( (alice= LP_coinfind(alicecoin)) != 0 ) { - bitcoin_address(Adestaddr,coin->chain->pubtype,pubkey33,33); + bitcoin_address(Adestaddr,alice->pubtype,pubkey33,33); ABdest = Adestaddr; } } @@ -817,15 +722,15 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) sentflags[BASILISK_ALICEPAYMENT] = 1; - else if ( (sentobj= basilisk_swapgettx(myinfo,alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) + else if ( (sentobj= LP_swapgettx(alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) { sentflags[BASILISK_ALICEPAYMENT] = 1; free_json(sentobj); } } - paymentspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBPAYMENT,BASILISK_ALICESPEND,BASILISK_BOBRECLAIM,0,Adest,Bdest); - Apaymentspent = basilisk_swap_spendupdate(myinfo,alicecoin,sentflags,txids,BASILISK_ALICEPAYMENT,BASILISK_ALICERECLAIM,BASILISK_BOBSPEND,0,AAdest,ABdest); - depositspent = basilisk_swap_spendupdate(myinfo,bobcoin,sentflags,txids,BASILISK_BOBDEPOSIT,BASILISK_ALICECLAIM,BASILISK_BOBREFUND,0,Adest,Bdest); + paymentspent = basilisk_swap_spendupdate(bobcoin,sentflags,txids,BASILISK_BOBPAYMENT,BASILISK_ALICESPEND,BASILISK_BOBRECLAIM,0,Adest,Bdest); + Apaymentspent = basilisk_swap_spendupdate(alicecoin,sentflags,txids,BASILISK_ALICEPAYMENT,BASILISK_ALICERECLAIM,BASILISK_BOBSPEND,0,AAdest,ABdest); + depositspent = basilisk_swap_spendupdate(bobcoin,sentflags,txids,BASILISK_BOBDEPOSIT,BASILISK_ALICECLAIM,BASILISK_BOBREFUND,0,Adest,Bdest); finishedflag = basilisk_swap_isfinished(iambob,txids,sentflags,paymentspent,Apaymentspent,depositspent); if ( iambob == 0 ) { @@ -845,13 +750,13 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); printf("alicespend len.%d redeemlen.%d\n",len,redeemlen); - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend("alicespend",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND])) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND])) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } if ( txbytes[BASILISK_ALICESPEND] != 0 ) { - txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction(myinfo,"alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); + txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction("alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested { sentflags[BASILISK_ALICESPEND] = 1; @@ -870,13 +775,13 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend("aliceclaim",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM])) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM])) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } if ( txbytes[BASILISK_ALICECLAIM] != 0 ) { - txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); + txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction("aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // tested { sentflags[BASILISK_ALICECLAIM] = 1; @@ -889,16 +794,16 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { //if ( txbytes[BASILISK_ALICERECLAIM] == 0 ) { - privBn = basilisk_swap_privBn_extract(myinfo,&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); + privBn = basilisk_swap_privBn_extract(&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM])) != 0 ) + if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",alicecoin,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM])) != 0 ) printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); } } if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) { - txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); + txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction("alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // tested { sentflags[BASILISK_ALICERECLAIM] = 1; @@ -918,17 +823,17 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t { if ( bits256_nonz(privAm) == 0 ) { - privAm = basilisk_swap_privbob_extract(myinfo,bobcoin,txids[BASILISK_ALICESPEND],0,1); + privAm = basilisk_swap_privbob_extract(bobcoin,txids[BASILISK_ALICESPEND],0,1); } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",myinfo,alicecoin,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND])) != 0 ) + if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",alicecoin,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND])) != 0 ) printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); } } if ( txbytes[BASILISK_BOBSPEND] != 0 ) { - txids[BASILISK_BOBSPEND] = basilisk_swap_sendrawtransaction(myinfo,"bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); + txids[BASILISK_BOBSPEND] = basilisk_swap_sendrawtransaction("bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) // tested { sentflags[BASILISK_BOBSPEND] = 1; @@ -946,7 +851,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM])) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM])) != 0 ) { int32_t z; for (z=0; z<20; z++) @@ -957,7 +862,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t } if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) { - txids[BASILISK_BOBRECLAIM] = basilisk_swap_sendrawtransaction(myinfo,"bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); + txids[BASILISK_BOBRECLAIM] = basilisk_swap_sendrawtransaction("bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) // tested { sentflags[BASILISK_BOBRECLAIM] = 1; @@ -976,12 +881,12 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend("bobrefund",myinfo,bobcoin,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND])) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND])) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) { - txids[BASILISK_BOBREFUND] = basilisk_swap_sendrawtransaction(myinfo,"bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); + txids[BASILISK_BOBREFUND] = basilisk_swap_sendrawtransaction("bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) // tested { sentflags[BASILISK_BOBREFUND] = 1; @@ -1001,7 +906,7 @@ cJSON *basilisk_remember(struct supernet_info *myinfo,int64_t *KMDtotals,int64_t sentflags[BASILISK_BOBDEPOSIT] = 1; for (i=0; inumswaps; i++) + /*for (i=0; inumswaps; i++) if ( (swap= myinfo->swaps[i]) != 0 && swap->I.req.requestid == requestid && swap->I.req.quoteid == quoteid ) { - jaddi(array,basilisk_swapjson(myinfo,swap)); + jaddi(array,basilisk_swapjson(swap)); flag = 1; break; - } + }*/ if ( flag == 0 ) { - if ( (item= basilisk_remember(myinfo,KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) + if ( (item= basilisk_remember(KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) { jaddi(array,item); if ( 1 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) @@ -1157,12 +1063,12 @@ char *basilisk_swaplist(struct supernet_info *myinfo) jaddnum(retjson,"avesell",(double)-Btotal/Ktotal); } array = cJSON_CreateArray(); - for (i=0; ilinfos)/sizeof(*myinfo->linfos); i++) + /*for (i=0; ilinfos)/sizeof(*myinfo->linfos); i++) { if ( myinfo->linfos[i].base[0] != 0 && myinfo->linfos[i].rel[0] != 0 ) jaddi(array,linfo_json(&myinfo->linfos[i])); } - jadd(retjson,"quotes",array); + jadd(retjson,"quotes",array);*/ return(jprint(retjson,1)); } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c new file mode 100644 index 000000000..be1108238 --- /dev/null +++ b/iguana/exchanges/LP_rpc.c @@ -0,0 +1,505 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_rpc.c +// marketmaker +// + +cJSON *basilisk_nullretjson(cJSON *retjson) +{ + char *outstr; + if ( retjson != 0 ) + { + outstr = jprint(retjson,0); + if ( strcmp(outstr,"{}") == 0 ) + { + free_json(retjson); + retjson = 0; + } + free(outstr); + } + return(retjson); +} + +void LP_unspentslock(char *symbol,cJSON *vins) +{ + +} + +void LP_unspents_mark(char *symbol,cJSON *vins) +{ + +} + +uint64_t LP_getestimatedfee(char *symbol) +{ + return(200); +} + +uint64_t LP_txfee(char *symbol) +{ + return(10000); +} + +char *dpow_validateaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *address) +{ + char buf[128],*retstr=0; + if ( coin->FULLNODE < 0 ) + { + sprintf(buf,"\"%s\"",address); + retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"validateaddress",buf); + usleep(10000); + } + else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) + { + retstr = bitcoinrpc_validateaddress(myinfo,coin,0,0,address); + } + else + { + return(0); + } + return(retstr); +} + +cJSON *dpow_gettxout(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout) +{ + char buf[128],str[65],*retstr=0; cJSON *json = 0; + sprintf(buf,"\"%s\", %d",bits256_str(str,txid),vout); + if ( coin->FULLNODE < 0 ) + { + retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"gettxout",buf); + usleep(10000); + } + else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) + { + printf("need to test following call\n"); + retstr = bitcoinrpc_gettxout(myinfo,coin,0,buf,txid,1,0); // untested + } + else + { + return(0); + } + if ( retstr != 0 ) + { + json = cJSON_Parse(retstr); + free(retstr); + } + //printf("dpow_gettxout.(%s)\n",retstr); + return(json); +} + +char *dpow_decoderawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx) +{ + char *retstr,*paramstr; cJSON *array; + if ( coin->FULLNODE < 0 ) + { + array = cJSON_CreateArray(); + jaddistr(array,rawtx); + paramstr = jprint(array,1); + retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"decoderawtransaction",paramstr); + //printf("%s decoderawtransaction.(%s) <- (%s)\n",coin->symbol,retstr,paramstr); + free(paramstr); + usleep(10000); + } + else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) + { + retstr = bitcoinrpc_decoderawtransaction(myinfo,coin,0,0,rawtx,1); + } + else + { + return(0); + } + return(retstr); +} + +cJSON *dpow_gettransaction(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid) +{ + char buf[128],str[65],*retstr=0; cJSON *json = 0; + if ( coin->FULLNODE < 0 ) + { + sprintf(buf,"[\"%s\", 1]",bits256_str(str,txid)); + if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"getrawtransaction",buf)) != 0 ) + { + } + usleep(10000); + } + else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) + { + retstr = bitcoinrpc_getrawtransaction(myinfo,coin,0,0,txid,1); + } + else + { + return(0); + } + if ( retstr != 0 ) + { + json = cJSON_Parse(retstr); + free(retstr); + } + return(json); +} + +cJSON *dpow_listunspent(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr) +{ + char buf[128],*retstr; cJSON *array,*json = 0; + if ( coin->FULLNODE < 0 ) + { + sprintf(buf,"0, 99999999, [\"%s\"]",coinaddr); + if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listunspent",buf)) != 0 ) + { + json = cJSON_Parse(retstr); + //printf("%s (%s) listunspent.(%s)\n",coin->symbol,buf,retstr); + free(retstr); + } else printf("%s null retstr from (%s)n",coin->symbol,buf); + } + else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) + { + array = cJSON_CreateArray(); + jaddistr(array,coinaddr); + json = iguana_listunspents(myinfo,coin,array,1,coin->longestchain,""); + free_json(array); + } + else + { + return(0); + } + return(json); +} + +cJSON *dpow_listtransactions(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,int32_t count,int32_t skip) +{ + char buf[128],*retstr; cJSON *json = 0; + if ( coin->FULLNODE < 0 ) + { + if ( count == 0 ) + count = 100; + sprintf(buf,"[\"%s\", %d, %d, true]",coinaddr,count,skip); + if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listtransactions",buf)) != 0 ) + { + //printf("LIST.(%s)\n",retstr); + json = cJSON_Parse(retstr); + free(retstr); + return(json); + } else printf("%s null retstr from (%s)n",coin->symbol,buf); + } + return(0); +} + +char *dpow_signrawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx,cJSON *vins) +{ + cJSON *array,*privkeys,*item; char *wifstr,*str,*paramstr,*retstr; uint8_t script[256]; int32_t i,n,len,hashtype; struct vin_info V; struct iguana_waddress *waddr; struct iguana_waccount *wacct; + if ( coin->FULLNODE < 0 ) + { + array = cJSON_CreateArray(); + jaddistr(array,rawtx); + jaddi(array,jduplicate(vins)); + paramstr = jprint(array,1); + //printf("signrawtransaction\n"); + retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"signrawtransaction",paramstr); + //printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); + free(paramstr); + usleep(10000); + return(retstr); + } + else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) + { + privkeys = cJSON_CreateArray(); + if ( (n= cJSON_GetArraySize(vins)) > 0 ) + { + for (i=0; i 0 && strlen(str) < sizeof(script)*2 ) + { + len = (int32_t)strlen(str) >> 1; + decode_hex(script,len,str); + V.spendlen = len; + memcpy(V.spendscript,script,len); + if ( (hashtype= _iguana_calcrmd160(coin,&V)) >= 0 && V.coinaddr[0] != 0 ) + { + if ( (waddr= iguana_waddresssearch(myinfo,&wacct,V.coinaddr)) != 0 ) + { + if ( bits256_nonz(waddr->privkey) != 0 ) + { + if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->chain->wiftype) > 0 ) + { + wifstr = waddr->wifstr; + } + } + } + } + } + jaddistr(privkeys,wifstr); + } + } + retstr = bitcoinrpc_signrawtransaction(myinfo,coin,0,0,rawtx,vins,privkeys,"ALL"); + printf("call sign.(%s) vins.(%s) privs.(%s) -> (%s)\n",rawtx,jprint(vins,0),jprint(privkeys,0),retstr); + free_json(privkeys); + return(retstr); + } + else + { + return(0); + } +} + +char *dpow_sendrawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *signedtx) +{ + bits256 txid; cJSON *json,*array; char *paramstr,*retstr; + if ( coin->FULLNODE < 0 ) + { + array = cJSON_CreateArray(); + jaddistr(array,signedtx); + paramstr = jprint(array,1); + retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"sendrawtransaction",paramstr); + printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> (%s)\n",coin->symbol,paramstr,retstr); + free(paramstr); + return(retstr); + } + else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) + { + txid = iguana_sendrawtransaction(myinfo,coin,signedtx); + json = cJSON_CreateObject(); + jaddbits256(json,"result",txid); + return(jprint(json,1)); + } + else + { + return(0); + } +} + +char *LP_importaddress(char *symbol,char *address) +{ + char buf[1024],*retstr; cJSON *validatejson; int32_t isvalid=0,doneflag = 0; + if ( (retstr= LP_validateaddress(symbol,address)) != 0 ) + { + if ( (validatejson= cJSON_Parse(retstr)) != 0 ) + { + if ( (isvalid= is_cJSON_True(jobj(validatejson,"isvalid")) != 0) != 0 ) + { + if ( is_cJSON_True(jobj(validatejson,"iswatchonly")) != 0 || is_cJSON_True(jobj(validatejson,"ismine")) != 0 ) + doneflag = 1; + } + free_json(validatejson); + } + free(retstr); + retstr = 0; + } + if ( isvalid == 0 ) + return(clonestr("{\"isvalid\":false}")); + update_alladdresses(myinfo,coin,address); + if ( doneflag != 0 ) + return(0); // success + if ( coin->FULLNODE < 0 ) + { + sprintf(buf,"[\"%s\", \"%s\", false]",address,address); + retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"importaddress",buf); + printf("%s importaddress.(%s) -> (%s)\n",coin->symbol,address,retstr); + return(retstr); + } + else return(0); +} + +char *LP_importaddress(char *symbol,char *coinaddr) +{ + return(0); +} + +char *LP_sendrawtransaction(char *symbol,char *signedtx) +{ + return(0); +} + +char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON *vins,char *rawtxbytes,cJSON *privkeys,struct vin_info *V) +{ + return(0); +} + +cJSON *LP_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) +{ + return(0); +} + +char *dex_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) +{ + return(0); +} + +bits256 LP_privkey(char *coinaddr) +{ + bits256 privkey; + return(privkey); +} + +bits256 LP_pubkey(bits256 privkey) +{ + bits256 pubkey; + pubkey = curve25519(privkey,curve25519_basepoint9()); + return(pubkey); +} + +cJSON *LP_swapgettxout(char *symbol,bits256 trigger,int32_t vout) +{ + cJSON *retjson=0; //char *retstr; struct iguana_info *coin; + /*if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + { + if ( (retstr= dex_gettxout(0,0,0,trigger,symbol,vout)) != 0 ) + { + //printf("dexgettxout.(%s)\n",retstr); + retjson = cJSON_Parse(retstr); + free(retstr); + } + if ( 0 && strcmp("BTC",symbol) == 0 ) + printf("%s gettxout.(%s)\n",symbol,jprint(retjson,0)); + } + else + { + retjson = dpow_gettxout(coin,trigger,vout); + //printf("need to verify passthru has this info\n"); + //printf("dpowgettxout.(%s)\n",jprint(retjson,0)); + }*/ + return(basilisk_nullretjson(retjson)); +} + +uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) +{ + uint64_t value = 0; + return(value); +} + +cJSON *LP_swapgettx(char *symbol,bits256 txid) +{ + cJSON *retjson=0; //char *retstr; struct iguana_info *coin; + /*if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + { + if ( (retstr= dex_gettransaction(0,0,0,txid,symbol)) != 0 ) + { + retjson = cJSON_Parse(retstr); + free(retstr); + } + //if ( strcmp("BTC",symbol) == 0 ) + // printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); + } else retjson = dpow_gettransaction(coin,txid);*/ + return(basilisk_nullretjson(retjson)); +} + +bits256 basilisk_swap_sendrawtransaction(char *txname,char *symbol,char *txbytes) +{ + char *retstr; bits256 txid; int32_t i,sentflag = 0; + memset(&txid,0,sizeof(txid)); + for (i=0; i<3; i++) + { + if ( (retstr= LP_sendrawtransaction(symbol,txbytes)) != 0 ) + { + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + sentflag = 1; + } + char str[65]; printf("[%s] %s RETSTR.(%s) %s.%s\n",txname,txbytes,retstr,symbol,bits256_str(str,txid)); + free(retstr); + } + if ( sentflag != 0 ) + break; + } + return(txid); +} + +bits256 LP_broadcast(char *name,char *symbol,uint8_t *data,int32_t datalen) +{ + bits256 txid; char *signedtx,*retstr; int32_t i; + memset(txid.bytes,0,sizeof(txid)); + if ( data != 0 && datalen != 0 ) + { + char str[65]; +#ifdef BASILISK_DISABLESENDTX + txid = bits256_doublesha256(0,data,datalen); + printf("%s <- dont sendrawtransaction (%s)\n",name,bits256_str(str,txid)); + return(txid); +#endif + signedtx = malloc(datalen*2 + 1); + init_hexbytes_noT(signedtx,data,datalen); + for (i=0; i<3; i++) + { + if ( (retstr= LP_sendrawtransaction(symbol,signedtx)) != 0 ) + { + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + free(retstr); + printf("sendrawtransaction.%s %s.(%s)\n",name,symbol,bits256_str(str,txid)); + break; + } + else + { + printf("sendrawtransaction.%s %s error.(%s)\n",name,symbol,retstr); + free(retstr); + } + } else printf("sendrawtransaction.%s %s got null return\n",name,symbol); + } + free(signedtx); + } + return(txid); +} + +int32_t basilisk_confirmsobj(cJSON *item) +{ + int32_t height,numconfirms; + height = jint(item,"height"); + numconfirms = jint(item,"numconfirms"); + if ( height > 0 && numconfirms >= 0 ) + return(numconfirms); + printf("basilisk_confirmsobj height.%d numconfirms.%d (%s)\n",height,numconfirms,jprint(item,0)); + return(-1); +} + +int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +{ +#ifdef BASILISK_DISABLEWAITTX + return(100); +#endif + /*cJSON *argjson,*valuearray=0; char *valstr; int32_t i,n,retval = -1; + argjson = cJSON_CreateObject(); + jaddbits256(argjson,"txid",rawtx->I.actualtxid); + jaddnum(argjson,"vout",0); + jaddstr(argjson,"coin",rawtx->coin->symbol); + if ( (valstr= basilisk_value(rawtx->coin,0,0,swap->persistent_pubkey,argjson,0)) != 0 ) + { + char str[65]; printf("basilisk_numconfirms required.%d %s %s valstr.(%s)\n",rawtx->I.numconfirms,rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); + //basilisk_numconfirms required.0 alicespend 29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85 valstr.({"result":"success","numconfirms":0,"address":"1JGvZ67oTdM7kCya4J8kj1uErbSRAoq3wH","satoshis":"1413818","value":0.01413818,"height":462440,"txid":"29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85","vout":0,"coin":"BTC"}) + + if ( (valuearray= cJSON_Parse(valstr)) != 0 ) + { + if ( valstr[0] == '[' && is_cJSON_Array(valuearray) != 0 ) + { + n = cJSON_GetArraySize(valuearray); + for (i=0; i= 0 ) + break; + } + } else retval = basilisk_confirmsobj(valuearray); + free_json(valuearray); + } else printf("parse error\n"); + free(valstr); + } + free_json(argjson); + printf("numconfirms.%d returned\n",retval); + return(retval);*/ +} diff --git a/iguana/exchanges/LP_secp.c b/iguana/exchanges/LP_secp.c new file mode 100644 index 000000000..7d4409911 --- /dev/null +++ b/iguana/exchanges/LP_secp.c @@ -0,0 +1,186 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_secp.c +// marketmaker +// + + +#include +#include +#include +#include +#include "../../includes/curve25519.h" +#include "../secp256k1/include/secp256k1.h" +#include "../secp256k1/include/secp256k1_ecdh.h" +#include "../secp256k1/include/secp256k1_schnorr.h" +#include "../secp256k1/include/secp256k1_rangeproof.h" +#include "../secp256k1/include/secp256k1_recovery.h" + +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; + +#define bits256_nonz(a) (((a).ulongs[0] | (a).ulongs[1] | (a).ulongs[2] | (a).ulongs[3]) != 0) + +#define SECP_ENSURE_CTX int32_t flag = 0; if ( ctx == 0 ) { ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); secp256k1_pedersen_context_initialize(ctx); secp256k1_rangeproof_context_initialize(ctx); flag++; } else flag = 0; if ( ctx != 0 ) +#define ENDSECP_ENSURE_CTX if ( flag != 0 ) secp256k1_context_destroy(ctx); + +void *bitcoin_ctx() +{ + void *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_pedersen_context_initialize(ctx); + secp256k1_rangeproof_context_initialize(ctx); + return(ctx); +} + +bits256 bitcoin_pubkey33(void *ctx,uint8_t *data,bits256 privkey) +{ + size_t plen; bits256 pubkey; secp256k1_pubkey secppub; + memset(pubkey.bytes,0,sizeof(pubkey)); + SECP_ENSURE_CTX + { + if ( secp256k1_ec_seckey_verify(ctx,privkey.bytes) == 0 ) + { + //printf("bitcoin_sign illegal privkey\n"); + return(pubkey); + } + if ( secp256k1_ec_pubkey_create(ctx,&secppub,privkey.bytes) != 0 ) + { + plen = 33; + secp256k1_ec_pubkey_serialize(ctx,data,&plen,&secppub,SECP256K1_EC_COMPRESSED); + if ( plen == 33 ) + memcpy(pubkey.bytes,data+1,sizeof(pubkey)); + } + ENDSECP_ENSURE_CTX + } + return(pubkey); +} + +bits256 bitcoin_pub256(void *ctx,bits256 *privkeyp,uint8_t odd_even) +{ + bits256 pub256; uint8_t pubkey[33]; int32_t i; + for (i=0; i<100; i++) + { + *privkeyp = rand256(0); + pub256 = bitcoin_pubkey33(ctx,pubkey,*privkeyp); + if ( pubkey[0] == odd_even+2 ) + return(pub256); + } + printf("bitcoin_pub256 couldnt generate pubkey.%d\n",odd_even+2); + memset(pub256.bytes,0,sizeof(pub256)); + return(pub256); +} + +int32_t bitcoin_sign(void *ctx,char *symbol,uint8_t *sig,bits256 txhash2,bits256 privkey,int32_t recoverflag) +{ + int32_t fCompressed = 1; + secp256k1_ecdsa_signature SIG; secp256k1_ecdsa_recoverable_signature rSIG; bits256 extra_entropy,seed; int32_t recid,retval = -1; size_t siglen = 72; secp256k1_pubkey SECPUB,CHECKPUB; + seed = rand256(0); + extra_entropy = rand256(0); + SECP_ENSURE_CTX + { + if ( secp256k1_ec_seckey_verify(ctx,privkey.bytes) == 0 ) + { + //printf("bitcoin_sign illegal privkey\n"); + return(-1); + } + if ( secp256k1_context_randomize(ctx,seed.bytes) != 0 ) + { + if ( recoverflag != 0 ) + { + if ( secp256k1_ecdsa_sign_recoverable(ctx,&rSIG,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,extra_entropy.bytes) != 0 ) + { + recid = -1; + secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx,sig+1,&recid,&rSIG); + if ( secp256k1_ecdsa_recover(ctx,&SECPUB,&rSIG,txhash2.bytes) != 0 ) + { + if ( secp256k1_ec_pubkey_create(ctx,&CHECKPUB,privkey.bytes) != 0 ) + { + if ( memcmp(&SECPUB,&CHECKPUB,sizeof(SECPUB)) == 0 ) + { + sig[0] = 27 + recid + (fCompressed != 0 ? 4 : 0); + retval = 64 + 1; + //size_t i,plen = 33; uint8_t pubkey[33]; + //secp256k1_ec_pubkey_serialize(ctx,pubkey,&plen,&CHECKPUB,SECP256K1_EC_COMPRESSED); + //for (i=0; i<33; i++) + // printf("%02x",pubkey[i]); + //printf(" bitcoin_sign's pubkey\n"); + + } //else printf("secpub mismatch\n"); + } else printf("pubkey create error\n"); + } //else printf("recover error\n"); + } else printf("secp256k1_ecdsa_sign_recoverable error\n"); + } + else + { + if ( secp256k1_ecdsa_sign(ctx,&SIG,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,extra_entropy.bytes) != 0 ) + { + if ( secp256k1_ecdsa_signature_serialize_der(ctx,sig,&siglen,&SIG) != 0 ) + retval = (int32_t)siglen; + } + } + } + ENDSECP_ENSURE_CTX + } + return(retval); +} + +int32_t bitcoin_recoververify(void *ctx,char *symbol,uint8_t *sig,bits256 messagehash2,uint8_t *pubkey,size_t plen) +{ + int32_t retval = -1; secp256k1_pubkey PUB; secp256k1_ecdsa_signature SIG; secp256k1_ecdsa_recoverable_signature rSIG; + pubkey[0] = 0; + SECP_ENSURE_CTX + { + if ( plen == 0 ) + { + plen = (sig[0] <= 31) ? 65 : 33; + sig++; + } + secp256k1_ecdsa_recoverable_signature_parse_compact(ctx,&rSIG,sig,0); + secp256k1_ecdsa_recoverable_signature_convert(ctx,&SIG,&rSIG); + if ( secp256k1_ecdsa_recover(ctx,&PUB,&rSIG,messagehash2.bytes) != 0 ) + { + plen = 33; + memset(pubkey,0,33); + secp256k1_ec_pubkey_serialize(ctx,pubkey,&plen,&PUB,SECP256K1_EC_COMPRESSED);//plen == 65 ? SECP256K1_EC_UNCOMPRESSED : SECP256K1_EC_COMPRESSED); + if ( secp256k1_ecdsa_verify(ctx,&SIG,messagehash2.bytes,&PUB) != 0 ) + { + retval = 0; + /*if ( pubkey[0] == 4 ) // experimentally looks like 04 is set + pubkey[0] = 2; + else if ( pubkey[0] != 2 ) + pubkey[0] = 3;*/ + } else printf("secp256k1_ecdsa_verify error\n"); + } else printf("secp256k1_ecdsa_recover error\n"); + ENDSECP_ENSURE_CTX + } + return(retval); +} + +int32_t bitcoin_verify(void *ctx,uint8_t *sig,int32_t siglen,bits256 txhash2,uint8_t *pubkey,int32_t plen) +{ + int32_t retval = -1; secp256k1_pubkey PUB; secp256k1_ecdsa_signature SIG; + SECP_ENSURE_CTX + { + if ( secp256k1_ec_pubkey_parse(ctx,&PUB,pubkey,plen) != 0 ) + { + secp256k1_ecdsa_signature_parse_der(ctx,&SIG,sig,siglen); + if ( secp256k1_ecdsa_verify(ctx,&SIG,txhash2.bytes,&PUB) != 0 ) + retval = 0; + } + ENDSECP_ENSURE_CTX + } + return(retval); +} diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c new file mode 100644 index 000000000..4cb663b99 --- /dev/null +++ b/iguana/exchanges/LP_statemachine.c @@ -0,0 +1,558 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_statemachine.c +// marketmaker +// + +int32_t basilisk_process_swapverify(void *ptr,int32_t (*internal_func)(void *ptr,uint8_t *data,int32_t datalen),uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen,uint32_t expiration,uint32_t duration) +{ + struct basilisk_swap *swap = ptr; + if ( internal_func != 0 ) + return((*internal_func)(swap,data,datalen)); + else return(0); +} + + + +int32_t basilisk_priviextract(struct iguana_info *coin,char *name,bits256 *destp,uint8_t secret160[20],bits256 srctxid,int32_t srcvout) +{ + /*bits256 txid; char str[65]; int32_t i,vini,scriptlen; uint8_t rmd160[20],scriptsig[IGUANA_MAXSCRIPTSIZE]; + memset(privkey.bytes,0,sizeof(privkey)); + // use dex_listtransactions! + if ( (vini= iguana_vinifind(coin,&txid,srctxid,srcvout)) >= 0 ) + { + if ( (scriptlen= iguana_scriptsigextract(coin,scriptsig,sizeof(scriptsig),txid,vini)) > 32 ) + { + for (i=0; i<32; i++) + privkey.bytes[i] = scriptsig[scriptlen - 33 + i]; + revcalc_rmd160_sha256(rmd160,privkey);//.bytes,sizeof(privkey)); + if ( memcmp(secret160,rmd160,sizeof(rmd160)) == sizeof(rmd160) ) + { + *destp = privkey; + printf("basilisk_priviextract found privi %s (%s)\n",name,bits256_str(str,privkey)); + return(0); + } + } + }*/ + return(-1); +} +int32_t basilisk_verify_privi(void *ptr,uint8_t *data,int32_t datalen); + +int32_t basilisk_privBn_extract(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + if ( basilisk_priviextract(&swap->bobcoin,"privBn",&swap->I.privBn,swap->I.secretBn,swap->bobrefund.I.actualtxid,0) == 0 ) + { + printf("extracted privBn from blockchain\n"); + } + else if ( basilisk_swapget(swap,0x40000000,data,maxlen,basilisk_verify_privi) == 0 ) + { + } + if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) + { + char str[65]; printf("got privBn.%s\n",bits256_str(str,swap->I.privBn)); + return(basilisk_alicepayment_spend(swap,&swap->alicereclaim)); + } + return(-1); +} + +int32_t basilisk_privAm_extract(struct basilisk_swap *swap) +{ + if ( basilisk_priviextract(&swap->bobcoin,"privAm",&swap->I.privAm,swap->I.secretAm,swap->bobpayment.I.actualtxid,0) == 0 ) + { + printf("extracted privAm from blockchain\n"); + } + if ( bits256_nonz(swap->I.privAm) != 0 && swap->bobspend.I.datalen == 0 ) + { + char str[65]; printf("got privAm.%s\n",bits256_str(str,swap->I.privAm)); + return(basilisk_alicepayment_spend(swap,&swap->bobspend)); + } + return(-1); +} + +int32_t basilisk_verify_otherstatebits(void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t retval; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(swap->I.otherstatebits) ) + { + retval = iguana_rwnum(0,data,sizeof(swap->I.otherstatebits),&swap->I.otherstatebits); + return(retval); + } else return(-1); +} + +int32_t basilisk_verify_statebits(void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t retval = -1; uint32_t statebits; struct basilisk_swap *swap = ptr; + if ( datalen == sizeof(swap->I.statebits) ) + { + retval = iguana_rwnum(0,data,sizeof(swap->I.statebits),&statebits); + if ( statebits != swap->I.statebits ) + { + printf("statebits.%x != %x\n",statebits,swap->I.statebits); + return(-1); + } + } + return(retval); +} + +void basilisk_sendstate(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t datalen=0; + datalen = iguana_rwnum(1,data,sizeof(swap->I.statebits),&swap->I.statebits); + LP_swapsend(swap,0x80000000,data,datalen,0,0); +} + +int32_t basilisk_swapiteration(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t j,datalen,retval = 0; uint32_t savestatebits=0,saveotherbits=0; + if ( swap->I.iambob != 0 ) + swap->I.statebits |= 0x80; + while ( swap->aborted == 0 && ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) + { + if ( swap->connected == 0 ) + basilisk_psockinit(swap,swap->I.iambob != 0); + printf("D r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); + if ( swap->I.iambob != 0 && (swap->I.statebits & 0x80) == 0 ) // wait for fee + { + if ( basilisk_swapget(swap,0x80,data,maxlen,basilisk_verify_otherfee) == 0 ) + { + // verify and submit otherfee + swap->I.statebits |= 0x80; + basilisk_sendstate(swap,data,maxlen); + } + } + else if ( swap->I.iambob == 0 ) + swap->I.statebits |= 0x80; + basilisk_sendstate(swap,data,maxlen); + basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + if ( (swap->I.otherstatebits & 0x80) != 0 && (swap->I.statebits & 0x80) != 0 ) + break; + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + basilisk_sendstate(swap,data,maxlen); + if ( (swap->I.otherstatebits & 0x80) == 0 ) + LP_swapdata_rawtxsend(swap,0x80,data,maxlen,&swap->myfee,0x40,0); + } + basilisk_swap_saveupdate(swap); + while ( swap->aborted == 0 && retval == 0 && time(NULL) < swap->I.expiration ) // both sides have setup required data and paid txfee + { + basilisk_swap_saveupdate(swap); + if ( swap->connected == 0 ) + basilisk_psockinit(swap,swap->I.iambob != 0); + //if ( (rand() % 30) == 0 ) + printf("E r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); + if ( swap->I.iambob != 0 ) + { + //printf("BOB\n"); + if ( (swap->I.statebits & 0x100) == 0 ) + { + printf("send bobdeposit\n"); + swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0); + } + // [BLOCKING: altfound] make sure altpayment is confirmed and send payment + else if ( (swap->I.statebits & 0x1000) == 0 ) + { + printf("check alicepayment\n"); + if ( basilisk_swapget(swap,0x1000,data,maxlen,basilisk_verify_alicepaid) == 0 ) + { + swap->I.statebits |= 0x1000; + printf("got alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); + } + } + else if ( (swap->I.statebits & 0x2000) == 0 ) + { + if ( (swap->I.aliceconfirms == 0 && swap->aliceunconf != 0) || LP_numconfirms(swap,&swap->alicepayment) >= swap->I.aliceconfirms ) + { + swap->I.statebits |= 0x2000; + printf("alicepayment confirmed\n"); + } + } + else if ( (swap->I.statebits & 0x4000) == 0 ) + { + basilisk_bobscripts_set(swap,0,1); + printf("send bobpayment\n"); + swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0); + } + // [BLOCKING: privM] Bob waits for privAm either from Alice or alice blockchain + else if ( (swap->I.statebits & 0xc0000) != 0xc0000 ) + { + if ( basilisk_swapget(swap,0x40000,data,maxlen,basilisk_verify_privi) == 0 || basilisk_privAm_extract(swap) == 0 ) // divulges privAm + { + //printf("got privi spend alicepayment, dont divulge privBn until bobspend propagated\n"); + basilisk_alicepayment_spend(swap,&swap->bobspend); + if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobspend,0x40000,1) == 0 ) + printf("Bob error spending alice payment\n"); + else + { + tradebot_swap_balancingtrade(swap,1); + printf("Bob spends alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); + swap->I.statebits |= 0x40000; + if ( LP_numconfirms(swap,&swap->bobspend) >= swap->I.aliceconfirms ) + { + printf("bobspend confirmed\n"); + swap->I.statebits |= 0x80000; + printf("Bob confirming spend of Alice's payment\n"); + sleep(DEX_SLEEP); + } + retval = 1; + } + } + } + if ( swap->bobpayment.I.locktime != 0 && time(NULL) > swap->bobpayment.I.locktime ) + { + // submit reclaim of payment + printf("bob reclaims bobpayment\n"); + swap->I.statebits |= (0x40000 | 0x80000); + if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobreclaim,0,0) == 0 ) + printf("Bob error reclaiming own payment after alice timed out\n"); + else + { + printf("Bob reclaimed own payment\n"); + while ( 0 && (swap->I.statebits & 0x100000) == 0 ) // why wait for own tx? + { + if ( LP_numconfirms(swap,&swap->bobreclaim) >= 1 ) + { + printf("bobreclaim confirmed\n"); + swap->I.statebits |= 0x100000; + printf("Bob confirms reclain of payment\n"); + break; + } + } + retval = 1; + } + } + } + else + { + //printf("ALICE\n"); + // [BLOCKING: depfound] Alice waits for deposit to confirm and sends altpayment + if ( (swap->I.statebits & 0x200) == 0 ) + { + printf("checkfor deposit\n"); + if ( basilisk_swapget(swap,0x200,data,maxlen,basilisk_verify_bobdeposit) == 0 ) + { + // verify deposit and submit, set confirmed height + printf("got bobdeposit\n"); + swap->I.statebits |= 0x200; + } else printf("no valid deposit\n"); + } + else if ( (swap->I.statebits & 0x400) == 0 ) + { + if ( basilisk_istrustedbob(swap) != 0 || (swap->I.bobconfirms == 0 && swap->depositunconf != 0) || LP_numconfirms(swap,&swap->bobdeposit) >= swap->I.bobconfirms ) + { + printf("bobdeposit confirmed\n"); + swap->I.statebits |= 0x400; + } + } + else if ( (swap->I.statebits & 0x800) == 0 ) + { + printf("send alicepayment\n"); + swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0); + } + // [BLOCKING: payfound] make sure payment is confrmed and send in spend or see bob's reclaim and claim + else if ( (swap->I.statebits & 0x8000) == 0 ) + { + if ( basilisk_swapget(swap,0x8000,data,maxlen,basilisk_verify_bobpaid) == 0 ) + { + printf("got bobpayment\n"); + tradebot_swap_balancingtrade(swap,0); + // verify payment and submit, set confirmed height + swap->I.statebits |= 0x8000; + } + } + else if ( (swap->I.statebits & 0x10000) == 0 ) + { + if ( basilisk_istrustedbob(swap) != 0 || (swap->I.bobconfirms == 0 && swap->paymentunconf != 0) || LP_numconfirms(swap,&swap->bobpayment) >= swap->I.bobconfirms ) + { + printf("bobpayment confirmed\n"); + swap->I.statebits |= 0x10000; + } + } + else if ( (swap->I.statebits & 0x20000) == 0 ) + { + printf("alicespend bobpayment\n"); + if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->alicespend,0x20000,0) != 0 )//&& (swap->aliceunconf != 0 || basilisk_numconfirms(swap,&swap->alicespend) > 0) ) + { + swap->I.statebits |= 0x20000; + } + } + else if ( (swap->I.statebits & 0x40000) == 0 ) + { + int32_t numconfs; + if ( (numconfs= LP_numconfirms(swap,&swap->alicespend)) >= swap->I.bobconfirms ) + { + for (j=datalen=0; j<32; j++) + data[datalen++] = swap->I.privAm.bytes[j]; + printf("send privAm %x\n",swap->I.statebits); + swap->I.statebits |= LP_swapsend(swap,0x40000,data,datalen,0x20000,swap->I.crcs_mypriv); + printf("Alice confirms spend of Bob's payment\n"); + retval = 1; + } else printf("alicespend numconfs.%d < %d\n",numconfs,swap->I.bobconfirms); + } + if ( swap->bobdeposit.I.locktime != 0 && time(NULL) > swap->bobdeposit.I.locktime ) + { + printf("Alice claims deposit\n"); + if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->aliceclaim,0,0) == 0 ) + printf("Alice couldnt claim deposit\n"); + else + { + printf("Alice claimed deposit\n"); + retval = 1; + } + } + else if ( swap->aborted != 0 || basilisk_privBn_extract(swap,data,maxlen) == 0 ) + { + printf("Alice reclaims her payment\n"); + swap->I.statebits |= 0x40000000; + if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->alicereclaim,0x40000000,0) == 0 ) + printf("Alice error sending alicereclaim\n"); + else + { + printf("Alice reclaimed her payment\n"); + retval = 1; + } + } + } + if ( (rand() % 30) == 0 ) + printf("finished swapstate.%x other.%x\n",swap->I.statebits,swap->I.otherstatebits); + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_sendstate(swap,data,maxlen); + basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + } + return(retval); +} + +int32_t swapcompleted(struct basilisk_swap *swap) +{ + if ( swap->I.iambob != 0 ) + return(swap->I.bobspent); + else return(swap->I.alicespent); +} + +cJSON *swapjson(struct basilisk_swap *swap) +{ + cJSON *retjson = cJSON_CreateObject(); + return(retjson); +} + +int32_t basilisk_rwDEXquote(int32_t rwflag,uint8_t *serialized,struct basilisk_request *rp) +{ + int32_t len = 0; + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->requestid),&rp->requestid); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->timestamp),&rp->timestamp); // must be 2nd + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->quoteid),&rp->quoteid); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->quotetime),&rp->quotetime); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->optionhours),&rp->optionhours); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->srcamount),&rp->srcamount); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->unused),&rp->unused); + len += iguana_rwbignum(rwflag,&serialized[len],sizeof(rp->srchash),rp->srchash.bytes); + len += iguana_rwbignum(rwflag,&serialized[len],sizeof(rp->desthash),rp->desthash.bytes); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->destamount),&rp->destamount); + if ( rwflag != 0 ) + { + memcpy(&serialized[len],rp->src,sizeof(rp->src)), len += sizeof(rp->src); + memcpy(&serialized[len],rp->dest,sizeof(rp->dest)), len += sizeof(rp->dest); + } + else + { + memcpy(rp->src,&serialized[len],sizeof(rp->src)), len += sizeof(rp->src); + memcpy(rp->dest,&serialized[len],sizeof(rp->dest)), len += sizeof(rp->dest); + } + //len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->DEXselector),&rp->DEXselector); + //len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->extraspace),&rp->extraspace); + if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) + printf(" basilisk_rwDEXquote.%d: quoteid.%u mismatch calc %u rp.%p\n",rwflag,rp->quoteid,basilisk_quoteid(rp),rp); + if ( basilisk_requestid(rp) != rp->requestid ) + printf(" basilisk_rwDEXquote.%d: requestid.%u mismatch calc %u rp.%p\n",rwflag,rp->requestid,basilisk_requestid(rp),rp); + return(len); +} + +struct basilisk_request *basilisk_parsejson(struct basilisk_request *rp,cJSON *reqjson) +{ + uint32_t requestid,quoteid; + memset(rp,0,sizeof(*rp)); + rp->srchash = jbits256(reqjson,"srchash"); + rp->desthash = jbits256(reqjson,"desthash"); + rp->srcamount = j64bits(reqjson,"srcamount"); + //rp->minamount = j64bits(reqjson,"minamount"); + //rp->destamount = j64bits(reqjson,"destamount"); + rp->destamount = j64bits(reqjson,"destsatoshis"); + //printf("parse DESTSATOSHIS.%llu (%s)\n",(long long)rp->destamount,jprint(reqjson,0)); + requestid = juint(reqjson,"requestid"); + quoteid = juint(reqjson,"quoteid"); + //if ( jstr(reqjson,"relay") != 0 ) + // rp->relaybits = (uint32_t)calc_ipbits(jstr(reqjson,"relay")); + rp->timestamp = juint(reqjson,"timestamp"); + rp->quotetime = juint(reqjson,"quotetime"); + safecopy(rp->src,jstr(reqjson,"src"),sizeof(rp->src)); + safecopy(rp->dest,jstr(reqjson,"dest"),sizeof(rp->dest)); + if ( quoteid != 0 ) + { + rp->quoteid = basilisk_quoteid(rp); + if ( quoteid != rp->quoteid ) + printf("basilisk_parsejson quoteid.%u != %u error\n",quoteid,rp->quoteid); + } + rp->requestid = basilisk_requestid(rp); + if ( requestid != rp->requestid ) + { + int32_t i; for (i=0; irequestid); + } + return(rp); +} + +cJSON *basilisk_requestjson(struct basilisk_request *rp) +{ + cJSON *item = cJSON_CreateObject(); + /*if ( rp->relaybits != 0 ) + { + expand_ipbits(ipaddr,rp->relaybits); + jaddstr(item,"relay",ipaddr); + }*/ + jaddbits256(item,"srchash",rp->srchash); + if ( bits256_nonz(rp->desthash) != 0 ) + jaddbits256(item,"desthash",rp->desthash); + jaddstr(item,"src",rp->src); + if ( rp->srcamount != 0 ) + jadd64bits(item,"srcamount",rp->srcamount); + //if ( rp->minamount != 0 ) + // jadd64bits(item,"minamount",rp->minamount); + jaddstr(item,"dest",rp->dest); + if ( rp->destamount != 0 ) + { + //jadd64bits(item,"destamount",rp->destamount); + jadd64bits(item,"destsatoshis",rp->destamount); + //printf("DESTSATOSHIS.%llu\n",(long long)rp->destamount); + } + jaddnum(item,"quotetime",rp->quotetime); + jaddnum(item,"timestamp",rp->timestamp); + jaddnum(item,"requestid",rp->requestid); + jaddnum(item,"quoteid",rp->quoteid); + //jaddnum(item,"DEXselector",rp->DEXselector); + jaddnum(item,"optionhours",rp->optionhours); + //jaddnum(item,"profit",(double)rp->profitmargin / 1000000.); + if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) + printf("quoteid mismatch %u vs %u\n",basilisk_quoteid(rp),rp->quoteid); + if ( basilisk_requestid(rp) != rp->requestid ) + printf("requestid mismatch %u vs calc %u\n",rp->requestid,basilisk_requestid(rp)); + { + int32_t i; struct basilisk_request R; + if ( basilisk_parsejson(&R,item) != 0 ) + { + if ( memcmp(&R,rp,sizeof(*rp)-sizeof(uint32_t)) != 0 ) + { + for (i=0; iI.req.requestid); + jaddnum(item,"quoteid",swap->I.req.quoteid); + jaddnum(item,"state",swap->I.statebits); + jaddnum(item,"otherstate",swap->I.otherstatebits); + jadd(item,"request",basilisk_requestjson(&swap->I.req)); + return(item); +} + +#ifdef later + +cJSON *basilisk_privkeyarray(struct iguana_info *coin,cJSON *vins) +{ + cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],typestr[64],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; double bidasks[2]; + privkeyarray = cJSON_CreateArray(); + //printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr); + if ( (n= cJSON_GetArraySize(vins)) > 0 ) + { + for (i=0; i= 0 ) + { + iguana_txidcategory(coin,account,coinaddr,txid,vout); + if ( coinaddr[0] == 0 && (sobj= jobj(item,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 && is_hexstr(hexstr,0) > 0 ) + { + len = (int32_t)strlen(hexstr) >> 1; + if ( len < (sizeof(script) << 1) ) + { + decode_hex(script,len,hexstr); + if ( len == 25 && script[0] == 0x76 && script[1] == 0xa9 && script[2] == 0x14 ) + bitcoin_address(coinaddr,coin->chain->pubtype,script+3,20); + } + } + if ( coinaddr[0] != 0 ) + { + if ( (waddr= iguana_waddresssearch(&wacct,coinaddr)) != 0 ) + { + bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype); + jaddistr(privkeyarray,waddr->wifstr); + } + else if ( smartaddress(typestr,bidasks,&privkey,coin->symbol,coinaddr) >= 0 ) + { + bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); + jaddistr(privkeyarray,wifstr); + } + else printf("cant find (%s) in wallet\n",coinaddr); + } else printf("cant coinaddr from (%s).v%d\n",bits256_str(str,txid),vout); + } else printf("invalid txid/vout %d of %d\n",i,n); + } + } + return(privkeyarray); +} + + +#endif + + +/*void basilisk_swap_purge(struct basilisk_swap *swap) + { + int32_t i,n; + // while still in orderbook, wait + //return; + portable_mutex_lock(&myinfo->DEX_swapmutex); + n = myinfo->numswaps; + for (i=0; iswaps[i] == swap ) + { + myinfo->swaps[i] = myinfo->swaps[--myinfo->numswaps]; + myinfo->swaps[myinfo->numswaps] = 0; + basilisk_swap_finished(swap); + break; + } + portable_mutex_unlock(&myinfo->DEX_swapmutex); + }*/ diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 5df4a6b86..2a1d96bef 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -22,17 +22,15 @@ make sure to broadcast deposit before claiming refund, or to just skip it if neither is done */ -#define DEX_SLEEP 10 -#define BASILISK_DEFAULT_NUMCONFIRMS 5 // Todo: monitor blockchains, ie complete extracting scriptsig // mode to autocreate required outputs // more better LP commands // depends on just three external functions: -// - basilisk_sendrawtransaction(myinfo,coin,signedtx); -// - basilisk_value(myinfo,rawtx->coin,0,0,myinfo->myaddr.persistent,argjson,0) -// basilisk_bitcoinrawtx(myinfo,rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V) +// - basilisk_sendrawtransaction(coin,signedtx); +// - basilisk_value(rawtx->coin,0,0,myinfo->myaddr.persistent,argjson,0) +// basilisk_bitcoinrawtx(rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V) // included from basilisk.c @@ -120,1209 +118,33 @@ */ -int32_t basilisk_istrustedbob(struct supernet_info *myinfo,struct basilisk_swap *swap) -{ - // for BTC and if trusted LP - return(0); -} - -struct basilisk_rawtx *basilisk_swapdata_rawtx(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx) -{ - if ( rawtx->I.datalen != 0 && rawtx->I.datalen <= maxlen ) - { - memcpy(data,rawtx->txbytes,rawtx->I.datalen); - return(rawtx); - } - return(0); -} - -int32_t basilisk_verify_otherfee(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) -{ - struct basilisk_swap *swap = ptr; - // add verification and broadcast - //swap->otherfee.txbytes = calloc(1,datalen); - memcpy(swap->otherfee.txbytes,data,datalen); - swap->otherfee.I.datalen = datalen; - swap->otherfee.I.actualtxid = swap->otherfee.I.signedtxid = bits256_doublesha256(0,data,datalen); - basilisk_txlog(myinfo,swap,&swap->otherfee,-1); - return(0); -} - -int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) -{ - int32_t datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; bits256 txid; - datalen = recvbuf[0]; - datalen += (int32_t)recvbuf[1] << 8; - if ( datalen > 65536 ) - return(-1); - rawtx->I.redeemlen = recvbuf[2]; - data = &recvbuf[3]; - if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) - memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); - //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); - if ( rawtx->I.datalen == 0 ) - { - //rawtx->txbytes = calloc(1,datalen); - memcpy(rawtx->txbytes,data,datalen); - rawtx->I.datalen = datalen; - } - else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) - { - int32_t i; for (i=0; iI.datalen; i++) - printf("%02x",rawtx->txbytes[i]); - printf(" <- rawtx\n"); - printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); - return(-1); - } - txid = bits256_doublesha256(0,data,datalen); - char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); - if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) - rawtx->I.actualtxid = txid; - if ( (txobj= bitcoin_data2json(rawtx->coin,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) - { - rawtx->I.actualtxid = rawtx->I.signedtxid; - //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,rawtx->signedtxid),jprint(txobj,0)); - rawtx->I.locktime = rawtx->msgtx.lock_time; - if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) - { - vout = jitem(vouts,v); - if ( j64bits(vout,"satoshis") == rawtx->I.amount && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) - { - if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) - { - decode_hex(rawtx->spendscript,hexlen,hexstr); - rawtx->I.spendlen = hexlen; - bitcoin_address(rawtx->p2shaddr,rawtx->coin->chain->p2shtype,rawtx->spendscript,hexlen); - if ( swap != 0 ) - basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment - retval = 0; - } - } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); - } - free_json(txobj); - } - return(retval); -} - -void basilisk_swap_coinaddr(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) -{ - cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; - if ( (txobj= bitcoin_data2json(coin,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) - { - //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); - if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) - { - vout = jitem(vouts,0); - //printf("VOUT.(%s)\n",jprint(vout,0)); - if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) - { - item = jitem(addresses,0); - //printf("item.(%s)\n",jprint(item,0)); - if ( (addr= jstr(item,0)) != 0 ) - { - safecopy(coinaddr,addr,64); - //printf("extracted.(%s)\n",coinaddr); - } - } - } - free_json(txobj); - } -} - -int32_t basilisk_swapuserdata(uint8_t *userdata,bits256 privkey,int32_t ifpath,bits256 signpriv,uint8_t *redeemscript,int32_t redeemlen) -{ - int32_t i,len = 0; -#ifdef DISABLE_CHECKSIG - userdata[len++] = sizeof(signpriv); - for (i=0; i if path, 0 -> else path - return(len); -} - -/* Bob deposit: - OP_IF - OP_CLTV OP_DROP OP_CHECKSIG - OP_ELSE - OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG - OP_ENDIF*/ - -void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,int32_t scriptlen) -{ - int32_t i; char scriptstr[513]; - if ( scriptlen != 0 ) - { - for (i=0; iI.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); - coinaddr[0] = secretAmstr[0] = secretAm256str[0] = secretBnstr[0] = secretBn256str[0] = 0; - memset(zeroes,0,sizeof(zeroes)); - if ( rawtx != 0 && (fp= fopen(fname,"wb")) != 0 ) - { - fprintf(fp,"{\"name\":\"%s\",\"coin\":\"%s\"",rawtx->name,rawtx->coin->symbol); - if ( rawtx->I.datalen > 0 ) - { - fprintf(fp,",\"tx\":\""); - for (i=0; iI.datalen; i++) - fprintf(fp,"%02x",rawtx->txbytes[i]); - fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); - if ( rawtx == &swap->bobdeposit || rawtx == &swap->bobpayment ) - { - basilisk_swap_coinaddr(myinfo,swap,swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); - if ( coinaddr[0] != 0 ) - { - if ( swap->bobcoin != 0 && swap->bobcoin->FULLNODE < 0 ) - { - if ( (tmp= dpow_importaddress(myinfo,swap->bobcoin,coinaddr)) != 0 ) - free(tmp); - } - if ( rawtx == &swap->bobdeposit ) - safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); - else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); - } - } - } - if ( swap->Bdeposit[0] != 0 ) - fprintf(fp,",\"%s\":\"%s\"","Bdeposit",swap->Bdeposit); - if ( swap->Bpayment[0] != 0 ) - fprintf(fp,",\"%s\":\"%s\"","Bpayment",swap->Bpayment); - fprintf(fp,",\"expiration\":%u",swap->I.expiration); - fprintf(fp,",\"iambob\":%d",swap->I.iambob); - fprintf(fp,",\"bobcoin\":\"%s\"",swap->bobcoin->symbol); - fprintf(fp,",\"alicecoin\":\"%s\"",swap->alicecoin->symbol); - fprintf(fp,",\"lock\":%u",locktime); - fprintf(fp,",\"amount\":%.8f",dstr(rawtx->I.amount)); - if ( bits256_nonz(triggertxid) != 0 ) - fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); - if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) - { - basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); - if ( swap->alicecoin != 0 && swap->alicecoin->FULLNODE < 0 ) - { - if ( (tmp= dpow_importaddress(myinfo,swap->alicecoin,coinaddr)) != 0 ) - free(tmp); - } - fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); - } - /*basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); - basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); - basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); - basilisk_dontforget_userdata("Bspend",fp,swap->I.userdata_bobspend,swap->I.userdata_bobspendlen); - basilisk_dontforget_userdata("Breclaim",fp,swap->I.userdata_bobreclaim,swap->I.userdata_bobreclaimlen); - basilisk_dontforget_userdata("Brefund",fp,swap->I.userdata_bobrefund,swap->I.userdata_bobrefundlen);*/ - fprintf(fp,"}\n"); - fclose(fp); - } - sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); - if ( (fp= fopen(fname,"wb")) != 0 ) - { - fprintf(fp,"{\"src\":\"%s\",\"srcamount\":%.8f,\"dest\":\"%s\",\"destamount\":%.8f,\"requestid\":%u,\"quoteid\":%u,\"iambob\":%d,\"state\":%u,\"otherstate\":%u,\"expiration\":%u,\"dlocktime\":%u,\"plocktime\":%u",swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.requestid,swap->I.req.quoteid,swap->I.iambob,swap->I.statebits,swap->I.otherstatebits,swap->I.expiration,swap->bobdeposit.I.locktime,swap->bobpayment.I.locktime); - if ( memcmp(zeroes,swap->I.secretAm,20) != 0 ) - { - init_hexbytes_noT(secretAmstr,swap->I.secretAm,20); - fprintf(fp,",\"secretAm\":\"%s\"",secretAmstr); - } - if ( memcmp(zeroes,swap->I.secretAm256,32) != 0 ) - { - init_hexbytes_noT(secretAm256str,swap->I.secretAm256,32); - fprintf(fp,",\"secretAm256\":\"%s\"",secretAm256str); - } - if ( memcmp(zeroes,swap->I.secretBn,20) != 0 ) - { - init_hexbytes_noT(secretBnstr,swap->I.secretBn,20); - fprintf(fp,",\"secretBn\":\"%s\"",secretBnstr); - } - if ( memcmp(zeroes,swap->I.secretBn256,32) != 0 ) - { - init_hexbytes_noT(secretBn256str,swap->I.secretBn256,32); - fprintf(fp,",\"secretBn256\":\"%s\"",secretBn256str); - } - for (i=0; i<2; i++) - if ( bits256_nonz(swap->I.myprivs[i]) != 0 ) - fprintf(fp,",\"myprivs%d\":\"%s\"",i,bits256_str(str,swap->I.myprivs[i])); - if ( bits256_nonz(swap->I.privAm) != 0 ) - fprintf(fp,",\"privAm\":\"%s\"",bits256_str(str,swap->I.privAm)); - if ( bits256_nonz(swap->I.privBn) != 0 ) - fprintf(fp,",\"privBn\":\"%s\"",bits256_str(str,swap->I.privBn)); - if ( bits256_nonz(swap->I.pubA0) != 0 ) - fprintf(fp,",\"pubA0\":\"%s\"",bits256_str(str,swap->I.pubA0)); - if ( bits256_nonz(swap->I.pubB0) != 0 ) - fprintf(fp,",\"pubB0\":\"%s\"",bits256_str(str,swap->I.pubB0)); - if ( bits256_nonz(swap->I.pubB1) != 0 ) - fprintf(fp,",\"pubB1\":\"%s\"",bits256_str(str,swap->I.pubB1)); - if ( bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) - fprintf(fp,",\"Bdeposit\":\"%s\"",bits256_str(str,swap->bobdeposit.I.actualtxid)); - if ( bits256_nonz(swap->bobrefund.I.actualtxid) != 0 ) - fprintf(fp,",\"Brefund\":\"%s\"",bits256_str(str,swap->bobrefund.I.actualtxid)); - if ( bits256_nonz(swap->aliceclaim.I.actualtxid) != 0 ) - fprintf(fp,",\"Aclaim\":\"%s\"",bits256_str(str,swap->aliceclaim.I.actualtxid)); - - if ( bits256_nonz(swap->bobpayment.I.actualtxid) != 0 ) - fprintf(fp,",\"Bpayment\":\"%s\"",bits256_str(str,swap->bobpayment.I.actualtxid)); - if ( bits256_nonz(swap->alicespend.I.actualtxid) != 0 ) - fprintf(fp,",\"Aspend\":\"%s\"",bits256_str(str,swap->alicespend.I.actualtxid)); - if ( bits256_nonz(swap->bobreclaim.I.actualtxid) != 0 ) - fprintf(fp,",\"Breclaim\":\"%s\"",bits256_str(str,swap->bobreclaim.I.actualtxid)); - - if ( bits256_nonz(swap->alicepayment.I.actualtxid) != 0 ) - fprintf(fp,",\"Apayment\":\"%s\"",bits256_str(str,swap->alicepayment.I.actualtxid)); - if ( bits256_nonz(swap->bobspend.I.actualtxid) != 0 ) - fprintf(fp,",\"Bspend\":\"%s\"",bits256_str(str,swap->bobspend.I.actualtxid)); - if ( bits256_nonz(swap->alicereclaim.I.actualtxid) != 0 ) - fprintf(fp,",\"Areclaim\":\"%s\"",bits256_str(str,swap->alicereclaim.I.actualtxid)); - - if ( bits256_nonz(swap->otherfee.I.actualtxid) != 0 ) - fprintf(fp,",\"otherfee\":\"%s\"",bits256_str(str,swap->otherfee.I.actualtxid)); - if ( bits256_nonz(swap->myfee.I.actualtxid) != 0 ) - fprintf(fp,",\"myfee\":\"%s\"",bits256_str(str,swap->myfee.I.actualtxid)); - fprintf(fp,",\"dest33\":\""); - for (i=0; i<33; i++) - fprintf(fp,"%02x",swap->persistent_pubkey33[i]); - fprintf(fp,"\"}\n"); - fclose(fp); - } -} - -void basilisk_dontforget_update(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) -{ - bits256 triggertxid; - memset(triggertxid.bytes,0,sizeof(triggertxid)); - if ( rawtx == 0 ) - { - basilisk_dontforget(myinfo,swap,0,0,triggertxid); - return; - } - if ( rawtx == &swap->myfee ) - basilisk_dontforget(myinfo,swap,&swap->myfee,0,triggertxid); - else if ( rawtx == &swap->otherfee ) - basilisk_dontforget(myinfo,swap,&swap->otherfee,0,triggertxid); - else if ( rawtx == &swap->bobdeposit ) - { - basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); - } - else if ( rawtx == &swap->bobrefund ) - basilisk_dontforget(myinfo,swap,&swap->bobrefund,swap->bobdeposit.I.locktime,triggertxid); - else if ( rawtx == &swap->aliceclaim ) - { - basilisk_dontforget(myinfo,swap,&swap->bobrefund,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->aliceclaim,0,swap->bobrefund.I.actualtxid); - } - else if ( rawtx == &swap->alicepayment ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - } - else if ( rawtx == &swap->bobspend ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - basilisk_dontforget(myinfo,swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid); - } - else if ( rawtx == &swap->alicereclaim ) - { - basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid); - basilisk_dontforget(myinfo,swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid); - } - else if ( rawtx == &swap->bobpayment ) - { - basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); - } - else if ( rawtx == &swap->alicespend ) - { - basilisk_dontforget(myinfo,swap,&swap->bobpayment,0,triggertxid); - basilisk_dontforget(myinfo,swap,&swap->alicespend,0,triggertxid); - } - else if ( rawtx == &swap->bobreclaim ) - basilisk_dontforget(myinfo,swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); -} - -int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) -{ - uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; - if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) - { - swap->bobdeposit.I.signedtxid = basilisk_swap_broadcast(swap->bobdeposit.name,myinfo,swap,swap->bobdeposit.coin,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); - if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) - swap->depositunconf = 1; - basilisk_dontforget_update(myinfo,swap,&swap->bobdeposit); - len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); - memcpy(swap->I.userdata_aliceclaim,userdata,len); - swap->I.userdata_aliceclaimlen = len; - if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) - { - for (i=0; ibobdeposit.I.datalen; i++) - printf("%02x",swap->bobdeposit.txbytes[i]); - printf(" <- bobdeposit\n"); - for (i=0; ialiceclaim.I.datalen; i++) - printf("%02x",swap->aliceclaim.txbytes[i]); - printf(" <- aliceclaim\n"); - basilisk_txlog(myinfo,swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); - return(retval); - } - } - printf("error with bobdeposit\n"); - return(-1); -} - -int32_t basilisk_bobdeposit_refund(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t delay) -{ - uint8_t userdata[512]; int32_t i,retval,len = 0; char str[65]; - len = basilisk_swapuserdata(userdata,swap->I.privBn,0,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); - memcpy(swap->I.userdata_bobrefund,userdata,len); - swap->I.userdata_bobrefundlen = len; - if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0)) == 0 ) - { - for (i=0; ibobrefund.I.datalen; i++) - printf("%02x",swap->bobrefund.txbytes[i]); - printf(" <- bobrefund.(%s)\n",bits256_str(str,swap->bobrefund.I.txid)); - basilisk_txlog(myinfo,swap,&swap->bobrefund,delay); - return(retval); - } - return(-1); -} - -/*Bob paytx: - OP_IF - OP_CLTV OP_DROP OP_CHECKSIG - OP_ELSE - OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG - OP_ENDIF*/ - -int32_t basilisk_bobpayment_reclaim(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t delay) -{ - uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; - printf("basilisk_bobpayment_reclaim\n"); - len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); - memcpy(swap->I.userdata_bobreclaim,userdata,len); - swap->I.userdata_bobreclaimlen = len; - if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1)) == 0 ) - { - for (i=0; ibobreclaim.I.datalen; i++) - printf("%02x",swap->bobreclaim.txbytes[i]); - printf(" <- bobreclaim\n"); - basilisk_txlog(myinfo,swap,&swap->bobreclaim,delay); - return(retval); - } - return(-1); -} - -int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) -{ - uint8_t userdata[512]; int32_t i,retval,len = 0; bits256 revAm; struct basilisk_swap *swap = ptr; - memset(revAm.bytes,0,sizeof(revAm)); - if ( basilisk_rawtx_spendscript(swap,swap->bobcoin->longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) - { - swap->bobpayment.I.signedtxid = basilisk_swap_broadcast(swap->bobpayment.name,myinfo,swap,swap->bobpayment.coin,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); - if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) - swap->paymentunconf = 1; - basilisk_dontforget_update(myinfo,swap,&swap->bobpayment); - for (i=0; i<32; i++) - revAm.bytes[i] = swap->I.privAm.bytes[31-i]; - len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); - memcpy(swap->I.userdata_alicespend,userdata,len); - swap->I.userdata_alicespendlen = len; - char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); - if ( (retval= basilisk_rawtx_sign(myinfo,swap->bobcoin->longestchain,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) - { - for (i=0; ibobpayment.I.datalen; i++) - printf("%02x",swap->bobpayment.txbytes[i]); - printf(" <- bobpayment\n"); - for (i=0; ialicespend.I.datalen; i++) - printf("%02x",swap->alicespend.txbytes[i]); - printf(" <- alicespend\n\n"); - swap->I.alicespent = 1; - basilisk_txlog(myinfo,swap,&swap->alicespend,-1); - return(retval); - } - } - return(-1); -} - -void basilisk_alicepayment(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) -{ - alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->chain->p2shtype,pubAm,pubBn); - basilisk_rawtx_gen("alicepayment",myinfo,swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->chain->txfee,1,0); -} - -int32_t basilisk_alicepayment_spend(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *dest) -{ - int32_t i,retval; - printf("alicepayment_spend\n"); - swap->alicepayment.I.spendlen = basilisk_alicescript(swap->alicepayment.redeemscript,&swap->alicepayment.I.redeemlen,swap->alicepayment.spendscript,0,swap->alicepayment.I.destaddr,swap->alicecoin->chain->p2shtype,swap->I.pubAm,swap->I.pubBn); - printf("alicepayment_spend len.%d\n",swap->alicepayment.I.spendlen); - if ( swap->I.iambob == 0 ) - { - memcpy(swap->I.userdata_alicereclaim,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); - swap->I.userdata_alicereclaimlen = swap->alicepayment.I.spendlen; - } - else - { - memcpy(swap->I.userdata_bobspend,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); - swap->I.userdata_bobspendlen = swap->alicepayment.I.spendlen; - } - if ( (retval= basilisk_rawtx_sign(myinfo,swap->alicecoin->longestchain,swap,dest,&swap->alicepayment,swap->I.privAm,&swap->I.privBn,0,0,1)) == 0 ) - { - for (i=0; iI.datalen; i++) - printf("%02x",dest->txbytes[i]); - printf(" <- msigspend\n\n"); - if ( dest == &swap->bobspend ) - swap->I.bobspent = 1; - basilisk_txlog(myinfo,swap,dest,0); // bobspend or alicereclaim - return(retval); - } - return(-1); -} - -int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) -{ - struct basilisk_swap *swap = ptr; - if ( basilisk_rawtx_spendscript(swap,swap->alicecoin->longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) - { - swap->alicepayment.I.signedtxid = basilisk_swap_broadcast(swap->alicepayment.name,myinfo,swap,swap->alicepayment.coin,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); - if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) - swap->aliceunconf = 1; - basilisk_dontforget_update(myinfo,swap,&swap->alicepayment); - return(0); - } - else return(-1); -} - -int32_t basilisk_verify_pubpair(int32_t *wrongfirstbytep,struct basilisk_swap *swap,int32_t ind,uint8_t pub0,bits256 pubi,uint64_t txid) -{ - if ( pub0 != (swap->I.iambob ^ 1) + 0x02 ) - { - (*wrongfirstbytep)++; - printf("wrongfirstbyte[%d] %02x\n",ind,pub0); - return(-1); - } - else if ( swap->otherdeck[ind][1] != pubi.txid ) - { - printf("otherdeck[%d] priv ->pub mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][1],(long long)pubi.txid); - return(-1); - } - else if ( swap->otherdeck[ind][0] != txid ) - { - printf("otherdeck[%d] priv mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][0],(long long)txid); - return(-1); - } - return(0); -} - -int32_t basilisk_bobscripts_set(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) -{ - int32_t i,j; //char str[65]; - if ( genflag != 0 && swap->I.iambob == 0 ) - printf("basilisk_bobscripts_set WARNING: alice generating BOB tx\n"); - if ( depositflag == 0 ) - { - swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); - bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); - //for (i=0; ibobpayment.redeemlen; i++) - // printf("%02x",swap->bobpayment.redeemscript[i]); - //printf(" <- bobpayment.%d\n",i); - if ( genflag != 0 && bits256_nonz(*(bits256 *)swap->I.secretBn256) != 0 && swap->bobpayment.I.datalen == 0 ) - { - for (i=0; i<3; i++) - { - //if ( swap->bobpayment.txbytes != 0 && swap->bobpayment.I.spendlen != 0 ) - // break; - basilisk_rawtx_gen("payment",myinfo,swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->chain->txfee,1,0); - if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) - { - printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); - sleep(DEX_SLEEP); - } - else - { - for (j=0; jbobpayment.I.datalen; j++) - printf("%02x",swap->bobpayment.txbytes[j]); - //printf(" <- bobpayment.%d\n",swap->bobpayment.datalen); - //for (j=0; jbobpayment.redeemlen; j++) - // printf("%02x",swap->bobpayment.redeemscript[j]); - //printf(" <- redeem.%d\n",swap->bobpayment.redeemlen); - printf(" <- GENERATED BOB PAYMENT.%d\n",swap->bobpayment.I.datalen); - iguana_unspents_mark(myinfo,swap->bobcoin,swap->bobpayment.vins); - basilisk_bobpayment_reclaim(myinfo,swap,swap->I.callduration); - printf("bobscripts set completed\n"); - return(0); - } - } - } - } - else - { - swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); - bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin->chain->p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); - if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) - { - for (i=0; i<3; i++) - { - //if ( swap->bobdeposit.txbytes != 0 && swap->bobdeposit.I.spendlen != 0 ) - // break; - basilisk_rawtx_gen("deposit",myinfo,swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->chain->txfee,1,0); - if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) - { - printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); - sleep(DEX_SLEEP); - } - else - { - for (j=0; jbobdeposit.I.datalen; j++) - printf("%02x",swap->bobdeposit.txbytes[j]); - printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); - //for (j=0; jbobdeposit.redeemlen; j++) - // printf("%02x",swap->bobdeposit.redeemscript[j]); - //printf(" <- redeem.%d\n",swap->bobdeposit.redeemlen); - //printf("GENERATED BOB DEPOSIT\n"); - iguana_unspents_mark(myinfo,swap->bobcoin,swap->bobdeposit.vins); - basilisk_bobdeposit_refund(myinfo,swap,swap->I.putduration); - printf("bobscripts set completed\n"); - return(0); - } - } - } - //for (i=0; ibobdeposit.redeemlen; i++) - // printf("%02x",swap->bobdeposit.redeemscript[i]); - //printf(" <- bobdeposit.%d\n",i); - } - return(0); -} - -int32_t basilisk_verify_privi(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) -{ - int32_t j,wrongfirstbyte,len = 0; bits256 privkey,pubi; char str[65],str2[65]; uint8_t secret160[20],pubkey33[33]; uint64_t txid; struct basilisk_swap *swap = ptr; - memset(privkey.bytes,0,sizeof(privkey)); - if ( datalen == sizeof(bits256) ) - { - for (j=0; j<32; j++) - privkey.bytes[j] = data[len++]; - revcalc_rmd160_sha256(secret160,privkey);//.bytes,sizeof(privkey)); - memcpy(&txid,secret160,sizeof(txid)); - pubi = bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); - if ( basilisk_verify_pubpair(&wrongfirstbyte,swap,swap->I.choosei,pubkey33[0],pubi,txid) == 0 ) - { - if ( swap->I.iambob != 0 ) - { - swap->I.privAm = privkey; - vcalc_sha256(0,swap->I.secretAm256,privkey.bytes,sizeof(privkey)); - printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); - basilisk_bobscripts_set(myinfo,swap,0,1); - } - else - { - swap->I.privBn = privkey; - vcalc_sha256(0,swap->I.secretBn256,privkey.bytes,sizeof(privkey)); - printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); - } - basilisk_dontforget_update(myinfo,swap,0); - char str[65]; printf("privi verified.(%s)\n",bits256_str(str,privkey)); - return(0); - } - } - return(-1); -} - -int32_t basilisk_process_swapverify(struct supernet_info *myinfo,void *ptr,int32_t (*internal_func)(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen),uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen,uint32_t expiration,uint32_t duration) -{ - struct basilisk_swap *swap = ptr; - if ( internal_func != 0 ) - return((*internal_func)(myinfo,swap,data,datalen)); - else return(0); -} - -void basilisk_swapgotdata(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t crc32,bits256 srchash,bits256 desthash,uint32_t quoteid,uint32_t msgbits,uint8_t *data,int32_t datalen,int32_t reinit) -{ - int32_t i; struct basilisk_swapmessage *mp; - for (i=0; inummessages; i++) - if ( crc32 == swap->messages[i].crc32 && msgbits == swap->messages[i].msgbits && bits256_cmp(srchash,swap->messages[i].srchash) == 0 && bits256_cmp(desthash,swap->messages[i].desthash) == 0 ) - return; - //printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); - swap->messages = realloc(swap->messages,sizeof(*swap->messages) * (swap->nummessages + 1)); - mp = &swap->messages[swap->nummessages++]; - mp->crc32 = crc32; - mp->srchash = srchash; - mp->desthash = desthash; - mp->msgbits = msgbits; - mp->quoteid = quoteid; - mp->data = malloc(datalen); - mp->datalen = datalen; - memcpy(mp->data,data,datalen); - if ( reinit == 0 && swap->fp != 0 ) - { - fwrite(mp,1,sizeof(*mp),swap->fp); - fwrite(data,1,datalen,swap->fp); - fflush(swap->fp); - } -} - -FILE *basilisk_swap_save(struct supernet_info *myinfo,struct basilisk_swap *swap,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) -{ - FILE *fp=0; /*char fname[512]; - sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,rp->requestid,rp->quoteid), OS_compatible_path(fname); - if ( (fp= fopen(fname,"rb+")) == 0 ) - { - if ( (fp= fopen(fname,"wb+")) != 0 ) - { - fwrite(privkey.bytes,1,sizeof(privkey),fp); - fwrite(rp,1,sizeof(*rp),fp); - fwrite(&statebits,1,sizeof(statebits),fp); - fwrite(&optionduration,1,sizeof(optionduration),fp); - fflush(fp); - } - } - else if ( reinit != 0 ) - { - }*/ - return(fp); -} - -int32_t basilisk_swap_load(uint32_t requestid,uint32_t quoteid,bits256 *privkeyp,struct basilisk_request *rp,uint32_t *statebitsp,int32_t *optiondurationp) -{ - FILE *fp=0; char fname[512]; int32_t retval = -1; - sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); - if ( (fp= fopen(fname,"rb+")) != 0 ) - { - if ( fread(privkeyp,1,sizeof(*privkeyp),fp) == sizeof(*privkeyp) && - fread(rp,1,sizeof(*rp),fp) == sizeof(*rp) && - fread(statebitsp,1,sizeof(*statebitsp),fp) == sizeof(*statebitsp) && - fread(optiondurationp,1,sizeof(*optiondurationp),fp) == sizeof(*optiondurationp) ) - retval = 0; - fclose(fp); - } - return(retval); -} - -struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit); - -void basilisk_swaps_init(struct supernet_info *myinfo) -{ - char fname[512]; uint32_t iter,swapcompleted,requestid,quoteid,optionduration,statebits; FILE *fp; bits256 privkey;struct basilisk_request R; struct basilisk_swapmessage M; struct basilisk_swap *swap = 0; - sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); - if ( (myinfo->swapsfp= fopen(fname,"rb+")) != 0 ) - { - while ( fread(&requestid,1,sizeof(requestid),myinfo->swapsfp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),myinfo->swapsfp) == sizeof(quoteid) ) - { - sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); - printf("%s\n",fname); - if ( (fp= fopen(fname,"rb+")) != 0 ) // check to see if completed - { - memset(&M,0,sizeof(M)); - swapcompleted = 1; - for (iter=0; iter<2; iter++) - { - if ( fread(privkey.bytes,1,sizeof(privkey),fp) == sizeof(privkey) && - fread(&R,1,sizeof(R),fp) == sizeof(R) && - fread(&statebits,1,sizeof(statebits),fp) == sizeof(statebits) && - fread(&optionduration,1,sizeof(optionduration),fp) == sizeof(optionduration) ) - { - while ( 0 && fread(&M,1,sizeof(M),fp) == sizeof(M) ) - { - M.data = 0; - //printf("entry iter.%d crc32.%x datalen.%d\n",iter,M.crc32,M.datalen); - if ( M.datalen < 100000 ) - { - M.data = malloc(M.datalen); - if ( fread(M.data,1,M.datalen,fp) == M.datalen ) - { - if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) - { - if ( iter == 1 ) - { - if ( swap == 0 ) - { - swap = basilisk_thread_start(myinfo,privkey,&R,statebits,optionduration,1); - swap->I.choosei = swap->I.otherchoosei = -1; - } - if ( swap != 0 ) - basilisk_swapgotdata(myinfo,swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); - } - } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); - } else printf("error reading M.datalen %d\n",M.datalen); - free(M.data), M.data = 0; - } - } - } - if ( swapcompleted != 0 ) - break; - rewind(fp); - } - } - } - } else myinfo->swapsfp = fopen(fname,"wb+"); -} - -void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t amlp); - -int32_t basilisk_swapget(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen)) -{ - uint8_t *ptr; bits256 srchash,desthash; uint32_t crc32,_msgbits,quoteid; int32_t i,size,offset,retval = -1; struct basilisk_swapmessage *mp = 0; - while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,0)) >= 0 ) - { - swap->lasttime = (uint32_t)time(NULL); - memset(srchash.bytes,0,sizeof(srchash)); - memset(desthash.bytes,0,sizeof(desthash)); - //printf("gotmsg.[%d] crc.%x\n",size,crc32); - offset = 0; - for (i=0; i<32; i++) - srchash.bytes[i] = ptr[offset++]; - for (i=0; i<32; i++) - desthash.bytes[i] = ptr[offset++]; - offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),"eid); - offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),&_msgbits); - if ( size > offset ) - { - crc32 = calc_crc32(0,&ptr[offset],size-offset); - if ( size > offset ) - { - //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); - basilisk_swapgotdata(myinfo,swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); - } - } - else if ( bits256_nonz(srchash) == 0 && bits256_nonz(desthash) == 0 ) - { - if ( swap->aborted == 0 ) - { - swap->aborted = (uint32_t)time(NULL); - printf("got abort signal from other side\n"); - } - } else printf("basilisk_swapget: got strange packet\n"); - if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0; - } - //char str[65],str2[65]; - for (i=0; inummessages; i++) - { - //printf("%d: %s vs %s\n",i,bits256_str(str,swap->messages[i].srchash),bits256_str(str2,swap->messages[i].desthash)); - if ( bits256_cmp(swap->messages[i].desthash,swap->I.myhash) == 0 ) - { - if ( swap->messages[i].msgbits == msgbits ) - { - if ( swap->I.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) - { - printf("nothing received for a while from Bob, try new sockets\n"); - if ( swap->pushsock >= 0 ) // - nn_close(swap->pushsock), swap->pushsock = -1; - if ( swap->subsock >= 0 ) // - nn_close(swap->subsock), swap->subsock = -1; - swap->connected = 0; - basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); - } - mp = &swap->messages[i]; - if ( msgbits != 0x80000000 ) - break; - } - } - } - if ( mp != 0 ) - retval = (*basilisk_verify_func)(myinfo,swap,mp->data,mp->datalen); - //printf("mine/other %s vs %s\n",bits256_str(str,swap->I.myhash),bits256_str(str2,swap->I.otherhash)); - return(retval); -} - -uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits,uint32_t crcs[2]) -{ - uint8_t *buf; int32_t sentbytes,offset=0,i; - buf = malloc(datalen + sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2); - for (i=0; i<32; i++) - buf[offset++] = swap->I.myhash.bytes[i]; - for (i=0; i<32; i++) - buf[offset++] = swap->I.otherhash.bytes[i]; - offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); - offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); - if ( datalen > 0 ) - memcpy(&buf[offset],data,datalen), offset += datalen; - if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) - { - printf("sentbytes.%d vs offset.%d\n",sentbytes,offset); - if ( sentbytes < 0 ) - { - if ( swap->pushsock >= 0 ) - nn_close(swap->pushsock), swap->pushsock = -1; //, - if ( swap->subsock >= 0 ) // - nn_close(swap->subsock), swap->subsock = -1; - swap->connected = swap->I.iambob != 0 ? -1 : 0; - swap->aborted = (uint32_t)time(NULL); - } - } - //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); - free(buf); - return(nextbits); -} - -void basilisk_swap_sendabort(struct supernet_info *myinfo,struct basilisk_swap *swap) -{ - uint32_t msgbits = 0; uint8_t buf[sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2]; int32_t sentbytes,offset=0; - memset(buf,0,sizeof(buf)); - offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); - offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); - if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) - { - if ( sentbytes < 0 ) - { - if ( swap->pushsock >= 0 ) // - nn_close(swap->pushsock), swap->pushsock = -1; - if ( swap->subsock >= 0 ) // - nn_close(swap->subsock), swap->subsock = -1; - swap->connected = 0; - } - } else printf("basilisk_swap_sendabort\n"); -} - -int32_t basilisk_privBn_extract(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) -{ - if ( basilisk_priviextract(myinfo,swap->bobcoin,"privBn",&swap->I.privBn,swap->I.secretBn,swap->bobrefund.I.actualtxid,0) == 0 ) - { - printf("extracted privBn from blockchain\n"); - } - else if ( basilisk_swapget(myinfo,swap,0x40000000,data,maxlen,basilisk_verify_privi) == 0 ) - { - } - if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) - { - char str[65]; printf("got privBn.%s\n",bits256_str(str,swap->I.privBn)); - return(basilisk_alicepayment_spend(myinfo,swap,&swap->alicereclaim)); - } - return(-1); -} - -int32_t basilisk_privAm_extract(struct supernet_info *myinfo,struct basilisk_swap *swap) -{ - if ( basilisk_priviextract(myinfo,swap->bobcoin,"privAm",&swap->I.privAm,swap->I.secretAm,swap->bobpayment.I.actualtxid,0) == 0 ) - { - printf("extracted privAm from blockchain\n"); - } - if ( bits256_nonz(swap->I.privAm) != 0 && swap->bobspend.I.datalen == 0 ) - { - char str[65]; printf("got privAm.%s\n",bits256_str(str,swap->I.privAm)); - return(basilisk_alicepayment_spend(myinfo,swap,&swap->bobspend)); - } - return(-1); -} - -bits256 instantdex_derivekeypair(void *ctx,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash) -{ - bits256 sharedsecret; - sharedsecret = curve25519_shared(privkey,orderhash); - vcalc_sha256cat(newprivp->bytes,orderhash.bytes,sizeof(orderhash),sharedsecret.bytes,sizeof(sharedsecret)); - return(bitcoin_pubkey33(ctx,pubkey,*newprivp)); -} - -int32_t instantdex_pubkeyargs(void *ctx,struct basilisk_swap *swap,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte) -{ - char buf[3]; int32_t i,n,m,len=0; bits256 pubi,reveal; uint64_t txid; uint8_t secret160[20],pubkey[33]; - sprintf(buf,"%c0",'A' - 0x02 + firstbyte); - if ( numpubs > 2 ) - { - if ( swap->I.numpubs+2 >= numpubs ) - return(numpubs); - //fprintf(stderr,">>>>>> start generating %s\n",buf); - } - for (i=n=m=0; iI.mypubs[n]) == 0 ) - { - swap->I.myprivs[n] = privkey; - memcpy(swap->I.mypubs[n].bytes,pubkey+1,sizeof(bits256)); - reveal = basilisk_revealkey(privkey,swap->I.mypubs[n]); - if ( swap->I.iambob != 0 ) - { - if ( n == 0 ) - swap->I.pubB0 = reveal; - else if ( n == 1 ) - swap->I.pubB1 = reveal; - } - else if ( swap->I.iambob == 0 ) - { - if ( n == 0 ) - swap->I.pubA0 = reveal; - else if ( n == 1 ) - swap->I.pubA1 = reveal; - } - } - } - if ( m < INSTANTDEX_DECKSIZE ) - { - swap->privkeys[m] = privkey; - revcalc_rmd160_sha256(secret160,privkey);//.bytes,sizeof(privkey)); - memcpy(&txid,secret160,sizeof(txid)); - len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][0],sizeof(txid),&txid); - len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][1],sizeof(pubi.txid),&pubi.txid); - m++; - if ( m > swap->I.numpubs ) - swap->I.numpubs = m; - } - n++; - } - if ( n > 2 || m > 2 ) - printf("n.%d m.%d len.%d numpubs.%d\n",n,m,len,swap->I.numpubs); - return(n); -} - -void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx *rawtx,struct iguana_info *coin,int32_t numconfirms,int32_t vintype,uint64_t satoshis,int32_t vouttype,uint8_t *pubkey33,int32_t jumblrflag) -{ - strcpy(rawtx->name,name); - rawtx->coin = coin; - strcpy(rawtx->I.coinstr,coin->symbol); - rawtx->I.numconfirms = numconfirms; - if ( (rawtx->I.amount= satoshis) < 50000 ) - rawtx->I.amount = 50000; - rawtx->I.vintype = vintype; // 0 -> std, 2 -> 2of2, 3 -> spend bobpayment, 4 -> spend bobdeposit - rawtx->I.vouttype = vouttype; // 0 -> fee, 1 -> std, 2 -> 2of2, 3 -> bobpayment, 4 -> bobdeposit - if ( rawtx->I.vouttype == 0 ) - { - if ( strcmp(coin->symbol,"BTC") == 0 && (quoteid % 10) == 0 ) - decode_hex(rawtx->I.rmd160,20,TIERNOLAN_RMD160); - else decode_hex(rawtx->I.rmd160,20,INSTANTDEX_RMD160); - bitcoin_address(rawtx->I.destaddr,rawtx->coin->chain->pubtype,rawtx->I.rmd160,20); - } - if ( pubkey33 != 0 ) - { - memcpy(rawtx->I.pubkey33,pubkey33,33); - bitcoin_address(rawtx->I.destaddr,rawtx->coin->chain->pubtype,rawtx->I.pubkey33,33); - bitcoin_addr2rmd160(&rawtx->I.addrtype,rawtx->I.rmd160,rawtx->I.destaddr); - } - if ( rawtx->I.vouttype <= 1 && rawtx->I.destaddr[0] != 0 ) - { - rawtx->I.spendlen = bitcoin_standardspend(rawtx->spendscript,0,rawtx->I.rmd160); - printf("%s spendlen.%d %s <- %.8f\n",name,rawtx->I.spendlen,rawtx->I.destaddr,dstr(rawtx->I.amount)); - } else printf("%s vouttype.%d destaddr.(%s)\n",name,rawtx->I.vouttype,rawtx->I.destaddr); -} int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct iguana_info **alicecoinp,char *src,char *dest,bits256 srchash,bits256 desthash) { - struct iguana_info *coin = iguana_coinfind(src); - if ( coin == 0 || iguana_coinfind(dest) == 0 ) + struct iguana_info *coin = LP_coinfind(src); + if ( coin == 0 || LP_coinfind(dest) == 0 ) return(0); *bobcoinp = *alicecoinp = 0; - *bobcoinp = iguana_coinfind(dest); - *alicecoinp = iguana_coinfind(src); + *bobcoinp = LP_coinfind(dest); + *alicecoinp = LP_coinfind(src); if ( bits256_cmp(pubkey,srchash) == 0 ) { if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) return(1); else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) - return(-1); - else return(0); - } - else if ( bits256_cmp(pubkey,desthash) == 0 ) - { - if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) - return(-1); - else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) - return(1); - else return(0); - } - return(0); -} - -void basilisk_swap_saveupdate(struct supernet_info *myinfo,struct basilisk_swap *swap) -{ - FILE *fp; char fname[512]; - sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); - if ( (fp= fopen(fname,"wb")) != 0 ) - { - fwrite(&swap->I,1,sizeof(swap->I),fp); - /*fwrite(&swap->bobdeposit,1,sizeof(swap->bobdeposit),fp); - fwrite(&swap->bobpayment,1,sizeof(swap->bobpayment),fp); - fwrite(&swap->alicepayment,1,sizeof(swap->alicepayment),fp); - fwrite(&swap->myfee,1,sizeof(swap->myfee),fp); - fwrite(&swap->otherfee,1,sizeof(swap->otherfee),fp); - fwrite(&swap->aliceclaim,1,sizeof(swap->aliceclaim),fp); - fwrite(&swap->alicespend,1,sizeof(swap->alicespend),fp); - fwrite(&swap->bobreclaim,1,sizeof(swap->bobreclaim),fp); - fwrite(&swap->bobspend,1,sizeof(swap->bobspend),fp); - fwrite(&swap->bobrefund,1,sizeof(swap->bobrefund),fp); - fwrite(&swap->alicereclaim,1,sizeof(swap->alicereclaim),fp);*/ - fwrite(swap->privkeys,1,sizeof(swap->privkeys),fp); - fwrite(swap->otherdeck,1,sizeof(swap->otherdeck),fp); - fwrite(swap->deck,1,sizeof(swap->deck),fp); - fclose(fp); - } -} - -int32_t basilisk_swap_loadtx(struct basilisk_rawtx *rawtx,FILE *fp,char *bobcoinstr,char *alicecoinstr) -{ - if ( fread(rawtx,1,sizeof(*rawtx),fp) == sizeof(*rawtx) ) - { - rawtx->coin = 0; - rawtx->vins = 0; - if ( strcmp(rawtx->I.coinstr,bobcoinstr) == 0 || strcmp(rawtx->I.coinstr,alicecoinstr) == 0 ) - { - rawtx->coin = iguana_coinfind(rawtx->I.coinstr); - if ( rawtx->vinstr[0] != 0 ) - rawtx->vins = cJSON_Parse(rawtx->vinstr); - printf("loaded.%s len.%d\n",rawtx->name,rawtx->I.datalen); - return(0); - } - } - return(-1); -} - -struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,bits256 privkey,uint8_t *pubkey33,bits256 pubkey25519,struct basilisk_swap *swap,int32_t optionduration,uint32_t statebits,int32_t reinit) -{ - FILE *fp; char fname[512]; uint8_t *alicepub33=0,*bobpub33=0; int32_t errs=0,jumblrflag,x = -1; - if ( reinit != 0 ) - { - sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); - printf("reinit.(%s)\n",fname); - if ( (fp= fopen(fname,"rb")) != 0 ) - { - if ( fread(&swap->I,1,sizeof(swap->I),fp) != sizeof(swap->I) ) - errs++; - if ( swap->bobcoin == 0 ) - swap->bobcoin = iguana_coinfind(swap->I.req.dest); - if ( swap->alicecoin == 0 ) - swap->alicecoin = iguana_coinfind(swap->I.req.src); - if ( swap->alicecoin != 0 && swap->bobcoin != 0 ) - { - /*basilisk_swap_loadtx(&swap->bobdeposit,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->bobpayment,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->alicepayment,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->myfee,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->otherfee,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->aliceclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->alicespend,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->bobreclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->bobspend,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->bobrefund,fp,swap->bobcoin->symbol,swap->alicecoin->symbol); - basilisk_swap_loadtx(&swap->alicereclaim,fp,swap->bobcoin->symbol,swap->alicecoin->symbol);*/ - } else printf("missing coins (%p %p)\n",swap->bobcoin,swap->alicecoin); - if ( fread(swap->privkeys,1,sizeof(swap->privkeys),fp) != sizeof(swap->privkeys) ) - errs++; - if ( fread(swap->otherdeck,1,sizeof(swap->otherdeck),fp) != sizeof(swap->otherdeck) ) - errs++; - if ( fread(swap->deck,1,sizeof(swap->deck),fp) != sizeof(swap->deck) ) - errs++; - fclose(fp); - } else printf("cant find.(%s)\n",fname); - } - else - { - swap->I.putduration = swap->I.callduration = INSTANTDEX_LOCKTIME; - if ( optionduration < 0 ) - swap->I.putduration -= optionduration; - else if ( optionduration > 0 ) - swap->I.callduration += optionduration; - swap->I.bobsatoshis = swap->I.req.destamount; - swap->I.alicesatoshis = swap->I.req.srcamount; - if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) - swap->I.bobinsurance = 50000; - if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) - swap->I.aliceinsurance = 50000; - strcpy(swap->I.bobstr,swap->I.req.dest); - strcpy(swap->I.alicestr,swap->I.req.src); - swap->I.started = (uint32_t)time(NULL); - swap->I.expiration = swap->I.req.timestamp + swap->I.putduration + swap->I.callduration; - OS_randombytes((uint8_t *)&swap->I.choosei,sizeof(swap->I.choosei)); - if ( swap->I.choosei < 0 ) - swap->I.choosei = -swap->I.choosei; - swap->I.choosei %= INSTANTDEX_DECKSIZE; - swap->I.otherchoosei = -1; - swap->I.myhash = pubkey25519; - if ( statebits != 0 ) - { - swap->I.iambob = 0; - swap->I.otherhash = swap->I.req.desthash; - } - else - { - swap->I.iambob = 1; - swap->I.otherhash = swap->I.req.srchash; - } - if ( bits256_nonz(privkey) == 0 || (x= instantdex_pubkeyargs(myinfo->ctx,swap,2 + INSTANTDEX_DECKSIZE,privkey,swap->I.orderhash,0x02+swap->I.iambob)) != 2 + INSTANTDEX_DECKSIZE ) - { - char str[65]; printf("couldnt generate privkeys %d %s\n",x,bits256_str(str,privkey)); - return(0); - } - } - swap->bobcoin = iguana_coinfind(swap->I.req.dest); - swap->alicecoin = iguana_coinfind(swap->I.req.src); - if ( swap->bobcoin == 0 || swap->alicecoin == 0 ) - { - printf("missing bobcoin.%p or missing alicecoin.%p src.%p dest.%p\n",swap->bobcoin,swap->alicecoin,iguana_coinfind(swap->I.req.src),iguana_coinfind(swap->I.req.dest)); - free(swap); - return(0); - } - if ( strcmp("BTC",swap->bobcoin->symbol) == 0 ) - { - swap->I.bobconfirms = (1*0 + sqrt(dstr(swap->I.bobsatoshis) * .1)); - swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); - } - else if ( strcmp("BTC",swap->alicecoin->symbol) == 0 ) - { - swap->I.aliceconfirms = (1*0 + sqrt(dstr(swap->I.alicesatoshis) * .1)); - swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); - } - else - { - swap->I.bobconfirms = BASILISK_DEFAULT_NUMCONFIRMS; - swap->I.aliceconfirms = BASILISK_DEFAULT_NUMCONFIRMS; - } - /*if ( swap->I.bobconfirms == 0 ) - swap->I.bobconfirms = swap->bobcoin->chain->minconfirms; - if ( swap->I.aliceconfirms == 0 ) - swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms;*/ - jumblrflag = (bits256_cmp(pubkey25519,myinfo->jumblr_pubkey) == 0 || bits256_cmp(pubkey25519,myinfo->jumblr_depositkey) == 0); - printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); - if ( swap->I.iambob != 0 ) - { - basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); - basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); - bobpub33 = pubkey33; - } - else - { - basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); - basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); - alicepub33 = pubkey33; - } - basilisk_rawtx_setparms("bobdeposit",swap->I.req.quoteid,&swap->bobdeposit,swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3) + swap->bobcoin->txfee,4,0,jumblrflag); - basilisk_rawtx_setparms("bobrefund",swap->I.req.quoteid,&swap->bobrefund,swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,bobpub33,jumblrflag); - swap->bobrefund.I.suppress_pubkeys = 1; - basilisk_rawtx_setparms("aliceclaim",swap->I.req.quoteid,&swap->aliceclaim,swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,alicepub33,jumblrflag); - swap->aliceclaim.I.suppress_pubkeys = 1; - swap->aliceclaim.I.locktime = swap->I.started + swap->I.putduration+swap->I.callduration + 1; - - basilisk_rawtx_setparms("bobpayment",swap->I.req.quoteid,&swap->bobpayment,swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + swap->bobcoin->txfee,3,0,jumblrflag); - basilisk_rawtx_setparms("alicespend",swap->I.req.quoteid,&swap->alicespend,swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,alicepub33,jumblrflag); - swap->alicespend.I.suppress_pubkeys = 1; - basilisk_rawtx_setparms("bobreclaim",swap->I.req.quoteid,&swap->bobreclaim,swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,bobpub33,jumblrflag); - swap->bobreclaim.I.suppress_pubkeys = 1; - swap->bobreclaim.I.locktime = swap->I.started + swap->I.putduration + 1; - basilisk_rawtx_setparms("alicepayment",swap->I.req.quoteid,&swap->alicepayment,swap->alicecoin,swap->I.aliceconfirms,0,swap->I.alicesatoshis+swap->alicecoin->txfee,2,0,jumblrflag); - basilisk_rawtx_setparms("bobspend",swap->I.req.quoteid,&swap->bobspend,swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,bobpub33,jumblrflag); - swap->bobspend.I.suppress_pubkeys = 1; - basilisk_rawtx_setparms("alicereclaim",swap->I.req.quoteid,&swap->alicereclaim,swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,alicepub33,jumblrflag); - swap->alicereclaim.I.suppress_pubkeys = 1; - printf("IAMBOB.%d\n",swap->I.iambob); - - return(swap); + return(-1); + else return(0); + } + else if ( bits256_cmp(pubkey,desthash) == 0 ) + { + if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) + return(-1); + else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) + return(1); + else return(0); + } + return(0); } -// end of alice/bob code void basilisk_rawtx_purge(struct basilisk_rawtx *rawtx) { @@ -1332,7 +154,7 @@ void basilisk_rawtx_purge(struct basilisk_rawtx *rawtx) // free(rawtx->txbytes), rawtx->txbytes = 0; } -void basilisk_swap_finished(struct supernet_info *myinfo,struct basilisk_swap *swap) +void basilisk_swap_finished(struct basilisk_swap *swap) { int32_t i; swap->I.finished = (uint32_t)time(NULL); @@ -1355,82 +177,33 @@ void basilisk_swap_finished(struct supernet_info *myinfo,struct basilisk_swap *s swap->nummessages = 0; } -void basilisk_swap_purge(struct supernet_info *myinfo,struct basilisk_swap *swap) -{ - int32_t i,n; - // while still in orderbook, wait - //return; - portable_mutex_lock(&myinfo->DEX_swapmutex); - n = myinfo->numswaps; - for (i=0; iswaps[i] == swap ) - { - myinfo->swaps[i] = myinfo->swaps[--myinfo->numswaps]; - myinfo->swaps[myinfo->numswaps] = 0; - basilisk_swap_finished(myinfo,swap); - break; - } - portable_mutex_unlock(&myinfo->DEX_swapmutex); -} - -int32_t basilisk_verify_otherstatebits(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) -{ - int32_t retval; struct basilisk_swap *swap = ptr; - if ( datalen == sizeof(swap->I.otherstatebits) ) - { - retval = iguana_rwnum(0,data,sizeof(swap->I.otherstatebits),&swap->I.otherstatebits); - return(retval); - } else return(-1); -} - -int32_t basilisk_verify_statebits(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +uint32_t basilisk_requestid(struct basilisk_request *rp) { - int32_t retval = -1; uint32_t statebits; struct basilisk_swap *swap = ptr; - if ( datalen == sizeof(swap->I.statebits) ) - { - retval = iguana_rwnum(0,data,sizeof(swap->I.statebits),&statebits); - if ( statebits != swap->I.statebits ) - { - printf("statebits.%x != %x\n",statebits,swap->I.statebits); - return(-1); - } - } - return(retval); + struct basilisk_request R; + R = *rp; + R.requestid = R.quoteid = R.quotetime = R.DEXselector = 0; + R.destamount = R.unused = 0; + memset(R.desthash.bytes,0,sizeof(R.desthash.bytes)); + if ( 0 ) + { + int32_t i; + for (i=0; i %s %.8f %s crc.%u\n",R.timestamp,R.requestid,R.quoteid,R.src,dstr(R.srcamount),bits256_str(str,R.srchash),R.dest,dstr(R.destamount),bits256_str(str2,R.desthash),calc_crc32(0,(void *)&R,sizeof(R))); + } + return(calc_crc32(0,(void *)&R,sizeof(R))); } -int32_t basilisk_verify_choosei(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) +uint32_t basilisk_quoteid(struct basilisk_request *rp) { - int32_t otherchoosei=-1,i,len = 0; struct basilisk_swap *swap = ptr; - if ( datalen == sizeof(otherchoosei)+sizeof(bits256)*2 ) - { - len += iguana_rwnum(0,data,sizeof(otherchoosei),&otherchoosei); - if ( otherchoosei >= 0 && otherchoosei < INSTANTDEX_DECKSIZE ) - { - //printf("otherchoosei.%d\n",otherchoosei); - swap->I.otherchoosei = otherchoosei; - if ( swap->I.iambob != 0 ) - { - for (i=0; i<32; i++) - swap->I.pubA0.bytes[i] = data[len++]; - for (i=0; i<32; i++) - swap->I.pubA1.bytes[i] = data[len++]; - char str[65]; printf("GOT pubA0/1 %s\n",bits256_str(str,swap->I.pubA0)); - } - else - { - for (i=0; i<32; i++) - swap->I.pubB0.bytes[i] = data[len++]; - for (i=0; i<32; i++) - swap->I.pubB1.bytes[i] = data[len++]; - } - return(0); - } - } - printf("illegal otherchoosei.%d datalen.%d vs %d\n",otherchoosei,datalen,(int32_t)(sizeof(otherchoosei)+sizeof(bits256)*2)); - return(-1); + struct basilisk_request R; + R = *rp; + R.requestid = R.quoteid = R.unused = R.DEXselector = 0; + return(calc_crc32(0,(void *)&R,sizeof(R))); } -int32_t basilisk_swapdata_deck(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +int32_t LP_pubkeys_data(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t i,datalen = 0; for (i=0; ideck)/sizeof(swap->deck[0][0]); i++) @@ -1438,133 +211,18 @@ int32_t basilisk_swapdata_deck(struct supernet_info *myinfo,struct basilisk_swap return(datalen); } -int32_t basilisk_verify_otherdeck(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) -{ - int32_t i,len = 0; struct basilisk_swap *swap = ptr; - for (i=0; iotherdeck)/sizeof(swap->otherdeck[0][0]); i++) - len += iguana_rwnum(0,&data[len],sizeof(swap->otherdeck[i>>1][i&1]),&swap->otherdeck[i>>1][i&1]); - return(0); -} - -int32_t basilisk_verify_privkeys(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) -{ - int32_t i,j,wrongfirstbyte=0,errs=0,len = 0; bits256 otherpriv,pubi; uint8_t secret160[20],otherpubkey[33]; uint64_t txid; struct basilisk_swap *swap = ptr; - //printf("verify privkeys choosei.%d otherchoosei.%d datalen.%d vs %d\n",swap->choosei,swap->otherchoosei,datalen,(int32_t)sizeof(swap->privkeys)+20+32); - memset(otherpriv.bytes,0,sizeof(otherpriv)); - if ( swap->I.cutverified == 0 && swap->I.otherchoosei >= 0 && datalen == sizeof(swap->privkeys)+20+2*32 ) - { - for (i=errs=0; iprivkeys)/sizeof(*swap->privkeys); i++) - { - for (j=0; j<32; j++) - otherpriv.bytes[j] = data[len++]; - if ( i != swap->I.choosei ) - { - pubi = bitcoin_pubkey33(myinfo->ctx,otherpubkey,otherpriv); - revcalc_rmd160_sha256(secret160,otherpriv);//.bytes,sizeof(otherpriv)); - memcpy(&txid,secret160,sizeof(txid)); - errs += basilisk_verify_pubpair(&wrongfirstbyte,swap,i,otherpubkey[0],pubi,txid); - } - } - if ( errs == 0 && wrongfirstbyte == 0 ) - { - swap->I.cutverified = 1, printf("CUT VERIFIED\n"); - if ( swap->I.iambob != 0 ) - { - for (i=0; i<32; i++) - swap->I.pubAm.bytes[i] = data[len++]; - for (i=0; i<20; i++) - swap->I.secretAm[i] = data[len++]; - for (i=0; i<32; i++) - swap->I.secretAm256[i] = data[len++]; - basilisk_bobscripts_set(myinfo,swap,1,1); - } - else - { - for (i=0; i<32; i++) - swap->I.pubBn.bytes[i] = data[len++]; - for (i=0; i<20; i++) - swap->I.secretBn[i] = data[len++]; - for (i=0; i<32; i++) - swap->I.secretBn256[i] = data[len++]; - //basilisk_bobscripts_set(myinfo,swap,0); - } - } else printf("failed verification: wrong firstbyte.%d errs.%d\n",wrongfirstbyte,errs); - } - //printf("privkeys errs.%d wrongfirstbyte.%d\n",errs,wrongfirstbyte); - return(errs); -} - -uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) -{ - uint8_t sendbuf[32768]; int32_t sendlen; - if ( basilisk_swapdata_rawtx(myinfo,swap,data,maxlen,rawtx) != 0 ) - { - if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) - { - char str[65],str2[65]; - rawtx->I.actualtxid = basilisk_swap_broadcast(rawtx->name,myinfo,swap,rawtx->coin,rawtx->txbytes,rawtx->I.datalen); - if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) - { - printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); - rawtx->I.actualtxid = rawtx->I.signedtxid; - } - if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) - { - sendlen = 0; - sendbuf[sendlen++] = rawtx->I.datalen & 0xff; - sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; - sendbuf[sendlen++] = rawtx->I.redeemlen; - memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; - if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) - { - memcpy(&sendbuf[sendlen],rawtx->redeemscript,rawtx->I.redeemlen); - sendlen += rawtx->I.redeemlen; - } - basilisk_dontforget_update(myinfo,swap,rawtx); - //printf("sendlen.%d datalen.%d redeemlen.%d\n",sendlen,rawtx->datalen,rawtx->redeemlen); - if ( suppress_swapsend == 0 ) - return(basilisk_swapsend(myinfo,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs)); - else - { - printf("suppress swapsend %x\n",msgbits); - return(0); - } - } - } - return(nextbits); - } else if ( swap->I.iambob == 0 ) - printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); - return(0); -} - -void basilisk_sendpubkeys(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) -{ - int32_t datalen; - datalen = basilisk_swapdata_deck(myinfo,swap,data,maxlen); - printf("send deck.%d\n",datalen); - swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x02,data,datalen,0x01,swap->I.crcs_mypub); -} - -int32_t basilisk_checkdeck(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +int32_t LP_pubkeys_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { - if ( (swap->I.statebits & 0x02) == 0 ) + int32_t i,len = 0; + if ( datalen == sizeof(swap->otherdeck) ) { - //printf("check for other deck\n"); - if ( basilisk_swapget(myinfo,swap,0x02,data,maxlen,basilisk_verify_otherdeck) == 0 ) - swap->I.statebits |= 0x02; - else return(-1); - } - return(0); -} - -void basilisk_sendstate(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) -{ - int32_t datalen=0; - datalen = iguana_rwnum(1,data,sizeof(swap->I.statebits),&swap->I.statebits); - basilisk_swapsend(myinfo,swap,0x80000000,data,datalen,0,0); + for (i=0; iotherdeck)/sizeof(swap->otherdeck[0][0]); i++) + len += iguana_rwnum(0,&data[len],sizeof(swap->otherdeck[i>>1][i&1]),&swap->otherdeck[i>>1][i&1]); + return(0); + } else return(-1); } -void basilisk_sendchoosei(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +int32_t LP_choosei_data(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t i,datalen; char str[65]; datalen = iguana_rwnum(1,data,sizeof(swap->I.choosei),&swap->I.choosei); @@ -1584,46 +242,56 @@ void basilisk_sendchoosei(struct supernet_info *myinfo,struct basilisk_swap *swa data[datalen++] = swap->I.pubA1.bytes[i]; printf("SEND pubA0/1 %s\n",bits256_str(str,swap->I.pubA0)); } - swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x08,data,datalen,0x04,swap->I.crcs_mychoosei); + return(datalen); } -void basilisk_waitchoosei(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +int32_t LP_choosei_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { - uint8_t pubkey33[33]; char str[65],str2[65]; - //printf("check otherchoosei\n"); - if ( basilisk_swapget(myinfo,swap,0x08,data,maxlen,basilisk_verify_choosei) == 0 ) + int32_t otherchoosei=-1,i,len = 0; uint8_t pubkey33[33]; char str[65],str2[65]; + if ( datalen == sizeof(otherchoosei)+sizeof(bits256)*2 ) { - if ( swap->I.iambob != 0 ) + len += iguana_rwnum(0,data,sizeof(otherchoosei),&otherchoosei); + if ( otherchoosei >= 0 && otherchoosei < INSTANTDEX_DECKSIZE ) { - if ( bits256_nonz(swap->I.privBn) == 0 ) + swap->I.otherchoosei = otherchoosei; + if ( swap->I.iambob != 0 ) { + for (i=0; i<32; i++) + swap->I.pubA0.bytes[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.pubA1.bytes[i] = data[len++]; + printf("GOT pubA0/1 %s\n",bits256_str(str,swap->I.pubA0)); swap->I.privBn = swap->privkeys[swap->I.otherchoosei]; memset(&swap->privkeys[swap->I.otherchoosei],0,sizeof(swap->privkeys[swap->I.otherchoosei])); revcalc_rmd160_sha256(swap->I.secretBn,swap->I.privBn);//.bytes,sizeof(swap->privBn)); vcalc_sha256(0,swap->I.secretBn256,swap->I.privBn.bytes,sizeof(swap->I.privBn)); - swap->I.pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,swap->I.privBn); + swap->I.pubBn = bitcoin_pubkey33(swap->ctx,pubkey33,swap->I.privBn); printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); - basilisk_bobscripts_set(myinfo,swap,1,1); + basilisk_bobscripts_set(swap,1,1); } - } - else - { - if ( bits256_nonz(swap->I.privAm) == 0 ) + else { + for (i=0; i<32; i++) + swap->I.pubB0.bytes[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.pubB1.bytes[i] = data[len++]; + printf("GOT pubB0/1 %s\n",bits256_str(str,swap->I.pubB0)); swap->I.privAm = swap->privkeys[swap->I.otherchoosei]; memset(&swap->privkeys[swap->I.otherchoosei],0,sizeof(swap->privkeys[swap->I.otherchoosei])); revcalc_rmd160_sha256(swap->I.secretAm,swap->I.privAm);//.bytes,sizeof(swap->privAm)); vcalc_sha256(0,swap->I.secretAm256,swap->I.privAm.bytes,sizeof(swap->I.privAm)); - swap->I.pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,swap->I.privAm); - char str[65],str2[65]; printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); - //basilisk_bobscripts_set(myinfo,swap,0); + swap->I.pubAm = bitcoin_pubkey33(swap->ctx,pubkey33,swap->I.privAm); + printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); + //basilisk_bobscripts_set(swap,0); } + return(0); } - swap->I.statebits |= 0x08; } + printf("illegal otherchoosei.%d datalen.%d vs %d\n",otherchoosei,datalen,(int32_t)(sizeof(otherchoosei)+sizeof(bits256)*2)); + return(-1); } -void basilisk_sendmostprivs(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +int32_t LP_mostprivs_data(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t i,j,datalen; datalen = 0; @@ -1650,408 +318,276 @@ void basilisk_sendmostprivs(struct supernet_info *myinfo,struct basilisk_swap *s for (i=0; i<32; i++) data[datalen++] = swap->I.secretAm256[i]; } - //printf("send privkeys.%d\n",datalen); - swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x20,data,datalen,0x10,swap->I.crcs_myprivs); + return(datalen); } -int32_t basilisk_swapiteration(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +int32_t basilisk_verify_pubpair(int32_t *wrongfirstbytep,struct basilisk_swap *swap,int32_t ind,uint8_t pub0,bits256 pubi,uint64_t txid) { - int32_t j,datalen,retval = 0; uint32_t savestatebits=0,saveotherbits=0; - if ( swap->I.iambob != 0 ) - swap->I.statebits |= 0x80; - while ( swap->aborted == 0 && ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) + if ( pub0 != (swap->I.iambob ^ 1) + 0x02 ) { - if ( swap->connected == 0 ) - basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); - printf("D r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); - if ( swap->I.iambob != 0 && (swap->I.statebits & 0x80) == 0 ) // wait for fee - { - if ( basilisk_swapget(myinfo,swap,0x80,data,maxlen,basilisk_verify_otherfee) == 0 ) - { - // verify and submit otherfee - swap->I.statebits |= 0x80; - basilisk_sendstate(myinfo,swap,data,maxlen); - } - } - else if ( swap->I.iambob == 0 ) - swap->I.statebits |= 0x80; - basilisk_sendstate(myinfo,swap,data,maxlen); - basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); - if ( (swap->I.otherstatebits & 0x80) != 0 && (swap->I.statebits & 0x80) != 0 ) - break; - if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) - sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); - savestatebits = swap->I.statebits; - saveotherbits = swap->I.otherstatebits; - basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); - basilisk_sendstate(myinfo,swap,data,maxlen); - if ( (swap->I.otherstatebits & 0x80) == 0 ) - basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); + (*wrongfirstbytep)++; + printf("wrongfirstbyte[%d] %02x\n",ind,pub0); + return(-1); } - basilisk_swap_saveupdate(myinfo,swap); - while ( swap->aborted == 0 && retval == 0 && time(NULL) < swap->I.expiration ) // both sides have setup required data and paid txfee + else if ( swap->otherdeck[ind][1] != pubi.txid ) { - basilisk_swap_saveupdate(myinfo,swap); - if ( swap->connected == 0 ) - basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); - //if ( (rand() % 30) == 0 ) - printf("E r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); - if ( swap->I.iambob != 0 ) + printf("otherdeck[%d] priv ->pub mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][1],(long long)pubi.txid); + return(-1); + } + else if ( swap->otherdeck[ind][0] != txid ) + { + printf("otherdeck[%d] priv mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][0],(long long)txid); + return(-1); + } + return(0); +} + +int32_t basilisk_verify_privi(void *ptr,uint8_t *data,int32_t datalen) +{ + int32_t j,wrongfirstbyte,len = 0; bits256 privkey,pubi; char str[65],str2[65]; uint8_t secret160[20],pubkey33[33]; uint64_t txid; struct basilisk_swap *swap = ptr; + memset(privkey.bytes,0,sizeof(privkey)); + if ( datalen == sizeof(bits256) ) + { + for (j=0; j<32; j++) + privkey.bytes[j] = data[len++]; + revcalc_rmd160_sha256(secret160,privkey);//.bytes,sizeof(privkey)); + memcpy(&txid,secret160,sizeof(txid)); + pubi = bitcoin_pubkey33(swap->ctx,pubkey33,privkey); + if ( basilisk_verify_pubpair(&wrongfirstbyte,swap,swap->I.choosei,pubkey33[0],pubi,txid) == 0 ) { - //printf("BOB\n"); - if ( (swap->I.statebits & 0x100) == 0 ) - { - printf("send bobdeposit\n"); - swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0); - } - // [BLOCKING: altfound] make sure altpayment is confirmed and send payment - else if ( (swap->I.statebits & 0x1000) == 0 ) - { - printf("check alicepayment\n"); - if ( basilisk_swapget(myinfo,swap,0x1000,data,maxlen,basilisk_verify_alicepaid) == 0 ) - { - swap->I.statebits |= 0x1000; - printf("got alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); - } - } - else if ( (swap->I.statebits & 0x2000) == 0 ) - { - if ( (swap->I.aliceconfirms == 0 && swap->aliceunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->alicepayment) >= swap->I.aliceconfirms ) - { - swap->I.statebits |= 0x2000; - printf("alicepayment confirmed\n"); - } - } - else if ( (swap->I.statebits & 0x4000) == 0 ) - { - basilisk_bobscripts_set(myinfo,swap,0,1); - printf("send bobpayment\n"); - swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0); - } - // [BLOCKING: privM] Bob waits for privAm either from Alice or alice blockchain - else if ( (swap->I.statebits & 0xc0000) != 0xc0000 ) + if ( swap->I.iambob != 0 ) { - if ( basilisk_swapget(myinfo,swap,0x40000,data,maxlen,basilisk_verify_privi) == 0 || basilisk_privAm_extract(myinfo,swap) == 0 ) // divulges privAm - { - //printf("got privi spend alicepayment, dont divulge privBn until bobspend propagated\n"); - basilisk_alicepayment_spend(myinfo,swap,&swap->bobspend); - if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobspend,0x40000,1) == 0 ) - printf("Bob error spending alice payment\n"); - else - { - tradebot_swap_balancingtrade(myinfo,swap,1); - printf("Bob spends alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); - swap->I.statebits |= 0x40000; - if ( basilisk_numconfirms(myinfo,swap,&swap->bobspend) >= swap->I.aliceconfirms ) - { - printf("bobspend confirmed\n"); - swap->I.statebits |= 0x80000; - printf("Bob confirming spend of Alice's payment\n"); - sleep(DEX_SLEEP); - } - retval = 1; - } - } + swap->I.privAm = privkey; + vcalc_sha256(0,swap->I.secretAm256,privkey.bytes,sizeof(privkey)); + printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); + basilisk_bobscripts_set(swap,0,1); } - if ( swap->bobpayment.I.locktime != 0 && time(NULL) > swap->bobpayment.I.locktime ) + else { - // submit reclaim of payment - printf("bob reclaims bobpayment\n"); - swap->I.statebits |= (0x40000 | 0x80000); - if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobreclaim,0,0) == 0 ) - printf("Bob error reclaiming own payment after alice timed out\n"); - else - { - printf("Bob reclaimed own payment\n"); - while ( 0 && (swap->I.statebits & 0x100000) == 0 ) // why wait for own tx? - { - if ( basilisk_numconfirms(myinfo,swap,&swap->bobreclaim) >= 1 ) - { - printf("bobreclaim confirmed\n"); - swap->I.statebits |= 0x100000; - printf("Bob confirms reclain of payment\n"); - break; - } - } - retval = 1; - } + swap->I.privBn = privkey; + vcalc_sha256(0,swap->I.secretBn256,privkey.bytes,sizeof(privkey)); + printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); } + basilisk_dontforget_update(swap,0); + char str[65]; printf("privi verified.(%s)\n",bits256_str(str,privkey)); + return(0); } - else - { - //printf("ALICE\n"); - // [BLOCKING: depfound] Alice waits for deposit to confirm and sends altpayment - if ( (swap->I.statebits & 0x200) == 0 ) - { - printf("checkfor deposit\n"); - if ( basilisk_swapget(myinfo,swap,0x200,data,maxlen,basilisk_verify_bobdeposit) == 0 ) - { - // verify deposit and submit, set confirmed height - printf("got bobdeposit\n"); - swap->I.statebits |= 0x200; - } else printf("no valid deposit\n"); - } - else if ( (swap->I.statebits & 0x400) == 0 ) - { - if ( basilisk_istrustedbob(myinfo,swap) != 0 || (swap->I.bobconfirms == 0 && swap->depositunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobdeposit) >= swap->I.bobconfirms ) - { - printf("bobdeposit confirmed\n"); - swap->I.statebits |= 0x400; - } - } - else if ( (swap->I.statebits & 0x800) == 0 ) - { - printf("send alicepayment\n"); - swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0); - } - // [BLOCKING: payfound] make sure payment is confrmed and send in spend or see bob's reclaim and claim - else if ( (swap->I.statebits & 0x8000) == 0 ) - { - if ( basilisk_swapget(myinfo,swap,0x8000,data,maxlen,basilisk_verify_bobpaid) == 0 ) - { - printf("got bobpayment\n"); - tradebot_swap_balancingtrade(myinfo,swap,0); - // verify payment and submit, set confirmed height - swap->I.statebits |= 0x8000; - } - } - else if ( (swap->I.statebits & 0x10000) == 0 ) - { - if ( basilisk_istrustedbob(myinfo,swap) != 0 || (swap->I.bobconfirms == 0 && swap->paymentunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobpayment) >= swap->I.bobconfirms ) - { - printf("bobpayment confirmed\n"); - swap->I.statebits |= 0x10000; - } - } - else if ( (swap->I.statebits & 0x20000) == 0 ) - { - printf("alicespend bobpayment\n"); - if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicespend,0x20000,0) != 0 )//&& (swap->aliceunconf != 0 || basilisk_numconfirms(myinfo,swap,&swap->alicespend) > 0) ) - { - swap->I.statebits |= 0x20000; - } - } - else if ( (swap->I.statebits & 0x40000) == 0 ) + } + return(-1); +} + +int32_t LP_mostprivs_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) +{ + int32_t i,j,wrongfirstbyte=0,errs=0,len = 0; bits256 otherpriv,pubi; uint8_t secret160[20],otherpubkey[33]; uint64_t txid; + //printf("verify privkeys choosei.%d otherchoosei.%d datalen.%d vs %d\n",swap->choosei,swap->otherchoosei,datalen,(int32_t)sizeof(swap->privkeys)+20+32); + memset(otherpriv.bytes,0,sizeof(otherpriv)); + if ( swap->I.cutverified == 0 && swap->I.otherchoosei >= 0 && datalen == sizeof(swap->privkeys)+20+2*32 ) + { + for (i=errs=0; iprivkeys)/sizeof(*swap->privkeys); i++) + { + for (j=0; j<32; j++) + otherpriv.bytes[j] = data[len++]; + if ( i != swap->I.choosei ) { - int32_t numconfs; - if ( (numconfs= basilisk_numconfirms(myinfo,swap,&swap->alicespend)) >= swap->I.bobconfirms ) - { - for (j=datalen=0; j<32; j++) - data[datalen++] = swap->I.privAm.bytes[j]; - printf("send privAm %x\n",swap->I.statebits); - swap->I.statebits |= basilisk_swapsend(myinfo,swap,0x40000,data,datalen,0x20000,swap->I.crcs_mypriv); - printf("Alice confirms spend of Bob's payment\n"); - retval = 1; - } else printf("alicespend numconfs.%d < %d\n",numconfs,swap->I.bobconfirms); + pubi = bitcoin_pubkey33(swap->ctx,otherpubkey,otherpriv); + revcalc_rmd160_sha256(secret160,otherpriv);//.bytes,sizeof(otherpriv)); + memcpy(&txid,secret160,sizeof(txid)); + errs += basilisk_verify_pubpair(&wrongfirstbyte,swap,i,otherpubkey[0],pubi,txid); } - if ( swap->bobdeposit.I.locktime != 0 && time(NULL) > swap->bobdeposit.I.locktime ) + } + if ( errs == 0 && wrongfirstbyte == 0 ) + { + swap->I.cutverified = 1, printf("CUT VERIFIED\n"); + if ( swap->I.iambob != 0 ) { - printf("Alice claims deposit\n"); - if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->aliceclaim,0,0) == 0 ) - printf("Alice couldnt claim deposit\n"); - else - { - printf("Alice claimed deposit\n"); - retval = 1; - } + for (i=0; i<32; i++) + swap->I.pubAm.bytes[i] = data[len++]; + for (i=0; i<20; i++) + swap->I.secretAm[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.secretAm256[i] = data[len++]; + basilisk_bobscripts_set(swap,1,1); } - else if ( swap->aborted != 0 || basilisk_privBn_extract(myinfo,swap,data,maxlen) == 0 ) + else { - printf("Alice reclaims her payment\n"); - swap->I.statebits |= 0x40000000; - if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicereclaim,0x40000000,0) == 0 ) - printf("Alice error sending alicereclaim\n"); - else - { - printf("Alice reclaimed her payment\n"); - retval = 1; - } + for (i=0; i<32; i++) + swap->I.pubBn.bytes[i] = data[len++]; + for (i=0; i<20; i++) + swap->I.secretBn[i] = data[len++]; + for (i=0; i<32; i++) + swap->I.secretBn256[i] = data[len++]; + //basilisk_bobscripts_set(swap,0); } - } - if ( (rand() % 30) == 0 ) - printf("finished swapstate.%x other.%x\n",swap->I.statebits,swap->I.otherstatebits); - if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) - sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); - savestatebits = swap->I.statebits; - saveotherbits = swap->I.otherstatebits; - basilisk_sendstate(myinfo,swap,data,maxlen); - basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + } else printf("failed verification: wrong firstbyte.%d errs.%d\n",wrongfirstbyte,errs); } - return(retval); -} - -int32_t swapcompleted(struct supernet_info *myinfo,struct basilisk_swap *swap) -{ - if ( swap->I.iambob != 0 ) - return(swap->I.bobspent); - else return(swap->I.alicespent); + //printf("privkeys errs.%d wrongfirstbyte.%d\n",errs,wrongfirstbyte); + return(errs); } -cJSON *swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap) +int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen)) { - cJSON *retjson = cJSON_CreateObject(); - return(retjson); + void *data; int32_t datalen,retval = -1; uint32_t expiration = (uint32_t)time(NULL) + timeout; + while ( time(NULL) < expiration ) + { + if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) + { + retval = (*verify)(swap,data,datalen); + nn_freemsg(data); + } + } + return(retval); } -void basilisk_psockinit(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t amlp) +int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { - char keystr[64],databuf[1024],pubkeystr[128],*retstr,*retstr2,*datastr,*pushaddr=0,*subaddr=0; cJSON *retjson,*addrjson; uint8_t data[512]; int32_t datalen,timeout,pushsock = -1,subsock = -1; - if ( swap->connected == 1 ) - return; - if ( swap->pushsock < 0 && swap->subsock < 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) - { - timeout = 1000; - nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - timeout = 1; - nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - swap->pushsock = pushsock; - swap->subsock = subsock; - } - if ( (subsock= swap->subsock) < 0 || (pushsock= swap->pushsock) < 0 ) - { - printf("error getting nn_sockets\n"); - return; - } - sprintf(keystr,"%08x-%08x",swap->I.req.requestid,swap->I.req.quoteid); - if ( swap->connected == 0 && (retstr= _dex_kvsearch(myinfo,"KV",keystr)) != 0 ) + int32_t datalen,sendlen,retval = -1; + if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) + if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { - if ( (datastr= jstr(retjson,"value")) != 0 ) + if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { - datalen = (int32_t)strlen(datastr) >> 1; - decode_hex((uint8_t *)databuf,datalen,datastr); - if ( (addrjson= cJSON_Parse(databuf)) != 0 ) - { - pushaddr = jstr(addrjson,"push"); - subaddr = jstr(addrjson,"sub"); - if ( pushaddr != 0 && subaddr != 0 ) - { - printf("KV decoded (%s and %s) %d %d\n",pushaddr,subaddr,swap->pushsock,swap->subsock); - if ( nn_connect(swap->pushsock,pushaddr) >= 0 && nn_connect(swap->subsock,subaddr) >= 0 ) - swap->connected = 1; - } - free_json(addrjson); - } - } - free_json(retjson); + retval = 0; + } else printf("send %s error\n",statename); } - printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d) amlp.%d\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock,amlp); - free(retstr); - } - printf("connected.%d amlp.%d subsock.%d pushsock.%d\n",swap->connected,amlp,subsock,pushsock); - if ( swap->connected <= 0 && amlp != 0 && subsock >= 0 && pushsock >= 0 ) + } else printf("didnt get pubkeys\n"); + return(retval); +} + +int32_t LP_sendwait(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) +{ + int32_t datalen,sendlen,retval = -1; + if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { - if ( (retstr= _dex_psock(myinfo,"{}")) != 0 ) + if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { - printf("psock returns.(%s)\n",retstr); - // {"result":"success","pushaddr":"tcp://5.9.102.210:30002","subaddr":"tcp://5.9.102.210:30003","randipbits":3606291758,"coin":"KMD","tag":"6952562460568228137"} - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - pushaddr = jstr(retjson,"pushaddr"); - subaddr = jstr(retjson,"subaddr"); - if ( pushaddr != 0 && subaddr != 0 ) - { - if ( nn_connect(pushsock,pushaddr) >= 0 ) - { - printf("connected to %d pushaddr.(%s)\n",pushsock,pushaddr); - if ( nn_connect(subsock,subaddr) >= 0 ) - { - swap->connected = 1; - init_hexbytes_noT(pubkeystr,myinfo->persistent_pubkey33,33); - sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f],\"pub\":\"%s\"}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),pubkeystr); - datalen = (int32_t)strlen((char *)data) + 1; - printf("datalen.%d (%s)\n",datalen,(char *)data); - init_hexbytes_noT(databuf,data,datalen); - printf("%s -> %s\n",keystr,databuf); - if ( (retstr2= _dex_kvupdate(myinfo,"KV",keystr,databuf,1)) != 0 ) - { - printf("KVupdate.(%s)\n",retstr2); - free(retstr2); - } - } else printf("nn_connect error to %d subaddr.(%s)\n",subsock,subaddr); - } else printf("nn_connect error to %d pushaddr.(%s)\n",pushsock,pushaddr); - } - else printf("missing addr (%p) (%p) (%s)\n",pushaddr,subaddr,jprint(retjson,0)); - free_json(retjson); - } else printf("Error parsing psock.(%s)\n",retstr); - free(retstr); - } else printf("error issuing _dex_psock\n"); + if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) + retval = 0; + else printf("didnt get %s\n",statename); + } else printf("send pubkeys error\n"); } + return(retval); } -int32_t basilisk_alicetxs(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +void LP_swapsfp_update(struct basilisk_request *rp) { - int32_t i,retval = -1; - printf("alicetxs\n"); - for (i=0; i<3; i++) + static FILE *swapsfp; + if ( swapsfp == 0 ) { - if ( swap->alicepayment.I.datalen == 0 ) - basilisk_alicepayment(myinfo,swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); - if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) - { - printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); - sleep(20); - } - else - { - retval = 0; - for (i=0; ialicepayment.I.datalen; i++) - printf("%02x",swap->alicepayment.txbytes[i]); - printf(" ALICE PAYMENT created\n"); - iguana_unspents_mark(myinfo,swap->alicecoin,swap->alicepayment.vins); - basilisk_txlog(myinfo,swap,&swap->alicepayment,-1); - break; - } + char fname[512]; + sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); + if ( (swapsfp= fopen(fname,"rb+")) == 0 ) + swapsfp = fopen(fname,"wb+"); + else fseek(swapsfp,0,SEEK_END); + printf("LIST fp.%p\n",swapsfp); } - if ( swap->myfee.I.datalen == 0 ) + if ( swapsfp != 0 ) { - printf("generate fee\n"); - if ( basilisk_rawtx_gen("myfee",myinfo,swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->chain->txfee,1,0) == 0 ) + fwrite(&rp->requestid,1,sizeof(rp->requestid),swapsfp); + fwrite(&rp->quoteid,1,sizeof(rp->quoteid),swapsfp); + fflush(swapsfp); + } +} + +void LP_bobloop(void *_utxo) +{ + uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; + fprintf(stderr,"start swap iambob\n"); + maxlen = 1024*1024 + sizeof(*swap); + data = malloc(maxlen); + expiration = (uint32_t)time(NULL) + 10; + while ( (swap= utxo->swap) == 0 && time(NULL) < expiration ) + sleep(1); + if ( (utxo->swap= swap) != 0 ) + { + if ( LP_waitsend("pubkeys",10,utxo->pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + printf("error waitsend pubkeys\n"); + else if ( LP_waitsend("choosei",10,utxo->pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + printf("error waitsend choosei\n"); + else if ( LP_waitsend("mostprivs",10,utxo->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + printf("error waitsend mostprivs\n"); + else if ( basilisk_bobscripts_set(swap,1,1) < 0 ) + printf("error bobscripts\n"); + else { - swap->I.statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40,0); - iguana_unspents_mark(myinfo,swap->I.iambob!=0?swap->bobcoin:swap->alicecoin,swap->myfee.vins); - basilisk_txlog(myinfo,swap,&swap->myfee,-1); - for (i=0; imyfee.I.spendlen; i++) - printf("%02x",swap->myfee.txbytes[i]); - printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); - swap->I.statebits |= 0x40; + LP_swapsfp_update(&swap->I.req); + // wait alicefee + // send bobdeposit + // wait alicepayment + // send bobpayment + // bobspend + // bobrefund + // done } + } else printf("swap timed out\n"); + basilisk_swap_finished(swap); + free(utxo->swap); + utxo->swap = 0; + nn_close(utxo->pair); + utxo->pair = -1; +} + +void LP_aliceloop(void *_utxo) +{ + uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; + fprintf(stderr,"start swap iambob\n"); + maxlen = 1024*1024 + sizeof(*swap); + data = malloc(maxlen); + expiration = (uint32_t)time(NULL) + 10; + while ( (swap= utxo->swap) == 0 && time(NULL) < expiration ) + sleep(1); + if ( (utxo->swap= swap) != 0 ) + { + if ( LP_sendwait("pubkeys",10,utxo->pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + printf("error LP_sendwait pubkeys\n"); + else if ( LP_sendwait("choosei",10,utxo->pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + printf("error LP_sendwait choosei\n"); + else if ( LP_sendwait("mostprivs",10,utxo->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + printf("error LP_sendwait mostprivs\n"); + else if ( basilisk_alicetxs(swap,data,maxlen) != 0 ) + printf("basilisk_alicetxs error\n"); else { - printf("error creating myfee\n"); - return(-2); + LP_swapsfp_update(&swap->I.req); + // send alicefee + // wait bobdeposit + // send alicepayment + // wait bobpayment + // alicespend + // done } - } - if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 && swap->myfee.I.datalen != 0 && swap->myfee.I.spendlen > 0 ) - return(0); - return(-1); + } else printf("swap timed out\n"); + basilisk_swap_finished(swap); + free(utxo->swap); + utxo->swap = 0; + nn_close(utxo->pair); + utxo->pair = -1; } -void basilisk_swaploop(void *_swap) +#ifdef old +void basilisk_swaploop(void *_utxo) { - uint8_t *data; uint32_t expiration,savestatebits=0,saveotherbits=0; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct supernet_info *myinfo; struct basilisk_swap *swap = _swap; - myinfo = swap->myinfoptr; - fprintf(stderr,"start swap\n"); + uint8_t *data; uint32_t expiration,savestatebits=0,saveotherbits=0; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; + swap = utxo->swap; + fprintf(stderr,"start swap iambob.%d\n",swap->I.iambob); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + 300; - myinfo->DEXactive = expiration; + //myinfo->DEXactive = expiration; channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) { - dex_channelsend(myinfo,swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); + LP_channelsend(swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); if ( swap->connected == 0 ) - basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + basilisk_psockinit(swap,swap->I.iambob != 0); if ( swap->connected > 0 ) { printf("A r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); - basilisk_sendstate(myinfo,swap,data,maxlen); - basilisk_sendpubkeys(myinfo,swap,data,maxlen); // send pubkeys - if ( basilisk_checkdeck(myinfo,swap,data,maxlen) == 0) // check for other deck 0x02 - basilisk_sendchoosei(myinfo,swap,data,maxlen); - basilisk_waitchoosei(myinfo,swap,data,maxlen); // wait for choosei 0x08 + basilisk_sendstate(swap,data,maxlen); + basilisk_sendpubkeys(swap,data,maxlen); // send pubkeys + if ( basilisk_checkdeck(swap,data,maxlen) == 0) // check for other deck 0x02 + basilisk_sendchoosei(swap,data,maxlen); + basilisk_waitchoosei(swap,data,maxlen); // wait for choosei 0x08 if ( (swap->I.statebits & (0x08|0x02)) == (0x08|0x02) ) break; } @@ -2068,12 +604,12 @@ void basilisk_swaploop(void *_swap) while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 ) { if ( swap->connected == 0 ) - basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + basilisk_psockinit(swap,swap->I.iambob != 0); printf("B r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); - basilisk_sendstate(myinfo,swap,data,maxlen); - basilisk_sendchoosei(myinfo,swap,data,maxlen); - basilisk_sendmostprivs(myinfo,swap,data,maxlen); - if ( basilisk_swapget(myinfo,swap,0x20,data,maxlen,basilisk_verify_privkeys) == 0 ) + basilisk_sendstate(swap,data,maxlen); + basilisk_sendchoosei(swap,data,maxlen); + basilisk_sendmostprivs(swap,data,maxlen); + if ( basilisk_swapget(swap,0x20,data,maxlen,basilisk_verify_privkeys) == 0 ) { swap->I.statebits |= 0x20; break; @@ -2085,11 +621,11 @@ void basilisk_swaploop(void *_swap) if ( time(NULL) > expiration ) break; } - myinfo->DEXactive = swap->I.expiration; + //myinfo->DEXactive = swap->I.expiration; if ( time(NULL) >= expiration ) { retval = -1; - myinfo->DEXactive = 0; + //myinfo->DEXactive = 0; } if ( swap->aborted != 0 ) { @@ -2101,16 +637,16 @@ void basilisk_swaploop(void *_swap) while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x40) == 0 && iters++ < 10 ) // send fee { if ( swap->connected == 0 ) - basilisk_psockinit(myinfo,swap,swap->I.iambob != 0); + basilisk_psockinit(swap,swap->I.iambob != 0); //printf("sendstate.%x\n",swap->I.statebits); - basilisk_sendstate(myinfo,swap,data,maxlen); + basilisk_sendstate(swap,data,maxlen); //printf("swapget\n"); - basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); //printf("after swapget\n"); if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) { printf("bobscripts set\n"); - if ( basilisk_bobscripts_set(myinfo,swap,1,1) < 0 ) + if ( basilisk_bobscripts_set(swap,1,1) < 0 ) { sleep(DEX_SLEEP); printf("bobscripts set error\n"); @@ -2149,7 +685,7 @@ void basilisk_swaploop(void *_swap) for (i=0; i<32; i++) printf("%02x",swap->pubB1.bytes[i]); printf(" <- pubB1\n");*/ - if ( (retval= basilisk_alicetxs(myinfo,swap,data,maxlen)) != 0 ) + if ( (retval= basilisk_alicetxs(swap,data,maxlen)) != 0 ) { printf("basilisk_alicetxs error\n"); break; @@ -2174,15 +710,15 @@ void basilisk_swaploop(void *_swap) retval = -7; } } - while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(myinfo,swap,data,maxlen) == 0 ) + while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(swap,data,maxlen) == 0 ) { if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; - basilisk_sendstate(myinfo,swap,data,maxlen); - basilisk_swapget(myinfo,swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); - basilisk_swap_saveupdate(myinfo,swap); + basilisk_sendstate(swap,data,maxlen); + basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + basilisk_swap_saveupdate(swap); if ( time(NULL) > swap->I.expiration ) break; } @@ -2191,8 +727,8 @@ void basilisk_swaploop(void *_swap) printf("BOB waiting for confirm state.%x\n",swap->I.statebits); sleep(60); // wait for confirm/propagation of msig printf("BOB reclaims refund\n"); - basilisk_bobdeposit_refund(myinfo,swap,0); - if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobrefund,0x40000000,0) == 0 ) // use secretBn + basilisk_bobdeposit_refund(swap,0); + if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobrefund,0x40000000,0) == 0 ) // use secretBn { printf("Bob submit error getting refund of deposit\n"); } @@ -2201,47 +737,279 @@ void basilisk_swaploop(void *_swap) // maybe wait for bobrefund to be confirmed for (j=datalen=0; j<32; j++) data[datalen++] = swap->I.privBn.bytes[j]; - basilisk_swapsend(myinfo,swap,0x40000000,data,datalen,0x40000000,swap->I.crcs_mypriv); + LP_swapsend(swap,0x40000000,data,datalen,0x40000000,swap->I.crcs_mypriv); } - basilisk_swap_saveupdate(myinfo,swap); + basilisk_swap_saveupdate(swap); } if ( retval != 0 ) - basilisk_swap_sendabort(myinfo,swap); + basilisk_swap_sendabort(swap); printf("end of atomic swap\n"); - if ( swapcompleted(myinfo,swap) > 0 ) // only if swap completed + if ( swapcompleted(swap) > 0 ) // only if swap completed { if ( swap->I.iambob != 0 ) - tradebot_pendingadd(myinfo,swapjson(myinfo,swap),swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); - else tradebot_pendingadd(myinfo,swapjson(myinfo,swap),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.src,dstr(swap->I.req.srcamount)); + tradebot_pendingadd(swapjson(swap),swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); + else tradebot_pendingadd(swapjson(swap),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.src,dstr(swap->I.req.srcamount)); } printf("%s swap finished statebits %x\n",swap->I.iambob!=0?"BOB":"ALICE",swap->I.statebits); - basilisk_swap_purge(myinfo,swap); + //basilisk_swap_purge(swap); free(data); } +#endif + +bits256 instantdex_derivekeypair(void *ctx,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash) +{ + bits256 sharedsecret; + sharedsecret = curve25519_shared(privkey,orderhash); + vcalc_sha256cat(newprivp->bytes,orderhash.bytes,sizeof(orderhash),sharedsecret.bytes,sizeof(sharedsecret)); + return(bitcoin_pubkey33(ctx,pubkey,*newprivp)); +} + +bits256 basilisk_revealkey(bits256 privkey,bits256 pubkey) +{ + bits256 reveal; +#ifdef DISABLE_CHECKSIG + vcalc_sha256(0,reveal.bytes,privkey.bytes,sizeof(privkey)); + //reveal = revcalc_sha256(privkey); + char str[65],str2[65]; printf("priv.(%s) -> reveal.(%s)\n",bits256_str(str,privkey),bits256_str(str2,reveal)); +#else + reveal = pubkey; +#endif + return(reveal); +} + +int32_t instantdex_pubkeyargs(struct basilisk_swap *swap,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte) +{ + char buf[3]; int32_t i,n,m,len=0; bits256 pubi,reveal; uint64_t txid; uint8_t secret160[20],pubkey[33]; + sprintf(buf,"%c0",'A' - 0x02 + firstbyte); + if ( numpubs > 2 ) + { + if ( swap->I.numpubs+2 >= numpubs ) + return(numpubs); + //fprintf(stderr,">>>>>> start generating %s\n",buf); + } + for (i=n=m=0; ictx,&privkey,pubkey,privkey,hash); + //fprintf(stderr,"i.%d n.%d numpubs.%d %02x vs %02x\n",i,n,numpubs,pubkey[0],firstbyte); + if ( pubkey[0] != firstbyte ) + continue; + if ( n < 2 ) + { + if ( bits256_nonz(swap->I.mypubs[n]) == 0 ) + { + swap->I.myprivs[n] = privkey; + memcpy(swap->I.mypubs[n].bytes,pubkey+1,sizeof(bits256)); + reveal = basilisk_revealkey(privkey,swap->I.mypubs[n]); + if ( swap->I.iambob != 0 ) + { + if ( n == 0 ) + swap->I.pubB0 = reveal; + else if ( n == 1 ) + swap->I.pubB1 = reveal; + } + else if ( swap->I.iambob == 0 ) + { + if ( n == 0 ) + swap->I.pubA0 = reveal; + else if ( n == 1 ) + swap->I.pubA1 = reveal; + } + } + } + if ( m < INSTANTDEX_DECKSIZE ) + { + swap->privkeys[m] = privkey; + revcalc_rmd160_sha256(secret160,privkey);//.bytes,sizeof(privkey)); + memcpy(&txid,secret160,sizeof(txid)); + len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][0],sizeof(txid),&txid); + len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][1],sizeof(pubi.txid),&pubi.txid); + m++; + if ( m > swap->I.numpubs ) + swap->I.numpubs = m; + } + n++; + } + if ( n > 2 || m > 2 ) + printf("n.%d m.%d len.%d numpubs.%d\n",n,m,len,swap->I.numpubs); + return(n); +} + +void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx *rawtx,struct iguana_info *coin,int32_t numconfirms,int32_t vintype,uint64_t satoshis,int32_t vouttype,uint8_t *pubkey33,int32_t jumblrflag) +{ + strcpy(rawtx->name,name); + rawtx->coin = coin; + strcpy(rawtx->I.coinstr,coin->symbol); + rawtx->I.numconfirms = numconfirms; + if ( (rawtx->I.amount= satoshis) < 50000 ) + rawtx->I.amount = 50000; + rawtx->I.vintype = vintype; // 0 -> std, 2 -> 2of2, 3 -> spend bobpayment, 4 -> spend bobdeposit + rawtx->I.vouttype = vouttype; // 0 -> fee, 1 -> std, 2 -> 2of2, 3 -> bobpayment, 4 -> bobdeposit + if ( rawtx->I.vouttype == 0 ) + { + if ( strcmp(coin->symbol,"BTC") == 0 && (quoteid % 10) == 0 ) + decode_hex(rawtx->I.rmd160,20,TIERNOLAN_RMD160); + else decode_hex(rawtx->I.rmd160,20,INSTANTDEX_RMD160); + bitcoin_address(rawtx->I.destaddr,rawtx->coin->pubtype,rawtx->I.rmd160,20); + } + if ( pubkey33 != 0 ) + { + memcpy(rawtx->I.pubkey33,pubkey33,33); + bitcoin_address(rawtx->I.destaddr,rawtx->coin->pubtype,rawtx->I.pubkey33,33); + bitcoin_addr2rmd160(&rawtx->I.addrtype,rawtx->I.rmd160,rawtx->I.destaddr); + } + if ( rawtx->I.vouttype <= 1 && rawtx->I.destaddr[0] != 0 ) + { + rawtx->I.spendlen = bitcoin_standardspend(rawtx->spendscript,0,rawtx->I.rmd160); + printf("%s spendlen.%d %s <- %.8f\n",name,rawtx->I.spendlen,rawtx->I.destaddr,dstr(rawtx->I.amount)); + } else printf("%s vouttype.%d destaddr.(%s)\n",name,rawtx->I.vouttype,rawtx->I.destaddr); +} + +struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 pubkey25519,struct basilisk_swap *swap,int32_t optionduration,uint32_t statebits) +{ + //FILE *fp; char fname[512]; + uint8_t *alicepub33=0,*bobpub33=0; int32_t jumblrflag=-2,x = -1; struct iguana_info *coin; + swap->I.putduration = swap->I.callduration = INSTANTDEX_LOCKTIME; + if ( optionduration < 0 ) + swap->I.putduration -= optionduration; + else if ( optionduration > 0 ) + swap->I.callduration += optionduration; + swap->I.bobsatoshis = swap->I.req.destamount; + swap->I.alicesatoshis = swap->I.req.srcamount; + if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) + swap->I.bobinsurance = 50000; + if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) + swap->I.aliceinsurance = 50000; + strcpy(swap->I.bobstr,swap->I.req.dest); + strcpy(swap->I.alicestr,swap->I.req.src); + swap->I.started = (uint32_t)time(NULL); + swap->I.expiration = swap->I.req.timestamp + swap->I.putduration + swap->I.callduration; + OS_randombytes((uint8_t *)&swap->I.choosei,sizeof(swap->I.choosei)); + if ( swap->I.choosei < 0 ) + swap->I.choosei = -swap->I.choosei; + swap->I.choosei %= INSTANTDEX_DECKSIZE; + swap->I.otherchoosei = -1; + swap->I.myhash = pubkey25519; + if ( statebits != 0 ) + { + swap->I.iambob = 0; + swap->I.otherhash = swap->I.req.desthash; + } + else + { + swap->I.iambob = 1; + swap->I.otherhash = swap->I.req.srchash; + } + if ( bits256_nonz(privkey) == 0 || (x= instantdex_pubkeyargs(swap,2 + INSTANTDEX_DECKSIZE,privkey,swap->I.orderhash,0x02+swap->I.iambob)) != 2 + INSTANTDEX_DECKSIZE ) + { + char str[65]; printf("couldnt generate privkeys %d %s\n",x,bits256_str(str,privkey)); + return(0); + } + if ( (coin= LP_coinfind(swap->I.req.dest)) != 0 ) + swap->bobcoin = *coin; + else + { + printf("missing bobcoin.%p or missing alicecoin.%p src.%p dest.%p\n",&swap->bobcoin,&swap->alicecoin,LP_coinfind(swap->I.req.src),LP_coinfind(swap->I.req.dest)); + free(swap); + return(0); + } + if ( (coin= LP_coinfind(swap->I.req.src)) != 0 ) + swap->alicecoin = *coin; + else + { + printf("missing bobcoin.%p or missing alicecoin.%p src.%p dest.%p\n",&swap->bobcoin,&swap->alicecoin,LP_coinfind(swap->I.req.src),LP_coinfind(swap->I.req.dest)); + free(swap); + return(0); + } + if ( strcmp("BTC",swap->bobcoin.symbol) == 0 ) + { + swap->I.bobconfirms = (1*0 + sqrt(dstr(swap->I.bobsatoshis) * .1)); + swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); + } + else if ( strcmp("BTC",swap->alicecoin.symbol) == 0 ) + { + swap->I.aliceconfirms = (1*0 + sqrt(dstr(swap->I.alicesatoshis) * .1)); + swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); + } + else + { + swap->I.bobconfirms = BASILISK_DEFAULT_NUMCONFIRMS; + swap->I.aliceconfirms = BASILISK_DEFAULT_NUMCONFIRMS; + } + /*if ( swap->I.bobconfirms == 0 ) + swap->I.bobconfirms = swap->bobcoin->chain->minconfirms; + if ( swap->I.aliceconfirms == 0 ) + swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms;*/ + //jumblrflag = (bits256_cmp(pubkey25519,myinfo->jumblr_pubkey) == 0 || bits256_cmp(pubkey25519,myinfo->jumblr_depositkey) == 0); + printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); + if ( swap->I.iambob != 0 ) + { + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,&swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,&swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + bobpub33 = pubkey33; + } + else + { + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,&swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,&swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + alicepub33 = pubkey33; + } + basilisk_rawtx_setparms("bobdeposit",swap->I.req.quoteid,&swap->bobdeposit,&swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3) + swap->bobcoin.txfee,4,0,jumblrflag); + basilisk_rawtx_setparms("bobrefund",swap->I.req.quoteid,&swap->bobrefund,&swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,bobpub33,jumblrflag); + swap->bobrefund.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("aliceclaim",swap->I.req.quoteid,&swap->aliceclaim,&swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,alicepub33,jumblrflag); + swap->aliceclaim.I.suppress_pubkeys = 1; + swap->aliceclaim.I.locktime = swap->I.started + swap->I.putduration+swap->I.callduration + 1; + + basilisk_rawtx_setparms("bobpayment",swap->I.req.quoteid,&swap->bobpayment,&swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + swap->bobcoin.txfee,3,0,jumblrflag); + basilisk_rawtx_setparms("alicespend",swap->I.req.quoteid,&swap->alicespend,&swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,alicepub33,jumblrflag); + swap->alicespend.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("bobreclaim",swap->I.req.quoteid,&swap->bobreclaim,&swap->bobcoin,swap->I.bobconfirms,3,swap->I.bobsatoshis,1,bobpub33,jumblrflag); + swap->bobreclaim.I.suppress_pubkeys = 1; + swap->bobreclaim.I.locktime = swap->I.started + swap->I.putduration + 1; + basilisk_rawtx_setparms("alicepayment",swap->I.req.quoteid,&swap->alicepayment,&swap->alicecoin,swap->I.aliceconfirms,0,swap->I.alicesatoshis+swap->alicecoin.txfee,2,0,jumblrflag); + basilisk_rawtx_setparms("bobspend",swap->I.req.quoteid,&swap->bobspend,&swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,bobpub33,jumblrflag); + swap->bobspend.I.suppress_pubkeys = 1; + basilisk_rawtx_setparms("alicereclaim",swap->I.req.quoteid,&swap->alicereclaim,&swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,alicepub33,jumblrflag); + swap->alicereclaim.I.suppress_pubkeys = 1; + printf("IAMBOB.%d\n",swap->I.iambob); + return(swap); +} -cJSON *basilisk_swapjson(struct supernet_info *myinfo,struct basilisk_swap *swap) +struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp) { - cJSON *item = cJSON_CreateObject(); - jaddnum(item,"requestid",swap->I.req.requestid); - jaddnum(item,"quoteid",swap->I.req.quoteid); - jaddnum(item,"state",swap->I.statebits); - jaddnum(item,"otherstate",swap->I.otherstatebits); - jadd(item,"request",basilisk_requestjson(&swap->I.req)); - return(item); + struct basilisk_swap *swap; bits256 pubkey25519; uint8_t pubkey33[33]; + swap = calloc(1,sizeof(*swap)); + swap->ctx = bitcoin_ctx(); + vcalc_sha256(0,swap->I.orderhash.bytes,(uint8_t *)rp,sizeof(*rp)); + swap->I.req = *rp; + printf("basilisk_thread_start request.%u iambob.%d (%s/%s)\n",rp->requestid,iambob,rp->src,rp->dest); + bitcoin_pubkey33(swap->ctx,pubkey33,privkey); + pubkey25519 = curve25519(privkey,curve25519_basepoint9()); + swap->persistent_pubkey = pubkey25519; + swap->persistent_privkey = privkey; + memcpy(swap->persistent_pubkey33,pubkey33,33); + if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,!iambob) == 0 ) + { + printf("error doing swapinit\n"); + free(swap); + swap = 0; + } + return(swap); } -struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) +#ifdef notanymore +struct basilisk_swap *basilisk_thread_start(bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) { int32_t i,m,n,iter; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; // statebits 1 -> client, 0 -> LP - if ( myinfo->numswaps > 0 ) + /*if ( myinfo->numswaps > 0 ) { - if ( (coin= iguana_coinfind(rp->src)) == 0 || coin->FULLNODE >= 0 ) + if ( (coin= LP_coinfind(rp->src)) == 0 || coin->FULLNODE >= 0 ) { printf("dont have SRC coin.%s or not native and already swap pending\n",rp->src); return(0); } - if ( (coin= iguana_coinfind(rp->dest)) == 0 || coin->FULLNODE >= 0 ) + if ( (coin= LP_coinfind(rp->dest)) == 0 || coin->FULLNODE >= 0 ) { printf("dont have DEST coin.%s or not native and already swap pending\n",rp->dest); return(0); @@ -2254,31 +1022,32 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 printf("basilisk_thread_start error trying to start requestid.%u which is already started\n",rp->requestid); break; } - if ( i == myinfo->numswaps && i < sizeof(myinfo->swaps)/sizeof(*myinfo->swaps) ) + if ( i == myinfo->numswaps && i < sizeof(myinfo->swaps)/sizeof(*myinfo->swaps) )*/ { swap = calloc(1,sizeof(*swap)); + swap->ctx = bitcoin_ctx(); swap->subsock = swap->pushsock = -1; vcalc_sha256(0,swap->I.orderhash.bytes,(uint8_t *)rp,sizeof(*rp)); swap->I.req = *rp; - swap->myinfoptr = myinfo; + //swap->myinfoptr = myinfo; printf("basilisk_thread_start request.%u statebits.%d (%s/%s) reinit.%d\n",rp->requestid,statebits,rp->src,rp->dest,reinit); - bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); + bitcoin_pubkey33(swap->ctx,pubkey33,privkey); pubkey25519 = curve25519(privkey,curve25519_basepoint9()); swap->persistent_pubkey = pubkey25519; swap->persistent_privkey = privkey; memcpy(swap->persistent_pubkey33,pubkey33,33); m = n = 0; - if ( bitcoin_swapinit(myinfo,privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) + if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) { for (iter=0; iter<16; iter++) { - basilisk_psockinit(myinfo,swap,statebits == 0); + basilisk_psockinit(swap,statebits == 0); sleep(3); if ( swap->connected > 0 ) break; sleep(10); - /*basilisk_sendstate(myinfo,swap,data,sizeof(data)); - basilisk_swapget(myinfo,swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); + /*basilisk_sendstate(swap,data,sizeof(data)); + basilisk_swapget(swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); if ( swap->connected > 0 ) break; printf("loopback didntwork with %d %d\n",swap->pushsock,swap->subsock);*/ @@ -2289,7 +1058,7 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 { } - myinfo->swaps[myinfo->numswaps++] = swap; + //myinfo->swaps[myinfo->numswaps++] = swap; } else { @@ -2304,9 +1073,9 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); datalen = basilisk_rwDEXquote(1,data,rp); msgid = (uint32_t)time(NULL); - printf("other req.%d >>>>>>>>>>> send response (%llx -> %llx) last.%u r.%u quoteid.%u\n",i,(long long)rp->desthash.txid,(long long)rp->srchash.txid,myinfo->lastdexrequestid,rp->requestid,rp->quoteid); - dex_channelsend(myinfo,rp->desthash,rp->srchash,channel,msgid,data,datalen); - if ( (retarray= basilisk_channelget(myinfo,rp->srchash,rp->desthash,channel,0x4000000,30)) != 0 ) + printf("other req.%d >>>>>>>>>>> send response (%llx -> %llx) r.%u quoteid.%u\n",i,(long long)rp->desthash.txid,(long long)rp->srchash.txid,rp->requestid,rp->quoteid); + LP_channelsend(rp->desthash,rp->srchash,channel,msgid,data,datalen); + if ( (retarray= basilisk_channelget(rp->srchash,rp->desthash,channel,0x4000000,30)) != 0 ) { if ( is_cJSON_Array(retarray) != 0 && (n= cJSON_GetArraySize(retarray)) > 0 ) { @@ -2329,39 +1098,39 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 { //for (i=0; iI.req); i++) // fprintf(stderr,"%02x",((uint8_t *)&swap->I.req)[i]); - fprintf(stderr," M.%d N.%d launch.%d %d %p reinit.%d\n",m,n,myinfo->numswaps,(int32_t)(sizeof(myinfo->swaps)/sizeof(*myinfo->swaps)),&swap->I.req,reinit); - if ( (swap->fp= basilisk_swap_save(myinfo,swap,privkey,rp,statebits,optionduration,reinit)) != 0 ) + if ( (swap->fp= basilisk_swap_save(swap,privkey,rp,statebits,optionduration,reinit)) != 0 ) { } if ( reinit == 0 ) { - if ( myinfo->swapsfp == 0 ) + static FILE *swapsfp; + if ( swapsfp == 0 ) { char fname[512]; sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); - if ( (myinfo->swapsfp= fopen(fname,"rb+")) == 0 ) - myinfo->swapsfp = fopen(fname,"wb+"); - else fseek(myinfo->swapsfp,0,SEEK_END); - printf("LIST fp.%p\n",myinfo->swapsfp); + if ( (swapsfp= fopen(fname,"rb+")) == 0 ) + swapsfp = fopen(fname,"wb+"); + else fseek(swapsfp,0,SEEK_END); + printf("LIST fp.%p\n",swapsfp); } - if ( myinfo->swapsfp != 0 ) + if ( swapsfp != 0 ) { - fwrite(&rp->requestid,1,sizeof(rp->requestid),myinfo->swapsfp); - fwrite(&rp->quoteid,1,sizeof(rp->quoteid),myinfo->swapsfp); - fflush(myinfo->swapsfp); + fwrite(&rp->requestid,1,sizeof(rp->requestid),swapsfp); + fwrite(&rp->quoteid,1,sizeof(rp->quoteid),swapsfp); + fflush(swapsfp); } } if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) { } - myinfo->swaps[myinfo->numswaps++] = swap; + //myinfo->swaps[myinfo->numswaps++] = swap; } else { if ( statebits != 0 ) { - if ( (coin= iguana_coinfind(rp->src)) != 0 ) + if ( (coin= LP_coinfind(rp->src)) != 0 ) { } @@ -2371,9 +1140,9 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256 } } } - portable_mutex_unlock(&myinfo->DEX_swapmutex); + //portable_mutex_unlock(&myinfo->DEX_swapmutex); return(swap); } +#endif -/////////////// remember functions diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c new file mode 100644 index 000000000..2512c83f9 --- /dev/null +++ b/iguana/exchanges/LP_transaction.c @@ -0,0 +1,1657 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_transaction.c +// marketmaker +// + + + +#ifdef later +int32_t iguana_msgtx_Vset(uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,struct vin_info *V) +{ + int32_t vini,j,scriptlen,p2shlen,userdatalen,siglen,plen,need_op0=0,len = 0; uint8_t *script,*redeemscript=0,*userdata=0; struct vin_info *vp; + for (vini=0; vinitx_in; vini++) + { + vp = &V[vini]; + if ( (userdatalen= vp->userdatalen) == 0 ) + { + userdatalen = vp->userdatalen = msgtx->vins[vini].userdatalen; + userdata = msgtx->vins[vini].userdata; + } else userdata = vp->userdata; + if ( (p2shlen= vp->p2shlen) == 0 ) + { + p2shlen = vp->p2shlen = msgtx->vins[vini].p2shlen; + redeemscript = msgtx->vins[vini].redeemscript; + } + else + { + redeemscript = vp->p2shscript; + msgtx->vins[vini].redeemscript = redeemscript; + } + if ( msgtx->vins[vini].spendlen > 33 && msgtx->vins[vini].spendscript[msgtx->vins[vini].spendlen - 1] == SCRIPT_OP_CHECKMULTISIG ) + { + need_op0 = 1; + printf("found multisig spendscript\n"); + } + if ( redeemscript != 0 && p2shlen > 33 && redeemscript[p2shlen - 1] == SCRIPT_OP_CHECKMULTISIG ) + { + need_op0 = 1; + //printf("found multisig redeemscript\n"); + } + msgtx->vins[vini].vinscript = script = &serialized[len]; + msgtx->vins[vini].vinscript[0] = 0; + scriptlen = need_op0; + for (j=0; jN; j++) + { + if ( (siglen= vp->signers[j].siglen) > 0 ) + { + script[scriptlen++] = siglen; + memcpy(&script[scriptlen],vp->signers[j].sig,siglen); + scriptlen += siglen; + } + } + msgtx->vins[vini].scriptlen = scriptlen; + if ( vp->suppress_pubkeys == 0 && (vp->N > 1 || bitcoin_pubkeylen(&vp->spendscript[1]) != vp->spendscript[0] || vp->spendscript[vp->spendlen-1] != 0xac) ) + { + for (j=0; jN; j++) + { + if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) > 0 ) + { + script[scriptlen++] = plen; + memcpy(&script[scriptlen],vp->signers[j].pubkey,plen); + scriptlen += plen; + } + } + msgtx->vins[vini].scriptlen = scriptlen; + } + if ( userdatalen != 0 ) + { + memcpy(&script[scriptlen],userdata,userdatalen); + msgtx->vins[vini].userdata = &script[scriptlen]; + msgtx->vins[vini].userdatalen = userdatalen; + scriptlen += userdatalen; + } + //printf("USERDATALEN.%d scriptlen.%d redeemlen.%d\n",userdatalen,scriptlen,p2shlen); + if ( p2shlen != 0 ) + { + if ( p2shlen < 76 ) + script[scriptlen++] = p2shlen; + else if ( p2shlen <= 0xff ) + { + script[scriptlen++] = 0x4c; + script[scriptlen++] = p2shlen; + } + else if ( p2shlen <= 0xffff ) + { + script[scriptlen++] = 0x4d; + script[scriptlen++] = (p2shlen & 0xff); + script[scriptlen++] = ((p2shlen >> 8) & 0xff); + } else return(-1); + msgtx->vins[vini].p2shlen = p2shlen; + memcpy(&script[scriptlen],redeemscript,p2shlen); + scriptlen += p2shlen; + } + len += scriptlen; + } + if ( (0) ) + { + int32_t i; for (i=0; itx_out; + vpnstr[0] = 0; + *signedtx = 0; + memset(signedtxidp,0,sizeof(*signedtxidp)); + for (vini=0; vinitx_in; vini++) + { + if ( V->p2shscript[0] != 0 && V->p2shlen != 0 ) + { + script = V->p2shscript; + scriptlen = V->p2shlen; + //printf("V->p2shlen.%d\n",V->p2shlen); + } + else + { + script = msgtx->vins[vini].spendscript; + scriptlen = msgtx->vins[vini].spendlen; + } + sigtxid = bitcoin_sigtxid(pubtype,p2shtype,isPoS,height,serialized,maxlen,msgtx,vini,script,scriptlen,sighash,vpnstr,suppress_pubkeys); + if ( bits256_nonz(sigtxid) != 0 ) + { + vp = &V[vini]; + vp->sigtxid = sigtxid; + for (j=numsigs=0; jN; j++) + { + sig = vp->signers[j].sig; + siglen = vp->signers[j].siglen; + if ( signtx != 0 && bits256_nonz(vp->signers[j].privkey) != 0 ) + { + siglen = bitcoin_sign(swap->ctx,sig,sigtxid,vp->signers[j].privkey,0); + //if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) <= 0 ) + bitcoin_pubkey33(swap->ctx,vp->signers[j].pubkey,vp->signers[j].privkey); + sig[siglen++] = sighash; + vp->signers[j].siglen = siglen; + /*char str[65]; printf("SIGTXID.(%s) ",bits256_str(str,sigtxid)); + int32_t i; for (i=0; isigners[j].pubkey[i]); + // s2 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1; + printf(" SIGNEDTX.[%02x] siglen.%d priv.%s\n",sig[siglen-1],siglen,bits256_str(str,vp->signers[j].privkey));*/ + } + if ( sig == 0 || siglen == 0 ) + { + memset(vp->signers[j].pubkey,0,sizeof(vp->signers[j].pubkey)); + continue; + } + if ( bitcoin_verify(sig,siglen-1,sigtxid,vp->signers[j].pubkey,bitcoin_pubkeylen(vp->signers[j].pubkey)) < 0 ) + { + int32_t k; for (k=0; ksigners[j].pubkey); k++) + printf("%02x",vp->signers[j].pubkey[k]); + printf(" SIG.%d.%d ERROR siglen.%d\n",vini,j,siglen); + } + else + { + flag++; + numsigs++; + /*int32_t z; + for (z=0; zsigners[j].pubkey[z]); + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M);*/ + } + } + if ( numsigs >= vp->M ) + complete = 1; + } + } + iguana_msgtx_Vset(serialized,maxlen,msgtx,V); + cJSON *txobj = cJSON_CreateObject(); + *signedtx = iguana_rawtxbytes(pubtype,p2shtype,isPoS,height,txobj,msgtx,suppress_pubkeys); + //printf("SIGNEDTX.(%s)\n",jprint(txobj,1)); + *signedtxidp = msgtx->txid; + return(complete); +} + +int32_t iguana_vininfo_create(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msgtx,cJSON *vins,int32_t numinputs,struct vin_info *V) +{ + int32_t i,plen,finalized = 1,len = 0; struct vin_info *vp; //struct iguana_waccount *wacct; struct iguana_waddress *waddr; uint32_t sigsize,pubkeysize,p2shsize,userdatalen; + msgtx->tx_in = numinputs; + maxsize -= (sizeof(struct iguana_msgvin) * msgtx->tx_in); + msgtx->vins = (struct iguana_msgvin *)&serialized[maxsize]; + memset(msgtx->vins,0,sizeof(struct iguana_msgvin) * msgtx->tx_in); + if ( msgtx->tx_in > 0 && msgtx->tx_in*sizeof(struct iguana_msgvin) < maxsize ) + { + for (i=0; itx_in; i++) + { + vp = &V[i]; + //printf("VINS.(%s)\n",jprint(jitem(vins,i),0)); + len += iguana_parsevinobj(&serialized[len],maxsize,&msgtx->vins[i],jitem(vins,i),vp); + if ( msgtx->vins[i].sequence < IGUANA_SEQUENCEID_FINAL ) + finalized = 0; + if ( msgtx->vins[i].spendscript == 0 ) + { + /*if ( iguana_RTunspentindfind(coin,&outpt,vp->coinaddr,vp->spendscript,&vp->spendlen,&vp->amount,&vp->height,msgtx->vins[i].prev_hash,msgtx->vins[i].prev_vout,coin->bundlescount-1,0) == 0 ) + { + vp->unspentind = outpt.unspentind; + msgtx->vins[i].spendscript = vp->spendscript; + msgtx->vins[i].spendlen = vp->spendlen; + vp->hashtype = iguana_vinscriptparse(coin,vp,&sigsize,&pubkeysize,&p2shsize,&userdatalen,vp->spendscript,vp->spendlen); + vp->userdatalen = userdatalen; + printf("V %.8f (%s) spendscript.[%d] userdatalen.%d\n",dstr(vp->amount),vp->coinaddr,vp->spendlen,userdatalen); + }*/ + } + else + { + memcpy(vp->spendscript,msgtx->vins[i].spendscript,msgtx->vins[i].spendlen); + vp->spendlen = msgtx->vins[i].spendlen; + _iguana_calcrmd160(pubtype,p2shtype,vp); + if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) > 0 ) + bitcoin_address(vp->coinaddr,pubtype,vp->signers[0].pubkey,plen); + } + if ( vp->M == 0 && vp->N == 0 ) + vp->M = vp->N = 1; + /*if ( vp->coinaddr[i] != 0 && (waddr= iguana_waddresssearch(&wacct,vp->coinaddr)) != 0 ) + { + vp->signers[0].privkey = waddr->privkey; + if ( (plen= bitcoin_pubkeylen(waddr->pubkey)) != vp->spendscript[1] || vp->spendscript[vp->spendlen-1] != 0xac ) + { + if ( plen > 0 && plen < sizeof(vp->signers[0].pubkey) ) + memcpy(vp->signers[0].pubkey,waddr->pubkey,plen); + } + }*/ + } + } + return(finalized); +} + +void iguana_ensure_privkey(struct iguana_info *coin,bits256 privkey) +{ + uint8_t pubkey33[33]; struct iguana_waccount *wacct; struct iguana_waddress *waddr,addr; char coinaddr[128]; + bitcoin_pubkey33(swap->ctx,pubkey33,privkey); + bitcoin_address(coinaddr,coin->pubtype,pubkey33,33); + //printf("privkey for (%s)\n",coinaddr); + if ( myinfo->expiration != 0 && ((waddr= iguana_waddresssearch(&wacct,coinaddr)) == 0 || bits256_nonz(waddr->privkey) == 0) ) + { + if ( waddr == 0 ) + { + memset(&addr,0,sizeof(addr)); + iguana_waddresscalc(coin->pubtype,coin->wiftype,&addr,privkey); + if ( (wacct= iguana_waccountfind("default")) != 0 ) + waddr = iguana_waddressadd(coin,wacct,&addr,0); + } + if ( waddr != 0 ) + { + waddr->privkey = privkey; + if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->wiftype) > 0 ) + { + if ( (0) && waddr->wiftype != coin->wiftype ) + printf("ensurepriv warning: mismatched wiftype %02x != %02x\n",waddr->wiftype,coin->wiftype); + if ( (0) && waddr->addrtype != coin->pubtype ) + printf("ensurepriv warning: mismatched addrtype %02x != %02x\n",waddr->addrtype,coin->pubtype); + } + } + } +} + +int32_t iguana_interpreter(struct iguana_info *coin,cJSON *logarray,int64_t nLockTime,struct vin_info *V,int32_t numvins) +{ + uint8_t script[IGUANA_MAXSCRIPTSIZE],*activescript,savescript[IGUANA_MAXSCRIPTSIZE]; char str[IGUANA_MAXSCRIPTSIZE*2+1]; int32_t vini,scriptlen,activescriptlen,savelen,errs = 0; cJSON *spendscript,*item=0; + for (vini=0; vini 0 ) + { + activescript = V[vini].p2shscript; + activescriptlen = V[vini].p2shlen; + } + else + { + activescript = V[vini].spendscript; + activescriptlen = V[vini].spendlen; + } + memcpy(V[vini].spendscript,activescript,activescriptlen); + V[vini].spendlen = activescriptlen; + spendscript = iguana_spendasm(coin,activescript,activescriptlen); + if ( activescriptlen < 16 ) + continue; + //printf("interpreter.(%s)\n",jprint(spendscript,0)); + if ( (scriptlen= bitcoin_assembler(coin,logarray,script,spendscript,1,nLockTime,&V[vini])) < 0 ) + { + //printf("bitcoin_assembler error scriptlen.%d\n",scriptlen); + errs++; + } + else if ( scriptlen != activescriptlen || memcmp(script,activescript,scriptlen) != 0 ) + { + if ( logarray != 0 ) + { + item = cJSON_CreateObject(); + jaddstr(item,"error","script reconstruction failed"); + } + init_hexbytes_noT(str,activescript,activescriptlen); + //printf("activescript.(%s)\n",str); + if ( logarray != 0 && item != 0 ) + jaddstr(item,"original",str); + init_hexbytes_noT(str,script,scriptlen); + //printf("reconstructed.(%s)\n",str); + if ( logarray != 0 ) + { + jaddstr(item,"reconstructed",str); + jaddi(logarray,item); + } else printf(" scriptlen mismatch.%d vs %d or miscompare\n",scriptlen,activescriptlen); + errs++; + } + memcpy(V[vini].spendscript,savescript,savelen); + V[vini].spendlen = savelen; + } + if ( errs != 0 ) + return(-errs); + if ( logarray != 0 ) + { + item = cJSON_CreateObject(); + jaddstr(item,"result","success"); + jaddi(logarray,item); + } + return(0); +} + +bits256 iguana_str2priv(char *str) +{ + bits256 privkey; int32_t n; uint8_t addrtype; //struct iguana_waccount *wacct=0; struct iguana_waddress *waddr; + memset(&privkey,0,sizeof(privkey)); + if ( str != 0 ) + { + n = (int32_t)strlen(str) >> 1; + if ( n == sizeof(bits256) && is_hexstr(str,sizeof(bits256)) > 0 ) + decode_hex(privkey.bytes,sizeof(privkey),str); + else if ( bitcoin_wif2priv(&addrtype,&privkey,str) != sizeof(bits256) ) + { + //if ( (waddr= iguana_waddresssearch(&wacct,str)) != 0 ) + // privkey = waddr->privkey; + //else memset(privkey.bytes,0,sizeof(privkey)); + } + } + return(privkey); +} + +int32_t iguana_signrawtransaction(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,struct iguana_msgtx *msgtx,char **signedtxp,bits256 *signedtxidp,struct vin_info *V,int32_t numinputs,char *rawtx,cJSON *vins,cJSON *privkeysjson) +{ + uint8_t *serialized,*serialized2,*serialized3,*serialized4,*extraspace,pubkeys[64][33]; int32_t finalized,i,len,n,z,plen,maxsize,complete = 0,extralen = 65536; char *privkeystr,*signedtx = 0; bits256 privkeys[64],privkey,txid; cJSON *item; cJSON *txobj = 0; + maxsize = 1000000; + memset(privkey.bytes,0,sizeof(privkey)); + if ( rawtx != 0 && rawtx[0] != 0 && (len= (int32_t)strlen(rawtx)>>1) < maxsize ) + { + serialized = malloc(maxsize); + serialized2 = malloc(maxsize); + serialized3 = malloc(maxsize); + serialized4 = malloc(maxsize); + extraspace = malloc(extralen); + memset(msgtx,0,sizeof(*msgtx)); + decode_hex(serialized,len,rawtx); + // printf("call hex2json.(%s) vins.(%s)\n",rawtx,jprint(vins,0)); + if ( (txobj= bitcoin_hex2json(pubtype,p2shtype,isPoS,height,&txid,msgtx,rawtx,extraspace,extralen,serialized4,vins,V->suppress_pubkeys)) != 0 ) + { + //printf("back from bitcoin_hex2json (%s)\n",jprint(vins,0)); + } else fprintf(stderr,"no txobj from bitcoin_hex2json\n"); + if ( (numinputs= cJSON_GetArraySize(vins)) > 0 ) + { + //printf("numinputs.%d msgtx.%d\n",numinputs,msgtx->tx_in); + memset(msgtx,0,sizeof(*msgtx)); + if ( iguana_rwmsgtx(pubtype,p2shtype,isPoS,height,0,0,serialized,maxsize,msgtx,&txid,"",extraspace,65536,vins,V->suppress_pubkeys) > 0 && numinputs == msgtx->tx_in ) + { + memset(pubkeys,0,sizeof(pubkeys)); + memset(privkeys,0,sizeof(privkeys)); + if ( (n= cJSON_GetArraySize(privkeysjson)) > 0 ) + { + for (i=0; ictx,pubkeys[i],privkey); + //if ( bits256_nonz(privkey) != 0 ) + // iguana_ensure_privkey(coin,privkey); + } + } + //printf("after privkeys tx_in.%d\n",msgtx->tx_in); + for (i=0; itx_in; i++) + { + if ( msgtx->vins[i].p2shlen != 0 ) + { + char coinaddr[64]; uint32_t userdatalen,sigsize,pubkeysize; uint8_t *userdata; int32_t j,k,hashtype,type,flag; struct vin_info mvin,mainvin; bits256 zero; + memset(zero.bytes,0,sizeof(zero)); + coinaddr[0] = 0; + sigsize = 0; + flag = (msgtx->vins[i].vinscript[0] == 0); + type = bitcoin_scriptget(pubtype,p2shtype,&hashtype,&sigsize,&pubkeysize,&userdata,&userdatalen,&mainvin,msgtx->vins[i].vinscript+flag,msgtx->vins[i].scriptlen-flag,0); + //printf("i.%d flag.%d type.%d scriptlen.%d\n",i,flag,type,msgtx->vins[i].scriptlen); + if ( msgtx->vins[i].redeemscript != 0 ) + { + //for (j=0; jvins[i].p2shlen; j++) + // printf("%02x",msgtx->vins[i].redeemscript[j]); + bitcoin_address(coinaddr,p2shtype,msgtx->vins[i].redeemscript,msgtx->vins[i].p2shlen); + type = iguana_calcrmd160(pubtype,p2shtype,0,&mvin,msgtx->vins[i].redeemscript,msgtx->vins[i].p2shlen,zero,0,0); + for (j=0; jsuppress_pubkeys == 0 ) + { + for (z=0; z<33; z++) + V[i].signers[j].pubkey[z] = mvin.signers[j].pubkey[z]; + } + if ( flag != 0 && pubkeysize == 33 && mainvin.signers[0].siglen != 0 ) // jl777: need to generalize + { + if ( memcmp(mvin.signers[j].pubkey,mainvin.signers[0].pubkey,33) == 0 ) + { + for (z=0; zsuppress_pubkeys == 0 ) + { + for (z=0; z<33; z++) + V[i].signers[j].pubkey[z] = pubkeys[k][z]; + } + //printf("%s -> V[%d].signer.[%d] <- privkey.%d\n",mvin.signers[j].coinaddr,i,j,k); + break; + } + } + } + //printf("type.%d p2sh.[%d] -> %s M.%d N.%d\n",type,i,mvin.coinaddr,mvin.M,mvin.N); + } + } + if ( i < V->N ) + V->signers[i].privkey = privkey; + if ( i < numinputs ) + V[i].signers[0].privkey = privkey; + plen = bitcoin_pubkeylen(V->signers[i].pubkey); + if ( V->suppress_pubkeys == 0 && plen <= 0 ) + { + if ( i < numinputs ) + { + for (z=0; zsigners[i].pubkey[z]; + } + } + } + finalized = iguana_vininfo_create(pubtype,p2shtype,isPoS,serialized2,maxsize,msgtx,vins,numinputs,V); + //printf("finalized.%d\n",finalized); + if ( (complete= bitcoin_verifyvins(pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) + { + /*int32_t tmp; //char str[65]; + if ( (tmp= iguana_interpreter(coin,0,iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) + { + printf("iguana_interpreter %d error.(%s)\n",tmp,signedtx); + complete = 0; + } */ + } else printf("complete.%d\n",complete); + } else printf("rwmsgtx error\n"); + } else fprintf(stderr,"no inputs in vins.(%s)\n",vins!=0?jprint(vins,0):"null"); + free(extraspace); + free(serialized), free(serialized2), free(serialized3), free(serialized4); + } else return(-1); + if ( txobj != 0 ) + free_json(txobj); + *signedtxp = signedtx; + return(complete); +} +#endif + +/*int32_t basilisk_rawtx_return(struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) +{ + char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; + if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) + { + privkeyarray = cJSON_CreateArray(); + jaddistr(privkeyarray,wifstr); + if ( (signedtx= LP_signrawtx(rawtx->coin->symbol,&rawtx->I.signedtxid,&rawtx->I.completed,vins,txbytes,privkeyarray,V)) != 0 ) + { + if ( lockinputs != 0 ) + { + //printf("lockinputs\n"); + LP_unspentslock(rawtx->coin->symbol,vins); + if ( (n= cJSON_GetArraySize(vins)) != 0 ) + { + bits256 txid; int32_t vout; + for (i=0; iI.datalen = (int32_t)strlen(signedtx) >> 1; + //rawtx->txbytes = calloc(1,rawtx->I.datalen); + decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); + //printf("%s SIGNEDTX.(%s)\n",rawtx->name,signedtx); + free(signedtx); + retval = 0; + } else printf("error signrawtx\n"); //do a very short timeout so it finishes via local poll + free_json(privkeyarray); + } + return(retval); +} + +cJSON *LP_createvins(struct basilisk_rawtx *dest,struct vin_info *V,struct basilisk_rawtx *rawtx,uint8_t *userdata,int32_t userdatalen,uint32_t sequenceid) +{ + cJSON *vins,*item,*sobj; char hexstr[8192]; + vins = cJSON_CreateArray(); + item = cJSON_CreateObject(); + if ( userdata != 0 && userdatalen > 0 ) + { + memcpy(V[0].userdata,userdata,userdatalen); + V[0].userdatalen = userdatalen; + init_hexbytes_noT(hexstr,userdata,userdatalen); + jaddstr(item,"userdata",hexstr); +#ifdef DISABLE_CHECKSIG + needsig = 0; +#endif + } + //printf("rawtx B\n"); + if ( bits256_nonz(rawtx->I.actualtxid) != 0 ) + jaddbits256(item,"txid",rawtx->I.actualtxid); + else jaddbits256(item,"txid",rawtx->I.signedtxid); + jaddnum(item,"vout",0); + sobj = cJSON_CreateObject(); + init_hexbytes_noT(hexstr,rawtx->spendscript,rawtx->I.spendlen); + jaddstr(sobj,"hex",hexstr); + jadd(item,"scriptPubKey",sobj); + jaddnum(item,"suppress",dest->I.suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); + if ( (dest->I.redeemlen= rawtx->I.redeemlen) != 0 ) + { + init_hexbytes_noT(hexstr,rawtx->redeemscript,rawtx->I.redeemlen); + memcpy(dest->redeemscript,rawtx->redeemscript,rawtx->I.redeemlen); + jaddstr(item,"redeemScript",hexstr); + } + jaddi(vins,item); + return(vins); +} + +int32_t _basilisk_rawtx_gen(char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey) +{ + char scriptstr[1024],wifstr[256],coinaddr[64],*signedtx,*rawtxbytes; uint32_t basilisktag; int32_t retval = -1; cJSON *vins,*privkeys,*addresses,*valsobj; struct vin_info *V; + //bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,myinfo->persistent_pubkey33,33); + if ( rawtx->coin->changeaddr[0] == 0 ) + { + bitcoin_address(rawtx->coin->changeaddr,rawtx->coin->pubtype,pubkey33,33); + printf("set change address.(%s)\n",rawtx->coin->changeaddr); + } + init_hexbytes_noT(scriptstr,script,scriptlen); + basilisktag = (uint32_t)rand(); + valsobj = cJSON_CreateObject(); + jaddstr(valsobj,"coin",rawtx->coin->symbol); + jaddstr(valsobj,"spendscript",scriptstr); + jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); + jadd64bits(valsobj,"satoshis",rawtx->I.amount); + if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) + txfee = 50000; + jadd64bits(valsobj,"txfee",txfee); + jaddnum(valsobj,"minconf",minconf); + if ( locktime == 0 ) + locktime = (uint32_t)time(NULL) - 777; + jaddnum(valsobj,"locktime",locktime); + jaddnum(valsobj,"timeout",30000); + jaddnum(valsobj,"timestamp",swapstarted+delay); + addresses = cJSON_CreateArray(); + bitcoin_address(coinaddr,rawtx->coin->pubtype,pubkey33,33); + jaddistr(addresses,coinaddr); + jadd(valsobj,"addresses",addresses); + rawtx->I.locktime = locktime; + printf("%s locktime.%u\n",rawtx->name,locktime); + V = calloc(256,sizeof(*V)); + privkeys = cJSON_CreateArray(); + bitcoin_priv2wif(wifstr,privkey,rawtx->coin->wiftype); + jaddistr(privkeys,wifstr); + vins = LP_createvins(rawtx,V,rawtx,0,0,0xffffffff); + rawtx->vins = jduplicate(vins); + jdelete(valsobj,"vin"); + jadd(valsobj,"vin",vins); + if ( (rawtxbytes= bitcoin_json2hex(rawtx->coin->isPoS,&rawtx->I.txid,valsobj,V)) != 0 ) + { + //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); + if ( (signedtx= LP_signrawtx(rawtx->coin->symbol,&rawtx->I.signedtxid,&rawtx->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) + { + rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) + decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); + else printf("DEX tx is too big %d vs %d\n",rawtx->I.datalen,(int32_t)sizeof(rawtx->txbytes)); + if ( signedtx != rawtxbytes ) + free(signedtx); + if ( rawtx->I.completed != 0 ) + retval = 0; + else printf("couldnt complete sign transaction %s\n",rawtx->name); + } else printf("error signing\n"); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(valsobj); + free(V); + return(retval); +} + + +int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,uint32_t timestamp,uint32_t locktime,uint32_t sequenceid,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) +{ + char *rawtxbytes=0,*signedtx=0,wifstr[128]; cJSON *txobj,*vins,*privkeys; int32_t needsig=1,retval = -1; struct vin_info *V; + V = calloc(256,sizeof(*V)); + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(swap->ctx,V[0].signers[0].pubkey,privkey); + privkeys = cJSON_CreateArray(); + bitcoin_priv2wif(wifstr,privkey,wiftype); + jaddistr(privkeys,wifstr); + if ( privkey2 != 0 ) + { + V[0].signers[1].privkey = *privkey2; + bitcoin_pubkey33(swap->ctx,V[0].signers[1].pubkey,*privkey2); + bitcoin_priv2wif(wifstr,*privkey2,wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 2; + //char str[65]; printf("add second privkey.(%s) %s\n",jprint(privkeys,0),bits256_str(str,*privkey2)); + } else V[0].N = V[0].M = 1; + V[0].suppress_pubkeys = dest->I.suppress_pubkeys; + V[0].ignore_cltverr = ignore_cltverr; + if ( dest->I.redeemlen != 0 ) + memcpy(V[0].p2shscript,dest->redeemscript,dest->I.redeemlen), V[0].p2shlen = dest->I.redeemlen; + txobj = bitcoin_txcreate(symbol,isPoS,locktime,userdata == 0 ? 1 : 1,timestamp);//rawtx->coin->locktime_txversion); + vins = LP_createvins(dest,V,rawtx,userdata,userdatalen,sequenceid); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + //printf("basilisk_rawtx_sign locktime.%u/%u for %s spendscript.%s -> %s, suppress.%d\n",rawtx->I.locktime,dest->I.locktime,rawtx->name,hexstr,dest->name,dest->I.suppress_pubkeys); + txobj = bitcoin_txoutput(txobj,dest->spendscript,dest->I.spendlen,dest->I.amount); + if ( (rawtxbytes= bitcoin_json2hex(isPoS,&dest->I.txid,txobj,V)) != 0 ) + { + //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); + if ( needsig == 0 ) + signedtx = rawtxbytes; + if ( signedtx != 0 || (signedtx= LP_signrawtx(symbol,&dest->I.signedtxid,&dest->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) + { + dest->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( dest->I.datalen <= sizeof(dest->txbytes) ) + decode_hex(dest->txbytes,dest->I.datalen,signedtx); + else printf("DEX tx is too big %d vs %d\n",dest->I.datalen,(int32_t)sizeof(dest->txbytes)); + if ( signedtx != rawtxbytes ) + free(signedtx); + if ( dest->I.completed != 0 ) + retval = 0; + else printf("couldnt complete sign transaction %s\n",rawtx->name); + } else printf("error signing\n"); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(txobj); + free(V); + return(retval); +}*/ + +char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp) +{ + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount; + *destamountp = 0; + memset(signedtxidp,0,sizeof(*signedtxidp)); + if ( finalseqid == 0 ) + locktime = expiration; + //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + if ( redeemlen < 0 ) + return(0); + if ( (utxoobj= LP_swapgettxout(symbol,utxotxid,vout)) == 0 ) + { + printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); + return(0); + } + if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + { + printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); + free_json(utxoobj); + return(0); + } else free_json(utxoobj); + *destamountp = destamount; + if ( destamount > txfee ) + destamount -= txfee; + timestamp = (uint32_t)time(NULL); + V = calloc(256,sizeof(*V)); + privkeys = cJSON_CreateArray(); + if ( privkey2p != 0 ) + { + V[0].signers[1].privkey = *privkey2p; + bitcoin_pubkey33(ctx,V[0].signers[1].pubkey,*privkey2p); + bitcoin_priv2wif(wifstr,*privkey2p,wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 2; + } else V[0].N = V[0].M = 1; + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(ctx,V[0].signers[0].pubkey,privkey); + bitcoin_priv2wif(wifstr,privkey,wiftype); + jaddistr(privkeys,wifstr); + V[0].suppress_pubkeys = suppress_pubkeys; + V[0].ignore_cltverr = ignore_cltverr; + if ( redeemlen != 0 ) + memcpy(V[0].p2shscript,redeemscript,redeemlen), V[0].p2shlen = redeemlen; + txobj = bitcoin_txcreate(symbol,isPoS,locktime,1,timestamp); + vins = cJSON_CreateArray(); + item = cJSON_CreateObject(); + if ( userdata != 0 && userdatalen > 0 ) + { + memcpy(V[0].userdata,userdata,userdatalen); + V[0].userdatalen = userdatalen; + init_hexbytes_noT(hexstr,userdata,userdatalen); + jaddstr(item,"userdata",hexstr); + } + jaddbits256(item,"txid",utxotxid); + jaddnum(item,"vout",vout); + sobj = cJSON_CreateObject(); + bitcoin_address(destaddr,pubtype,pubkey33,33); + bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); + /*int32_t i; + for (i=0; i<33; i++) + printf("%02x",pubkey33[i]); + printf(" pubkey33 ->\n"); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" destaddr.(%s)\n",destaddr); + calc_rmd160_sha256(rmd160,pubkey33,33); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- vs direct calc\n");*/ + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + init_hexbytes_noT(hexstr,spendscript,spendlen); + jaddstr(sobj,"hex",hexstr); + jadd(item,"scriptPubKey",sobj); + jaddnum(item,"suppress",suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); + if ( redeemlen != 0 ) + { + init_hexbytes_noT(hexstr,redeemscript,redeemlen); + jaddstr(item,"redeemScript",hexstr); + } + jaddi(vins,item); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); + if ( (rawtxbytes= bitcoin_json2hex(isPoS,&txid,txobj,V)) != 0 ) + { + //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); + if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) + printf("couldnt sign transaction\n"); + else if ( completed == 0 ) + { + printf("incomplete signing\n"); + if ( signedtx != 0 ) + free(signedtx), signedtx = 0; + } else printf("%s -> %s\n",name,bits256_str(str,*signedtxidp)); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(txobj); + free(V); + return(signedtx); +} + +int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey) +{ + int32_t retval=-1,len,iter; char *signedtx; struct iguana_info *coin; int64_t newtxfee=0,destamount; + if ( (coin= rawtx->coin) == 0 ) + return(-1); + //return(_basilisk_rawtx_gen(str,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay,privkey)); + for (iter=0; iter<2; iter++) + { + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,pubkey33,1,0,&destamount)) != 0 ) + { + rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) + { + decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); + rawtx->I.completed = 1; + retval = 0; + } + free(signedtx); + if ( strcmp(coin->symbol,"BTC") != 0 ) + return(retval); + len = rawtx->I.datalen; + if ( coin->estimatedfee == 0 ) + coin->estimatedfee = LP_getestimatedfee(coin->symbol); + newtxfee = coin->estimatedfee * len; + printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); + } else break; + } + return(retval); +} + +int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) +{ + char *signedtx; int64_t txfee,newtxfee=0,estimatedfee,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; + timestamp = swap->I.started; + if ( dest == &swap->aliceclaim ) + locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; + else if ( dest == &swap->bobreclaim ) + locktime = swap->bobpayment.I.locktime + 1, sequenceid = 0; + txfee = strcmp("BTC",symbol) == 0 ? 0 : 10000; + for (iter=0; iter<2; iter++) + { + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,rawtx->pubkey33,1,0,&destamount)) != 0 ) + { + rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) + { + decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); + rawtx->I.completed = 1; + retval = 0; + } + free(signedtx); + if ( strcmp(symbol,"BTC") != 0 ) + return(retval); + len = rawtx->I.datalen; + estimatedfee = LP_getestimatedfee(symbol); + newtxfee = estimatedfee * len; + } else break; + } + return(retval); + //return(_basilisk_rawtx_sign(symbol,pubtype,p2shtype,isPoS,wiftype,swap,timestamp,locktime,sequenceid,dest,rawtx,privkey,privkey2,userdata,userdatalen,ignore_cltverr)); +} + +int32_t basilisk_alicescript(uint8_t *redeemscript,int32_t *redeemlenp,uint8_t *script,int32_t n,char *msigaddr,uint8_t altps2h,bits256 pubAm,bits256 pubBn) +{ + uint8_t p2sh160[20]; struct vin_info V; + memset(&V,0,sizeof(V)); + memcpy(&V.signers[0].pubkey[1],pubAm.bytes,sizeof(pubAm)), V.signers[0].pubkey[0] = 0x02; + memcpy(&V.signers[1].pubkey[1],pubBn.bytes,sizeof(pubBn)), V.signers[1].pubkey[0] = 0x03; + V.M = V.N = 2; + *redeemlenp = bitcoin_MofNspendscript(p2sh160,redeemscript,n,&V); + bitcoin_address(msigaddr,altps2h,p2sh160,sizeof(p2sh160)); + n = bitcoin_p2shspend(script,0,p2sh160); + //for (i=0; i<*redeemlenp; i++) + // printf("%02x",redeemscript[i]); + //printf(" <- redeemscript alicetx\n"); + return(n); +} + +char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp) +{ + char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn,signedtxid; uint64_t txfee; + if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) + { + pubAm = bitcoin_pubkey33(ctx,tmp33,privAm); + pubBn = bitcoin_pubkey33(ctx,tmp33,privBn); + //char str[65]; + //printf("pubAm.(%s)\n",bits256_str(str,pubAm)); + //printf("pubBn.(%s)\n",bits256_str(str,pubBn)); + spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,p2shtype,pubAm,pubBn); + //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); + /*rev = privAm; + for (i=0; i<32; i++) + privAm.bytes[i] = rev.bytes[31 - i]; + rev = privBn; + for (i=0; i<32; i++) + privBn.bytes[i] = rev.bytes[31 - i];*/ + txfee = LP_txfee(symbol); + signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration,destamountp); + } + return(signedtx); +} + +int32_t LP_swap_txdestaddr(char *destaddr,bits256 txid,int32_t vout,cJSON *txobj) +{ + int32_t n,m,retval = -1; cJSON *vouts,*item,*addresses,*skey; char *addr; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && vout < n ) + { + item = jitem(vouts,vout); + if ( (skey= jobj(item,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + { + item = jitem(addresses,0); + if ( (addr= jstr(item,0)) != 0 ) + { + safecopy(destaddr,addr,64); + retval = 0; + } + //printf("item.(%s) -> dest.(%s)\n",jprint(item,0),destaddr); + } + } + return(retval); +} + +int32_t LP_swap_getcoinaddr(char *symbol,char *coinaddr,bits256 txid,int32_t vout) +{ + cJSON *retjson; + coinaddr[0] = 0; + if ( (retjson= LP_swapgettx(symbol,txid)) != 0 ) + { + LP_swap_txdestaddr(coinaddr,txid,vout,retjson); + free_json(retjson); + } + return(coinaddr[0] != 0); +} + +int32_t basilisk_swap_getsigscript(char *symbol,uint8_t *script,int32_t maxlen,bits256 txid,int32_t vini) +{ + cJSON *retjson,*vins,*item,*skey; int32_t n,scriptlen = 0; char *hexstr; + if ( (retjson= LP_swapgettx(symbol,txid)) != 0 ) + { + if ( (vins= jarray(&n,retjson,"vin")) != 0 && vini < n ) + { + item = jitem(vins,vini); + if ( (skey= jobj(item,"scriptSig")) != 0 && (hexstr= jstr(skey,"hex")) != 0 && (scriptlen= (int32_t)strlen(hexstr)) < maxlen*2 ) + { + scriptlen >>= 1; + decode_hex(script,scriptlen,hexstr); + //char str[65]; printf("%s/v%d sigscript.(%s)\n",bits256_str(str,txid),vini,hexstr); + } + } + free_json(retjson); + } + return(scriptlen); +} + +int64_t basilisk_txvalue(char *symbol,bits256 txid,int32_t vout) +{ + cJSON *txobj,*vouts,*item; int32_t n; int64_t value = 0; + //char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid)); + if ( (txobj= LP_swapgettx(symbol,txid)) != 0 ) + { + //printf("txobj.(%s)\n",jprint(txobj,0)); + if ( (vouts= jarray(&n,txobj,"vout")) != 0 ) + { + item = jitem(vouts,vout); + if ( (value= jdouble(item,"amount") * SATOSHIDEN) == 0 ) + value = jdouble(item,"value") * SATOSHIDEN; + } + free_json(txobj); + } + return(value); +} + +bits256 _LP_swap_spendtxid(char *symbol,char *destaddr,char *coinaddr,bits256 utxotxid,int32_t vout) +{ + char *retstr,*addr; cJSON *array,*item,*array2; int32_t i,n,m; bits256 spendtxid,txid; + memset(&spendtxid,0,sizeof(spendtxid)); + if ( (retstr= dex_listtransactions(symbol,coinaddr,100,0)) != 0 ) + { + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i %s\n",bits256_str(str,spendtxid),destaddr); + break; + } + } + } + } + free_json(array); + } + free(retstr); + } + return(spendtxid); +} + +bits256 LP_swap_spendtxid(char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) +{ + bits256 spendtxid,txid; char *catstr,*addr; cJSON *array,*item,*item2,*txobj,*vins; int32_t i,n,m; char coinaddr[64],str[65]; + // listtransactions or listspents + destaddr[0] = 0; + coinaddr[0] = 0; + memset(&spendtxid,0,sizeof(spendtxid)); + //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); + if ( strcmp("BTC",symbol) == 0 ) + { + //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] + LP_swap_getcoinaddr(symbol,coinaddr,utxotxid,vout); + if ( coinaddr[0] != 0 ) + spendtxid = _LP_swap_spendtxid(symbol,destaddr,coinaddr,utxotxid,vout); + } + else + { + if ( (array= LP_listtransactions(symbol,destaddr,1000,0)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i 0 ) + { + for (i=0; i jint(item,"vout") ) + { + item2 = jitem(vins,jint(item,"vout")); + if ( bits256_cmp(utxotxid,jbits256(item2,"txid")) == 0 && vout == jint(item2,"vout") ) + { + spendtxid = txid; + break; + } + } + } + } + } + if ( i == n ) + printf("dpowlist: native couldnt find spendtxid for %s\n",bits256_str(str,utxotxid)); + } + free_json(array); + } + if ( bits256_nonz(spendtxid) != 0 ) + return(spendtxid); + } + /*if ( iguana_isnotarychain(symbol) >= 0 ) + { + LP_swap_getcoinaddr(symbol,coinaddr,utxotxid,vout); + printf("fallback use DEX for native (%s) (%s)\n",coinaddr,bits256_str(str,utxotxid)); + if ( coinaddr[0] != 0 ) + { + spendtxid = _LP_swap_spendtxid(symbol,destaddr,coinaddr,utxotxid,vout); + printf("spendtxid.(%s)\n",bits256_str(str,spendtxid)); + } + }*/ + } + return(spendtxid); +} + +int32_t basilisk_swap_bobredeemscript(int32_t depositflag,int32_t *secretstartp,uint8_t *redeemscript,uint32_t locktime,bits256 pubA0,bits256 pubB0,bits256 pubB1,bits256 privAm,bits256 privBn,uint8_t *secretAm,uint8_t *secretAm256,uint8_t *secretBn,uint8_t *secretBn256) +{ + int32_t i,n=0; bits256 cltvpub,destpub,privkey; uint8_t pubkeyA[33],pubkeyB[33],secret160[20],secret256[32]; + if ( depositflag != 0 ) + { + pubkeyA[0] = 0x02, cltvpub = pubA0; + pubkeyB[0] = 0x03, destpub = pubB0; + privkey = privBn; + memcpy(secret160,secretBn,20); + memcpy(secret256,secretBn256,32); + } + else + { + pubkeyA[0] = 0x03, cltvpub = pubB1; + pubkeyB[0] = 0x02, destpub = pubA0; + privkey = privAm; + memcpy(secret160,secretAm,20); + memcpy(secret256,secretAm256,32); + } + //for (i=0; i<32; i++) + // printf("%02x",secret256[i]); + //printf(" <- secret256 depositflag.%d nonz.%d\n",depositflag,bits256_nonz(privkey)); + if ( bits256_nonz(cltvpub) == 0 || bits256_nonz(destpub) == 0 ) + return(-1); + for (i=0; i<20; i++) + if ( secret160[i] != 0 ) + break; + if ( i == 20 ) + return(-1); + memcpy(pubkeyA+1,cltvpub.bytes,sizeof(cltvpub)); + memcpy(pubkeyB+1,destpub.bytes,sizeof(destpub)); + redeemscript[n++] = SCRIPT_OP_IF; + n = bitcoin_checklocktimeverify(redeemscript,n,locktime); +#ifdef DISABLE_CHECKSIG + n = bitcoin_secret256spend(redeemscript,n,cltvpub); +#else + n = bitcoin_pubkeyspend(redeemscript,n,pubkeyA); +#endif + redeemscript[n++] = SCRIPT_OP_ELSE; + if ( secretstartp != 0 ) + *secretstartp = n + 2; + if ( 1 ) + { + if ( 1 && bits256_nonz(privkey) != 0 ) + { + uint8_t bufA[20],bufB[20]; + revcalc_rmd160_sha256(bufA,privkey); + calc_rmd160_sha256(bufB,privkey.bytes,sizeof(privkey)); + /*if ( memcmp(bufA,secret160,sizeof(bufA)) == 0 ) + printf("MATCHES BUFA\n"); + else if ( memcmp(bufB,secret160,sizeof(bufB)) == 0 ) + printf("MATCHES BUFB\n"); + else printf("secret160 matches neither\n"); + for (i=0; i<20; i++) + printf("%02x",bufA[i]); + printf(" <- revcalc\n"); + for (i=0; i<20; i++) + printf("%02x",bufB[i]); + printf(" <- calc\n");*/ + memcpy(secret160,bufB,20); + } + n = bitcoin_secret160verify(redeemscript,n,secret160); + } + else + { + redeemscript[n++] = 0xa8;//IGUANA_OP_SHA256; + redeemscript[n++] = 0x20; + memcpy(&redeemscript[n],secret256,0x20), n += 0x20; + redeemscript[n++] = 0x88; //SCRIPT_OP_EQUALVERIFY; + } +#ifdef DISABLE_CHECKSIG + n = bitcoin_secret256spend(redeemscript,n,destpub); +#else + n = bitcoin_pubkeyspend(redeemscript,n,pubkeyB); +#endif + redeemscript[n++] = SCRIPT_OP_ENDIF; + return(n); +} + +int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeemlenp,uint8_t *script,int32_t n,uint32_t *locktimep,int32_t *secretstartp,struct basilisk_swapinfo *swap,int32_t depositflag) +{ + if ( depositflag != 0 ) + *locktimep = swap->started + swap->putduration + swap->callduration; + else *locktimep = swap->started + swap->putduration; + *redeemlenp = n = basilisk_swap_bobredeemscript(depositflag,secretstartp,redeemscript,*locktimep,swap->pubA0,swap->pubB0,swap->pubB1,swap->privAm,swap->privBn,swap->secretAm,swap->secretAm256,swap->secretBn,swap->secretBn256); + if ( n > 0 ) + { + calc_rmd160_sha256(rmd160,redeemscript,n); + n = bitcoin_p2shspend(script,0,rmd160); + //for (i=0; i if path, 0 -> else path + return(len); +} + +/*Bob paytx: + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF*/ + +int32_t basilisk_bobpayment_reclaim(struct basilisk_swap *swap,int32_t delay) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; + printf("basilisk_bobpayment_reclaim\n"); + len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_bobreclaim,userdata,len); + swap->I.userdata_bobreclaimlen = len; + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobreclaim.I.datalen; i++) + printf("%02x",swap->bobreclaim.txbytes[i]); + printf(" <- bobreclaim\n"); + //basilisk_txlog(swap,&swap->bobreclaim,delay); + return(retval); + } + return(-1); +} + +int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) +{ + int32_t datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; bits256 txid; + datalen = recvbuf[0]; + datalen += (int32_t)recvbuf[1] << 8; + if ( datalen > 65536 ) + return(-1); + rawtx->I.redeemlen = recvbuf[2]; + data = &recvbuf[3]; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); + //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); + if ( rawtx->I.datalen == 0 ) + { + //rawtx->txbytes = calloc(1,datalen); + memcpy(rawtx->txbytes,data,datalen); + rawtx->I.datalen = datalen; + } + else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) + { + int32_t i; for (i=0; iI.datalen; i++) + printf("%02x",rawtx->txbytes[i]); + printf(" <- rawtx\n"); + printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); + return(-1); + } + txid = bits256_doublesha256(0,data,datalen); + char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); + if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + rawtx->I.actualtxid = txid; + if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + rawtx->I.actualtxid = rawtx->I.signedtxid; + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,rawtx->signedtxid),jprint(txobj,0)); + rawtx->I.locktime = rawtx->msgtx.lock_time; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) + { + vout = jitem(vouts,v); + if ( j64bits(vout,"satoshis") == rawtx->I.amount && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) + { + if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) + { + decode_hex(rawtx->spendscript,hexlen,hexstr); + rawtx->I.spendlen = hexlen; + bitcoin_address(rawtx->p2shaddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); + //if ( swap != 0 ) + // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment + retval = 0; + } + } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); + } + free_json(txobj); + } + return(retval); +} + +int32_t basilisk_verify_bobpaid(void *ptr,uint8_t *data,int32_t datalen) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; bits256 revAm; struct basilisk_swap *swap = ptr; + memset(revAm.bytes,0,sizeof(revAm)); + if ( basilisk_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) + { + swap->bobpayment.I.signedtxid = LP_broadcast(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) + swap->paymentunconf = 1; + basilisk_dontforget_update(swap,&swap->bobpayment); + for (i=0; i<32; i++) + revAm.bytes[i] = swap->I.privAm.bytes[31-i]; + len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_alicespend,userdata,len); + swap->I.userdata_alicespendlen = len; + char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobpayment.I.datalen; i++) + printf("%02x",swap->bobpayment.txbytes[i]); + printf(" <- bobpayment\n"); + for (i=0; ialicespend.I.datalen; i++) + printf("%02x",swap->alicespend.txbytes[i]); + printf(" <- alicespend\n\n"); + swap->I.alicespent = 1; + //basilisk_txlog(swap,&swap->alicespend,-1); + return(retval); + } + } + return(-1); +} + +int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; char str[65]; + len = basilisk_swapuserdata(userdata,swap->I.privBn,0,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_bobrefund,userdata,len); + swap->I.userdata_bobrefundlen = len; + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0)) == 0 ) + { + for (i=0; ibobrefund.I.datalen; i++) + printf("%02x",swap->bobrefund.txbytes[i]); + printf(" <- bobrefund.(%s)\n",bits256_str(str,swap->bobrefund.I.txid)); + //basilisk_txlog(swap,&swap->bobrefund,delay); + return(retval); + } + return(-1); +} + +int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) +{ + int32_t i,j; //char str[65]; + if ( genflag != 0 && swap->I.iambob == 0 ) + printf("basilisk_bobscripts_set WARNING: alice generating BOB tx\n"); + if ( depositflag == 0 ) + { + swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); + bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + //for (i=0; ibobpayment.redeemlen; i++) + // printf("%02x",swap->bobpayment.redeemscript[i]); + //printf(" <- bobpayment.%d\n",i); + if ( genflag != 0 && bits256_nonz(*(bits256 *)swap->I.secretBn256) != 0 && swap->bobpayment.I.datalen == 0 ) + { + for (i=0; i<3; i++) + { + //if ( swap->bobpayment.txbytes != 0 && swap->bobpayment.I.spendlen != 0 ) + // break; + basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey); + if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) + { + printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); + sleep(DEX_SLEEP); + } + else + { + for (j=0; jbobpayment.I.datalen; j++) + printf("%02x",swap->bobpayment.txbytes[j]); + //printf(" <- bobpayment.%d\n",swap->bobpayment.datalen); + //for (j=0; jbobpayment.redeemlen; j++) + // printf("%02x",swap->bobpayment.redeemscript[j]); + //printf(" <- redeem.%d\n",swap->bobpayment.redeemlen); + printf(" <- GENERATED BOB PAYMENT.%d\n",swap->bobpayment.I.datalen); + LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); + basilisk_bobpayment_reclaim(swap,swap->I.callduration); + printf("bobscripts set completed\n"); + return(0); + } + } + } + } + else + { + swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); + bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) + { + for (i=0; i<3; i++) + { + //if ( swap->bobdeposit.txbytes != 0 && swap->bobdeposit.I.spendlen != 0 ) + // break; + basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey); + if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) + { + printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); + sleep(DEX_SLEEP); + } + else + { + for (j=0; jbobdeposit.I.datalen; j++) + printf("%02x",swap->bobdeposit.txbytes[j]); + printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); + //for (j=0; jbobdeposit.redeemlen; j++) + // printf("%02x",swap->bobdeposit.redeemscript[j]); + //printf(" <- redeem.%d\n",swap->bobdeposit.redeemlen); + //printf("GENERATED BOB DEPOSIT\n"); + LP_unspents_mark(swap->bobcoin.symbol,swap->bobdeposit.vins); + basilisk_bobdeposit_refund(swap,swap->I.putduration); + printf("bobscripts set completed\n"); + return(0); + } + } + } + //for (i=0; ibobdeposit.redeemlen; i++) + // printf("%02x",swap->bobdeposit.redeemscript[i]); + //printf(" <- bobdeposit.%d\n",i); + } + return(0); +} + +/**/ + +struct basilisk_rawtx *LP_swapdata_rawtx(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx) +{ + if ( rawtx->I.datalen != 0 && rawtx->I.datalen <= maxlen ) + { + memcpy(data,rawtx->txbytes,rawtx->I.datalen); + return(rawtx); + } + return(0); +} + +uint32_t LP_swapdata_rawtxsend(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) +{ + uint8_t sendbuf[32768]; int32_t sendlen; + if ( LP_swapdata_rawtx(swap,data,maxlen,rawtx) != 0 ) + { + if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + { + char str[65],str2[65]; + rawtx->I.actualtxid = LP_broadcast(rawtx->name,rawtx->coin->symbol,rawtx->txbytes,rawtx->I.datalen); + if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) + { + printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); + rawtx->I.actualtxid = rawtx->I.signedtxid; + } + if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) + { + sendlen = 0; + sendbuf[sendlen++] = rawtx->I.datalen & 0xff; + sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; + sendbuf[sendlen++] = rawtx->I.redeemlen; + memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + { + memcpy(&sendbuf[sendlen],rawtx->redeemscript,rawtx->I.redeemlen); + sendlen += rawtx->I.redeemlen; + } + basilisk_dontforget_update(swap,rawtx); + //printf("sendlen.%d datalen.%d redeemlen.%d\n",sendlen,rawtx->datalen,rawtx->redeemlen); + if ( suppress_swapsend == 0 ) + return(LP_swapsend(swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs)); + else + { + printf("suppress swapsend %x\n",msgbits); + return(0); + } + } + } + return(nextbits); + } else if ( swap->I.iambob == 0 ) + printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); + return(0); +} + +void basilisk_swap_coinaddr(struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) +{ + cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; + if ( (txobj= bitcoin_data2json(coin->pubtype,coin->p2shtype,coin->isPoS,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) + { + vout = jitem(vouts,0); + //printf("VOUT.(%s)\n",jprint(vout,0)); + if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + { + item = jitem(addresses,0); + //printf("item.(%s)\n",jprint(item,0)); + if ( (addr= jstr(item,0)) != 0 ) + { + safecopy(coinaddr,addr,64); + //printf("extracted.(%s)\n",coinaddr); + } + } + } + free_json(txobj); + } +} + +int32_t basilisk_verify_otherfee(void *ptr,uint8_t *data,int32_t datalen) +{ + struct basilisk_swap *swap = ptr; + // add verification and broadcast + //swap->otherfee.txbytes = calloc(1,datalen); + memcpy(swap->otherfee.txbytes,data,datalen); + swap->otherfee.I.datalen = datalen; + swap->otherfee.I.actualtxid = swap->otherfee.I.signedtxid = bits256_doublesha256(0,data,datalen); + //basilisk_txlog(swap,&swap->otherfee,-1); + return(0); +} + +/* Bob deposit: + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF*/ + +int32_t basilisk_verify_bobdeposit(void *ptr,uint8_t *data,int32_t datalen) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; + if ( basilisk_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) + { + swap->bobdeposit.I.signedtxid = LP_broadcast(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) + swap->depositunconf = 1; + basilisk_dontforget_update(swap,&swap->bobdeposit); + len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_aliceclaim,userdata,len); + swap->I.userdata_aliceclaimlen = len; + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) + { + for (i=0; ibobdeposit.I.datalen; i++) + printf("%02x",swap->bobdeposit.txbytes[i]); + printf(" <- bobdeposit\n"); + for (i=0; ialiceclaim.I.datalen; i++) + printf("%02x",swap->aliceclaim.txbytes[i]); + printf(" <- aliceclaim\n"); + //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); + return(retval); + } + } + printf("error with bobdeposit\n"); + return(-1); +} + +void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) +{ + alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); + basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey); +} + +int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_rawtx *dest) +{ + int32_t i,retval; + printf("alicepayment_spend\n"); + swap->alicepayment.I.spendlen = basilisk_alicescript(swap->alicepayment.redeemscript,&swap->alicepayment.I.redeemlen,swap->alicepayment.spendscript,0,swap->alicepayment.I.destaddr,swap->alicecoin.p2shtype,swap->I.pubAm,swap->I.pubBn); + printf("alicepayment_spend len.%d\n",swap->alicepayment.I.spendlen); + if ( swap->I.iambob == 0 ) + { + memcpy(swap->I.userdata_alicereclaim,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); + swap->I.userdata_alicereclaimlen = swap->alicepayment.I.spendlen; + } + else + { + memcpy(swap->I.userdata_bobspend,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); + swap->I.userdata_bobspendlen = swap->alicepayment.I.spendlen; + } + if ( (retval= basilisk_rawtx_sign(swap->alicecoin.symbol,swap->alicecoin.pubtype,swap->alicecoin.p2shtype,swap->alicecoin.isPoS,swap->alicecoin.wiftype,swap,dest,&swap->alicepayment,swap->I.privAm,&swap->I.privBn,0,0,1)) == 0 ) + { + for (i=0; iI.datalen; i++) + printf("%02x",dest->txbytes[i]); + printf(" <- msigspend\n\n"); + if ( dest == &swap->bobspend ) + swap->I.bobspent = 1; + //basilisk_txlog(swap,dest,0); // bobspend or alicereclaim + return(retval); + } + return(-1); +} + +int32_t basilisk_verify_alicepaid(void *ptr,uint8_t *data,int32_t datalen) +{ + struct basilisk_swap *swap = ptr; + if ( basilisk_rawtx_spendscript(swap,swap->alicecoin.longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) + { + swap->alicepayment.I.signedtxid = LP_broadcast(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) + swap->aliceunconf = 1; + basilisk_dontforget_update(swap,&swap->alicepayment); + return(0); + } + else return(-1); +} + +int32_t basilisk_alicetxs(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +{ + int32_t i,retval = -1; + printf("alicetxs\n"); + for (i=0; i<3; i++) + { + if ( swap->alicepayment.I.datalen == 0 ) + basilisk_alicepayment(swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) + { + printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); + sleep(20); + } + else + { + retval = 0; + for (i=0; ialicepayment.I.datalen; i++) + printf("%02x",swap->alicepayment.txbytes[i]); + printf(" ALICE PAYMENT created\n"); + LP_unspents_mark(swap->alicecoin.symbol,swap->alicepayment.vins); + //basilisk_txlog(swap,&swap->alicepayment,-1); + break; + } + } + if ( swap->myfee.I.datalen == 0 ) + { + printf("generate fee\n"); + if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey) == 0 ) + { + swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x80,data,maxlen,&swap->myfee,0x40,0); + LP_unspents_mark(swap->I.iambob!=0?swap->bobcoin.symbol:swap->alicecoin.symbol,swap->myfee.vins); + //basilisk_txlog(swap,&swap->myfee,-1); + for (i=0; imyfee.I.spendlen; i++) + printf("%02x",swap->myfee.txbytes[i]); + printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); + swap->I.statebits |= 0x40; + } + else + { + printf("error creating myfee\n"); + return(-2); + } + } + if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 && swap->myfee.I.datalen != 0 && swap->myfee.I.spendlen > 0 ) + return(0); + return(-1); +} diff --git a/iguana/m_mm b/iguana/m_mm index 9672d7988..2e310704b 100755 --- a/iguana/m_mm +++ b/iguana/m_mm @@ -1 +1,2 @@ -gcc -o marketmaker -I../crypto777 exchanges/mm.c ../crypto777/cJSON.c ../agents/libcrypto777.a -lnanomsg -lcurl -lpthread -lm +cd secp256k1; ./m_unix; cd .. +gcc -o marketmaker -I../crypto777 exchanges/mm.c mini-gmp.c secp256k1.o ../agents/libcrypto777.a -lnanomsg -lcurl -lpthread -lm From 1d229591d2fade41da02fd675842b2d11c308b5a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 28 May 2017 12:05:39 +0300 Subject: [PATCH 0651/2705] Test --- iguana/dpow/dpow_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 2a98ed265..6bf9df4a7 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -163,7 +163,7 @@ int32_t signed_nn_recv(void **freeptrp,struct supernet_info *myinfo,uint8_t nota { //for (i=0; ipacketlen == recvbytes-sizeof(*sigpacket)); + //printf(" <- [%d] RECV.%d crc.%08x cmp.%d\n",i,recvbytes,calc_crc32(0,(void *)sigpacket,recvbytes),sigpacket->packetlen == recvbytes-sizeof(*sigpacket)); } if ( sigpacket != 0 && recvbytes > sizeof(*sigpacket) && sigpacket->packetlen == recvbytes-sizeof(*sigpacket) ) { From 1da85c540ff3219070a14fb9e241ede82e869238 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 28 May 2017 12:10:52 +0300 Subject: [PATCH 0652/2705] Improve basilisk latency --- iguana/dpow/dpow_network.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index 6bf9df4a7..dfe3e84f8 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -148,7 +148,7 @@ int32_t signed_nn_recv(void **freeptrp,struct supernet_info *myinfo,uint8_t nota int32_t i=0,recvbytes; uint8_t pubkey33[33],pubkey0[33]; bits256 packethash; struct signed_nnpacket *sigpacket=0; *(void **)packetp = 0; *freeptrp = 0; - /*for (i=0; i<100; i++) + /*for (i=0; i<100; i++) cant do this!! slows down notary servers, big latency { struct nn_pollfd pfd; pfd.fd = myinfo->reqsock; @@ -2160,11 +2160,11 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo) if ( (flags & 4) == 0 && (size= nn_recv(myinfo->repsock,&dexp,NN_MSG,0)) > 0 ) { num2++; - printf("REP got %d crc.%08x\n",size,calc_crc32(0,(void *)dexp,size)); + //printf("REP got %d crc.%08x\n",size,calc_crc32(0,(void *)dexp,size)); if ( (retstr= dex_response(&broadcastflag,myinfo,dexp)) != 0 ) { signed_nn_send(myinfo,myinfo->ctx,myinfo->persistent_priv,myinfo->repsock,retstr,(int32_t)strlen(retstr)+1); - printf("send back[%ld]\n",strlen(retstr)+1); + //printf("send back[%ld]\n",strlen(retstr)+1); free(retstr); if ( broadcastflag != 0 ) { From a7687d78e86f89ffe14cc6d1f42eb44ab75e8a9c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 28 May 2017 12:15:55 +0300 Subject: [PATCH 0653/2705] Test --- iguana/dpow/dpow_network.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index dfe3e84f8..ac02d3bce 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -199,9 +199,9 @@ int32_t signed_nn_recv(void **freeptrp,struct supernet_info *myinfo,uint8_t nota printf(" pubkey[%d]\n",i); } } - for (i=0; i<33; i++) - printf("%02x",pubkey33[i]); - printf(" invalid pubkey33 n.%d\n",n); + //for (i=0; i<33; i++) + // printf("%02x",pubkey33[i]); + //printf(" invalid pubkey33 n.%d\n",n); } else printf("recoververify error nonce.%u packetlen.%d\n",sigpacket->nonce,sigpacket->packetlen); } else printf("hash mismatch or bad nonce.%u packetlen.%d\n",sigpacket->nonce,sigpacket->packetlen); } else if ( recvbytes > 0 ) @@ -478,7 +478,7 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 if ( nn_poll(&pfd,1,100) > 0 ) { sentbytes = nn_send(myinfo->reqsock,dexp,size,0); - printf(" [%d] sent.%d:%d datalen.%d crc.%08x\n",i,sentbytes,size,datalen,calc_crc32(0,(void *)dexp,size)); + //printf(" [%d] sent.%d:%d datalen.%d crc.%08x\n",i,sentbytes,size,datalen,calc_crc32(0,(void *)dexp,size)); break; } usleep(1000); @@ -487,7 +487,7 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 // printf("%02x",((uint8_t *)data)[i]); if ( (recvbytes= signed_nn_recv(&freeptr,myinfo,myinfo->notaries,myinfo->numnotaries,myinfo->reqsock,&retptr)) >= 0 ) { - printf("req returned.[%d]\n",recvbytes); + //printf("req returned.[%d]\n",recvbytes); portable_mutex_lock(&myinfo->dexmutex); ipbits = 0; if ( strcmp(handler,"DEX") == 0 ) From 6dc608deb5d456fcfeb551fbcdad8dbdda9f0864 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 28 May 2017 12:22:23 +0300 Subject: [PATCH 0654/2705] Test --- iguana/dpow/dpow_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c index ac02d3bce..33592f0b8 100755 --- a/iguana/dpow/dpow_network.c +++ b/iguana/dpow/dpow_network.c @@ -407,8 +407,8 @@ char *_dex_reqsend(struct supernet_info *myinfo,char *handler,uint8_t *key,int32 for (i=0; idexseed_ipaddrs)/sizeof(*myinfo->dexseed_ipaddrs); i++) { prio = (i/2) + 1; - nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_SNDPRIO,&prio,sizeof(prio)); - nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_RCVPRIO,&prio,sizeof(prio)); + //nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_SNDPRIO,&prio,sizeof(prio)); + //nn_setsockopt(reqsock,NN_SOL_SOCKET,NN_RCVPRIO,&prio,sizeof(prio)); if ( nn_connect(reqsock,nanomsg_tcpname(0,str,myinfo->dexseed_ipaddrs[i],REP_SOCK)) < 0 ) { nn_close(reqsock); From 6f9176a724c746b3bae55512c74d7ae41df1d42e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 10:20:04 +0300 Subject: [PATCH 0655/2705] Test --- iguana/exchanges/LP_include.h | 3 +- iguana/exchanges/LP_nativeDEX.c | 4 +- iguana/exchanges/LP_rpc.c | 312 +++++++++----------------------- 3 files changed, 88 insertions(+), 231 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 965b2a7ae..1c455f17e 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -174,7 +174,7 @@ struct iguana_info uint64_t txfee,estimatedfee; int32_t longestchain; uint8_t pubtype,p2shtype,isPoS,wiftype; - char symbol[16],changeaddr[64]; + char symbol[16],changeaddr[64],userpass[1024],serverport[128]; }; struct basilisk_swap @@ -465,5 +465,6 @@ enum opcodetype void basilisk_dontforget_update(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx); uint32_t basilisk_requestid(struct basilisk_request *rp); uint32_t basilisk_quoteid(struct basilisk_request *rp); +char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0c2ecb51d..417968d91 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -675,7 +675,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) } } -#ifdef __APPLE__ +/*#ifdef __APPLE__ int32_t nn_bind() { return(-1); } int32_t nn_close() { return(-1); } int32_t nn_connect() { return(-1); } @@ -686,4 +686,4 @@ int32_t nn_send() { return(-1); } int32_t nn_setsockopt() { return(-1); } int32_t nn_socket() { return(-1); } -#endif +#endif*/ diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index be1108238..ef731e08e 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -34,6 +34,24 @@ cJSON *basilisk_nullretjson(cJSON *retjson) return(retjson); } +char *dex_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) +{ + return(0); +} + +bits256 LP_privkey(char *coinaddr) +{ + bits256 privkey; + return(privkey); +} + +bits256 LP_pubkey(bits256 privkey) +{ + bits256 pubkey; + pubkey = curve25519(privkey,curve25519_basepoint9()); + return(pubkey); +} + void LP_unspentslock(char *symbol,cJSON *vins) { @@ -54,44 +72,20 @@ uint64_t LP_txfee(char *symbol) return(10000); } -char *dpow_validateaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *address) +char *LP_validateaddress(char *symbol,char *address) { - char buf[128],*retstr=0; - if ( coin->FULLNODE < 0 ) - { - sprintf(buf,"\"%s\"",address); - retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"validateaddress",buf); - usleep(10000); - } - else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) - { - retstr = bitcoinrpc_validateaddress(myinfo,coin,0,0,address); - } - else - { - return(0); - } + char buf[128],*retstr=0; struct iguana_info *coin = LP_coinfind(symbol); + sprintf(buf,"\"%s\"",address); + retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"validateaddress",buf); + usleep(10000); return(retstr); } -cJSON *dpow_gettxout(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid,int32_t vout) +cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout) { - char buf[128],str[65],*retstr=0; cJSON *json = 0; + char buf[128],str[65],*retstr=0; cJSON *json=0; struct iguana_info *coin = LP_coinfind(symbol); sprintf(buf,"\"%s\", %d",bits256_str(str,txid),vout); - if ( coin->FULLNODE < 0 ) - { - retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"gettxout",buf); - usleep(10000); - } - else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) - { - printf("need to test following call\n"); - retstr = bitcoinrpc_gettxout(myinfo,coin,0,buf,txid,1,0); // untested - } - else - { - return(0); - } + retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"gettxout",buf); if ( retstr != 0 ) { json = cJSON_Parse(retstr); @@ -101,48 +95,24 @@ cJSON *dpow_gettxout(struct supernet_info *myinfo,struct iguana_info *coin,bits2 return(json); } -char *dpow_decoderawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx) +char *LP_decoderawtransaction(char *symbol,char *rawtx) { - char *retstr,*paramstr; cJSON *array; - if ( coin->FULLNODE < 0 ) - { - array = cJSON_CreateArray(); - jaddistr(array,rawtx); - paramstr = jprint(array,1); - retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"decoderawtransaction",paramstr); - //printf("%s decoderawtransaction.(%s) <- (%s)\n",coin->symbol,retstr,paramstr); - free(paramstr); - usleep(10000); - } - else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) - { - retstr = bitcoinrpc_decoderawtransaction(myinfo,coin,0,0,rawtx,1); - } - else - { - return(0); - } + char *retstr,*paramstr; cJSON *array; struct iguana_info *coin = LP_coinfind(symbol); + array = cJSON_CreateArray(); + jaddistr(array,rawtx); + paramstr = jprint(array,1); + retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"decoderawtransaction",paramstr); + //printf("%s decoderawtransaction.(%s) <- (%s)\n",coin->symbol,retstr,paramstr); + free(paramstr); return(retstr); } -cJSON *dpow_gettransaction(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid) +cJSON *LP_gettransaction(char *symbol,bits256 txid) { - char buf[128],str[65],*retstr=0; cJSON *json = 0; - if ( coin->FULLNODE < 0 ) - { - sprintf(buf,"[\"%s\", 1]",bits256_str(str,txid)); - if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"getrawtransaction",buf)) != 0 ) - { - } - usleep(10000); - } - else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) - { - retstr = bitcoinrpc_getrawtransaction(myinfo,coin,0,0,txid,1); - } - else + char buf[128],str[65],*retstr=0; cJSON *json = 0; struct iguana_info *coin = LP_coinfind(symbol); + sprintf(buf,"[\"%s\", 1]",bits256_str(str,txid)); + if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"getrawtransaction",buf)) != 0 ) { - return(0); } if ( retstr != 0 ) { @@ -152,140 +122,64 @@ cJSON *dpow_gettransaction(struct supernet_info *myinfo,struct iguana_info *coin return(json); } -cJSON *dpow_listunspent(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr) +cJSON *LP_listunspent(char *symbol,char *coinaddr) { - char buf[128],*retstr; cJSON *array,*json = 0; - if ( coin->FULLNODE < 0 ) + char buf[128],*retstr; cJSON *json = 0; struct iguana_info *coin = LP_coinfind(symbol); + sprintf(buf,"0, 99999999, [\"%s\"]",coinaddr); + if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"listunspent",buf)) != 0 ) { - sprintf(buf,"0, 99999999, [\"%s\"]",coinaddr); - if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listunspent",buf)) != 0 ) - { - json = cJSON_Parse(retstr); - //printf("%s (%s) listunspent.(%s)\n",coin->symbol,buf,retstr); - free(retstr); - } else printf("%s null retstr from (%s)n",coin->symbol,buf); - } - else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) - { - array = cJSON_CreateArray(); - jaddistr(array,coinaddr); - json = iguana_listunspents(myinfo,coin,array,1,coin->longestchain,""); - free_json(array); - } - else - { - return(0); - } + json = cJSON_Parse(retstr); + //printf("%s (%s) listunspent.(%s)\n",coin->symbol,buf,retstr); + free(retstr); + } else printf("%s null retstr from (%s)n",coin->symbol,buf); return(json); } -cJSON *dpow_listtransactions(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,int32_t count,int32_t skip) +cJSON *LP_listtransactions(char *symbol,char *coinaddr,int32_t count,int32_t skip) { - char buf[128],*retstr; cJSON *json = 0; - if ( coin->FULLNODE < 0 ) + char buf[128],*retstr; cJSON *json = 0; struct iguana_info *coin = LP_coinfind(symbol); + if ( count == 0 ) + count = 100; + sprintf(buf,"[\"%s\", %d, %d, true]",coinaddr,count,skip); + if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"listtransactions",buf)) != 0 ) { - if ( count == 0 ) - count = 100; - sprintf(buf,"[\"%s\", %d, %d, true]",coinaddr,count,skip); - if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listtransactions",buf)) != 0 ) - { - //printf("LIST.(%s)\n",retstr); - json = cJSON_Parse(retstr); - free(retstr); - return(json); - } else printf("%s null retstr from (%s)n",coin->symbol,buf); - } + //printf("LIST.(%s)\n",retstr); + json = cJSON_Parse(retstr); + free(retstr); + return(json); + } else printf("%s null retstr from (%s)n",coin->symbol,buf); return(0); } -char *dpow_signrawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx,cJSON *vins) +char *LP_signrawtransaction(char *symbol,char *rawtx,cJSON *vins) { - cJSON *array,*privkeys,*item; char *wifstr,*str,*paramstr,*retstr; uint8_t script[256]; int32_t i,n,len,hashtype; struct vin_info V; struct iguana_waddress *waddr; struct iguana_waccount *wacct; - if ( coin->FULLNODE < 0 ) - { - array = cJSON_CreateArray(); - jaddistr(array,rawtx); - jaddi(array,jduplicate(vins)); - paramstr = jprint(array,1); - //printf("signrawtransaction\n"); - retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"signrawtransaction",paramstr); - //printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); - free(paramstr); - usleep(10000); - return(retstr); - } - else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) - { - privkeys = cJSON_CreateArray(); - if ( (n= cJSON_GetArraySize(vins)) > 0 ) - { - for (i=0; i 0 && strlen(str) < sizeof(script)*2 ) - { - len = (int32_t)strlen(str) >> 1; - decode_hex(script,len,str); - V.spendlen = len; - memcpy(V.spendscript,script,len); - if ( (hashtype= _iguana_calcrmd160(coin,&V)) >= 0 && V.coinaddr[0] != 0 ) - { - if ( (waddr= iguana_waddresssearch(myinfo,&wacct,V.coinaddr)) != 0 ) - { - if ( bits256_nonz(waddr->privkey) != 0 ) - { - if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->chain->wiftype) > 0 ) - { - wifstr = waddr->wifstr; - } - } - } - } - } - jaddistr(privkeys,wifstr); - } - } - retstr = bitcoinrpc_signrawtransaction(myinfo,coin,0,0,rawtx,vins,privkeys,"ALL"); - printf("call sign.(%s) vins.(%s) privs.(%s) -> (%s)\n",rawtx,jprint(vins,0),jprint(privkeys,0),retstr); - free_json(privkeys); - return(retstr); - } - else - { - return(0); - } + cJSON *array; char *paramstr,*retstr; struct iguana_info *coin = LP_coinfind(symbol); + array = cJSON_CreateArray(); + jaddistr(array,rawtx); + jaddi(array,jduplicate(vins)); + paramstr = jprint(array,1); + //printf("signrawtransaction\n"); + retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"signrawtransaction",paramstr); + //printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); + free(paramstr); + return(retstr); } -char *dpow_sendrawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *signedtx) +char *LP_sendrawtransaction(char *symbol,char *signedtx) { - bits256 txid; cJSON *json,*array; char *paramstr,*retstr; - if ( coin->FULLNODE < 0 ) - { - array = cJSON_CreateArray(); - jaddistr(array,signedtx); - paramstr = jprint(array,1); - retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"sendrawtransaction",paramstr); - printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> (%s)\n",coin->symbol,paramstr,retstr); - free(paramstr); - return(retstr); - } - else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) - { - txid = iguana_sendrawtransaction(myinfo,coin,signedtx); - json = cJSON_CreateObject(); - jaddbits256(json,"result",txid); - return(jprint(json,1)); - } - else - { - return(0); - } + cJSON *array; char *paramstr,*retstr; struct iguana_info *coin = LP_coinfind(symbol); + array = cJSON_CreateArray(); + jaddistr(array,signedtx); + paramstr = jprint(array,1); + retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"sendrawtransaction",paramstr); + printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> (%s)\n",coin->symbol,paramstr,retstr); + free(paramstr); + return(retstr); } char *LP_importaddress(char *symbol,char *address) { - char buf[1024],*retstr; cJSON *validatejson; int32_t isvalid=0,doneflag = 0; + char buf[1024],*retstr; cJSON *validatejson; int32_t isvalid=0,doneflag = 0; struct iguana_info *coin = LP_coinfind(symbol); if ( (retstr= LP_validateaddress(symbol,address)) != 0 ) { if ( (validatejson= cJSON_Parse(retstr)) != 0 ) @@ -302,27 +196,12 @@ char *LP_importaddress(char *symbol,char *address) } if ( isvalid == 0 ) return(clonestr("{\"isvalid\":false}")); - update_alladdresses(myinfo,coin,address); if ( doneflag != 0 ) return(0); // success - if ( coin->FULLNODE < 0 ) - { - sprintf(buf,"[\"%s\", \"%s\", false]",address,address); - retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"importaddress",buf); - printf("%s importaddress.(%s) -> (%s)\n",coin->symbol,address,retstr); - return(retstr); - } - else return(0); -} - -char *LP_importaddress(char *symbol,char *coinaddr) -{ - return(0); -} - -char *LP_sendrawtransaction(char *symbol,char *signedtx) -{ - return(0); + sprintf(buf,"[\"%s\", \"%s\", false]",address,address); + retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"importaddress",buf); + printf("%s importaddress.(%s) -> (%s)\n",coin->symbol,address,retstr); + return(retstr); } char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON *vins,char *rawtxbytes,cJSON *privkeys,struct vin_info *V) @@ -330,33 +209,10 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * return(0); } -cJSON *LP_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) -{ - return(0); -} - -char *dex_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) -{ - return(0); -} - -bits256 LP_privkey(char *coinaddr) -{ - bits256 privkey; - return(privkey); -} - -bits256 LP_pubkey(bits256 privkey) -{ - bits256 pubkey; - pubkey = curve25519(privkey,curve25519_basepoint9()); - return(pubkey); -} - cJSON *LP_swapgettxout(char *symbol,bits256 trigger,int32_t vout) { cJSON *retjson=0; //char *retstr; struct iguana_info *coin; - /*if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + /*if ( ((coin= LP_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) { if ( (retstr= dex_gettxout(0,0,0,trigger,symbol,vout)) != 0 ) { @@ -385,7 +241,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) cJSON *LP_swapgettx(char *symbol,bits256 txid) { cJSON *retjson=0; //char *retstr; struct iguana_info *coin; - /*if ( ((coin= iguana_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) + /*if ( ((coin= LP_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) { if ( (retstr= dex_gettransaction(0,0,0,txid,symbol)) != 0 ) { From 7eddb039bc50e968814b4d2f23524feb9237e908 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 10:22:20 +0300 Subject: [PATCH 0656/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/mm.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 417968d91..9243b0649 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -663,7 +663,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { len = (int32_t)strlen((char *)ptr) + 1; portable_mutex_lock(&LP_commandmutex); - LP_command(mypeer,mypub,argjson,&ptr[len],recvsize - len,profitmargin); + LP_command(mypeer,mypub,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin); portable_mutex_unlock(&LP_commandmutex); free_json(argjson); } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 04f20f410..ca30cf3d2 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -35,6 +35,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port); #include "../../crypto777/nanosrc/pipeline.h" #include "../../crypto777/nanosrc/reqrep.h" #include "../../crypto777/nanosrc/tcp.h" +#include "../../crypto777/nanosrc/pair.h" #else #include "/usr/local/include/nanomsg/nn.h" #include "/usr/local/include/nanomsg/bus.h" @@ -42,6 +43,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port); #include "/usr/local/include/nanomsg/pipeline.h" #include "/usr/local/include/nanomsg/reqrep.h" #include "/usr/local/include/nanomsg/tcp.h" +#include "/usr/local/include/nanomsg/pair.h" #endif char DEX_baseaddr[64],DEX_reladdr[64]; From 9439511dec69bb40b00d535ab96d64c65489a0e9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:02:24 +0300 Subject: [PATCH 0657/2705] Test --- iguana/exchanges/LP_bitcoin.c | 38 ++++ iguana/exchanges/LP_include.h | 3 +- iguana/exchanges/LP_nativeDEX.c | 242 ++++++++++++++++---- iguana/exchanges/LP_remember.c | 24 +- iguana/exchanges/LP_rpc.c | 358 +++++++++--------------------- iguana/exchanges/LP_transaction.c | 115 ++++++++-- 6 files changed, 440 insertions(+), 340 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 078bc1d3f..79c78dc9c 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -18,6 +18,29 @@ // marketmaker // +struct { bits256 privkey; uint8_t rmd160[20]; } LP_privkeys[100]; int32_t LP_numprivkeys; + +bits256 LP_privkeyfind(uint8_t rmd160[20]) +{ + int32_t i; static bits256 zero; + for (i=0; isymbol,symbol); - return(coin); - } -} - -void tradebot_swap_balancingtrade(struct basilisk_swap *swap,int32_t iambob) -{ - -} - -void tradebot_pendingadd(cJSON *tradejson,char *base,double basevolume,char *rel,double relvolume) -{ - // add to trades -} - -char GLOBAL_DBDIR[] = "."; - -#include "LP_secp.c" -#include "LP_rpc.c" -#include "LP_bitcoin.c" -#include "LP_transaction.c" -#include "LP_remember.c" -#include "LP_statemachine.c" -#include "LP_swap.c" -#include "LP_commands.c" - void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) { char *myipaddr=0,*retstr; long filesize,n; int32_t len,timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 547f8ab9c..d8951c9a5 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -169,7 +169,7 @@ void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,in void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx,int32_t locktime,bits256 triggertxid) { - char zeroes[32],fname[512],str[65],coinaddr[64],secretAmstr[41],secretAm256str[65],secretBnstr[41],secretBn256str[65],*tmp; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; + char zeroes[32],fname[512],str[65],coinaddr[64],secretAmstr[41],secretAm256str[65],secretBnstr[41],secretBn256str[65]; FILE *fp; int32_t i,len; uint8_t redeemscript[256],script[256]; sprintf(fname,"%s/SWAPS/%u-%u.%s",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid,rawtx->name), OS_compatible_path(fname); coinaddr[0] = secretAmstr[0] = secretAm256str[0] = secretBnstr[0] = secretBn256str[0] = 0; memset(zeroes,0,sizeof(zeroes)); @@ -187,8 +187,7 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx basilisk_swap_coinaddr(swap,&swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); if ( coinaddr[0] != 0 ) { - if ( (tmp= LP_importaddress(swap->bobcoin.symbol,coinaddr)) != 0 ) - free(tmp); + LP_importaddress(swap->bobcoin.symbol,coinaddr); if ( rawtx == &swap->bobdeposit ) safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); @@ -210,8 +209,7 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) { basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin.p2shtype,swap->I.pubAm,swap->I.pubBn); - if ( (tmp= LP_importaddress(swap->alicecoin.symbol,coinaddr)) != 0 ) - free(tmp); + LP_importaddress(swap->alicecoin.symbol,coinaddr); fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); } /*basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); @@ -658,7 +656,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti safecopy(alicecoin,symbol,sizeof(alicecoin)); if ( finishedflag == 0 ) { - if ( (sentobj= LP_swapgettx(symbol,txid)) == 0 ) + if ( (sentobj= LP_gettx(symbol,txid)) == 0 ) { //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); } @@ -722,7 +720,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti printf("txbytes.%p Apayment.%s\n",txbytes[BASILISK_ALICEPAYMENT],bits256_str(str,txids[BASILISK_ALICEPAYMENT])); if ( txbytes[BASILISK_ALICEPAYMENT] != 0 ) sentflags[BASILISK_ALICEPAYMENT] = 1; - else if ( (sentobj= LP_swapgettx(alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) + else if ( (sentobj= LP_gettx(alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 ) { sentflags[BASILISK_ALICEPAYMENT] = 1; free_json(sentobj); @@ -756,7 +754,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_ALICESPEND] != 0 ) { - txids[BASILISK_ALICESPEND] = basilisk_swap_sendrawtransaction("alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); + txids[BASILISK_ALICESPEND] = LP_broadcast("alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested { sentflags[BASILISK_ALICESPEND] = 1; @@ -781,7 +779,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_ALICECLAIM] != 0 ) { - txids[BASILISK_ALICECLAIM] = basilisk_swap_sendrawtransaction("aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); + txids[BASILISK_ALICECLAIM] = LP_broadcast("aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // tested { sentflags[BASILISK_ALICECLAIM] = 1; @@ -803,7 +801,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) { - txids[BASILISK_ALICERECLAIM] = basilisk_swap_sendrawtransaction("alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); + txids[BASILISK_ALICERECLAIM] = LP_broadcast("alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // tested { sentflags[BASILISK_ALICERECLAIM] = 1; @@ -833,7 +831,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_BOBSPEND] != 0 ) { - txids[BASILISK_BOBSPEND] = basilisk_swap_sendrawtransaction("bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); + txids[BASILISK_BOBSPEND] = LP_broadcast("bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) // tested { sentflags[BASILISK_BOBSPEND] = 1; @@ -862,7 +860,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) { - txids[BASILISK_BOBRECLAIM] = basilisk_swap_sendrawtransaction("bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); + txids[BASILISK_BOBRECLAIM] = LP_broadcast("bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) // tested { sentflags[BASILISK_BOBRECLAIM] = 1; @@ -886,7 +884,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_BOBREFUND] != 0 ) { - txids[BASILISK_BOBREFUND] = basilisk_swap_sendrawtransaction("bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); + txids[BASILISK_BOBREFUND] = LP_broadcast("bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) // tested { sentflags[BASILISK_BOBREFUND] = 1; diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index ef731e08e..c72a80ec4 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -18,13 +18,18 @@ // marketmaker // +char *LP_getdatadir() +{ + return("/root"); +} + cJSON *basilisk_nullretjson(cJSON *retjson) { char *outstr; if ( retjson != 0 ) { outstr = jprint(retjson,0); - if ( strcmp(outstr,"{}") == 0 ) + if ( strcmp(outstr,"{}") == 0 || strcmp(outstr,"[]") == 0 ) { free_json(retjson); retjson = 0; @@ -34,328 +39,163 @@ cJSON *basilisk_nullretjson(cJSON *retjson) return(retjson); } -char *dex_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) +char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) { return(0); } -bits256 LP_privkey(char *coinaddr) -{ - bits256 privkey; - return(privkey); -} - -bits256 LP_pubkey(bits256 privkey) +cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) { - bits256 pubkey; - pubkey = curve25519(privkey,curve25519_basepoint9()); - return(pubkey); -} - -void LP_unspentslock(char *symbol,cJSON *vins) -{ - + char *retstr; cJSON *retjson = 0; + if ( coin != 0 ) + { + retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); + if ( retstr != 0 && retstr[0] != 0 ) + { + retjson = cJSON_Parse(retstr); + free(retstr); + } + //printf("dpow_gettxout.(%s)\n",retstr); + } + return(basilisk_nullretjson(retjson)); } void LP_unspents_mark(char *symbol,cJSON *vins) { - -} - -uint64_t LP_getestimatedfee(char *symbol) -{ - return(200); -} - -uint64_t LP_txfee(char *symbol) -{ - return(10000); -} - -char *LP_validateaddress(char *symbol,char *address) -{ - char buf[128],*retstr=0; struct iguana_info *coin = LP_coinfind(symbol); - sprintf(buf,"\"%s\"",address); - retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"validateaddress",buf); - usleep(10000); - return(retstr); + printf("LOCK (%s)\n",jprint(vins,0)); } cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout) { - char buf[128],str[65],*retstr=0; cJSON *json=0; struct iguana_info *coin = LP_coinfind(symbol); + char buf[128],str[65]; struct iguana_info *coin = LP_coinfind(symbol); sprintf(buf,"\"%s\", %d",bits256_str(str,txid),vout); - retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"gettxout",buf); - if ( retstr != 0 ) - { - json = cJSON_Parse(retstr); - free(retstr); - } - //printf("dpow_gettxout.(%s)\n",retstr); - return(json); + return(bitcoin_json(coin,"gettxout",buf)); } -char *LP_decoderawtransaction(char *symbol,char *rawtx) +cJSON *LP_gettx(char *symbol,bits256 txid) { - char *retstr,*paramstr; cJSON *array; struct iguana_info *coin = LP_coinfind(symbol); - array = cJSON_CreateArray(); - jaddistr(array,rawtx); - paramstr = jprint(array,1); - retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"decoderawtransaction",paramstr); - //printf("%s decoderawtransaction.(%s) <- (%s)\n",coin->symbol,retstr,paramstr); - free(paramstr); - return(retstr); -} - -cJSON *LP_gettransaction(char *symbol,bits256 txid) -{ - char buf[128],str[65],*retstr=0; cJSON *json = 0; struct iguana_info *coin = LP_coinfind(symbol); + char buf[128],str[65]; struct iguana_info *coin = LP_coinfind(symbol); sprintf(buf,"[\"%s\", 1]",bits256_str(str,txid)); - if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"getrawtransaction",buf)) != 0 ) - { - } - if ( retstr != 0 ) - { - json = cJSON_Parse(retstr); - free(retstr); - } - return(json); + return(bitcoin_json(coin,"getrawtransaction",buf)); } cJSON *LP_listunspent(char *symbol,char *coinaddr) { - char buf[128],*retstr; cJSON *json = 0; struct iguana_info *coin = LP_coinfind(symbol); + char buf[128]; struct iguana_info *coin = LP_coinfind(symbol); sprintf(buf,"0, 99999999, [\"%s\"]",coinaddr); - if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"listunspent",buf)) != 0 ) - { - json = cJSON_Parse(retstr); - //printf("%s (%s) listunspent.(%s)\n",coin->symbol,buf,retstr); - free(retstr); - } else printf("%s null retstr from (%s)n",coin->symbol,buf); - return(json); + return(bitcoin_json(coin,"listunspent",buf)); } cJSON *LP_listtransactions(char *symbol,char *coinaddr,int32_t count,int32_t skip) { - char buf[128],*retstr; cJSON *json = 0; struct iguana_info *coin = LP_coinfind(symbol); + char buf[128]; struct iguana_info *coin = LP_coinfind(symbol); if ( count == 0 ) count = 100; sprintf(buf,"[\"%s\", %d, %d, true]",coinaddr,count,skip); - if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"listtransactions",buf)) != 0 ) - { - //printf("LIST.(%s)\n",retstr); - json = cJSON_Parse(retstr); - free(retstr); - return(json); - } else printf("%s null retstr from (%s)n",coin->symbol,buf); - return(0); + return(bitcoin_json(coin,"listtransactions",buf)); } -char *LP_signrawtransaction(char *symbol,char *rawtx,cJSON *vins) +cJSON *LP_validateaddress(char *symbol,char *address) { - cJSON *array; char *paramstr,*retstr; struct iguana_info *coin = LP_coinfind(symbol); - array = cJSON_CreateArray(); - jaddistr(array,rawtx); - jaddi(array,jduplicate(vins)); - paramstr = jprint(array,1); - //printf("signrawtransaction\n"); - retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"signrawtransaction",paramstr); - //printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); - free(paramstr); - return(retstr); -} - -char *LP_sendrawtransaction(char *symbol,char *signedtx) -{ - cJSON *array; char *paramstr,*retstr; struct iguana_info *coin = LP_coinfind(symbol); - array = cJSON_CreateArray(); - jaddistr(array,signedtx); - paramstr = jprint(array,1); - retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"sendrawtransaction",paramstr); - printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> (%s)\n",coin->symbol,paramstr,retstr); - free(paramstr); - return(retstr); + char buf[512]; struct iguana_info *coin = LP_coinfind(symbol); + sprintf(buf,"\"%s\"",address); + return(bitcoin_json(coin,"validateaddress",buf)); } -char *LP_importaddress(char *symbol,char *address) +int32_t LP_importaddress(char *symbol,char *address) { char buf[1024],*retstr; cJSON *validatejson; int32_t isvalid=0,doneflag = 0; struct iguana_info *coin = LP_coinfind(symbol); - if ( (retstr= LP_validateaddress(symbol,address)) != 0 ) + if ( coin == 0 ) + return(-2); + if ( (validatejson= LP_validateaddress(symbol,address)) != 0 ) { - if ( (validatejson= cJSON_Parse(retstr)) != 0 ) + if ( (isvalid= is_cJSON_True(jobj(validatejson,"isvalid")) != 0) != 0 ) { - if ( (isvalid= is_cJSON_True(jobj(validatejson,"isvalid")) != 0) != 0 ) - { - if ( is_cJSON_True(jobj(validatejson,"iswatchonly")) != 0 || is_cJSON_True(jobj(validatejson,"ismine")) != 0 ) - doneflag = 1; - } - free_json(validatejson); + if ( is_cJSON_True(jobj(validatejson,"iswatchonly")) != 0 || is_cJSON_True(jobj(validatejson,"ismine")) != 0 ) + doneflag = 1; } - free(retstr); - retstr = 0; + free_json(validatejson); } if ( isvalid == 0 ) - return(clonestr("{\"isvalid\":false}")); + return(-1); if ( doneflag != 0 ) return(0); // success sprintf(buf,"[\"%s\", \"%s\", false]",address,address); - retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"importaddress",buf); - printf("%s importaddress.(%s) -> (%s)\n",coin->symbol,address,retstr); - return(retstr); -} - -char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON *vins,char *rawtxbytes,cJSON *privkeys,struct vin_info *V) -{ - return(0); -} - -cJSON *LP_swapgettxout(char *symbol,bits256 trigger,int32_t vout) -{ - cJSON *retjson=0; //char *retstr; struct iguana_info *coin; - /*if ( ((coin= LP_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) - { - if ( (retstr= dex_gettxout(0,0,0,trigger,symbol,vout)) != 0 ) - { - //printf("dexgettxout.(%s)\n",retstr); - retjson = cJSON_Parse(retstr); - free(retstr); - } - if ( 0 && strcmp("BTC",symbol) == 0 ) - printf("%s gettxout.(%s)\n",symbol,jprint(retjson,0)); - } - else - { - retjson = dpow_gettxout(coin,trigger,vout); - //printf("need to verify passthru has this info\n"); - //printf("dpowgettxout.(%s)\n",jprint(retjson,0)); - }*/ - return(basilisk_nullretjson(retjson)); -} - -uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) -{ - uint64_t value = 0; - return(value); -} - -cJSON *LP_swapgettx(char *symbol,bits256 txid) -{ - cJSON *retjson=0; //char *retstr; struct iguana_info *coin; - /*if ( ((coin= LP_coinfind(symbol)) == 0 || coin->FULLNODE == 0) && iguana_isnotarychain(symbol) >= 0 ) - { - if ( (retstr= dex_gettransaction(0,0,0,txid,symbol)) != 0 ) - { - retjson = cJSON_Parse(retstr); - free(retstr); - } - //if ( strcmp("BTC",symbol) == 0 ) - // printf("%s gettx.(%s)\n",symbol,jprint(retjson,0)); - } else retjson = dpow_gettransaction(coin,txid);*/ - return(basilisk_nullretjson(retjson)); + if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"importaddress",buf)) != 0 ) + free(retstr); + return(1); } -bits256 basilisk_swap_sendrawtransaction(char *txname,char *symbol,char *txbytes) +uint64_t LP_getestimatedrate(char *symbol) { - char *retstr; bits256 txid; int32_t i,sentflag = 0; - memset(&txid,0,sizeof(txid)); - for (i=0; i<3; i++) + char buf[512],*retstr; uint64_t rate = 200; struct iguana_info *coin = LP_coinfind(symbol); + if ( coin != 0 ) { - if ( (retstr= LP_sendrawtransaction(symbol,txbytes)) != 0 ) + sprintf(buf,"[%d]",3); + if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"importaddress",buf)) != 0 ) { - if ( is_hexstr(retstr,0) == 64 ) - { - decode_hex(txid.bytes,32,retstr); - sentflag = 1; - } - char str[65]; printf("[%s] %s RETSTR.(%s) %s.%s\n",txname,txbytes,retstr,symbol,bits256_str(str,txid)); + rate = atof(retstr); + printf("estimated rate %s -> %llu\n",retstr,(long long)rate); free(retstr); } - if ( sentflag != 0 ) - break; } - return(txid); + return(rate); } -bits256 LP_broadcast(char *name,char *symbol,uint8_t *data,int32_t datalen) +uint64_t LP_txfee(char *symbol) { - bits256 txid; char *signedtx,*retstr; int32_t i; - memset(txid.bytes,0,sizeof(txid)); - if ( data != 0 && datalen != 0 ) - { - char str[65]; -#ifdef BASILISK_DISABLESENDTX - txid = bits256_doublesha256(0,data,datalen); - printf("%s <- dont sendrawtransaction (%s)\n",name,bits256_str(str,txid)); - return(txid); -#endif - signedtx = malloc(datalen*2 + 1); - init_hexbytes_noT(signedtx,data,datalen); - for (i=0; i<3; i++) - { - if ( (retstr= LP_sendrawtransaction(symbol,signedtx)) != 0 ) - { - if ( is_hexstr(retstr,0) == 64 ) - { - decode_hex(txid.bytes,32,retstr); - free(retstr); - printf("sendrawtransaction.%s %s.(%s)\n",name,symbol,bits256_str(str,txid)); - break; - } - else - { - printf("sendrawtransaction.%s %s error.(%s)\n",name,symbol,retstr); - free(retstr); - } - } else printf("sendrawtransaction.%s %s got null return\n",name,symbol); - } - free(signedtx); - } - return(txid); + uint64_t txfee = 0; + if ( strcmp(symbol,"BTC") != 0 ) + txfee = 50000; + return(txfee); } -int32_t basilisk_confirmsobj(cJSON *item) +char *LP_sendrawtransaction(char *symbol,char *signedtx) { - int32_t height,numconfirms; - height = jint(item,"height"); - numconfirms = jint(item,"numconfirms"); - if ( height > 0 && numconfirms >= 0 ) - return(numconfirms); - printf("basilisk_confirmsobj height.%d numconfirms.%d (%s)\n",height,numconfirms,jprint(item,0)); - return(-1); + cJSON *array; char *paramstr,*retstr; struct iguana_info *coin = LP_coinfind(symbol); + if ( coin == 0 ) + return(0); + array = cJSON_CreateArray(); + jaddistr(array,signedtx); + paramstr = jprint(array,1); + retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"sendrawtransaction",paramstr); + printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> (%s)\n",coin->symbol,paramstr,retstr); + free(paramstr); + return(retstr); } -int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON *vins,char *rawtx,cJSON *privkeys,struct vin_info *V) { -#ifdef BASILISK_DISABLEWAITTX - return(100); -#endif - /*cJSON *argjson,*valuearray=0; char *valstr; int32_t i,n,retval = -1; - argjson = cJSON_CreateObject(); - jaddbits256(argjson,"txid",rawtx->I.actualtxid); - jaddnum(argjson,"vout",0); - jaddstr(argjson,"coin",rawtx->coin->symbol); - if ( (valstr= basilisk_value(rawtx->coin,0,0,swap->persistent_pubkey,argjson,0)) != 0 ) + cJSON *array,*json; int32_t len; uint8_t *data; char *paramstr,*retstr,*hexstr,*signedtx=0; struct iguana_info *coin = LP_coinfind(symbol); + memset(signedtxidp,0,sizeof(*signedtxidp)); + *completedp = 0; + if ( coin == 0 ) + return(0); + array = cJSON_CreateArray(); + jaddistr(array,rawtx); + jaddi(array,jduplicate(vins)); + jaddi(array,jduplicate(privkeys)); + paramstr = jprint(array,1); + //printf("signrawtransaction\n"); + if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"signrawtransaction",paramstr)) != 0 ) { - char str[65]; printf("basilisk_numconfirms required.%d %s %s valstr.(%s)\n",rawtx->I.numconfirms,rawtx->name,bits256_str(str,rawtx->I.actualtxid),valstr); - //basilisk_numconfirms required.0 alicespend 29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85 valstr.({"result":"success","numconfirms":0,"address":"1JGvZ67oTdM7kCya4J8kj1uErbSRAoq3wH","satoshis":"1413818","value":0.01413818,"height":462440,"txid":"29a2a6b4a61b1da82096d533c71b6762d61a82ca771a633269d97c0ccb94fe85","vout":0,"coin":"BTC"}) - - if ( (valuearray= cJSON_Parse(valstr)) != 0 ) +printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); + if ( (json= cJSON_Parse(retstr)) != 0 ) { - if ( valstr[0] == '[' && is_cJSON_Array(valuearray) != 0 ) + if ( (hexstr= jstr(json,"hex")) != 0 ) { - n = cJSON_GetArraySize(valuearray); - for (i=0; i= 0 ) - break; - } - } else retval = basilisk_confirmsobj(valuearray); - free_json(valuearray); - } else printf("parse error\n"); - free(valstr); + len = (int32_t)strlen(hexstr); + signedtx = calloc(1,len+1); + strcpy(signedtx,hexstr); + *completedp = jint(json,"completed"); + data = malloc(len >> 1); + decode_hex(data,len>>1,hexstr); + *signedtxidp = bits256_doublesha256(0,data,len >> 1); + } + free_json(json); + } + free(retstr); } - free_json(argjson); - printf("numconfirms.%d returned\n",retval); - return(retval);*/ + free(paramstr); + return(signedtx); } diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 2512c83f9..74d820b5f 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -19,6 +19,81 @@ // +bits256 LP_broadcast(char *txname,char *symbol,char *txbytes) +{ + char *retstr; bits256 txid; int32_t i,sentflag = 0; + memset(&txid,0,sizeof(txid)); + for (i=0; i<3; i++) + { + if ( (retstr= LP_sendrawtransaction(symbol,txbytes)) != 0 ) + { + if ( is_hexstr(retstr,0) == 64 ) + { + decode_hex(txid.bytes,32,retstr); + sentflag = 1; + } + char str[65]; printf("[%s] %s RETSTR.(%s) %s.%s\n",txname,txbytes,retstr,symbol,bits256_str(str,txid)); + free(retstr); + } + if ( sentflag != 0 ) + break; + } + return(txid); +} + +bits256 LP_broadcast_tx(char *name,char *symbol,uint8_t *data,int32_t datalen) +{ + bits256 txid; char *signedtx; + memset(txid.bytes,0,sizeof(txid)); + if ( data != 0 && datalen != 0 ) + { + char str[65]; +#ifdef BASILISK_DISABLESENDTX + txid = bits256_doublesha256(0,data,datalen); + printf("%s <- dont sendrawtransaction (%s)\n",name,bits256_str(str,txid)); + return(txid); +#endif + signedtx = malloc(datalen*2 + 1); + init_hexbytes_noT(signedtx,data,datalen); + txid = LP_broadcast(name,symbol,signedtx); + // sent to nn_socket! + free(signedtx); + } + return(txid); +} + +uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) +{ + uint64_t value = 0; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; + if ( (txobj= LP_gettx(symbol,txid)) != 0 ) + { + if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 && vout < numvouts ) + { + utxoobj = jitem(vouts,vout); + if ( (value= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + { + char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d/%d\n",symbol,bits256_str(str,txid),jprint(utxoobj,0),vout,numvouts); + } + } + free_json(txobj); + } + return(value); +} + +int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +{ + int32_t numconfirms = 100; +#ifndef BASILISK_DISABLEWAITTX + cJSON *txobj; + if ( (txobj= LP_gettx(symbol,txid)) != 0 ) + { + numconfirms = jint(txobj,"confirmations"); + free_json(txobj); + } +#endif + return(numconfirms); +} + #ifdef later int32_t iguana_msgtx_Vset(uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,struct vin_info *V) @@ -488,9 +563,8 @@ int32_t iguana_signrawtransaction(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS *signedtxp = signedtx; return(complete); } -#endif -/*int32_t basilisk_rawtx_return(struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) +int32_t basilisk_rawtx_return(struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) { char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) @@ -676,7 +750,8 @@ int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8 free_json(txobj); free(V); return(retval); -}*/ +} +#endif char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp) { @@ -688,7 +763,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 ) return(0); - if ( (utxoobj= LP_swapgettxout(symbol,utxotxid,vout)) == 0 ) + if ( (utxoobj= LP_gettxout(symbol,utxotxid,vout)) == 0 ) { printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); return(0); @@ -802,9 +877,9 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub if ( strcmp(coin->symbol,"BTC") != 0 ) return(retval); len = rawtx->I.datalen; - if ( coin->estimatedfee == 0 ) - coin->estimatedfee = LP_getestimatedfee(coin->symbol); - newtxfee = coin->estimatedfee * len; + if ( coin->estimatedrate == 0 ) + coin->estimatedrate = LP_getestimatedrate(coin->symbol); + newtxfee = coin->estimatedrate * len; printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); } else break; } @@ -813,7 +888,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) { - char *signedtx; int64_t txfee,newtxfee=0,estimatedfee,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; + char *signedtx; int64_t txfee,newtxfee=0,estimatedrate,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; timestamp = swap->I.started; if ( dest == &swap->aliceclaim ) locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; @@ -835,8 +910,8 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ if ( strcmp(symbol,"BTC") != 0 ) return(retval); len = rawtx->I.datalen; - estimatedfee = LP_getestimatedfee(symbol); - newtxfee = estimatedfee * len; + estimatedrate = LP_getestimatedrate(symbol); + newtxfee = estimatedrate * len; } else break; } return(retval); @@ -907,7 +982,7 @@ int32_t LP_swap_getcoinaddr(char *symbol,char *coinaddr,bits256 txid,int32_t vou { cJSON *retjson; coinaddr[0] = 0; - if ( (retjson= LP_swapgettx(symbol,txid)) != 0 ) + if ( (retjson= LP_gettx(symbol,txid)) != 0 ) { LP_swap_txdestaddr(coinaddr,txid,vout,retjson); free_json(retjson); @@ -918,7 +993,7 @@ int32_t LP_swap_getcoinaddr(char *symbol,char *coinaddr,bits256 txid,int32_t vou int32_t basilisk_swap_getsigscript(char *symbol,uint8_t *script,int32_t maxlen,bits256 txid,int32_t vini) { cJSON *retjson,*vins,*item,*skey; int32_t n,scriptlen = 0; char *hexstr; - if ( (retjson= LP_swapgettx(symbol,txid)) != 0 ) + if ( (retjson= LP_gettx(symbol,txid)) != 0 ) { if ( (vins= jarray(&n,retjson,"vin")) != 0 && vini < n ) { @@ -939,7 +1014,7 @@ int64_t basilisk_txvalue(char *symbol,bits256 txid,int32_t vout) { cJSON *txobj,*vouts,*item; int32_t n; int64_t value = 0; //char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid)); - if ( (txobj= LP_swapgettx(symbol,txid)) != 0 ) + if ( (txobj= LP_gettx(symbol,txid)) != 0 ) { //printf("txobj.(%s)\n",jprint(txobj,0)); if ( (vouts= jarray(&n,txobj,"vout")) != 0 ) @@ -957,7 +1032,7 @@ bits256 _LP_swap_spendtxid(char *symbol,char *destaddr,char *coinaddr,bits256 ut { char *retstr,*addr; cJSON *array,*item,*array2; int32_t i,n,m; bits256 spendtxid,txid; memset(&spendtxid,0,sizeof(spendtxid)); - if ( (retstr= dex_listtransactions(symbol,coinaddr,100,0)) != 0 ) + if ( (retstr= blocktrail_listtransactions(symbol,coinaddr,100,0)) != 0 ) { if ( (array= cJSON_Parse(retstr)) != 0 ) { @@ -1014,7 +1089,7 @@ bits256 LP_swap_spendtxid(char *symbol,char *destaddr,bits256 utxotxid,int32_t v coinaddr[0] = 0; memset(&spendtxid,0,sizeof(spendtxid)); //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); - if ( strcmp("BTC",symbol) == 0 ) + if ( 0 && strcmp("BTC",symbol) == 0 ) { //[{"type":"sent","confirmations":379,"height":275311,"timestamp":1492084664,"txid":"8703c5517bc57db38134058370a14e99b8e662b99ccefa2061dea311bbd02b8b","vout":0,"amount":117.50945263,"spendtxid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","vin":0,"paid":{"type":"paid","txid":"cf2509e076fbb9b22514923df916b7aacb1391dce9c7e1460b74947077b12510","height":275663,"timestamp":1492106024,"vouts":[{"RUDpN6PEBsE7ZFbGjUxk1W3QVsxnjBLYw6":117.50935263}]}}] LP_swap_getcoinaddr(symbol,coinaddr,utxotxid,vout); @@ -1069,7 +1144,7 @@ bits256 LP_swap_spendtxid(char *symbol,char *destaddr,bits256 utxotxid,int32_t v if ( (catstr= jstr(item,"category")) != 0 && strcmp(catstr,"send") == 0 ) { txid = jbits256(item,"txid"); - if ( (txobj= LP_swapgettx(symbol,txid)) != 0 ) + if ( (txobj= LP_gettx(symbol,txid)) != 0 ) { if ( (vins= jarray(&m,txobj,"vin")) != 0 && m > jint(item,"vout") ) { @@ -1309,7 +1384,7 @@ int32_t basilisk_verify_bobpaid(void *ptr,uint8_t *data,int32_t datalen) memset(revAm.bytes,0,sizeof(revAm)); if ( basilisk_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { - swap->bobpayment.I.signedtxid = LP_broadcast(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + swap->bobpayment.I.signedtxid = LP_broadcast_tx(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) swap->paymentunconf = 1; basilisk_dontforget_update(swap,&swap->bobpayment); @@ -1452,7 +1527,7 @@ uint32_t LP_swapdata_rawtxsend(struct basilisk_swap *swap,uint32_t msgbits,uint8 if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) { char str[65],str2[65]; - rawtx->I.actualtxid = LP_broadcast(rawtx->name,rawtx->coin->symbol,rawtx->txbytes,rawtx->I.datalen); + rawtx->I.actualtxid = LP_broadcast_tx(rawtx->name,rawtx->coin->symbol,rawtx->txbytes,rawtx->I.datalen); if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) { printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); @@ -1536,7 +1611,7 @@ int32_t basilisk_verify_bobdeposit(void *ptr,uint8_t *data,int32_t datalen) uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { - swap->bobdeposit.I.signedtxid = LP_broadcast(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) swap->depositunconf = 1; basilisk_dontforget_update(swap,&swap->bobdeposit); @@ -1599,7 +1674,7 @@ int32_t basilisk_verify_alicepaid(void *ptr,uint8_t *data,int32_t datalen) struct basilisk_swap *swap = ptr; if ( basilisk_rawtx_spendscript(swap,swap->alicecoin.longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) { - swap->alicepayment.I.signedtxid = LP_broadcast(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + swap->alicepayment.I.signedtxid = LP_broadcast_tx(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) swap->aliceunconf = 1; basilisk_dontforget_update(swap,&swap->alicepayment); From 36ba6f9ff15a9b1a95bc959a3de76433d932b8f0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:03:51 +0300 Subject: [PATCH 0658/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4e7be2b89..fba18f5ad 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -763,6 +763,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } + LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_privkey_init(mypeer,pubsock,"KMD",60,"test",""); printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); while ( 1 ) From 9c49e988c00d48fd7f65cfaf4a6d002150bbbefb Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:07:09 +0300 Subject: [PATCH 0659/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fba18f5ad..8c8ab3e7f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -521,9 +521,16 @@ void LP_statefname(char *fname,char *symbol,char *assetname,char *str) strcat(fname,".litecoin"); else { - if ( assetname[0] == 0 ) - strcat(fname,".komodo"); - else strcat(fname,assetname); + strcat(fname,".komodo"); + if ( strcmp(symbol,"KMD") != 0 ) + { +#ifdef WIN32 + strcat(fname,"\\"); +#else + strcat(fname,"/"); +#endif + strcat(fname,assetname); + } } #ifdef WIN32 strcat(fname,"\\"); @@ -623,6 +630,7 @@ struct iguana_info *LP_coinfind(char *symbol) cdata.wiftype = 188; LP_userpass(cdata.userpass,symbol,symbol,strcmp(symbol,"KMD") == 0 ? "komodo" : symbol); } + printf("%s: (%s) (%s)\n",symbol,cdata.serverport,cdata.userpass); LP_coins = realloc(LP_coins,sizeof(*LP_coins) * (LP_numcoins+1)); coin = &LP_coins[LP_numcoins++]; *coin = cdata; @@ -763,7 +771,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } - LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); + LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); LP_privkey_init(mypeer,pubsock,"KMD",60,"test",""); printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); while ( 1 ) From 2fcc19d52af6fa5280378ba4bcc3511cd81025ea Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:11:17 +0300 Subject: [PATCH 0660/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 8c8ab3e7f..e434224df 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -637,21 +637,26 @@ struct iguana_info *LP_coinfind(char *symbol) return(coin); } -uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,uint8_t addrtype,char *passphrase,char *wifstr) +uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr) { - char *retstr,coinaddr[64],*script; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; + char *retstr,coinaddr[64],*script; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + if ( coin == 0 ) + { + printf("cant add privkey for %s, coin not active\n",symbol); + return(0); + } if ( passphrase != 0 ) conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); - iguana_priv2pub(pubkey33,coinaddr,privkey,addrtype); + iguana_priv2pub(pubkey33,coinaddr,privkey,coin->pubtype); bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); - retstr = iguana_listunspent(coin,coinaddr); + retstr = iguana_listunspent(symbol,coinaddr); if ( retstr != 0 && retstr[0] == '[' && retstr[1] == ']' ) free(retstr), retstr = 0; if ( retstr == 0 ) { - if ( (retstr= DEX_listunspent(coin,coinaddr)) == 0 ) + if ( (retstr= DEX_listunspent(symbol,coinaddr)) == 0 ) { printf("null listunspent\n"); return(0); @@ -693,7 +698,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin { value = values[i]; values[i] = 0, used++; - LP_addutxo(mypeer,mypubsock,coin,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); + LP_addutxo(mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); total += value; } } @@ -772,7 +777,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) exit(-1); } LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); - LP_privkey_init(mypeer,pubsock,"KMD",60,"test",""); + LP_privkey_init(mypeer,pubsock,"KMD","test",""); printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); while ( 1 ) { From 9e7e1dda47321bafd7f9111636cf9c0108ffb01c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:12:46 +0300 Subject: [PATCH 0661/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e434224df..c0fe51e0c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -649,6 +649,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); iguana_priv2pub(pubkey33,coinaddr,privkey,coin->pubtype); + printf("%s coinaddr.%s %d\n",symbol,coinaddr,coin->pubtype); bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); retstr = iguana_listunspent(symbol,coinaddr); From 3dc34a54bbdcd55e8b68d3dedefe6f9cd25bf16a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:14:49 +0300 Subject: [PATCH 0662/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 17 ++--------------- iguana/exchanges/mm.c | 4 ++-- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c0fe51e0c..3386c7964 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -639,7 +639,7 @@ struct iguana_info *LP_coinfind(char *symbol) uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr) { - char *retstr,coinaddr[64],*script; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + char coinaddr[64],*script; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) { printf("cant add privkey for %s, coin not active\n",symbol); @@ -652,19 +652,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb printf("%s coinaddr.%s %d\n",symbol,coinaddr,coin->pubtype); bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); - retstr = iguana_listunspent(symbol,coinaddr); - if ( retstr != 0 && retstr[0] == '[' && retstr[1] == ']' ) - free(retstr), retstr = 0; - if ( retstr == 0 ) - { - if ( (retstr= DEX_listunspent(symbol,coinaddr)) == 0 ) - { - printf("null listunspent\n"); - return(0); - } - } - printf("LP_privkey_init.(%s)\n",retstr); - if ( (array= cJSON_Parse(retstr)) != 0 ) + if ( (array= LP_listunspent(symbol,coinaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { @@ -709,7 +697,6 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } free_json(array); } - free(retstr); return(total); } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index ca30cf3d2..814ada65e 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -170,13 +170,13 @@ char *iguana_walletpassphrase(char *passphrase,int32_t timeout) return(bitcoind_RPC(0,"",url,0,"walletpassphrase",postdata)); } -char *iguana_listunspent(char *coin,char *coinaddr) +/*char *iguana_listunspent(char *coin,char *coinaddr) { char url[512],postdata[1024]; sprintf(url,"%s/coin=%s&agent=bitcoinrpc&method=listunspent?",IGUANA_URL,coin); sprintf(postdata,"[\"%s\"]",coinaddr); return(bitcoind_RPC(0,"",url,0,"listunspent",postdata)); -} +}*/ /*char *issue_LP_intro(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers) { From e71e8b482141da3ce04465518f8fb3fb55c0218b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:16:27 +0300 Subject: [PATCH 0663/2705] Test --- iguana/exchanges/LP_rpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index c72a80ec4..4d07fd765 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -25,7 +25,7 @@ char *LP_getdatadir() cJSON *basilisk_nullretjson(cJSON *retjson) { - char *outstr; + /*char *outstr; if ( retjson != 0 ) { outstr = jprint(retjson,0); @@ -35,7 +35,7 @@ cJSON *basilisk_nullretjson(cJSON *retjson) retjson = 0; } free(outstr); - } + }*/ return(retjson); } From ad663744a213f5510840e7fd6061e91c61b6e2e3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:17:30 +0300 Subject: [PATCH 0664/2705] Test --- iguana/exchanges/LP_rpc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 4d07fd765..921720400 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,6 +52,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) { + printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); retjson = cJSON_Parse(retstr); free(retstr); } From 74fbd2c268aab5f534d8964afce01286e9202b23 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:18:38 +0300 Subject: [PATCH 0665/2705] Test --- iguana/exchanges/LP_rpc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 921720400..a28c4d9f4 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -49,6 +49,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) char *retstr; cJSON *retjson = 0; if ( coin != 0 ) { + printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) { From 4b2b791e778a50a4aea22cc4b4d132b7d73e2300 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:21:54 +0300 Subject: [PATCH 0666/2705] Test --- crypto777/bitcoind_RPC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index 2a4636801..02c8e71d7 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -136,7 +136,7 @@ char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char * else specialcase = 0; if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7776"); - if ( specialcase != 0 && (0) ) + //if ( specialcase != 0 && (0) ) printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params); try_again: if ( retstrp != 0 ) From cfa382c2053fd9906b8eb1d2a5fc00cb6640a413 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:27:17 +0300 Subject: [PATCH 0667/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_rpc.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 5aae7da4a..ed0f4fde2 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -467,5 +467,6 @@ uint32_t basilisk_requestid(struct basilisk_request *rp); uint32_t basilisk_quoteid(struct basilisk_request *rp); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); struct iguana_info *LP_coinfind(char *symbol); +void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3); #endif diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index a28c4d9f4..21d8b8a8e 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -46,11 +46,13 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) { + static void *cHandle; char *retstr; cJSON *retjson = 0; if ( coin != 0 ) { printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); - retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); + retstr = curl_post(&cHandle,coin->serverport,coin->userpass,params,method,0,0,0); + //retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) { printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); From b42dad372b11c16110ebc47d9c4114c88b058db9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:29:31 +0300 Subject: [PATCH 0668/2705] Test --- iguana/exchanges/LP_rpc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 21d8b8a8e..604e58aa0 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -46,13 +46,14 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) { - static void *cHandle; + //static void *cHandle; char *retstr; cJSON *retjson = 0; if ( coin != 0 ) { printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); - retstr = curl_post(&cHandle,coin->serverport,coin->userpass,params,method,0,0,0); + //retstr = curl_post(&cHandle,coin->serverport,coin->userpass,params,method,0,0,0); //retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); + retstr = bitcoind_RPC(0,"",coin->serverport,0,method,params); if ( retstr != 0 && retstr[0] != 0 ) { printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); From 849296498ef76f40a8eb9fba80644166f674fb9f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:34:53 +0300 Subject: [PATCH 0669/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3386c7964..3ccad5825 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -765,6 +765,7 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) exit(-1); } LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); + LP_privkey_init(mypeer,pubsock,"BTC","test",""); LP_privkey_init(mypeer,pubsock,"KMD","test",""); printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); while ( 1 ) From 2049ed933f43a648d58ef5d9a4692fdacabfd93f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:36:45 +0300 Subject: [PATCH 0670/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 +++ iguana/exchanges/LP_rpc.c | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3ccad5825..c00db99ed 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -765,6 +765,9 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) exit(-1); } LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); + printf("%s\n",jprint(LP_getinfo("BTC"),1)); + printf("%s\n",jprint(LP_getinfo("KMD"),1)); + LP_privkey_init(mypeer,pubsock,"BTC","test",""); LP_privkey_init(mypeer,pubsock,"KMD","test",""); printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 604e58aa0..ddb156dee 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -70,6 +70,12 @@ void LP_unspents_mark(char *symbol,cJSON *vins) printf("LOCK (%s)\n",jprint(vins,0)); } +cJSON *LP_getinfo(char *symbol) +{ + struct iguana_info *coin = LP_coinfind(symbol); + return(bitcoin_json(coin,"getinfo","[]")); +} + cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout) { char buf[128],str[65]; struct iguana_info *coin = LP_coinfind(symbol); From 80de82f18d460f2f2f2126968cebdd35eaa80e3e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:50:13 +0300 Subject: [PATCH 0671/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c00db99ed..249e17411 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -574,7 +574,7 @@ uint32_t LP_assetmagic(char *symbol,uint64_t supply) uint16_t LP_assetport(uint32_t magic) { if ( magic == 0x8de4eef9 ) - return(7770); + return(7771); else return(8000 + (magic % 7777)); } @@ -583,7 +583,7 @@ uint16_t LP_port(char *symbol,uint64_t supply,uint32_t *magicp) if ( symbol == 0 || symbol[0] == 0 || strcmp("KMD",symbol) == 0 ) { *magicp = 0x8de4eef9; - return(7770); + return(7771); } else if ( strcmp("BTC",symbol) == 0 ) return(8332); From 4d7e7a2b8640da5eaf838c856044ed804fd947d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:57:22 +0300 Subject: [PATCH 0672/2705] Test --- crypto777/bitcoind_RPC.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index 02c8e71d7..47e4e6d45 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -137,7 +137,7 @@ char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char * if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7776"); //if ( specialcase != 0 && (0) ) - printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params); + printf("<<<<<<<<<<< bitcoind_RPC: userpass.(%s) url.(%s) command.(%s) params.(%s)\n",userpass,url,command,params); try_again: if ( retstrp != 0 ) *retstrp = 0; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 249e17411..ddb5eb343 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -578,7 +578,7 @@ uint16_t LP_assetport(uint32_t magic) else return(8000 + (magic % 7777)); } -uint16_t LP_port(char *symbol,uint64_t supply,uint32_t *magicp) +uint16_t LP_rpcport(char *symbol,uint64_t supply,uint32_t *magicp) { if ( symbol == 0 || symbol[0] == 0 || strcmp("KMD",symbol) == 0 ) { @@ -590,7 +590,7 @@ uint16_t LP_port(char *symbol,uint64_t supply,uint32_t *magicp) else if ( strcmp("LTC",symbol) == 0 ) return(9332); *magicp = LP_assetmagic(symbol,supply); - return(LP_assetport(*magicp)); + return(LP_assetport(*magicp)+1); } struct iguana_info *LP_coinfind(char *symbol) @@ -602,7 +602,7 @@ struct iguana_info *LP_coinfind(char *symbol) return(&LP_coins[i]); coin = &cdata; safecopy(cdata.symbol,symbol,sizeof(cdata.symbol)); - port = LP_port(symbol,10,&magic); + port = LP_rpcport(symbol,10,&magic); sprintf(cdata.serverport,"127.0.0.1:%u",port); cdata.longestchain = 100000; cdata.txfee = 10000; @@ -759,6 +759,8 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); exit(-1); } +//curl --url "bitcoing54g44rpc:passgh6456h5word@127.0.0.1:8332" --data "{\"method\":\"getinfo\",\"params\":[]}" +// curl --url "bitcoinrp456454z4zhhc:passwg45hgz64g499ord@127.0.0.1:7771" --data "{\"method\":\"getinfo\",\"params\":[]}" if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); From 6f334dfa7bb388c600c1e4d48a94b71287a2faa5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 13:59:58 +0300 Subject: [PATCH 0673/2705] Test --- iguana/exchanges/LP_rpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index ddb156dee..f688c6c7a 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,8 +52,8 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) { printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); //retstr = curl_post(&cHandle,coin->serverport,coin->userpass,params,method,0,0,0); - //retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); - retstr = bitcoind_RPC(0,"",coin->serverport,0,method,params); + retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); + //retstr = bitcoind_RPC(0,"",coin->serverport,0,method,params); if ( retstr != 0 && retstr[0] != 0 ) { printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); From 53d31b871d477ce7edb80da2b77ef57dc57b9bb0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:00:42 +0300 Subject: [PATCH 0674/2705] Test --- crypto777/bitcoind_RPC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index 47e4e6d45..975208ddd 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -136,7 +136,7 @@ char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char * else specialcase = 0; if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7776"); - //if ( specialcase != 0 && (0) ) + if ( specialcase != 0 && (0) ) printf("<<<<<<<<<<< bitcoind_RPC: userpass.(%s) url.(%s) command.(%s) params.(%s)\n",userpass,url,command,params); try_again: if ( retstrp != 0 ) From d302c018de0a22cd04b9b16e8b5a13bfdc6cdf32 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:02:59 +0300 Subject: [PATCH 0675/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ddb5eb343..f033c3950 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -600,6 +600,7 @@ struct iguana_info *LP_coinfind(char *symbol) for (i=0; i Date: Mon, 29 May 2017 14:05:22 +0300 Subject: [PATCH 0676/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f033c3950..ea342563d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -631,7 +631,7 @@ struct iguana_info *LP_coinfind(char *symbol) cdata.wiftype = 188; LP_userpass(cdata.userpass,symbol,symbol,strcmp(symbol,"KMD") == 0 ? "komodo" : symbol); } - printf("%s: (%s) (%s)\n",symbol,cdata.serverport,cdata.userpass); + //printf("%s: (%s) (%s)\n",symbol,cdata.serverport,cdata.userpass); LP_coins = realloc(LP_coins,sizeof(*LP_coins) * (LP_numcoins+1)); coin = &LP_coins[LP_numcoins++]; *coin = cdata; @@ -650,7 +650,11 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); iguana_priv2pub(pubkey33,coinaddr,privkey,coin->pubtype); - printf("%s coinaddr.%s %d\n",symbol,coinaddr,coin->pubtype); + { + char tmpstr[128]; + bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); + printf("%s coinaddr.%s %d wif.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr); + } bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); if ( (array= LP_listunspent(symbol,coinaddr)) != 0 ) From 80cf618f4dec9e48721b916aadc5452f71bea44c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:13:27 +0300 Subject: [PATCH 0677/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 ++++--- iguana/exchanges/LP_rpc.c | 3 +++ iguana/exchanges/mm.c | 9 +++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ea342563d..8a5a53aff 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -654,6 +654,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); printf("%s coinaddr.%s %d wif.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr); + LP_importaddress(coin->symbol,tmpstr); } bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); @@ -705,7 +706,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb return(total); } -void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) +void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin,char *passphrase) { char *myipaddr=0,*retstr; long filesize,n; int32_t len,timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; portable_mutex_init(&LP_peermutex); @@ -772,8 +773,8 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin) exit(-1); } LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); - LP_privkey_init(mypeer,pubsock,"BTC","test",""); - LP_privkey_init(mypeer,pubsock,"KMD","test",""); + LP_privkey_init(mypeer,pubsock,"BTC",passphrase,""); + LP_privkey_init(mypeer,pubsock,"KMD",passphrase,""); printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); while ( 1 ) { diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index f688c6c7a..96432470e 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -133,7 +133,10 @@ int32_t LP_importaddress(char *symbol,char *address) return(0); // success sprintf(buf,"[\"%s\", \"%s\", false]",address,address); if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"importaddress",buf)) != 0 ) + { + printf("importaddress.(%s %s) -> (%s)\n",symbol,address,retstr); free(retstr); + } else printf("importaddress.(%s %s)\n",symbol,address); return(1); } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 814ada65e..f75f708f6 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -798,8 +798,8 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double void LP_main(void *ptr) { - double profitmargin = *(double *)ptr; - LPinit(7779,7780,7781,profitmargin); + double profitmargin = 0.01; char *passphrase = ptr; + LPinit(7779,7780,7781,profitmargin,passphrase); } int main(int argc, const char * argv[]) @@ -812,7 +812,9 @@ int main(int argc, const char * argv[]) minask = jdouble(retjson,"minask"); maxbid = jdouble(retjson,"maxbid"); profitmargin = jdouble(retjson,"profitmargin"); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_main,(void *)&profitmargin) != 0 ) + if ( (passphrase= jstr(retjson,"passphrase")) == 0 ) + passphrase = "test"; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_main,(void *)passphrase) != 0 ) { printf("error launching LP_main %f\n",profitmargin); exit(-1); @@ -821,7 +823,6 @@ int main(int argc, const char * argv[]) incrratio = jdouble(retjson,"lotratio"); start_base = jdouble(retjson,"start_base"); start_rel = jdouble(retjson,"start_rel"); - passphrase = jstr(retjson,"passphrase"); apikey = jstr(retjson,"apikey"); apisecret = jstr(retjson,"apisecret"); base = jstr(retjson,"base"); From 54d449ba6b37e8a5a9e0c755d26f5ca819baae6d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:15:18 +0300 Subject: [PATCH 0678/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_rpc.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 8a5a53aff..7c677a6f4 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -654,7 +654,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); printf("%s coinaddr.%s %d wif.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr); - LP_importaddress(coin->symbol,tmpstr); + LP_importprivkey(coin->symbol,tmpstr); } bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 96432470e..0a2b56888 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -113,6 +113,13 @@ cJSON *LP_validateaddress(char *symbol,char *address) return(bitcoin_json(coin,"validateaddress",buf)); } +cJSON *LP_importprivkey(char *symbol,char *wifstr) +{ + char buf[512]; struct iguana_info *coin = LP_coinfind(symbol); + sprintf(buf,"\"%s\"",wifstr); + return(bitcoin_json(coin,"importprivkey",buf)); +} + int32_t LP_importaddress(char *symbol,char *address) { char buf[1024],*retstr; cJSON *validatejson; int32_t isvalid=0,doneflag = 0; struct iguana_info *coin = LP_coinfind(symbol); From 205e70ed15492719d1f06a8e2ec6362c06934312 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:16:09 +0300 Subject: [PATCH 0679/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7c677a6f4..1a53a9052 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -640,7 +640,7 @@ struct iguana_info *LP_coinfind(char *symbol) uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr) { - char coinaddr[64],*script; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + char coinaddr[64],*script; cJSON *array,*item,*retjson; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) { printf("cant add privkey for %s, coin not active\n",symbol); @@ -654,7 +654,8 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); printf("%s coinaddr.%s %d wif.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr); - LP_importprivkey(coin->symbol,tmpstr); + if ( (retjson= LP_importprivkey(coin->symbol,tmpstr)) != 0 ) + printf("importprivkey -> (%s)\n",jprint(retjson,1)); } bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); From 04dc3a8627a03b7be9b171ab5a67442b88657f8f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:17:20 +0300 Subject: [PATCH 0680/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_rpc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1a53a9052..687af36a1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -654,7 +654,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); printf("%s coinaddr.%s %d wif.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr); - if ( (retjson= LP_importprivkey(coin->symbol,tmpstr)) != 0 ) + if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 0a2b56888..58370c2d6 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -113,10 +113,10 @@ cJSON *LP_validateaddress(char *symbol,char *address) return(bitcoin_json(coin,"validateaddress",buf)); } -cJSON *LP_importprivkey(char *symbol,char *wifstr) +cJSON *LP_importprivkey(char *symbol,char *wifstr,int32_t flag) { char buf[512]; struct iguana_info *coin = LP_coinfind(symbol); - sprintf(buf,"\"%s\"",wifstr); + sprintf(buf,"[\"%s\", %s]",wifstr,flag < 0 ? "false" : "true"); return(bitcoin_json(coin,"importprivkey",buf)); } From f75ffa9f2c572a671f245722be62572ddf3cf49a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:22:18 +0300 Subject: [PATCH 0681/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_rpc.c | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 687af36a1..6291b7e8e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -654,7 +654,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); printf("%s coinaddr.%s %d wif.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr); - if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,-1)) != 0 ) + if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 58370c2d6..6336b6a93 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -46,14 +46,11 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) { - //static void *cHandle; char *retstr; cJSON *retjson = 0; if ( coin != 0 ) { - printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); - //retstr = curl_post(&cHandle,coin->serverport,coin->userpass,params,method,0,0,0); + //printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); - //retstr = bitcoind_RPC(0,"",coin->serverport,0,method,params); if ( retstr != 0 && retstr[0] != 0 ) { printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); @@ -113,10 +110,10 @@ cJSON *LP_validateaddress(char *symbol,char *address) return(bitcoin_json(coin,"validateaddress",buf)); } -cJSON *LP_importprivkey(char *symbol,char *wifstr,int32_t flag) +cJSON *LP_importprivkey(char *symbol,char *wifstr,char *label,int32_t flag) { char buf[512]; struct iguana_info *coin = LP_coinfind(symbol); - sprintf(buf,"[\"%s\", %s]",wifstr,flag < 0 ? "false" : "true"); + sprintf(buf,"[\"%s\", \"%s\", %s]",wifstr,label,flag < 0 ? "false" : "true"); return(bitcoin_json(coin,"importprivkey",buf)); } From 6de34cc13ddb7c7f06f8865e901935a1d1cc8a94 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:44:52 +0300 Subject: [PATCH 0682/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6291b7e8e..e97888a76 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -653,7 +653,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - printf("%s coinaddr.%s %d wif.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr); + printf("%s coinaddr.%s %d wif.(%s) passphrase.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } From 3eedaabb82eedca191a6baf3867fed377c0041f4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:47:33 +0300 Subject: [PATCH 0683/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 -- iguana/exchanges/mm.c | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e97888a76..a4c3502fb 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -766,8 +766,6 @@ void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin,c printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); exit(-1); } -//curl --url "bitcoing54g44rpc:passgh6456h5word@127.0.0.1:8332" --data "{\"method\":\"getinfo\",\"params\":[]}" -// curl --url "bitcoinrp456454z4zhhc:passwg45hgz64g499ord@127.0.0.1:7771" --data "{\"method\":\"getinfo\",\"params\":[]}" if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index f75f708f6..3df00e582 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -814,11 +814,12 @@ int main(int argc, const char * argv[]) profitmargin = jdouble(retjson,"profitmargin"); if ( (passphrase= jstr(retjson,"passphrase")) == 0 ) passphrase = "test"; - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_main,(void *)passphrase) != 0 ) + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_main,(void *)clonestr(passphrase)) != 0 ) { printf("error launching LP_main %f\n",profitmargin); exit(-1); - } getchar(); + } else printf("launched.(%s)\n",passphrase); +getchar(); maxexposure = jdouble(retjson,"maxexposure"); incrratio = jdouble(retjson,"lotratio"); start_base = jdouble(retjson,"start_base"); From 63109071181b62fe53fddc4fcb360b7b6e002bd6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:48:16 +0300 Subject: [PATCH 0684/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 3df00e582..99bdb7ada 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -818,7 +818,7 @@ int main(int argc, const char * argv[]) { printf("error launching LP_main %f\n",profitmargin); exit(-1); - } else printf("launched.(%s)\n",passphrase); + } else printf("(%s) launched.(%s)\n",argv[1],passphrase); getchar(); maxexposure = jdouble(retjson,"maxexposure"); incrratio = jdouble(retjson,"lotratio"); From 2edf6668aac848e84a88ced9896d6dd3e5eb1e21 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:52:23 +0300 Subject: [PATCH 0685/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 6336b6a93..486ffce72 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -53,7 +53,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) { - printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); + //printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); retjson = cJSON_Parse(retstr); free(retstr); } From 73b949004233995cc4466b37c005bf35c1ddb1be Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 14:58:18 +0300 Subject: [PATCH 0686/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a4c3502fb..5e95b876d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -653,7 +653,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - printf("%s coinaddr.%s %d wif.(%s) passphrase.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); + printf("%s coinaddr.(%s) %d wif.(%s) passphrase.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } @@ -710,12 +710,14 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin,char *passphrase) { char *myipaddr=0,*retstr; long filesize,n; int32_t len,timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; + OS_randombytes((void *)&n,sizeof(n)); + srand((int32_t)n); portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); portable_mutex_init(&LP_commandmutex); - if ( profitmargin == 0. ) + if ( profitmargin == 0. || profitmargin == 0.01 ) { - profitmargin = 0.01; + profitmargin = 0.01 + (double)(rand() % 100)/10000; printf("default profit margin %f\n",profitmargin); } if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) From 4d8f779289c99fa0b1345041fa1f69cbf4e2515f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 17:15:17 +0300 Subject: [PATCH 0687/2705] Test --- iguana/exchanges/LP_commands.c | 29 ++-- iguana/exchanges/LP_nativeDEX.c | 258 ++++++++++++++++++-------------- iguana/exchanges/mm.c | 20 ++- 3 files changed, 172 insertions(+), 135 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7db343df6..5c52bdbd0 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -149,21 +149,24 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { - if ( (pushport= juint(argjson,"push")) == 0 ) - pushport = argport + 1; - if ( (subport= juint(argjson,"sub")) == 0 ) - subport = argport + 2; - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) + if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) { - if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) - peer->numpeers = otherpeers; - if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) + if ( (pushport= juint(argjson,"push")) == 0 ) + pushport = argport + 1; + if ( (subport= juint(argjson,"sub")) == 0 ) + subport = argport + 2; + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) { - printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer->numutxos); - peer->numutxos = othernumutxos; - } - //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); - } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); + if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) + peer->numpeers = otherpeers; + if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) + { + printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer->numutxos); + peer->numutxos = othernumutxos; + } + //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); + } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); + } if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5e95b876d..cde7e1707 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -257,12 +257,14 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); - if ( peer != 0 ) { - peer->lasttime = now; - if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers < n ) - peer->numpeers = n; + peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + if ( peer != 0 ) + { + peer->lasttime = now; + if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers < n ) + peer->numpeers = n; + } } } } @@ -351,24 +353,27 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( peer != 0 && peer->errors > 0 ) return; - if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) + if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer!=0?mypeer->numpeers:0,mypeer!=0?mypeer->numutxos:0)) != 0 ) { //printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); - HASH_ITER(hh,LP_peerinfos,peer,tmp) + if ( mypeer != 0 ) { - if ( peer->lasttime != now ) + HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("{%s:%u %.6f} ",peer->ipaddr,peer->port,peer->profitmargin); - flag++; - if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->profitmargin,peer->numpeers,0)) != 0 ) - free(retstr); + if ( peer->lasttime != now ) + { + printf("{%s:%u %.6f} ",peer->ipaddr,peer->port,peer->profitmargin); + flag++; + if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->profitmargin,peer->numpeers,0)) != 0 ) + free(retstr); + } } + if ( flag != 0 ) + printf(" <- missing peers\n"); } - if ( flag != 0 ) - printf(" <- missing peers\n"); } else if ( peer != 0 ) peer->errors++; } @@ -638,7 +643,7 @@ struct iguana_info *LP_coinfind(char *symbol) return(coin); } -uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr) +uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t amclient) { char coinaddr[64],*script; cJSON *array,*item,*retjson; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) @@ -659,7 +664,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); - if ( (array= LP_listunspent(symbol,coinaddr)) != 0 ) + if ( amclient == 0 && (array= LP_listunspent(symbol,coinaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { @@ -707,132 +712,157 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb return(total); } -void LPinit(uint16_t myport,uint16_t mypull,uint16_t mypub,double profitmargin,char *passphrase) +void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) { - char *myipaddr=0,*retstr; long filesize,n; int32_t len,timeout,maxsize,recvsize,nonz,i,lastn,pullsock=-1,pubsock=-1; struct LP_peerinfo *peer,*tmp,*mypeer=0; char pushaddr[128],subaddr[128]; void *ptr; cJSON *argjson; - OS_randombytes((void *)&n,sizeof(n)); - srand((int32_t)n); - portable_mutex_init(&LP_peermutex); - portable_mutex_init(&LP_utxomutex); - portable_mutex_init(&LP_commandmutex); - if ( profitmargin == 0. || profitmargin == 0.01 ) - { - profitmargin = 0.01 + (double)(rand() % 100)/10000; - printf("default profit margin %f\n",profitmargin); - } - if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) + char *retstr; int32_t i,len,recvsize,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson; + for (i=0; i>>>>>>>> myipaddr.%s (%s %s)\n",myipaddr,pushaddr,subaddr); - if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) - { - if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) - { - timeout = 10; - nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - timeout = 1; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - timeout = 1; - maxsize = 1024 * 1024; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - } - else - { - printf("error binding to (%s).%d (%s).%d\n",pushaddr,pullsock,subaddr,pubsock); - if ( pullsock >= 0 ) - nn_close(pullsock), pullsock = -1; - if ( pubsock >= 0 ) - nn_close(pubsock), pubsock = -1; - } - } else printf("error getting sockets %d %d\n",pullsock,pubsock); - LP_mypubsock = pubsock; - LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); - //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); - for (i=0; i 25 ) - continue; - LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,myipaddr,myport,profitmargin); - } - } else printf("error getting myipaddr\n"); - } else printf("error issuing curl\n"); - if ( myipaddr == 0 || mypeer == 0 ) - { - printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); - exit(-1); + if ( amclient == 0 && (rand() % 100) > 25 ) + continue; + LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer!=0?mypeer->ipaddr:"127.0.0.1",myport,profitmargin); } if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } - LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); - LP_privkey_init(mypeer,pubsock,"BTC",passphrase,""); - LP_privkey_init(mypeer,pubsock,"KMD",passphrase,""); - printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); - while ( 1 ) + LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); + LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); + if ( amclient != 0 ) { - nonz = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers != mypeer->numpeers || (rand() % 10) == 0 ) - { - if ( peer->numpeers != mypeer->numpeers ) - printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); - if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); - } - if ( peer->numutxos != mypeer->numutxos ) + printf("%s:%u ",peer->ipaddr,peer->port); + } + printf("peers\n"); + while ( 1 ) + { + sleep(1); + } + } + else + { + LP_privkey_init(mypeer,pubsock,"BTC",passphrase,"",amclient); + LP_privkey_init(mypeer,pubsock,"KMD",passphrase,"",amclient); + while ( 1 ) + { + nonz = 0; + HASH_ITER(hh,LP_peerinfos,peer,tmp) { - lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; - if ( lastn < 0 ) - lastn = LP_PROPAGATION_SLACK * 2; - printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); - if ( strcmp(peer->ipaddr,myipaddr) != 0 ) - LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,myipaddr,myport,profitmargin); + if ( peer->numpeers != mypeer->numpeers || (rand() % 10) == 0 ) + { + if ( peer->numpeers != mypeer->numpeers ) + printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); + if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) + LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); + } + if ( peer->numutxos != mypeer->numutxos ) + { + lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; + if ( lastn < 0 ) + lastn = LP_PROPAGATION_SLACK * 2; + printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); + if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) + LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer->ipaddr,myport,profitmargin); + } + while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) + { + nonz++; + if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) + { + portable_mutex_lock(&LP_commandmutex); + if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypubport)) != 0 ) + { + printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + free(retstr); + } + portable_mutex_unlock(&LP_commandmutex); + free_json(argjson); + } else printf("error parsing.(%s)\n",(char *)ptr); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } } - while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) + while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { + len = (int32_t)strlen((char *)ptr) + 1; portable_mutex_lock(&LP_commandmutex); - if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypub)) != 0 ) - { - printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); - free(retstr); - } + LP_command(mypeer,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin); portable_mutex_unlock(&LP_commandmutex); free_json(argjson); - } else printf("error parsing.(%s)\n",(char *)ptr); + } if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; } + if ( nonz == 0 ) + sleep(mypeer->numpeers + 1); + } + } +} + +void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient) +{ + char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128]; + OS_randombytes((void *)&n,sizeof(n)); + srand((int32_t)n); + portable_mutex_init(&LP_peermutex); + portable_mutex_init(&LP_utxomutex); + portable_mutex_init(&LP_commandmutex); + if ( amclient == 0 ) + { + if ( profitmargin == 0. || profitmargin == 0.01 ) + { + profitmargin = 0.01 + (double)(rand() % 100)/100000; + printf("default profit margin %f\n",profitmargin); } - while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) { - nonz++; - if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) + if ( (myipaddr= OS_filestr(&filesize,"/tmp/myipaddr")) != 0 && myipaddr[0] != 0 ) { - len = (int32_t)strlen((char *)ptr) + 1; - portable_mutex_lock(&LP_commandmutex); - LP_command(mypeer,mypub,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin); - portable_mutex_unlock(&LP_commandmutex); - free_json(argjson); - } - if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0; + n = strlen(myipaddr); + if ( myipaddr[n-1] == '\n' ) + myipaddr[--n] = 0; + pullsock = pubsock = -1; + nanomsg_tcpname(pushaddr,myipaddr,mypullport); + nanomsg_tcpname(subaddr,myipaddr,mypubport); + printf(">>>>>>>>> myipaddr.%s (%s %s)\n",myipaddr,pushaddr,subaddr); + if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) + { + if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) + { + timeout = 10; + nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + maxsize = 1024 * 1024; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + } + else + { + printf("error binding to (%s).%d (%s).%d\n",pushaddr,pullsock,subaddr,pubsock); + if ( pullsock >= 0 ) + nn_close(pullsock), pullsock = -1; + if ( pubsock >= 0 ) + nn_close(pubsock), pubsock = -1; + } + } else printf("error getting sockets %d %d\n",pullsock,pubsock); + LP_mypubsock = pubsock; + LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); + //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); + } else printf("error getting myipaddr\n"); + } else printf("error issuing curl\n"); + if ( myipaddr == 0 || mypeer == 0 ) + { + printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); + exit(-1); } - if ( nonz == 0 ) - sleep(mypeer->numpeers + 1); + printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); } + LP_mainloop(mypeer,mypubport,pubsock,pullsock,myport,amclient,passphrase,profitmargin); } /*#ifdef __APPLE__ diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 99bdb7ada..1ffef2e92 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -798,8 +798,12 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double void LP_main(void *ptr) { - double profitmargin = 0.01; char *passphrase = ptr; - LPinit(7779,7780,7781,profitmargin,passphrase); + char *passphrase; double profitmargin; cJSON *argjson = ptr; + if ( (passphrase= jstr(argjson,"passphrase")) != 0 ) + { + profitmargin = jdouble(argjson,"profitmargin"); + LPinit(7779,7780,7781,profitmargin,passphrase,jint(argjson,"client")); + } } int main(int argc, const char * argv[]) @@ -809,17 +813,17 @@ int main(int argc, const char * argv[]) cJSON *retjson,*loginjson; int32_t i; if ( argc > 1 && (retjson= cJSON_Parse(argv[1])) != 0 ) { - minask = jdouble(retjson,"minask"); - maxbid = jdouble(retjson,"maxbid"); - profitmargin = jdouble(retjson,"profitmargin"); if ( (passphrase= jstr(retjson,"passphrase")) == 0 ) - passphrase = "test"; - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_main,(void *)clonestr(passphrase)) != 0 ) + jaddstr(retjson,"passphrase","test"); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_main,(void *)retjson) != 0 ) { - printf("error launching LP_main %f\n",profitmargin); + printf("error launching LP_main (%s)\n",jprint(retjson,0)); exit(-1); } else printf("(%s) launched.(%s)\n",argv[1],passphrase); getchar(); + profitmargin = jdouble(retjson,"profitmargin"); + minask = jdouble(retjson,"minask"); + maxbid = jdouble(retjson,"maxbid"); maxexposure = jdouble(retjson,"maxexposure"); incrratio = jdouble(retjson,"lotratio"); start_base = jdouble(retjson,"start_base"); From 4df9c9dc08d5530f160489ce0280cdbc30440995 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 17:23:22 +0300 Subject: [PATCH 0688/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index cde7e1707..5de30c593 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -728,6 +728,8 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); + LP_privkey_init(mypeer,pubsock,"BTC",passphrase,"",amclient); + LP_privkey_init(mypeer,pubsock,"KMD",passphrase,"",amclient); if ( amclient != 0 ) { HASH_ITER(hh,LP_peerinfos,peer,tmp) @@ -742,8 +744,6 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } else { - LP_privkey_init(mypeer,pubsock,"BTC",passphrase,"",amclient); - LP_privkey_init(mypeer,pubsock,"KMD",passphrase,"",amclient); while ( 1 ) { nonz = 0; From c69bcde1f32dd937b4b0a4acec8c6f248422f387 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 17:54:12 +0300 Subject: [PATCH 0689/2705] Test --- iguana/exchanges/LP_commands.c | 7 +++--- iguana/exchanges/LP_nativeDEX.c | 43 +++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 5c52bdbd0..21eeb0a14 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -142,7 +142,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; + char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); else @@ -166,7 +166,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); - } + amclient = 0; + } else amclient = 1; if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) @@ -176,7 +177,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } else printf("malformed request.(%s)\n",jprint(argjson,0)); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5de30c593..ea2dd90c2 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -42,11 +42,11 @@ struct LP_peerinfo struct LP_utxoinfo { UT_hash_handle hh; - bits256 txid,deposittxid,otherpubkey; + bits256 txid,deposittxid,feetxid,otherpubkey; void *swap; - uint64_t satoshis,depositsatoshis; + uint64_t satoshis,depositsatoshis,feesatoshis; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; - int32_t vout,depositvout,pair; uint32_t lasttime,errors,swappending; + int32_t vout,depositvout,feevout,pair; uint32_t lasttime,errors,swappending; double profitmargin; char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; uint16_t port; @@ -188,7 +188,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char return(peer); } -struct LP_utxoinfo *LP_addutxo(struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) +struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) { struct LP_utxoinfo *utxo = 0; uint8_t key[sizeof(txid) + sizeof(vout)]; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) @@ -219,9 +219,18 @@ struct LP_utxoinfo *LP_addutxo(struct LP_peerinfo *mypeer,int32_t mypubsock,char utxo->txid = txid; utxo->vout = vout; utxo->satoshis = satoshis; - utxo->deposittxid = deposittxid; - utxo->depositvout = depositvout; - utxo->depositsatoshis = depositsatoshis; + if ( amclient == 0 ) + { + utxo->deposittxid = deposittxid; + utxo->depositvout = depositvout; + utxo->depositsatoshis = depositsatoshis; + } + else + { + utxo->feetxid = deposittxid; + utxo->feevout = depositvout; + utxo->feesatoshis = depositsatoshis; + } memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); memcpy(utxo->key,key,sizeof(key)); @@ -274,7 +283,7 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa return(n); } -int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer,*destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; if ( (array= cJSON_Parse(retstr)) != 0 ) @@ -296,7 +305,7 @@ int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - utxo = LP_addutxo(mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } @@ -378,7 +387,7 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr peer->errors++; } -void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) +void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); @@ -389,7 +398,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) { now = (uint32_t)time(NULL); - LP_utxosparse(mypeer,mypubsock,destipaddr,destport,retstr,now); + LP_utxosparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); i = 0; if ( lastn >= mypeer->numutxos ) @@ -664,7 +673,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); LP_privkeyadd(privkey,rmd160); - if ( amclient == 0 && (array= LP_listunspent(symbol,coinaddr)) != 0 ) + if ( (array= LP_listunspent(symbol,coinaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { @@ -688,7 +697,9 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb script = jstr(item,"scriptPubKey"); depositval = values[i]; values[i] = 0, used++; - targetval = (depositval / 9) * 8; + if ( amclient != 0 ) + targetval = (depositval / 777); + else targetval = (depositval / 9) * 8; printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) { @@ -699,7 +710,9 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { value = values[i]; values[i] = 0, used++; - LP_addutxo(mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); + if ( amclient == 0 ) + LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); + else LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,"127.0.0.1",0,0); total += value; } } @@ -763,7 +776,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i lastn = LP_PROPAGATION_SLACK * 2; printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) - LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer->ipaddr,myport,profitmargin); + LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer->ipaddr,myport,profitmargin); } while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) { From 06fd4493f8c4de86937c3674ddeabfdb1d214430 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 17:57:03 +0300 Subject: [PATCH 0690/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ea2dd90c2..aae484341 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -237,13 +237,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_lock(&LP_utxomutex); HASH_ADD(hh,LP_utxoinfos,key,sizeof(key),utxo); if ( mypeer != 0 ) - { mypeer->numutxos++; - printf("%s:%u LP_addutxo.(%.8f %.8f) numutxos.%d\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis),mypeer->numutxos); - } portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); + printf("%s:%u LP_addutxo.(%.8f %.8f) numutxos.%d\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0); } return(utxo); } From 4fa2204136fe828156df7bf43a6dcfa80b62d3f6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:21:32 +0300 Subject: [PATCH 0691/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index aae484341..b4c987d8c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -372,7 +372,7 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr { if ( peer->lasttime != now ) { - printf("{%s:%u %.6f} ",peer->ipaddr,peer->port,peer->profitmargin); + printf("{%s:%u %.6f}.%d ",peer->ipaddr,peer->port,peer->profitmargin,peer->lasttime - now); flag++; if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->profitmargin,peer->numpeers,0)) != 0 ) free(retstr); From a07fe51ddc34f03a6e1a332ec167c82bc767744a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:22:22 +0300 Subject: [PATCH 0692/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b4c987d8c..11e21c895 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -362,7 +362,7 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr return; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer!=0?mypeer->numpeers:0,mypeer!=0?mypeer->numutxos:0)) != 0 ) { - //printf("got.(%s)\n",retstr); + printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); From 33df0bc0d8f3a028672b17074c7ef32dd0cab6b1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:24:26 +0300 Subject: [PATCH 0693/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 11e21c895..1d5cb459d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -273,7 +273,7 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa peer->numpeers = n; } } - } + } } } free_json(array); From 2b3920992d9d75ae6ef476bc94314bed59ad0474 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:25:30 +0300 Subject: [PATCH 0694/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1d5cb459d..b4c987d8c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -273,7 +273,7 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa peer->numpeers = n; } } - } + } } } free_json(array); @@ -362,7 +362,7 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr return; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer!=0?mypeer->numpeers:0,mypeer!=0?mypeer->numutxos:0)) != 0 ) { - printf("got.(%s)\n",retstr); + //printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); From ab940b986d4d44ec312e511e9b4b14c08c1b7823 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:28:04 +0300 Subject: [PATCH 0695/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b4c987d8c..4a4d36dd2 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -325,10 +325,12 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { - char url[512]; + char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); //printf("send.(%s)\n",url); - return(issue_curl(url)); + retstr = issue_curl(url); + printf("GETPEERS.(%s)\n",retstr); + return(retstr); } char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) From 6bab3468ce90629070e2601f7c62f7e14e3f19d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:30:57 +0300 Subject: [PATCH 0696/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4a4d36dd2..d5ae87bcc 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -329,7 +329,7 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); //printf("send.(%s)\n",url); retstr = issue_curl(url); - printf("GETPEERS.(%s)\n",retstr); + //printf("GETPEERS.(%s)\n",retstr); return(retstr); } @@ -340,6 +340,13 @@ char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn, return(issue_curl(url)); } +char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t lastn) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d",destip,destport,coin,lastn); + return(issue_curl(url)); +} + char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { char url[512]; @@ -727,7 +734,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) { - char *retstr; int32_t i,len,recvsize,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson; + char *retstr,*utxostr; int32_t i,len,recvsize,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson; for (i=0; i 25 ) @@ -747,7 +754,8 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("%s:%u ",peer->ipaddr,peer->port); + utxostr = issue_LP_clientgetutxos(peer->ipaddr,peer->port,"KMD",0); + printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); } printf("peers\n"); while ( 1 ) From 9cb89eba9c2b5c133a62bb75ebb49a5439b2718c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:32:54 +0300 Subject: [PATCH 0697/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d5ae87bcc..72ebdeeee 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -336,7 +336,7 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); return(issue_curl(url)); } From 24d59fc33c2ea854a2cc8aba53f63f6399c851eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:34:18 +0300 Subject: [PATCH 0698/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 72ebdeeee..ce53e6842 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -336,14 +336,14 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); return(issue_curl(url)); } char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t lastn) { char url[512]; - sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d",destip,destport,coin,lastn); + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); return(issue_curl(url)); } From 20c9f28d420225974b2b9d45047c0421ac737d60 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:35:20 +0300 Subject: [PATCH 0699/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ce53e6842..fbc34f07c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -735,7 +735,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) { char *retstr,*utxostr; int32_t i,len,recvsize,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson; - for (i=0; i 25 ) continue; From 78d57ddf890a3be3ed350d4136137d4258cf1b00 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:37:51 +0300 Subject: [PATCH 0700/2705] Test --- iguana/exchanges/LP_commands.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 21eeb0a14..65a6a6ace 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -147,6 +147,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port return(clonestr("{\"error\":\"need method in request\"}")); else { + amclient = 0; if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) @@ -168,19 +169,19 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); amclient = 0; } else amclient = 1; - if ( strcmp(method,"getpeers") == 0 ) - retstr = LP_peers(); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) - retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - else if ( strcmp(method,"notify") == 0 ) - retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( strcmp(method,"notifyutxo") == 0 ) - { - printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),ipaddr,argport,jdouble(argjson,"profit")); - retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); - } - } else printf("malformed request.(%s)\n",jprint(argjson,0)); + } + if ( strcmp(method,"getpeers") == 0 ) + retstr = LP_peers(); + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); + else if ( strcmp(method,"notify") == 0 ) + retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); + else if ( strcmp(method,"notifyutxo") == 0 ) + { + printf("utxonotify.(%s)\n",jprint(argjson,0)); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); + } } if ( retstr != 0 ) return(retstr); From b862bcf788f22f8c94dbffe11744d2adb5b0a63c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:42:05 +0300 Subject: [PATCH 0701/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fbc34f07c..6f46d0da9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -264,14 +264,12 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - { peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); - if ( peer != 0 ) - { - peer->lasttime = now; - if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers < n ) - peer->numpeers = n; - } + if ( peer != 0 ) + { + peer->lasttime = now; + if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers < n ) + peer->numpeers = n; } } } From af51b9bc7cb529977a9bf1c0b11618c6708cd9aa Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 18:46:36 +0300 Subject: [PATCH 0702/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6f46d0da9..396cd2481 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -268,7 +268,7 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa if ( peer != 0 ) { peer->lasttime = now; - if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers < n ) + if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers != n ) peer->numpeers = n; } } @@ -752,7 +752,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { HASH_ITER(hh,LP_peerinfos,peer,tmp) { - utxostr = issue_LP_clientgetutxos(peer->ipaddr,peer->port,"KMD",0); + utxostr = issue_LP_clientgetutxos(peer->ipaddr,peer->port,"KMD",10); printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); } printf("peers\n"); From d9fb711d4bcc4d306ef18117e53ab776f0087d14 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:13:39 +0300 Subject: [PATCH 0703/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 396cd2481..7777d1ad8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -732,7 +732,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) { - char *retstr,*utxostr; int32_t i,len,recvsize,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson; + char *retstr,*utxostr; int32_t i,n,len,recvsize,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson,*array,*reqjson,*item; for (i=amclient; i 25 ) @@ -750,10 +750,37 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_privkey_init(mypeer,pubsock,"KMD",passphrase,"",amclient); if ( amclient != 0 ) { + nonz = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { - utxostr = issue_LP_clientgetutxos(peer->ipaddr,peer->port,"KMD",10); - printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); + if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,"KMD",10)) != 0 ) + { + printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); + if ( (array= cJSON_Parse(utxostr)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i<1; i++) + { + item = jitem(array,i); + reqjson = cJSON_CreateObject(); + jaddbits256(reqjson,"txid",jbits256(item,"txid")); + jaddnum(reqjson,"vout",jint(item,"vout")); + jaddstr(reqjson,"base",jstr(item,"base")); + jaddstr(reqjson,"rel","BTC"); + jaddstr(reqjson,"method","price"); + //5.9.253.196:7779 [{"ipaddr":"5.9.253.196","port":7779,"profit":0.01064000,"coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}] + + LP_send(peer->pushsock,jprint(reqjson,1),1); + nonz = 1; + } + } + free_json(array); + } + free(utxostr); + } + if ( nonz != 0 ) + break; } printf("peers\n"); while ( 1 ) From aa694c6f09da14ef3b220dc6d1ad4bbbc9c980f1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:15:28 +0300 Subject: [PATCH 0704/2705] Test --- iguana/exchanges/LP_commands.c | 1 + iguana/exchanges/LP_network.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 65a6a6ace..d9ae10154 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -38,6 +38,7 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr,*pairstr; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; + printf("LP_command.(%s)\n",jprint(argjson,0)); if ( (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index c32ded7f4..bd6855e9d 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -115,6 +115,13 @@ char *nanomsg_tcpname(char *str,char *ipaddr,uint16_t port) int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) { int32_t sentbytes,len,i; struct nn_pollfd pfd; + if ( sock < 0 ) + { + printf("LP_send to illegal socket\n"); + if ( freeflag != 0 ) + free(msg); + return(-1); + } for (i=0; i<100; i++) { pfd.fd = sock; @@ -132,6 +139,8 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) usleep(1000); } printf("error LP_send\n"); + if ( freeflag != 0 ) + free(msg); return(-1); } From 323f473806ca6d2e5e68fdf5b540fe388d93a2a9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:17:19 +0300 Subject: [PATCH 0705/2705] Test --- iguana/exchanges/LP_commands.c | 1 + iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index d9ae10154..7dc7b3a18 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -39,6 +39,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ { char *method,*base,*rel,*retstr,*pairstr; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; printf("LP_command.(%s)\n",jprint(argjson,0)); + //LP_command.({"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"rel":"BTC","method":"price"}) if ( (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7777d1ad8..94d4af905 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -766,7 +766,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i reqjson = cJSON_CreateObject(); jaddbits256(reqjson,"txid",jbits256(item,"txid")); jaddnum(reqjson,"vout",jint(item,"vout")); - jaddstr(reqjson,"base",jstr(item,"base")); + jaddstr(reqjson,"base",jstr(item,"coin")); jaddstr(reqjson,"rel","BTC"); jaddstr(reqjson,"method","price"); //5.9.253.196:7779 [{"ipaddr":"5.9.253.196","port":7779,"profit":0.01064000,"coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}] From 0b68601ee620b715e54dfd90cf95ed3681adc7de Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:21:04 +0300 Subject: [PATCH 0706/2705] Test --- iguana/exchanges/LP_commands.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7dc7b3a18..2c1e8b78e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -38,13 +38,13 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr,*pairstr; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; - printf("LP_command.(%s)\n",jprint(argjson,0)); - //LP_command.({"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"rel":"BTC","method":"price"}) + //LP_command.({"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"base":"KMD","rel":"BTC","method":"price"}) if ( (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(txid,jint(argjson,"vout"))) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { + printf("LP_command.(%s)\n",jprint(argjson,0)); if ( time(NULL) > utxo->swappending ) utxo->swappending = 0; if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) @@ -77,8 +77,8 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ } retstr = jprint(retjson,1); LP_send(pubsock,retstr,1); - } - } + } else printf("null price\n"); + } else printf("swappending.%u pair.%d\n",utxo->swappending,utxo->pair); } else if ( strcmp(method,"connect") == 0 ) { From fb775092c228775c2f974bcc5f732970814fc156 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:29:41 +0300 Subject: [PATCH 0707/2705] Test --- iguana/exchanges/mm.c | 74 +++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 1ffef2e92..4f9d3e0b1 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -680,10 +680,43 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double return(n); } -void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double start_BASE,double start_REL,double profitmargin,double maxexposure,double ratioincr,char *exchange,char *name,char *base,char *rel) +double marketmaker_updateprice(char *name,char *base,char *rel,double theoretical,double *incrp) { static uint32_t counter; - cJSON *fiatjson; char *retstr; double bid,ask,start_DEXbase,start_DEXrel,USD_average=0.,DEX_base = 0.,DEX_rel = 0.,balance_base=0.,balance_rel=0.,mmbid,mmask,usdprice=0.,CMC_average=0.,aveprice,incr,pendingbids,pendingasks,buyvol,sellvol,bidincr,askincr,filledprice,avebid=0.,aveask=0.,val,changes[3],highbid=0.,lowask=0.,theoretical = 0.; uint32_t lasttime = 0; + cJSON *fiatjson; double USD_average=0.,usdprice=0.,CMC_average=0.,avebid=0.,aveask=0.,val,changes[3],highbid=0.,lowask=0.; + if ( (val= get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,name,base,rel,&USD_average)) != 0. ) + { + if ( theoretical == 0. ) + { + theoretical = val; + if ( *incrp > 2 ) + { + *incrp = (int32_t)*incrp; + *incrp += 0.777; + } + } else theoretical = (theoretical + val) * 0.5; + if ( (counter++ % 12) == 0 ) + { + if ( USD_average > SMALLVAL && CMC_average > SMALLVAL && theoretical > SMALLVAL ) + { + usdprice = USD_average * (theoretical / CMC_average); + printf("USD %.4f <- (%.6f * (%.8f / %.8f))\n",usdprice,USD_average,theoretical,CMC_average); + PAXPRICES[0] = usdprice; + if ( (fiatjson= yahoo_allcurrencies()) != 0 ) + { + marketmaker_fiatupdate(fiatjson); + free_json(fiatjson); + } + } + } + LP_priceupdate(base,rel,theoretical,avebid,aveask,highbid,lowask,PAXPRICES); + } + return(theoretical); +} + +void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double start_BASE,double start_REL,double profitmargin,double maxexposure,double ratioincr,char *exchange,char *name,char *base,char *rel) +{ + char *retstr; double bid,ask,start_DEXbase,start_DEXrel,DEX_base = 0.,DEX_rel = 0.,balance_base=0.,balance_rel=0.,mmbid,mmask,aveprice,incr,pendingbids,pendingasks,buyvol,sellvol,bidincr,askincr,filledprice,avebid=0.,aveask=0.,highbid=0.,lowask=0.,theoretical = 0.; uint32_t lasttime = 0; incr = maxexposure * ratioincr; buyvol = sellvol = 0.; start_DEXbase = dex_balance(base,baseaddr); @@ -692,34 +725,10 @@ void marketmaker(double minask,double maxbid,char *baseaddr,char *reladdr,double { if ( time(NULL) > lasttime+60 ) { - if ( (val= get_theoretical(&avebid,&aveask,&highbid,&lowask,&CMC_average,changes,name,base,rel,&USD_average)) != 0. ) + if ( (theoretical= marketmaker_updateprice(name,base,rel,theoretical,&incr)) != 0. ) { - if ( theoretical == 0. ) - { - theoretical = val; - incr /= theoretical; + if ( lasttime == 0 ) maxexposure /= theoretical; - if ( incr > 2 ) - { - incr = (int32_t)incr; - incr += 0.777; - } - } else theoretical = (theoretical + val) * 0.5; - if ( (counter++ % 12) == 0 ) - { - if ( USD_average > SMALLVAL && CMC_average > SMALLVAL && theoretical > SMALLVAL ) - { - usdprice = USD_average * (theoretical / CMC_average); - printf("USD %.4f <- (%.6f * (%.8f / %.8f))\n",usdprice,USD_average,theoretical,CMC_average); - PAXPRICES[0] = usdprice; - if ( (fiatjson= yahoo_allcurrencies()) != 0 ) - { - marketmaker_fiatupdate(fiatjson); - free_json(fiatjson); - } - } - } - LP_priceupdate(base,rel,theoretical,avebid,aveask,highbid,lowask,PAXPRICES); } if ( strcmp(exchange,"bittrex") == 0 ) { @@ -809,7 +818,7 @@ void LP_main(void *ptr) int main(int argc, const char * argv[]) { char *base,*rel,*name,*exchange,*apikey,*apisecret,*blocktrail,*retstr,*baseaddr,*reladdr,*passphrase; - double profitmargin,maxexposure,incrratio,start_rel,start_base,minask,maxbid; + double profitmargin,maxexposure,incrratio,start_rel,start_base,minask,maxbid,incr,theoretical = 0.; cJSON *retjson,*loginjson; int32_t i; if ( argc > 1 && (retjson= cJSON_Parse(argv[1])) != 0 ) { @@ -820,7 +829,12 @@ int main(int argc, const char * argv[]) printf("error launching LP_main (%s)\n",jprint(retjson,0)); exit(-1); } else printf("(%s) launched.(%s)\n",argv[1],passphrase); -getchar(); + incr = 100.; + while ( 1 ) + { + theoretical = marketmaker_updateprice("komodo","KMD","BTC",theoretical,&incr); + sleep(30); + } profitmargin = jdouble(retjson,"profitmargin"); minask = jdouble(retjson,"minask"); maxbid = jdouble(retjson,"maxbid"); From 34ca17cc9fdf131e6b3529546c7d4f99dd62bb43 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:37:21 +0300 Subject: [PATCH 0708/2705] Test --- iguana/exchanges/LP_commands.c | 11 ++++++----- iguana/exchanges/LP_include.h | 3 +++ iguana/exchanges/LP_nativeDEX.c | 3 +++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2c1e8b78e..a8f56afb0 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -64,13 +64,14 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ jaddbits256(retjson,"txid",txid); pubkey = LP_pubkey(LP_privkey(utxo->coinaddr)); jaddbits256(retjson,"srchash",pubkey); - txfee = LP_txfee(base); + if ( (txfee= LP_getestimatedrate(base)*LP_AVETXSIZE) < 10000 ) + txfee = 10000; jadd64bits(retjson,"txfee",txfee); jadd64bits(retjson,"satoshis",utxo->satoshis - txfee); jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee)); if ( strcmp(method,"request") == 0 ) { - utxo->swappending = (uint32_t)(time(NULL) + 60); + utxo->swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); utxo->otherpubkey = jbits256(argjson,"pubkey"); jaddstr(retjson,"result","reserved"); jaddnum(retjson,"pending",utxo->swappending); @@ -87,9 +88,9 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); - txfee = LP_txfee(base); + txfee = j64bits(argjson,"txfee"); satoshis = j64bits(argjson,"satoshis"); - desttxfee = LP_txfee(rel); + desttxfee = LP_getestimatedrate(rel) * LP_AVETXSIZE; desttxid = jbits256(argjson,"desttxid"); destvout = jint(argjson,"destvout"); timestamp = juint(argjson,"timestamp"); @@ -98,7 +99,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ pubkey = LP_pubkey(privkey); srchash = jbits256(argjson,"srchash"); value = j64bits(argjson,"destsatoshis"); - if ( timestamp == utxo->swappending-60 && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) + if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) { destsatoshis = value; if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index ed0f4fde2..7df5192aa 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -24,6 +24,9 @@ #define BASILISK_DISABLEWAITTX #define BASILISK_DISABLESENDTX +#define LP_RESERVETIME 60 +#define LP_AVETXSIZE 500 + #define BASILISK_DEFAULT_NUMCONFIRMS 5 #define DEX_SLEEP 3 #define BASILISK_DEXDURATION 300 diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 94d4af905..1a5cb048e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -771,6 +771,9 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i jaddstr(reqjson,"method","price"); //5.9.253.196:7779 [{"ipaddr":"5.9.253.196","port":7779,"profit":0.01064000,"coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}] + LP_send(peer->pushsock,jprint(reqjson,0),1); + jdelete(reqjson,"method"); + jaddstr(reqjson,"method","request"); LP_send(peer->pushsock,jprint(reqjson,1),1); nonz = 1; } From 85bb64e21908d76a0aa33bf3cdffc31255f767f6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:38:26 +0300 Subject: [PATCH 0709/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 486ffce72..a32b0232a 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -149,7 +149,7 @@ uint64_t LP_getestimatedrate(char *symbol) char buf[512],*retstr; uint64_t rate = 200; struct iguana_info *coin = LP_coinfind(symbol); if ( coin != 0 ) { - sprintf(buf,"[%d]",3); + sprintf(buf,"[\"%d\"]",3); if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"importaddress",buf)) != 0 ) { rate = atof(retstr); From bc93f83ea7900426e794b7952ac754681ad3bba5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:39:39 +0300 Subject: [PATCH 0710/2705] Test --- iguana/exchanges/LP_rpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index a32b0232a..ec25ae6d6 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -149,8 +149,8 @@ uint64_t LP_getestimatedrate(char *symbol) char buf[512],*retstr; uint64_t rate = 200; struct iguana_info *coin = LP_coinfind(symbol); if ( coin != 0 ) { - sprintf(buf,"[\"%d\"]",3); - if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"importaddress",buf)) != 0 ) + sprintf(buf,"[%d]",3); + if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"estimatefee",buf)) != 0 ) { rate = atof(retstr); printf("estimated rate %s -> %llu\n",retstr,(long long)rate); From 88895d2e6d22b50d325833b32091a1172fd92780 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:40:44 +0300 Subject: [PATCH 0711/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index ec25ae6d6..178c3ccf5 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -149,7 +149,7 @@ uint64_t LP_getestimatedrate(char *symbol) char buf[512],*retstr; uint64_t rate = 200; struct iguana_info *coin = LP_coinfind(symbol); if ( coin != 0 ) { - sprintf(buf,"[%d]",3); + sprintf(buf,"[%d]",13); if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"estimatefee",buf)) != 0 ) { rate = atof(retstr); From 3cd37204f8b641880832aa68da3dadc12c67cfeb Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:41:55 +0300 Subject: [PATCH 0712/2705] Test --- iguana/exchanges/LP_rpc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 178c3ccf5..3e523034c 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -152,8 +152,11 @@ uint64_t LP_getestimatedrate(char *symbol) sprintf(buf,"[%d]",13); if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"estimatefee",buf)) != 0 ) { - rate = atof(retstr); - printf("estimated rate %s -> %llu\n",retstr,(long long)rate); + if ( retstr[0] != '-' ) + { + rate = atof(retstr); + printf("estimated rate %s -> %llu\n",retstr,(long long)rate); + } free(retstr); } } @@ -164,7 +167,7 @@ uint64_t LP_txfee(char *symbol) { uint64_t txfee = 0; if ( strcmp(symbol,"BTC") != 0 ) - txfee = 50000; + txfee = 10000; return(txfee); } From 47f20b288ae013ef2686dcbfd5999a551a25597f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:50:56 +0300 Subject: [PATCH 0713/2705] Test --- iguana/exchanges/LP_commands.c | 6 +++--- iguana/exchanges/LP_nativeDEX.c | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a8f56afb0..a150ce32e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -94,12 +94,12 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ desttxid = jbits256(argjson,"desttxid"); destvout = jint(argjson,"destvout"); timestamp = juint(argjson,"timestamp"); - quotetime = juint(argjson,"quotetime"); privkey = LP_privkey(utxo->coinaddr); pubkey = LP_pubkey(privkey); srchash = jbits256(argjson,"srchash"); value = j64bits(argjson,"destsatoshis"); - if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) + quotetime = juint(argjson,"quotetime"); + //if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) { destsatoshis = value; if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) @@ -135,7 +135,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ nn_close(utxo->pair); utxo->pair = -1; } - } else printf("dest %.8f < required %.8f\n",dstr(value),dstr(price*(utxo->satoshis-txfee))); + } //else printf("dest %.8f < required %.8f\n",dstr(value),dstr(price*(utxo->satoshis-txfee))); } else printf("no price for %s/%s\n",base,rel); } else printf("utxo->pair.%d when connect came in (%s)\n",utxo->pair,jprint(argjson,0)); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1a5cb048e..cac96ca08 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -774,7 +774,12 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_send(peer->pushsock,jprint(reqjson,0),1); jdelete(reqjson,"method"); jaddstr(reqjson,"method","request"); - LP_send(peer->pushsock,jprint(reqjson,1),1); + LP_send(peer->pushsock,jprint(reqjson,0),1); + jdelete(reqjson,"method"); + jaddstr(reqjson,"method","connect"); + LP_send(peer->pushsock,jprint(reqjson,0),1); + + //SENT.({"base":"KMD","rel":"BTC","timestamp":1496076137,"price":0.00021791,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74","txfee":"100000","satoshis":"9999900000","destsatoshis":"2179101","result":"reserved","pending":1496076197} nonz = 1; } } From 3864cbf154a9355cd8341da1306de48f8ce90363 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:54:34 +0300 Subject: [PATCH 0714/2705] Test --- iguana/exchanges/LP_commands.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a150ce32e..3b193af49 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -37,7 +37,7 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel,*retstr,*pairstr; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; + char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; //LP_command.({"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"base":"KMD","rel":"BTC","method":"price"}) if ( (method= jstr(argjson,"method")) != 0 ) { @@ -102,9 +102,10 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ //if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) { destsatoshis = value; + nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) printf("error creating utxo->pair\n"); - else if ( (pairstr= jstr(argjson,"pair")) != 0 && nn_connect(utxo->pair,pairstr) >= 0 ) + else if ( nn_connect(utxo->pair,pairstr) >= 0 ) { desthash = jbits256(argjson,"desthash"); LP_requestinit(&R,srchash,desthash,base,satoshis,rel,destsatoshis,timestamp,quotetime,DEXselector); @@ -112,6 +113,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","connected"); + jaddstr(retjson,"pair",pairstr); jaddnum(retjson,"requestid",R.requestid); jaddnum(retjson,"quoteid",R.quoteid); retstr = jprint(retjson,1); From 17d6f615b8744d1042c2ac81056dd03bbe46d262 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:55:50 +0300 Subject: [PATCH 0715/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 3b193af49..891e99d78 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -109,7 +109,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ { desthash = jbits256(argjson,"desthash"); LP_requestinit(&R,srchash,desthash,base,satoshis,rel,destsatoshis,timestamp,quotetime,DEXselector); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) != 0 ) + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) == 0 ) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","connected"); From 429ccaf65bbfaf773cab4b1163cf59f8ee958bc3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 19:59:24 +0300 Subject: [PATCH 0716/2705] Test --- iguana/exchanges/LP_commands.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 891e99d78..29cd11dac 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -59,6 +59,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ retjson = cJSON_CreateObject(); jaddstr(retjson,"base",base); jaddstr(retjson,"rel",rel); + jaddstr(retjson,"address",utxo->coinaddr); jaddnum(retjson,"timestamp",time(NULL)); jaddnum(retjson,"price",price); jaddbits256(retjson,"txid",txid); @@ -131,9 +132,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ } else { - if ( pairstr != 0 ) - printf("printf error nn_connect to %s\n",pairstr); - else printf("(%s) missing pair\n",jprint(argjson,0)); + printf("printf error nn_connect to %s\n",pairstr); nn_close(utxo->pair); utxo->pair = -1; } From c876cdfcc19f5932291ce84cbcb71698ed6201b1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 20:02:57 +0300 Subject: [PATCH 0717/2705] Test --- iguana/exchanges/LP_bitcoin.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 79c78dc9c..db55e823d 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -26,7 +26,10 @@ bits256 LP_privkeyfind(uint8_t rmd160[20]) for (i=0; i no privkey\n"); + return(zero); } int32_t LP_privkeyadd(bits256 privkey,uint8_t rmd160[20]) @@ -37,6 +40,9 @@ int32_t LP_privkeyadd(bits256 privkey,uint8_t rmd160[20]) return(-bits256_cmp(privkey,tmpkey)); LP_privkeys[LP_numprivkeys].privkey = privkey; memcpy(LP_privkeys[LP_numprivkeys].rmd160,rmd160,20); + int32_t i; for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + char str[65]; printf(" -> privkey.(%s)\n",bits256_str(str,privkey)); LP_numprivkeys++; return(LP_numprivkeys); } From 331003c1c6bbf221f39ee274464dac003c2b97b7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 29 May 2017 20:04:02 +0300 Subject: [PATCH 0718/2705] Test --- iguana/exchanges/LP_bitcoin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index db55e823d..2b3a412f5 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -36,13 +36,13 @@ int32_t LP_privkeyadd(bits256 privkey,uint8_t rmd160[20]) { bits256 tmpkey; tmpkey = LP_privkeyfind(rmd160); - if ( bits256_nonz(privkey) != 0 ) + if ( bits256_nonz(tmpkey) != 0 ) return(-bits256_cmp(privkey,tmpkey)); LP_privkeys[LP_numprivkeys].privkey = privkey; memcpy(LP_privkeys[LP_numprivkeys].rmd160,rmd160,20); int32_t i; for (i=0; i<20; i++) printf("%02x",rmd160[i]); - char str[65]; printf(" -> privkey.(%s)\n",bits256_str(str,privkey)); + char str[65]; printf(" -> add privkey.(%s)\n",bits256_str(str,privkey)); LP_numprivkeys++; return(LP_numprivkeys); } From 49f9fcb3bf02ddc9dcc6f24dd27e5ac58bfeec87 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 10:30:03 +0300 Subject: [PATCH 0719/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- iguana/exchanges/LP_commands.c | 42 +++++++++++++++++++++++++ iguana/exchanges/LP_nativeDEX.c | 54 ++++++++------------------------- 3 files changed, 55 insertions(+), 43 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 2b3a412f5..1a4876b34 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -29,7 +29,7 @@ bits256 LP_privkeyfind(uint8_t rmd160[20]) for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" -> no privkey\n"); - return(zero); + return(zero); } int32_t LP_privkeyadd(bits256 privkey,uint8_t rmd160[20]) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 29cd11dac..298c9e52d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -35,6 +35,48 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } +struct LP_utxoinfo *LP_orderbook(char *base,char *rel) +{ + struct LP_peerinfo *peer,*tmp; char *utxostr; cJSON *array,*reqjson,*item; int32_t i,n; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,"KMD",10)) != 0 ) + { + printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); + if ( 0 && (array= cJSON_Parse(utxostr)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i<1; i++) + { + item = jitem(array,i); + reqjson = cJSON_CreateObject(); + jaddbits256(reqjson,"txid",jbits256(item,"txid")); + jaddnum(reqjson,"vout",jint(item,"vout")); + jaddstr(reqjson,"base",jstr(item,"coin")); + jaddstr(reqjson,"rel","BTC"); + jaddstr(reqjson,"method","price"); + //5.9.253.196:7779 [{"ipaddr":"5.9.253.196","port":7779,"profit":0.01064000,"coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}] + + LP_send(peer->pushsock,jprint(reqjson,0),1); + jdelete(reqjson,"method"); + jaddstr(reqjson,"method","request"); + LP_send(peer->pushsock,jprint(reqjson,0),1); + jdelete(reqjson,"method"); + jaddstr(reqjson,"method","connect"); + LP_send(peer->pushsock,jprint(reqjson,0),1); + + //SENT.({"base":"KMD","rel":"BTC","timestamp":1496076137,"price":0.00021791,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74","txfee":"100000","satoshis":"9999900000","destsatoshis":"2179101","result":"reserved","pending":1496076197} + } + } + free_json(array); + } + free(utxostr); + } + } + return(0); +} + void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index cac96ca08..5b220285f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -732,7 +732,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) { - char *retstr,*utxostr; int32_t i,n,len,recvsize,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson,*array,*reqjson,*item; + char *retstr; int32_t i,len,recvsize,counter,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson; for (i=amclient; i 25 ) @@ -746,51 +746,11 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); - LP_privkey_init(mypeer,pubsock,"BTC",passphrase,"",amclient); - LP_privkey_init(mypeer,pubsock,"KMD",passphrase,"",amclient); if ( amclient != 0 ) { nonz = 0; - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,"KMD",10)) != 0 ) - { - printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); - if ( (array= cJSON_Parse(utxostr)) != 0 ) - { - if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) - { - for (i=0; i<1; i++) - { - item = jitem(array,i); - reqjson = cJSON_CreateObject(); - jaddbits256(reqjson,"txid",jbits256(item,"txid")); - jaddnum(reqjson,"vout",jint(item,"vout")); - jaddstr(reqjson,"base",jstr(item,"coin")); - jaddstr(reqjson,"rel","BTC"); - jaddstr(reqjson,"method","price"); - //5.9.253.196:7779 [{"ipaddr":"5.9.253.196","port":7779,"profit":0.01064000,"coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}] - - LP_send(peer->pushsock,jprint(reqjson,0),1); - jdelete(reqjson,"method"); - jaddstr(reqjson,"method","request"); - LP_send(peer->pushsock,jprint(reqjson,0),1); - jdelete(reqjson,"method"); - jaddstr(reqjson,"method","connect"); - LP_send(peer->pushsock,jprint(reqjson,0),1); - - //SENT.({"base":"KMD","rel":"BTC","timestamp":1496076137,"price":0.00021791,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74","txfee":"100000","satoshis":"9999900000","destsatoshis":"2179101","result":"reserved","pending":1496076197} - nonz = 1; - } - } - free_json(array); - } - free(utxostr); - } - if ( nonz != 0 ) - break; - } printf("peers\n"); + LP_orderbook("KMD","BTC"); while ( 1 ) { sleep(1); @@ -798,9 +758,19 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } else { + counter = 0; while ( 1 ) { nonz = 0; + if ( (counter++ % 60) == 0 ) + { + LP_privkey_init(mypeer,pubsock,"BTC",passphrase,"",amclient); + LP_privkey_init(mypeer,pubsock,"KMD",passphrase,"",amclient); + LP_privkey_init(mypeer,pubsock,"LTC",passphrase,"",amclient); + LP_privkey_init(mypeer,pubsock,"USD",passphrase,"",amclient); + LP_privkey_init(mypeer,pubsock,"REVS",passphrase,"",amclient); + LP_privkey_init(mypeer,pubsock,"JUMBLR",passphrase,"",amclient); + } HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( peer->numpeers != mypeer->numpeers || (rand() % 10) == 0 ) From a0a0e1b978baec703674a5ba79742169c3c79a5a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:05:09 +0300 Subject: [PATCH 0720/2705] Test --- iguana/exchanges/LP_commands.c | 186 ++++++++++++++++++++++----- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_nativeDEX.c | 221 +++++++++++++++++++++++++------- iguana/exchanges/LP_prices.c | 2 + iguana/exchanges/mm.c | 11 +- 5 files changed, 342 insertions(+), 79 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 298c9e52d..77e8c3a71 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -35,46 +35,163 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } -struct LP_utxoinfo *LP_orderbook(char *base,char *rel) +double LP_pricequery(uint64_t *destsatoshisp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout) { - struct LP_peerinfo *peer,*tmp; char *utxostr; cJSON *array,*reqjson,*item; int32_t i,n; + cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,pushsock = -1; double price = 0.; + if ( ipaddr != 0 && port >= 1000 ) + { + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),port)) == 0 ) + peer = LP_addpeer(1,0,-1,ipaddr,port,port+1,port+2,0,0,0); + if ( peer != 0 ) + { + if ( (pushsock= peer->pushsock) >= 0 ) + { + reqjson = cJSON_CreateObject(); + jaddbits256(reqjson,"txid",txid); + jaddnum(reqjson,"vout",vout); + jaddstr(reqjson,"base",base); + jaddstr(reqjson,"rel",rel); + jaddstr(reqjson,"method","price"); + LP_send(pushsock,jprint(reqjson,1),1); + for (i=0; i<10; i++) + { + if ( (price= LP_pricecache(destsatoshisp,base,rel,txid,vout)) != 0. ) + break; + usleep(100000); + } + } else printf("no pushsock for peer.%s:%u\n",ipaddr,port); + } else printf("cant find/create peer.%s:%u\n",ipaddr,port); + } + return(price); +} + +/* + //5.9.253.196:7779 [{"ipaddr":"5.9.253.196","port":7779,"profit":0.01064000,"coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}] + + LP_send(peer->pushsock,jprint(reqjson,0),1); + jdelete(reqjson,"method"); + jaddstr(reqjson,"method","request"); + LP_send(peer->pushsock,jprint(reqjson,0),1); + jdelete(reqjson,"method"); + jaddstr(reqjson,"method","connect"); + LP_send(peer->pushsock,jprint(reqjson,0),1); + + //SENT.({"base":"KMD","rel":"BTC","timestamp":1496076137,"price":0.00021791,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74","txfee":"100000","satoshis":"9999900000","destsatoshis":"2179101","result":"reserved","pending":1496076197} +*/ +int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) +{ + if ( mysatoshis >= othersatoshis ) + return(0); + else return(-1); +} + +cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) +{ + struct LP_peerinfo *peer,*tmp; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase; uint64_t destsatoshis; + if ( (price= LP_price(base,myutxo->coin)) == .0 ) + return(0); + estimatedbase = myutxo->satoshis / price; + if ( estimatedbase <= 0 ) + return(0); + printf("%s -> %s price %.8f mysatoshis %llu estimated base %llu\n",base,myutxo->coin,price,(long long)myutxo->satoshis,(long long)estimatedbase); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,"KMD",10)) != 0 ) + if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); - if ( 0 && (array= cJSON_Parse(utxostr)) != 0 ) + if ( (array= cJSON_Parse(utxostr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { - for (i=0; i<1; i++) + retarray = cJSON_CreateArray(); + for (i=0; ipushsock,jprint(reqjson,0),1); - jdelete(reqjson,"method"); - jaddstr(reqjson,"method","request"); - LP_send(peer->pushsock,jprint(reqjson,0),1); - jdelete(reqjson,"method"); - jaddstr(reqjson,"method","connect"); - LP_send(peer->pushsock,jprint(reqjson,0),1); - - //SENT.({"base":"KMD","rel":"BTC","timestamp":1496076137,"price":0.00021791,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74","txfee":"100000","satoshis":"9999900000","destsatoshis":"2179101","result":"reserved","pending":1496076197} + safecopy(coinstr,jstr(item,"coin"),sizeof(coinstr)); + if ( strcmp(coinstr,base) == 0 && LP_sizematch(estimatedbase,j64bits(item,"satoshis")) == 0 ) + { + icopy = 0; + if ( (price= LP_pricecache(&destsatoshis,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) + { + if ( LP_sizematch(myutxo->satoshis,destsatoshis) == 0 ) + icopy = jduplicate(item); + } else icopy = jduplicate(item); + if ( icopy != 0 ) + { + jaddnum(icopy,"price",price); + jaddi(retarray,icopy); + } + } } } free_json(array); } free(utxostr); } + if ( retarray != 0 ) + break; + } + return(retarray); +} + +cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) +{ + int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; uint64_t destsatoshis[100]; + bestprice = 0.; + if ( (array= LP_tradecandidates(utxo,base)) != 0 ) + { + printf("%s %.8f -> (%s)\n",utxo->coin,dstr(utxo->satoshis),jprint(array,0)); + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + memset(prices,0,sizeof(prices)); + memset(destsatoshis,0,sizeof(destsatoshis)); + for (i=0; icoin,jbits256(item,"txid"),jint(item,"vout")); + if ( destsatoshis[i] != 0 && (double)j64bits(item,"satoshis")/destsatoshis[i] > price ) + price = (double)j64bits(item,"satoshis")/destsatoshis[i]; + } + if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) + bestprice = price; + } + if ( bestprice != 0. ) + { + bestmetric = 0.; + besti = -1; + for (i=0; i 0.9 ) + { + metric = destsatoshis[i] / metric * metric * metric; + if ( metric > bestmetric ) + { + besti = i; + bestmetric = metric; + } + } + } + } + if ( besti >= 0 ) + bestitem = jduplicate(jitem(array,besti)); + } + free_json(array); + } } - return(0); + return(bestitem); +} + +char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis) +{ + struct LP_cacheinfo *ptr; + if ( (ptr= LP_cacheadd(base,rel,txid,vout,price,satoshis)) != 0 ) + return(clonestr("{\"result\":\"updated\"}")); + else return(clonestr("{\"error\":\"nullptr\"}")); } void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) @@ -110,15 +227,18 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ if ( (txfee= LP_getestimatedrate(base)*LP_AVETXSIZE) < 10000 ) txfee = 10000; jadd64bits(retjson,"txfee",txfee); + if ( (desttxfee= LP_getestimatedrate(rel) * LP_AVETXSIZE) < 10000 ) + desttxfee = 10000; + jadd64bits(retjson,"desttxfee",desttxfee); jadd64bits(retjson,"satoshis",utxo->satoshis - txfee); - jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee)); + jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee) + desttxfee); if ( strcmp(method,"request") == 0 ) { utxo->swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); utxo->otherpubkey = jbits256(argjson,"pubkey"); - jaddstr(retjson,"result","reserved"); + jaddstr(retjson,"method","reserved"); jaddnum(retjson,"pending",utxo->swappending); - } + } else jaddstr(retjson,"method","quote"); retstr = jprint(retjson,1); LP_send(pubsock,retstr,1); } else printf("null price\n"); @@ -132,8 +252,8 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ { price *= (1. + profitmargin); txfee = j64bits(argjson,"txfee"); + desttxfee = j64bits(argjson,"desttxfee"); satoshis = j64bits(argjson,"satoshis"); - desttxfee = LP_getestimatedrate(rel) * LP_AVETXSIZE; desttxid = jbits256(argjson,"desttxid"); destvout = jint(argjson,"destvout"); timestamp = juint(argjson,"timestamp"); @@ -198,6 +318,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) { + amclient = 0; if ( (pushport= juint(argjson,"push")) == 0 ) pushport = argport + 1; if ( (subport= juint(argjson,"sub")) == 0 ) @@ -212,20 +333,21 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port peer->numutxos = othernumutxos; } //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); - } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); - amclient = 0; + } else LP_addpeer(amclient,LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); } else amclient = 1; } - if ( strcmp(method,"getpeers") == 0 ) + if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) + retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis")); + else if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"base")) != 0 ) retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"base"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 7df5192aa..3a01c34e0 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -26,6 +26,7 @@ #define LP_RESERVETIME 60 #define LP_AVETXSIZE 500 +#define LP_CACHEDURATION 60 #define BASILISK_DEFAULT_NUMCONFIRMS 5 #define DEX_SLEEP 3 diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5b220285f..d5fbf7f27 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -24,9 +24,12 @@ #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid +char *activecoins[] = { "BTC", "KMD", "LTC", "USD", "REVS", "JUMBLR" }; + char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; -portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex; +portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; int32_t LP_mypubsock = -1; +int32_t Client_connections; struct LP_peerinfo { @@ -52,6 +55,78 @@ struct LP_utxoinfo uint16_t port; } *LP_utxoinfos; +struct LP_cacheinfo +{ + UT_hash_handle hh; + uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(int32_t)]; + double price; + uint64_t satoshis,destsatoshis; + uint32_t timestamp; +} *LP_cacheinfos; + +int32_t LP_cachekey(uint8_t *key,char *base,char *rel,bits256 txid,int32_t vout) +{ + uint64_t basebits,relbits; int32_t offset = 0; + basebits = stringbits(base); + relbits = stringbits(rel); + memcpy(&key[offset],&basebits,sizeof(basebits)), offset += sizeof(basebits); + memcpy(&key[offset],&relbits,sizeof(relbits)), offset += sizeof(relbits); + memcpy(&key[offset],&txid,sizeof(txid)), offset += sizeof(txid); + memcpy(&key[offset],&vout,sizeof(vout)), offset += sizeof(vout); + return(offset); +} + +struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout) +{ + struct LP_cacheinfo *ptr=0; uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(vout)]; + if ( LP_cachekey(key,base,rel,txid,vout) == sizeof(key) ) + { + portable_mutex_lock(&LP_cachemutex); + HASH_FIND(hh,LP_cacheinfos,key,sizeof(key),ptr); + portable_mutex_unlock(&LP_cachemutex); + } else printf("LP_cachefind keysize mismatch?\n"); + if ( ptr->timestamp != 0 && ptr->timestamp < time(NULL)-LP_CACHEDURATION ) + { + printf("expire price %.8f\n",ptr->price); + ptr->price = 0.; + ptr->destsatoshis = 0; + ptr->timestamp = 0; + } + return(ptr); +} + +struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis) +{ + struct LP_cacheinfo *ptr=0; + if ( (ptr= LP_cachefind(base,rel,txid,vout)) == 0 ) + { + ptr = calloc(1,sizeof(*ptr)); + if ( LP_cachekey(ptr->key,base,rel,txid,vout) == sizeof(ptr->key) ) + { + portable_mutex_lock(&LP_cachemutex); + HASH_ADD(hh,LP_cacheinfos,key,sizeof(ptr->key),ptr); + portable_mutex_unlock(&LP_cachemutex); + } else printf("LP_cacheadd keysize mismatch?\n"); + } + ptr->price = price; + ptr->satoshis = satoshis; + ptr->destsatoshis = satoshis * price; + ptr->timestamp = (uint32_t)time(NULL); + printf("updated %s/%s %llu price %.8f\n",base,rel,(long long)satoshis,price); + return(ptr); +} + +double LP_pricecache(uint64_t *destsatoshisp,char *base,char *rel,bits256 txid,int32_t vout) +{ + struct LP_cacheinfo *ptr; + if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) + { + *destsatoshisp = ptr->destsatoshis; + return(ptr->price); + } else *destsatoshisp = 0; + return(0.); +} + struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) { struct LP_peerinfo *peer=0; uint64_t ip_port; @@ -88,7 +163,7 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) jaddstr(item,"ipaddr",utxo->ipaddr); jaddnum(item,"port",utxo->port); jaddnum(item,"profit",utxo->profitmargin); - jaddstr(item,"coin",utxo->coin); + jaddstr(item,"base",utxo->coin); jaddstr(item,"address",utxo->coinaddr); jaddstr(item,"script",utxo->spendscript); jaddbits256(item,"txid",utxo->txid); @@ -129,9 +204,9 @@ char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) return(jprint(utxosjson,1)); } -struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) +struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) { - uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; + uint32_t ipbits; int32_t pushsock,subsock,timeout,enabled; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) @@ -151,22 +226,32 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char peer = calloc(1,sizeof(*peer)); peer->pushsock = peer->subsock = pushsock = subsock = -1; strcpy(peer->ipaddr,ipaddr); - if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + if ( amclient == 0 ) + enabled = 1; + else enabled = (rand() % (1 << Client_connections)) == 0; + if ( enabled != 0 && pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { - if ( (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + timeout = 1000; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); + if ( nn_connect(peer->pushsock,pushaddr) >= 0 ) { - timeout = 1000; - nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - timeout = 1; - nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + printf("connected to push.(%s) %d\n",pushaddr,peer->pushsock); + peer->connected = (uint32_t)time(NULL); peer->pushsock = pushsock; - peer->subsock = subsock; - nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); - nanomsg_tcpname(subaddr,peer->ipaddr,subport); - printf("adding (%s and %s) %d %d\n",pushaddr,subaddr,peer->pushsock,peer->subsock); - if ( nn_connect(peer->pushsock,pushaddr) >= 0 && nn_connect(peer->subsock,subaddr) >= 0 ) - peer->connected = (uint32_t)time(NULL); + if ( enabled != 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + { + timeout = 1; + nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + nanomsg_tcpname(subaddr,peer->ipaddr,subport); + if ( nn_connect(peer->subsock,subaddr) >= 0 ) + { + peer->subsock = subsock; + printf("connected to sub.(%s) %d\n",subaddr,peer->subsock); + Client_connections += amclient; + } else nn_close(subsock); + } } else nn_close(pushsock); } peer->profitmargin = profitmargin; @@ -246,7 +331,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 return(utxo); } -int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; if ( (array= cJSON_Parse(retstr)) != 0 ) @@ -264,7 +349,7 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + peer = LP_addpeer(amclient,mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); if ( peer != 0 ) { peer->lasttime = now; @@ -282,6 +367,11 @@ int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer,*destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + if ( amclient != 0 ) + { + printf("LP_utxosparse not for clientside\n"); + return(-1); + } if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -297,11 +387,11 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + peer = LP_addpeer(amclient,mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"base"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } @@ -361,7 +451,7 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx return(issue_curl(url)); } -void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) +void LP_peersquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); @@ -371,7 +461,7 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr { //printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); - LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); + LP_peersparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); if ( mypeer != 0 ) { @@ -395,6 +485,11 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; + if ( amclient != 0 ) + { + printf("LP_utxosquery not for clientside\n"); + return; + } peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( (peer != 0 && peer->errors > 0) || mypeer == 0 ) return; @@ -630,7 +725,7 @@ struct iguana_info *LP_coinfind(char *symbol) if ( strcmp(symbol,"BTC") == 0 ) { cdata.txfee = 50000; - cdata.estimatedrate = 200; + cdata.estimatedrate = 300; cdata.p2shtype = 5; cdata.wiftype = 128; LP_userpass(cdata.userpass,symbol,"","bitcoin"); @@ -730,47 +825,80 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb return(total); } +void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphrase,int32_t amclient) +{ + int32_t i; + for (i=0; i 25 ) - continue; - LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer!=0?mypeer->ipaddr:"127.0.0.1",myport,profitmargin); + for (i=0; i 25 ) + continue; + LP_peersquery(amclient,mypeer,pubsock,default_LPnodes[i],myport,mypeer!=0?mypeer->ipaddr:"127.0.0.1",myport,profitmargin); + } + } + else + { + OS_randombytes((void *)&r,sizeof(r)); + for (j=0; jipaddr:"127.0.0.1",myport,profitmargin); + } } if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } - LP_coinfind("BTC"); LP_coinfind("LTC"); LP_coinfind("KMD"); - LP_coinfind("USD"); LP_coinfind("REVS"); LP_coinfind("JUMBLR"); + for (i=0; isubsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) + { + nonz++; + if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) + { + portable_mutex_lock(&LP_commandmutex); + if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypubport)) != 0 ) + { + printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + free(retstr); + } + portable_mutex_unlock(&LP_commandmutex); + free_json(argjson); + } else printf("error parsing.(%s)\n",(char *)ptr); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } + } + if ( nonz == 0 ) + sleep(n + 1); } } else { - counter = 0; while ( 1 ) { nonz = 0; if ( (counter++ % 60) == 0 ) - { - LP_privkey_init(mypeer,pubsock,"BTC",passphrase,"",amclient); - LP_privkey_init(mypeer,pubsock,"KMD",passphrase,"",amclient); - LP_privkey_init(mypeer,pubsock,"LTC",passphrase,"",amclient); - LP_privkey_init(mypeer,pubsock,"USD",passphrase,"",amclient); - LP_privkey_init(mypeer,pubsock,"REVS",passphrase,"",amclient); - LP_privkey_init(mypeer,pubsock,"JUMBLR",passphrase,"",amclient); - } + LP_privkey_updates(mypeer,pubsock,passphrase,amclient); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( peer->numpeers != mypeer->numpeers || (rand() % 10) == 0 ) @@ -778,7 +906,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( peer->numpeers != mypeer->numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) - LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); + LP_peersquery(amclient,mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); } if ( peer->numutxos != mypeer->numutxos ) { @@ -835,6 +963,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); portable_mutex_init(&LP_commandmutex); + portable_mutex_init(&LP_cachemutex); if ( amclient == 0 ) { if ( profitmargin == 0. || profitmargin == 0.01 ) @@ -875,7 +1004,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; - LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); + LP_mypeer = mypeer = LP_addpeer(amclient,mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 691325cc4..33bc6f897 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -20,6 +20,8 @@ double LP_kmdbtc; + + // very, very simple for now void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 4f9d3e0b1..34312e13a 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -819,7 +819,7 @@ int main(int argc, const char * argv[]) { char *base,*rel,*name,*exchange,*apikey,*apisecret,*blocktrail,*retstr,*baseaddr,*reladdr,*passphrase; double profitmargin,maxexposure,incrratio,start_rel,start_base,minask,maxbid,incr,theoretical = 0.; - cJSON *retjson,*loginjson; int32_t i; + cJSON *retjson,*loginjson,*matchjson; int32_t i; if ( argc > 1 && (retjson= cJSON_Parse(argv[1])) != 0 ) { if ( (passphrase= jstr(retjson,"passphrase")) == 0 ) @@ -834,6 +834,15 @@ int main(int argc, const char * argv[]) { theoretical = marketmaker_updateprice("komodo","KMD","BTC",theoretical,&incr); sleep(30); + if ( jint(retjson,"client") != 0 ) + { + struct LP_utxoinfo *utxo,*utmp; + HASH_ITER(hh,LP_utxoinfos,utxo,utmp) + { + if ( (matchjson= LP_bestprice(utxo,"KMD")) != 0 ) + printf("bestprice (%s)\n",jprint(matchjson,1)); + } + } } profitmargin = jdouble(retjson,"profitmargin"); minask = jdouble(retjson,"minask"); From fb64cba72678c90adcb140b5fea3d19f256dca73 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:06:52 +0300 Subject: [PATCH 0721/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d5fbf7f27..732e90bf6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -24,7 +24,7 @@ #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid -char *activecoins[] = { "BTC", "KMD", "LTC", "USD", "REVS", "JUMBLR" }; +char *activecoins[] = { "BTC", "KMD", };//"LTC", "USD", "REVS", "JUMBLR" }; char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; From 66ec96e0fac90f366aea68794fe8b6998a163e61 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:07:54 +0300 Subject: [PATCH 0722/2705] Test --- iguana/m_mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/m_mm b/iguana/m_mm index 2e310704b..2a2f6c130 100755 --- a/iguana/m_mm +++ b/iguana/m_mm @@ -1,2 +1,2 @@ cd secp256k1; ./m_unix; cd .. -gcc -o marketmaker -I../crypto777 exchanges/mm.c mini-gmp.c secp256k1.o ../agents/libcrypto777.a -lnanomsg -lcurl -lpthread -lm +gcc -g -o marketmaker -I../crypto777 exchanges/mm.c mini-gmp.c secp256k1.o ../agents/libcrypto777.a -lnanomsg -lcurl -lpthread -lm From af6046a918a84d2a5fbdc6ed5c8bc3e59f1f9882 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:12:34 +0300 Subject: [PATCH 0723/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 732e90bf6..dcdf2e3db 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -278,7 +278,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 struct LP_utxoinfo *utxo = 0; uint8_t key[sizeof(txid) + sizeof(vout)]; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) { - printf("malformed addutxo %d %d %d %d %d %d %d %d %d %d %d %d\n", coin == 0,coin[0] == 0,spendscript == 0,spendscript[0] == 0,coinaddr == 0,coinaddr[0] == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); + printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); return(0); } if ( (utxo= LP_utxofind(txid,vout)) != 0 ) From 3025bd5e38e8d2e170835f7a90d42aef89570d22 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:16:25 +0300 Subject: [PATCH 0724/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index dcdf2e3db..4ddfed183 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -85,7 +85,7 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout HASH_FIND(hh,LP_cacheinfos,key,sizeof(key),ptr); portable_mutex_unlock(&LP_cachemutex); } else printf("LP_cachefind keysize mismatch?\n"); - if ( ptr->timestamp != 0 && ptr->timestamp < time(NULL)-LP_CACHEDURATION ) + if ( ptr != 0 && ptr->timestamp != 0 && ptr->timestamp < time(NULL)-LP_CACHEDURATION ) { printf("expire price %.8f\n",ptr->price); ptr->price = 0.; From 2ba0fbe53543d86fdcbf140d4e586bff022826a8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:18:54 +0300 Subject: [PATCH 0725/2705] Test --- iguana/exchanges/LP_commands.c | 1 + iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 77e8c3a71..411a46f7b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -355,5 +355,6 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port return(retstr); retjson = cJSON_CreateObject(); jaddstr(retjson,"error","unrecognized command"); + printf("ERROR.(%s)\n",jprint(argjson,0)); return(clonestr(jprint(retjson,1))); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4ddfed183..956c35f60 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -391,7 +391,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"base"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } From 2be51f0f90b9856ee962b12eb41207a6d0254bb1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:21:56 +0300 Subject: [PATCH 0726/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 411a46f7b..9901e531a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -340,7 +340,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis")); else if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"base")) != 0 ) + else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); From 145ec12ab52b5e25f13d2904272102336e1e33ad Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:22:58 +0300 Subject: [PATCH 0727/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9901e531a..9610f6b0d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -329,7 +329,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port peer->numpeers = otherpeers; if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) { - printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer->numutxos); + printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer != 0 ? LP_mypeer->numutxos:0); peer->numutxos = othernumutxos; } //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); From 8416af8a29b43037448f94cb8b0c0bdd3f7abf24 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:30:41 +0300 Subject: [PATCH 0728/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9610f6b0d..8f35f0320 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -347,7 +347,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"base"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } From 982be563cfa89115b86bc024940216e2c117f2a8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:50:14 +0300 Subject: [PATCH 0729/2705] Test --- iguana/exchanges/LP_commands.c | 5 ++--- iguana/exchanges/LP_nativeDEX.c | 15 +++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 8f35f0320..cc447c97b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -313,12 +313,11 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port return(clonestr("{\"error\":\"need method in request\"}")); else { - amclient = 0; + amclient = (LP_mypeer == 0); if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) { - amclient = 0; if ( (pushport= juint(argjson,"push")) == 0 ) pushport = argport + 1; if ( (subport= juint(argjson,"sub")) == 0 ) @@ -334,7 +333,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); } else LP_addpeer(amclient,LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); - } else amclient = 1; + } } if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis")); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 956c35f60..38e864bb9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -301,20 +301,23 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 safecopy(utxo->coin,coin,sizeof(utxo->coin)); safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); - utxo->txid = txid; - utxo->vout = vout; - utxo->satoshis = satoshis; if ( amclient == 0 ) { + utxo->txid = txid; + utxo->vout = vout; + utxo->satoshis = satoshis; utxo->deposittxid = deposittxid; utxo->depositvout = depositvout; utxo->depositsatoshis = depositsatoshis; } else { - utxo->feetxid = deposittxid; - utxo->feevout = depositvout; - utxo->feesatoshis = depositsatoshis; + utxo->feetxid = txid; + utxo->feevout = vout; + utxo->feesatoshis = satoshis; + utxo->txid = deposittxid; + utxo->vout = depositvout; + utxo->satoshis = depositsatoshis; } memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); From 9f5d590c1b83fb3a7476fbb4b9e1e101995c8cdd Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:52:34 +0300 Subject: [PATCH 0730/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index cc447c97b..bac7fd116 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -107,7 +107,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) for (i=0; i Date: Tue, 30 May 2017 13:56:40 +0300 Subject: [PATCH 0731/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 38e864bb9..28144c8a4 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -350,6 +350,7 @@ int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs pushport = argport + 1; if ( (subport= juint(item,"sub")) == 0 ) subport = argport + 2; + printf("(%s)\n",jprint(item,0)); argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) peer = LP_addpeer(amclient,mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); @@ -466,7 +467,7 @@ void LP_peersquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock now = (uint32_t)time(NULL); LP_peersparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); - if ( mypeer != 0 ) + if ( amclient == 0 ) { HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -844,7 +845,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { if ( (rand() % 100) > 25 ) continue; - LP_peersquery(amclient,mypeer,pubsock,default_LPnodes[i],myport,mypeer!=0?mypeer->ipaddr:"127.0.0.1",myport,profitmargin); + LP_peersquery(amclient,mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport,profitmargin); } } else @@ -853,7 +854,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i for (j=0; jipaddr:"127.0.0.1",myport,profitmargin); + LP_peersquery(amclient,mypeer,pubsock,default_LPnodes[i],myport,"127.0.0.1",myport,profitmargin); } } if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) From d6be9dda264eaae6992515e58174a09f378b34bd Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 13:58:07 +0300 Subject: [PATCH 0732/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 28144c8a4..c4d99a2b2 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -229,7 +229,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 if ( amclient == 0 ) enabled = 1; else enabled = (rand() % (1 << Client_connections)) == 0; - if ( enabled != 0 && pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { timeout = 1000; nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); @@ -350,7 +350,6 @@ int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs pushport = argport + 1; if ( (subport= juint(item,"sub")) == 0 ) subport = argport + 2; - printf("(%s)\n",jprint(item,0)); argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) peer = LP_addpeer(amclient,mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); From 1a7bf25b20877a718129765b8f713be6d80c6afe Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:00:20 +0300 Subject: [PATCH 0733/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c4d99a2b2..c7b01e2f7 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -253,7 +253,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 } else nn_close(subsock); } } else nn_close(pushsock); - } + } else printf("%s pushport.%u subport.%u pushsock.%d\n",ipaddr,pushport,subport,pushsock); peer->profitmargin = profitmargin; peer->ipbits = ipbits; peer->port = port; From 63a7eb3b464803739442c3823c952f041c67b83b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:01:58 +0300 Subject: [PATCH 0734/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c7b01e2f7..9640866e2 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -211,7 +211,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) { - //printf("LPaddpeer %s\n",ipaddr); + printf("LPaddpeer %s\n",ipaddr); if ( (peer= LP_peerfind(ipbits,port)) != 0 ) { if ( peer->profitmargin == 0. ) @@ -269,7 +269,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); } - } + } else printf("LP_addpeer: checkip.(%s) vs (%s)\n",checkip,ipaddr); return(peer); } @@ -352,7 +352,10 @@ int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) + { peer = LP_addpeer(amclient,mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + printf("peer.%p after LP_addpeer\n",peer); + } else printf("have peer.%p\n",peer); if ( peer != 0 ) { peer->lasttime = now; From 9238021c86b62166402bfc08156a7544e2fc6059 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:03:03 +0300 Subject: [PATCH 0735/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9640866e2..725398a01 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -211,7 +211,6 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) { - printf("LPaddpeer %s\n",ipaddr); if ( (peer= LP_peerfind(ipbits,port)) != 0 ) { if ( peer->profitmargin == 0. ) @@ -223,6 +222,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 } else { + printf("LPaddpeer %s\n",ipaddr); peer = calloc(1,sizeof(*peer)); peer->pushsock = peer->subsock = pushsock = subsock = -1; strcpy(peer->ipaddr,ipaddr); From 10638942f93ccf10d78185a164ea0be202618882 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:05:01 +0300 Subject: [PATCH 0736/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 725398a01..917322782 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -232,6 +232,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { timeout = 1000; + printf("pushsock.%d\n",pushsock); nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); if ( nn_connect(peer->pushsock,pushaddr) >= 0 ) @@ -252,7 +253,12 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 Client_connections += amclient; } else nn_close(subsock); } - } else nn_close(pushsock); + } + else + { + nn_close(pushsock); + printf("error connecting to push.(%s)\n",pushaddr); + } } else printf("%s pushport.%u subport.%u pushsock.%d\n",ipaddr,pushport,subport,pushsock); peer->profitmargin = profitmargin; peer->ipbits = ipbits; From 81babac38da2975cce83713be2a620a962faf956 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:08:06 +0300 Subject: [PATCH 0737/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 917322782..d4292a695 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -235,9 +235,9 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("pushsock.%d\n",pushsock); nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); - if ( nn_connect(peer->pushsock,pushaddr) >= 0 ) + if ( nn_connect(pushsock,pushaddr) >= 0 ) { - printf("connected to push.(%s) %d\n",pushaddr,peer->pushsock); + printf("connected to push.(%s) %d\n",pushaddr,pushsock); peer->connected = (uint32_t)time(NULL); peer->pushsock = pushsock; if ( enabled != 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) @@ -246,7 +246,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); nanomsg_tcpname(subaddr,peer->ipaddr,subport); - if ( nn_connect(peer->subsock,subaddr) >= 0 ) + if ( nn_connect(subsock,subaddr) >= 0 ) { peer->subsock = subsock; printf("connected to sub.(%s) %d\n",subaddr,peer->subsock); From 02c36500907e5aca707418677234eca9a312a174 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:09:56 +0300 Subject: [PATCH 0738/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d4292a695..f684e1486 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -222,7 +222,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 } else { - printf("LPaddpeer %s\n",ipaddr); + //printf("LPaddpeer %s\n",ipaddr); peer = calloc(1,sizeof(*peer)); peer->pushsock = peer->subsock = pushsock = subsock = -1; strcpy(peer->ipaddr,ipaddr); @@ -232,7 +232,6 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { timeout = 1000; - printf("pushsock.%d\n",pushsock); nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); if ( nn_connect(pushsock,pushaddr) >= 0 ) @@ -360,8 +359,7 @@ int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) { peer = LP_addpeer(amclient,mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); - printf("peer.%p after LP_addpeer\n",peer); - } else printf("have peer.%p\n",peer); + } if ( peer != 0 ) { peer->lasttime = now; @@ -909,7 +907,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i while ( 1 ) { nonz = 0; - if ( (counter++ % 60) == 0 ) + if ( (counter++ % 300) == 0 ) LP_privkey_updates(mypeer,pubsock,passphrase,amclient); HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -962,7 +960,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i nn_freemsg(ptr), ptr = 0; } if ( nonz == 0 ) - sleep(mypeer->numpeers + 1); + sleep(1); } } } From 503216a9706b98424c3c41eab26f3a44816dc56b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:11:55 +0300 Subject: [PATCH 0739/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f684e1486..4af8b295d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -892,6 +892,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i free(retstr); } portable_mutex_unlock(&LP_commandmutex); + printf("subloop.(%s)\n",jprint(argjson,0)); free_json(argjson); } else printf("error parsing.(%s)\n",(char *)ptr); if ( ptr != 0 ) @@ -899,7 +900,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } } if ( nonz == 0 ) - sleep(n + 1); + sleep(1); } } else From 473aab4301ae9e46d2292dbd570e137a98312739 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:12:59 +0300 Subject: [PATCH 0740/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4af8b295d..54b5f17ed 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -228,7 +228,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 strcpy(peer->ipaddr,ipaddr); if ( amclient == 0 ) enabled = 1; - else enabled = (rand() % (1 << Client_connections)) == 0; + else enabled = 1;//(rand() % (1 << Client_connections)) == 0; if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { timeout = 1000; From a6a750862320ee0c27d8e90c28a68143e04d8c62 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:36:50 +0300 Subject: [PATCH 0741/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 54b5f17ed..a89289298 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -291,7 +291,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->deposittxid) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->depositvout || depositsatoshis != utxo->depositsatoshis || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) { utxo->errors++; - char str[65]; printf("error on subsequent utxo add.(%s)\n",bits256_str(str,txid)); + char str[65]; printf("error on subsequent utxo add.(%s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->deposittxid) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->depositvout,depositsatoshis != utxo->depositsatoshis,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); } else if ( profitmargin != 0. ) utxo->profitmargin = profitmargin; From 123ede953ec30f4138013600cb01ea3366cb8529 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:42:02 +0300 Subject: [PATCH 0742/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_nativeDEX.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 3a01c34e0..af134d939 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -38,6 +38,7 @@ #define BASILISK_KEYSIZE ((int32_t)(2*sizeof(bits256)+sizeof(uint32_t)*2)) extern char GLOBAL_DBDIR[]; +extern int32_t IAMCLIENT; void *bitcoin_ctx(); int32_t bitcoin_verify(void *ctx,uint8_t *sig,int32_t siglen,bits256 txhash2,uint8_t *pubkey,int32_t plen); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a89289298..055fea163 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -30,6 +30,7 @@ char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.25 portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; int32_t LP_mypubsock = -1; int32_t Client_connections; +int32_t IAMCLIENT = 0; struct LP_peerinfo { @@ -856,6 +857,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } else { + myport += 10; OS_randombytes((void *)&r,sizeof(r)); for (j=0; j Date: Tue, 30 May 2017 14:43:29 +0300 Subject: [PATCH 0743/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 055fea163..47da3f08c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -857,19 +857,20 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } else { - myport += 10; OS_randombytes((void *)&r,sizeof(r)); for (j=0; j Date: Tue, 30 May 2017 14:47:49 +0300 Subject: [PATCH 0744/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 47da3f08c..e4d0e9c81 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -329,7 +329,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); memcpy(utxo->key,key,sizeof(key)); portable_mutex_lock(&LP_utxomutex); - HASH_ADD(hh,LP_utxoinfos,key,sizeof(key),utxo); + HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(key),utxo); if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); From 756f5162fee13fa204acaf229aa02545ecb5d54e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:49:56 +0300 Subject: [PATCH 0745/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e4d0e9c81..df3f186dc 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -105,10 +105,10 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, if ( LP_cachekey(ptr->key,base,rel,txid,vout) == sizeof(ptr->key) ) { portable_mutex_lock(&LP_cachemutex); - HASH_ADD(hh,LP_cacheinfos,key,sizeof(ptr->key),ptr); + HASH_ADD_KEYPTR(hh,LP_cacheinfos,ptr->key,sizeof(ptr->key),ptr); portable_mutex_unlock(&LP_cachemutex); } else printf("LP_cacheadd keysize mismatch?\n"); - } + } else printf("CACHE hit!\n"); ptr->price = price; ptr->satoshis = satoshis; ptr->destsatoshis = satoshis * price; @@ -146,6 +146,8 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) portable_mutex_lock(&LP_utxomutex); HASH_FIND(hh,LP_utxoinfos,key,sizeof(key),utxo); portable_mutex_unlock(&LP_utxomutex); + if ( utxo != 0 ) + printf("found utxo\n"); return(utxo); } From 9e6986cf273ff0a162d461d14bc4440b5d81a8ca Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:52:40 +0300 Subject: [PATCH 0746/2705] Test --- iguana/exchanges/LP_commands.c | 3 +++ iguana/exchanges/LP_nativeDEX.c | 1 + 2 files changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bac7fd116..c4c7ce92c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -190,7 +190,10 @@ char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout, { struct LP_cacheinfo *ptr; if ( (ptr= LP_cacheadd(base,rel,txid,vout,price,satoshis)) != 0 ) + { +LP_cacheadd(base,rel,txid,vout,price,satoshis); return(clonestr("{\"result\":\"updated\"}")); + } else return(clonestr("{\"error\":\"nullptr\"}")); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index df3f186dc..d89d43726 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -405,6 +405,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs { txid = jbits256(item,"txid"); utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } From 52fbae0f201a04fe589218d921cfaa0ae5778f87 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:54:41 +0300 Subject: [PATCH 0747/2705] Test --- iguana/exchanges/LP_commands.c | 3 --- iguana/exchanges/LP_nativeDEX.c | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c4c7ce92c..bac7fd116 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -190,10 +190,7 @@ char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout, { struct LP_cacheinfo *ptr; if ( (ptr= LP_cacheadd(base,rel,txid,vout,price,satoshis)) != 0 ) - { -LP_cacheadd(base,rel,txid,vout,price,satoshis); return(clonestr("{\"result\":\"updated\"}")); - } else return(clonestr("{\"error\":\"nullptr\"}")); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d89d43726..e659471c6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -294,7 +294,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->deposittxid) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->depositvout || depositsatoshis != utxo->depositsatoshis || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) { utxo->errors++; - char str[65]; printf("error on subsequent utxo add.(%s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->deposittxid) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->depositvout,depositsatoshis != utxo->depositsatoshis,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); + char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->deposittxid) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->depositvout,depositsatoshis != utxo->depositsatoshis,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); } else if ( profitmargin != 0. ) utxo->profitmargin = profitmargin; @@ -405,7 +405,6 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs { txid = jbits256(item,"txid"); utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); - utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } From 62cdff4746614bfa67d8d99fa25b45edebc15160 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 14:58:16 +0300 Subject: [PATCH 0748/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e659471c6..7cdf69448 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -309,23 +309,20 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 safecopy(utxo->coin,coin,sizeof(utxo->coin)); safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); + utxo->txid = txid; + utxo->vout = vout; + utxo->satoshis = satoshis; if ( amclient == 0 ) { - utxo->txid = txid; - utxo->vout = vout; - utxo->satoshis = satoshis; utxo->deposittxid = deposittxid; utxo->depositvout = depositvout; utxo->depositsatoshis = depositsatoshis; } else { - utxo->feetxid = txid; - utxo->feevout = vout; - utxo->feesatoshis = satoshis; - utxo->txid = deposittxid; - utxo->vout = depositvout; - utxo->satoshis = depositsatoshis; + utxo->feetxid = deposittxid; + utxo->feevout = depositvout; + utxo->feesatoshis = depositsatoshis; } memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); @@ -825,7 +822,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb values[i] = 0, used++; if ( amclient == 0 ) LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); - else LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,"127.0.0.1",0,0); + else LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coinaddr,"127.0.0.1",0,0); total += value; } } From df5a754c030e903fcc50507ecf82e71796891ad4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 15:02:18 +0300 Subject: [PATCH 0749/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7cdf69448..bbfb43648 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -108,12 +108,13 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, HASH_ADD_KEYPTR(hh,LP_cacheinfos,ptr->key,sizeof(ptr->key),ptr); portable_mutex_unlock(&LP_cachemutex); } else printf("LP_cacheadd keysize mismatch?\n"); - } else printf("CACHE hit!\n"); + } //else printf("CACHE hit!\n"); + if ( price != ptr->price ) + printf("updated %s/%s %llu price %.8f\n",base,rel,(long long)satoshis,price); ptr->price = price; ptr->satoshis = satoshis; ptr->destsatoshis = satoshis * price; ptr->timestamp = (uint32_t)time(NULL); - printf("updated %s/%s %llu price %.8f\n",base,rel,(long long)satoshis,price); return(ptr); } @@ -146,8 +147,6 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) portable_mutex_lock(&LP_utxomutex); HASH_FIND(hh,LP_utxoinfos,key,sizeof(key),utxo); portable_mutex_unlock(&LP_utxomutex); - if ( utxo != 0 ) - printf("found utxo\n"); return(utxo); } @@ -312,18 +311,9 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 utxo->txid = txid; utxo->vout = vout; utxo->satoshis = satoshis; - if ( amclient == 0 ) - { - utxo->deposittxid = deposittxid; - utxo->depositvout = depositvout; - utxo->depositsatoshis = depositsatoshis; - } - else - { - utxo->feetxid = deposittxid; - utxo->feevout = depositvout; - utxo->feesatoshis = depositsatoshis; - } + utxo->deposittxid = deposittxid; + utxo->depositvout = depositvout; + utxo->depositsatoshis = depositsatoshis; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); memcpy(utxo->key,key,sizeof(key)); From 9cfc48cd44fbf2c515051c3c1af43b999489f8a9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 15:11:43 +0300 Subject: [PATCH 0750/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/LP_nativeDEX.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bac7fd116..79fb01c98 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -93,12 +93,12 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) estimatedbase = myutxo->satoshis / price; if ( estimatedbase <= 0 ) return(0); - printf("%s -> %s price %.8f mysatoshis %llu estimated base %llu\n",base,myutxo->coin,price,(long long)myutxo->satoshis,(long long)estimatedbase); + //printf("%s -> %s price %.8f mysatoshis %llu estimated base %llu\n",base,myutxo->coin,price,(long long)myutxo->satoshis,(long long)estimatedbase); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { - printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); + //printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); if ( (array= cJSON_Parse(utxostr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index bbfb43648..3f24c632c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -767,7 +767,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - printf("%s coinaddr.(%s) %d wif.(%s) passphrase.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); + //printf("%s coinaddr.(%s) %d wif.(%s) passphrase.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } @@ -783,9 +783,9 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb item = jitem(array,i); satoshis = SATOSHIDEN * jdouble(item,"amount"); values[i] = satoshis; - printf("%.8f ",dstr(satoshis)); + //printf("%.8f ",dstr(satoshis)); } - printf("array.%d\n",n); + //printf("array.%d\n",n); used = 0; while ( used < n ) { @@ -800,7 +800,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb if ( amclient != 0 ) targetval = (depositval / 777); else targetval = (depositval / 9) * 8; - printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); + //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) { item = jitem(array,i); @@ -867,7 +867,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i while ( 1 ) { nonz = n = 0; - if ( (counter++ % 60) == 0 ) + if ( (counter++ % 3600) == 0 ) LP_privkey_updates(mypeer,pubsock,passphrase,amclient); HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -880,11 +880,11 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypubport)) != 0 ) { - printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); - printf("subloop.(%s)\n",jprint(argjson,0)); + //printf("subloop.(%s)\n",jprint(argjson,0)); free_json(argjson); } else printf("error parsing.(%s)\n",(char *)ptr); if ( ptr != 0 ) From 32c88d96dc85834ed9f4dc81a348303cbb76afbf Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 15:17:55 +0300 Subject: [PATCH 0751/2705] Test --- iguana/exchanges/LP_bitcoin.c | 12 ++++++------ iguana/exchanges/LP_nativeDEX.c | 8 +++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 1a4876b34..319552e58 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -26,9 +26,9 @@ bits256 LP_privkeyfind(uint8_t rmd160[20]) for (i=0; i no privkey\n"); + //for (i=0; i<20; i++) + // printf("%02x",rmd160[i]); + //printf(" -> no privkey\n"); return(zero); } @@ -40,9 +40,9 @@ int32_t LP_privkeyadd(bits256 privkey,uint8_t rmd160[20]) return(-bits256_cmp(privkey,tmpkey)); LP_privkeys[LP_numprivkeys].privkey = privkey; memcpy(LP_privkeys[LP_numprivkeys].rmd160,rmd160,20); - int32_t i; for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - char str[65]; printf(" -> add privkey.(%s)\n",bits256_str(str,privkey)); + //int32_t i; for (i=0; i<20; i++) + // printf("%02x",rmd160[i]); + //char str[65]; printf(" -> add privkey.(%s)\n",bits256_str(str,privkey)); LP_numprivkeys++; return(LP_numprivkeys); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3f24c632c..1ed13badd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -834,6 +834,7 @@ void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphr void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) { + static uint16_t tmpport; char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; void *ptr; cJSON *argjson; if ( amclient == 0 ) { @@ -852,14 +853,15 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i i = (r + j) % (sizeof(default_LPnodes)/sizeof(*default_LPnodes)); LP_peersquery(amclient,mypeer,pubsock,default_LPnodes[i],myport,"127.0.0.1",myport,profitmargin); } - myport += 10; } - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) + if ( amclient != 0 ) + tmpport = myport + 10; + else tmpport = myport; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&tmpport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } - myport -= 10 * amclient; for (i=0; i Date: Tue, 30 May 2017 15:23:17 +0300 Subject: [PATCH 0752/2705] Test --- iguana/exchanges/LP_commands.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 79fb01c98..dc8ec5b77 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -337,13 +337,13 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis")); - else if ( strcmp(method,"getpeers") == 0 ) + else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); - else if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - else if ( strcmp(method,"notify") == 0 ) + else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( strcmp(method,"notifyutxo") == 0 ) + else if ( IAMCLIENT == 0 && strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); From 255e6cd4d834225ef9b807294896f75db59fa7c7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 15:25:45 +0300 Subject: [PATCH 0753/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1ed13badd..2a6b1f428 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -166,6 +166,7 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) jaddnum(item,"port",utxo->port); jaddnum(item,"profit",utxo->profitmargin); jaddstr(item,"base",utxo->coin); + jaddstr(item,"coin",utxo->coin); jaddstr(item,"address",utxo->coinaddr); jaddstr(item,"script",utxo->spendscript); jaddbits256(item,"txid",utxo->txid); From aecd6f7cd85283128126af9918887e3c3958bc83 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 15:31:50 +0300 Subject: [PATCH 0754/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 2a6b1f428..1956addb1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -418,7 +418,7 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); //printf("send.(%s)\n",url); retstr = issue_curl(url); - //printf("GETPEERS.(%s)\n",retstr); + printf("GETPEERS.(%s)\n",retstr); return(retstr); } From 66c011ff1c8f333b3c74aeb09c4907c6d80620a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 15:34:30 +0300 Subject: [PATCH 0755/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1956addb1..71fbcc1b6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -26,7 +26,7 @@ char *activecoins[] = { "BTC", "KMD", };//"LTC", "USD", "REVS", "JUMBLR" }; -char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; +char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; int32_t LP_mypubsock = -1; int32_t Client_connections; @@ -418,7 +418,7 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); //printf("send.(%s)\n",url); retstr = issue_curl(url); - printf("GETPEERS.(%s)\n",retstr); + //printf("GETPEERS.(%s)\n",retstr); return(retstr); } From 968420f4f5d0fbf231a7a0728afe485c50371e7a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 30 May 2017 15:41:35 +0300 Subject: [PATCH 0756/2705] Test --- iguana/exchanges/LP_commands.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index dc8ec5b77..27775d77b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -118,7 +118,8 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) } else icopy = jduplicate(item); if ( icopy != 0 ) { - jaddnum(icopy,"price",price); + if ( price != 0. ) + jaddnum(icopy,"price",price); jaddi(retarray,icopy); } } @@ -178,7 +179,12 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } } if ( besti >= 0 ) + { bestitem = jduplicate(jitem(array,besti)); + if ( jobj(bestitem,"price") != 0 ) + jdelete(bestitem,"price"); + jaddnum(bestitem,"price",prices[besti]); + } } free_json(array); } From 6591a7ae37190aa00cb5bd73528b845e152d9321 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 10:24:12 +0300 Subject: [PATCH 0757/2705] Test --- iguana/exchanges/LP_commands.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 27775d77b..43c7f3b2f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -141,22 +141,23 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) bestprice = 0.; if ( (array= LP_tradecandidates(utxo,base)) != 0 ) { - printf("%s %.8f -> (%s)\n",utxo->coin,dstr(utxo->satoshis),jprint(array,0)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); memset(destsatoshis,0,sizeof(destsatoshis)); + //BTC 0.02500000 -> ([{"ipaddr":"5.9.253.196","port":7779,"profit":0.01035000,"base":"KMD","coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}]) for (i=0; icoin,jbits256(item,"txid"),jint(item,"vout")); - if ( destsatoshis[i] != 0 && (double)j64bits(item,"satoshis")/destsatoshis[i] > price ) + if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) price = (double)j64bits(item,"satoshis")/destsatoshis[i]; } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; + printf("i.%d price %.8f bestprice %.8f\n",i,price,bestprice); } if ( bestprice != 0. ) { @@ -236,6 +237,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ if ( (desttxfee= LP_getestimatedrate(rel) * LP_AVETXSIZE) < 10000 ) desttxfee = 10000; jadd64bits(retjson,"desttxfee",desttxfee); + jadd64bits(retjson,"value",utxo->satoshis); jadd64bits(retjson,"satoshis",utxo->satoshis - txfee); jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee) + desttxfee); if ( strcmp(method,"request") == 0 ) From 2a9a4cca7ae2fcb3c3b93ea8bbb33b1692269db6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 10:33:22 +0300 Subject: [PATCH 0758/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 43c7f3b2f..f37c6ae76 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -157,7 +157,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; - printf("i.%d price %.8f bestprice %.8f\n",i,price,bestprice); + printf("i.%d price %.8f bestprice %.8f: (%s)\n",i,price,bestprice,jprint(item,0)); } if ( bestprice != 0. ) { From 8b01aa3518ff53c2e0b6874016fb36162d5f2a9a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 10:36:11 +0300 Subject: [PATCH 0759/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index f37c6ae76..503bb64ee 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -53,7 +53,7 @@ double LP_pricequery(uint64_t *destsatoshisp,char *ipaddr,uint16_t port,char *ba jaddstr(reqjson,"rel",rel); jaddstr(reqjson,"method","price"); LP_send(pushsock,jprint(reqjson,1),1); - for (i=0; i<10; i++) + for (i=0; i<30; i++) { if ( (price= LP_pricecache(destsatoshisp,base,rel,txid,vout)) != 0. ) break; From 28ce67314f97977a268de2c3c79ad325a5997d69 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 10:38:27 +0300 Subject: [PATCH 0760/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 71fbcc1b6..ea9d6f7cd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -124,6 +124,7 @@ double LP_pricecache(uint64_t *destsatoshisp,char *base,char *rel,bits256 txid,i if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) { *destsatoshisp = ptr->destsatoshis; + printf("found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } else *destsatoshisp = 0; return(0.); From cb50f0d7505872d0ec90251301801717c5170163 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 10:42:17 +0300 Subject: [PATCH 0761/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ea9d6f7cd..b63143f0e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -96,6 +96,22 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout return(ptr); } +double LP_pricecache(uint64_t *destsatoshisp,char *base,char *rel,bits256 txid,int32_t vout) +{ + struct LP_cacheinfo *ptr; + if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) + { + if ( destsatoshisp != 0 ) + *destsatoshisp = ptr->destsatoshis; + printf("found %s/%s %.8f\n",base,rel,ptr->price); + return(ptr->price); + } + else if ( destsatoshisp != 0 ) + *destsatoshisp = 0; + char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); + return(0.); +} + struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis) { struct LP_cacheinfo *ptr=0; @@ -115,21 +131,10 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, ptr->satoshis = satoshis; ptr->destsatoshis = satoshis * price; ptr->timestamp = (uint32_t)time(NULL); + LP_pricecache(0,base,rel,txid,vout); return(ptr); } -double LP_pricecache(uint64_t *destsatoshisp,char *base,char *rel,bits256 txid,int32_t vout) -{ - struct LP_cacheinfo *ptr; - if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) - { - *destsatoshisp = ptr->destsatoshis; - printf("found %s/%s %.8f\n",base,rel,ptr->price); - return(ptr->price); - } else *destsatoshisp = 0; - return(0.); -} - struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) { struct LP_peerinfo *peer=0; uint64_t ip_port; @@ -326,7 +331,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - printf("%s:%u LP_addutxo.(%.8f %.8f) numutxos.%d\n",ipaddr,port,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0); + printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0); } return(utxo); } From 8bd51e51a1b10d01ade34c7d21090b230b6bcdda Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 10:45:19 +0300 Subject: [PATCH 0762/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b63143f0e..968c7bfbc 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -121,12 +121,12 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, if ( LP_cachekey(ptr->key,base,rel,txid,vout) == sizeof(ptr->key) ) { portable_mutex_lock(&LP_cachemutex); - HASH_ADD_KEYPTR(hh,LP_cacheinfos,ptr->key,sizeof(ptr->key),ptr); + HASH_ADD(hh,LP_cacheinfos,key,sizeof(ptr->key),ptr); portable_mutex_unlock(&LP_cachemutex); } else printf("LP_cacheadd keysize mismatch?\n"); } //else printf("CACHE hit!\n"); - if ( price != ptr->price ) - printf("updated %s/%s %llu price %.8f\n",base,rel,(long long)satoshis,price); + char str[65]; if ( price != ptr->price ) + printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)satoshis,price); ptr->price = price; ptr->satoshis = satoshis; ptr->destsatoshis = satoshis * price; From 5b4ac8c57769c7e7020f9f3c78a728b379f189ba Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 10:50:45 +0300 Subject: [PATCH 0763/2705] Test --- iguana/exchanges/LP_commands.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 503bb64ee..592ad938b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -193,11 +193,17 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) return(bestitem); } -char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis) +char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee) { struct LP_cacheinfo *ptr; if ( (ptr= LP_cacheadd(base,rel,txid,vout,price,satoshis)) != 0 ) + { + //SENT.({"base":"KMD","rel":"BTC","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","timestamp":1496216835,"price":0.00021141,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"0bcabd875bfa724e26de5f35035ca3767c50b30960e23cbfcbd478cac9147412","txfee":"100000","desttxfee":"10000","value":"10000000000","satoshis":"9999900000","destsatoshis":"2124104","method":"quote"}) + ptr->txfee = txfee; + ptr->destsatoshis = destsatoshis; + ptr->desttxfee = desttxfee; return(clonestr("{\"result\":\"updated\"}")); + } else return(clonestr("{\"error\":\"nullptr\"}")); } @@ -229,6 +235,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ jaddnum(retjson,"timestamp",time(NULL)); jaddnum(retjson,"price",price); jaddbits256(retjson,"txid",txid); + jaddnum(retjson,"vout",utxo->vout); pubkey = LP_pubkey(LP_privkey(utxo->coinaddr)); jaddbits256(retjson,"srchash",pubkey); if ( (txfee= LP_getestimatedrate(base)*LP_AVETXSIZE) < 10000 ) @@ -344,7 +351,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } } if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) - retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis")); + retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee")); else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) From adac8c4d75cad0594dfb206d123a0032eefa44fb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 10:51:33 +0300 Subject: [PATCH 0764/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 968c7bfbc..834483132 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -61,7 +61,7 @@ struct LP_cacheinfo UT_hash_handle hh; uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(int32_t)]; double price; - uint64_t satoshis,destsatoshis; + uint64_t satoshis,txfee,destsatoshis,desttxfee; uint32_t timestamp; } *LP_cacheinfos; From 614c8bd979d11300b7c89ece75e900f1445eefaa Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:05:36 +0300 Subject: [PATCH 0765/2705] Test --- iguana/exchanges/LP_commands.c | 21 +++++++++++++-------- iguana/exchanges/LP_nativeDEX.c | 15 ++++++++++----- iguana/exchanges/mm.c | 2 +- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 592ad938b..7f8e9ac2d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -35,7 +35,7 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } -double LP_pricequery(uint64_t *destsatoshisp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout) +double LP_pricequery(uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,pushsock = -1; double price = 0.; if ( ipaddr != 0 && port >= 1000 ) @@ -53,11 +53,11 @@ double LP_pricequery(uint64_t *destsatoshisp,char *ipaddr,uint16_t port,char *ba jaddstr(reqjson,"rel",rel); jaddstr(reqjson,"method","price"); LP_send(pushsock,jprint(reqjson,1),1); - for (i=0; i<30; i++) + for (i=0; i<10; i++) { - if ( (price= LP_pricecache(destsatoshisp,base,rel,txid,vout)) != 0. ) + if ( (price= LP_pricecache(txfeep,destsatoshisp,desttxfeep,base,rel,txid,vout)) != 0. ) break; - usleep(100000); + usleep(250000); } } else printf("no pushsock for peer.%s:%u\n",ipaddr,port); } else printf("cant find/create peer.%s:%u\n",ipaddr,port); @@ -87,7 +87,7 @@ int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { - struct LP_peerinfo *peer,*tmp; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase; uint64_t destsatoshis; + struct LP_peerinfo *peer,*tmp; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase; uint64_t txfee,destsatoshis,desttxfee; if ( (price= LP_price(base,myutxo->coin)) == .0 ) return(0); estimatedbase = myutxo->satoshis / price; @@ -111,7 +111,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) if ( strcmp(coinstr,base) == 0 && LP_sizematch(estimatedbase,j64bits(item,"satoshis")) == 0 ) { icopy = 0; - if ( (price= LP_pricecache(&destsatoshis,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) + if ( (price= LP_pricecache(&txfee,&destsatoshis,&desttxfee,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) { if ( LP_sizematch(myutxo->satoshis,destsatoshis) == 0 ) icopy = jduplicate(item); @@ -137,21 +137,23 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { - int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; uint64_t destsatoshis[100]; + int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; bestprice = 0.; if ( (array= LP_tradecandidates(utxo,base)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); + memset(txfees,0,sizeof(txfees)); memset(destsatoshis,0,sizeof(destsatoshis)); + memset(desttxfees,0,sizeof(desttxfees)); //BTC 0.02500000 -> ([{"ipaddr":"5.9.253.196","port":7779,"profit":0.01035000,"base":"KMD","coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}]) for (i=0; icoin,jbits256(item,"txid"),jint(item,"vout")); + price = LP_pricequery(&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout")); if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) price = (double)j64bits(item,"satoshis")/destsatoshis[i]; } @@ -185,6 +187,9 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"price",prices[besti]); + jadd64bits(bestitem,"txfee",txfees[besti]); + jadd64bits(bestitem,"desttxfee",desttxfees[besti]); + jadd64bits(bestitem,"destsatoshis",destsatoshis[besti]); } } free_json(array); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 834483132..20ac4504a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -17,6 +17,8 @@ // LP_nativeDEX.c // marketmaker // +// jl777: fix price calcs based on specific txfees +// jl777: add change output #include #include "LP_include.h" @@ -90,25 +92,29 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout { printf("expire price %.8f\n",ptr->price); ptr->price = 0.; - ptr->destsatoshis = 0; + ptr->destsatoshis = ptr->txfee = ptr->desttxfee = 0; ptr->timestamp = 0; } return(ptr); } -double LP_pricecache(uint64_t *destsatoshisp,char *base,char *rel,bits256 txid,int32_t vout) +double LP_pricecache(uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *base,char *rel,bits256 txid,int32_t vout) { struct LP_cacheinfo *ptr; if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) { if ( destsatoshisp != 0 ) + { *destsatoshisp = ptr->destsatoshis; - printf("found %s/%s %.8f\n",base,rel,ptr->price); + *txfeep = ptr->txfee; + *desttxfeep = ptr->desttxfee; + } + //printf("found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } else if ( destsatoshisp != 0 ) *destsatoshisp = 0; - char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); + //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); return(0.); } @@ -131,7 +137,6 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, ptr->satoshis = satoshis; ptr->destsatoshis = satoshis * price; ptr->timestamp = (uint32_t)time(NULL); - LP_pricecache(0,base,rel,txid,vout); return(ptr); } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 34312e13a..08af48aac 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -840,7 +840,7 @@ int main(int argc, const char * argv[]) HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { if ( (matchjson= LP_bestprice(utxo,"KMD")) != 0 ) - printf("bestprice (%s)\n",jprint(matchjson,1)); + printf("bestprice %.8f txfees %.8f %.8f destsatoshis %.8f (%s)\n",jdouble(matchjson,"price"),dstr(j64bits(matchjson,"txfee")),dstr(j64bits(matchjson,"desttxfee")),dstr(j64bits(matchjson,"destsatoshis")),jprint(matchjson,1)); } } } From 139dcd5960d7069e1987c1375fdc215283d7177a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:09:53 +0300 Subject: [PATCH 0766/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 08af48aac..34312e13a 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -840,7 +840,7 @@ int main(int argc, const char * argv[]) HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { if ( (matchjson= LP_bestprice(utxo,"KMD")) != 0 ) - printf("bestprice %.8f txfees %.8f %.8f destsatoshis %.8f (%s)\n",jdouble(matchjson,"price"),dstr(j64bits(matchjson,"txfee")),dstr(j64bits(matchjson,"desttxfee")),dstr(j64bits(matchjson,"destsatoshis")),jprint(matchjson,1)); + printf("bestprice (%s)\n",jprint(matchjson,1)); } } } From adbb0513cdbaf5a551b682f0f4d8ffa363476dee Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:12:47 +0300 Subject: [PATCH 0767/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 3e523034c..57a5b6992 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -154,7 +154,7 @@ uint64_t LP_getestimatedrate(char *symbol) { if ( retstr[0] != '-' ) { - rate = atof(retstr); + rate = SATOSHIDEN * atof(retstr); printf("estimated rate %s -> %llu\n",retstr,(long long)rate); } free(retstr); From b26f751fc055ab52da6080623e31e29493e818bf Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:12:57 +0300 Subject: [PATCH 0768/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 57a5b6992..1f027728d 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -149,7 +149,7 @@ uint64_t LP_getestimatedrate(char *symbol) char buf[512],*retstr; uint64_t rate = 200; struct iguana_info *coin = LP_coinfind(symbol); if ( coin != 0 ) { - sprintf(buf,"[%d]",13); + sprintf(buf,"[%d]",3); if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"estimatefee",buf)) != 0 ) { if ( retstr[0] != '-' ) From 51e4c17acd4fbfe0005debba0718c96b146807e7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:17:00 +0300 Subject: [PATCH 0769/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_transaction.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index af134d939..a7e239f2b 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -176,7 +176,7 @@ struct basilisk_swapinfo struct iguana_info { - uint64_t txfee,estimatedrate; + uint64_t txfee; double estimatedrate; int32_t longestchain; uint8_t pubtype,p2shtype,isPoS,wiftype; char symbol[16],changeaddr[64],userpass[1024],serverport[128]; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 20ac4504a..4acbd7645 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -131,8 +131,8 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, portable_mutex_unlock(&LP_cachemutex); } else printf("LP_cacheadd keysize mismatch?\n"); } //else printf("CACHE hit!\n"); - char str[65]; if ( price != ptr->price ) - printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)satoshis,price); + //char str[65]; if ( price != ptr->price ) + // printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)satoshis,price); ptr->price = price; ptr->satoshis = satoshis; ptr->destsatoshis = satoshis * price; diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 1f027728d..a3131ac93 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -154,7 +154,7 @@ uint64_t LP_getestimatedrate(char *symbol) { if ( retstr[0] != '-' ) { - rate = SATOSHIDEN * atof(retstr); + rate = atof(retstr) / 1024.; printf("estimated rate %s -> %llu\n",retstr,(long long)rate); } free(retstr); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 74d820b5f..eea8a63fc 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -877,7 +877,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub if ( strcmp(coin->symbol,"BTC") != 0 ) return(retval); len = rawtx->I.datalen; - if ( coin->estimatedrate == 0 ) + if ( coin->estimatedrate == 0. ) coin->estimatedrate = LP_getestimatedrate(coin->symbol); newtxfee = coin->estimatedrate * len; printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); @@ -888,7 +888,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) { - char *signedtx; int64_t txfee,newtxfee=0,estimatedrate,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; + char *signedtx; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; double estimatedrate; timestamp = swap->I.started; if ( dest == &swap->aliceclaim ) locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; From 5d4c6ca0d7de830202b75dfb3e7c96b8fe319f69 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:28:47 +0300 Subject: [PATCH 0770/2705] Test --- iguana/exchanges/LP_commands.c | 23 +++++++++++++++-------- iguana/exchanges/LP_nativeDEX.c | 13 +++++++++++-- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7f8e9ac2d..eb9d3f16e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -35,7 +35,7 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } -double LP_pricequery(uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout) +double LP_pricequery(bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,pushsock = -1; double price = 0.; if ( ipaddr != 0 && port >= 1000 ) @@ -55,7 +55,7 @@ double LP_pricequery(uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfe LP_send(pushsock,jprint(reqjson,1),1); for (i=0; i<10; i++) { - if ( (price= LP_pricecache(txfeep,destsatoshisp,desttxfeep,base,rel,txid,vout)) != 0. ) + if ( (price= LP_pricecache(otherpubp,reservedp,txfeep,destsatoshisp,desttxfeep,base,rel,txid,vout)) != 0. ) break; usleep(250000); } @@ -87,7 +87,7 @@ int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { - struct LP_peerinfo *peer,*tmp; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase; uint64_t txfee,destsatoshis,desttxfee; + struct LP_peerinfo *peer,*tmp; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; bits256 otherpub; uint32_t reserved; int64_t estimatedbase; uint64_t txfee,destsatoshis,desttxfee; if ( (price= LP_price(base,myutxo->coin)) == .0 ) return(0); estimatedbase = myutxo->satoshis / price; @@ -111,7 +111,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) if ( strcmp(coinstr,base) == 0 && LP_sizematch(estimatedbase,j64bits(item,"satoshis")) == 0 ) { icopy = 0; - if ( (price= LP_pricecache(&txfee,&destsatoshis,&desttxfee,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) + if ( (price= LP_pricecache(&otherpub,&reserved,&txfee,&destsatoshis,&desttxfee,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) { if ( LP_sizematch(myutxo->satoshis,destsatoshis) == 0 ) icopy = jduplicate(item); @@ -137,13 +137,15 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { - int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; + int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; bits256 otherpubs[100]; uint32_t reserved[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; bestprice = 0.; if ( (array= LP_tradecandidates(utxo,base)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); + memset(reserved,0,sizeof(reserved)); + memset(otherpubs,0,sizeof(otherpubs)); memset(txfees,0,sizeof(txfees)); memset(destsatoshis,0,sizeof(destsatoshis)); memset(desttxfees,0,sizeof(desttxfees)); @@ -153,7 +155,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,i); if ( (price= jdouble(item,"price")) == 0. ) { - price = LP_pricequery(&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout")); + price = LP_pricequery(&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout")); if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) price = (double)j64bits(item,"satoshis")/destsatoshis[i]; } @@ -186,10 +188,12 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) bestitem = jduplicate(jitem(array,besti)); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); + jaddnum(bestitem,"reserved",reserved[besti]); jaddnum(bestitem,"price",prices[besti]); jadd64bits(bestitem,"txfee",txfees[besti]); jadd64bits(bestitem,"desttxfee",desttxfees[besti]); jadd64bits(bestitem,"destsatoshis",destsatoshis[besti]); + jaddbits256(bestitem,"otherpub",otherpubs[besti]); } } free_json(array); @@ -198,15 +202,17 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) return(bestitem); } -char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee) +char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 otherpub) { struct LP_cacheinfo *ptr; if ( (ptr= LP_cacheadd(base,rel,txid,vout,price,satoshis)) != 0 ) { //SENT.({"base":"KMD","rel":"BTC","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","timestamp":1496216835,"price":0.00021141,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"0bcabd875bfa724e26de5f35035ca3767c50b30960e23cbfcbd478cac9147412","txfee":"100000","desttxfee":"10000","value":"10000000000","satoshis":"9999900000","destsatoshis":"2124104","method":"quote"}) + ptr->reserved = reserved; ptr->txfee = txfee; ptr->destsatoshis = destsatoshis; ptr->desttxfee = desttxfee; + ptr->otherpub = otherpub; return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); @@ -256,6 +262,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ { utxo->swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); utxo->otherpubkey = jbits256(argjson,"pubkey"); + jaddbits256(retjson,"otherpubkey",utxo->otherpubkey); jaddstr(retjson,"method","reserved"); jaddnum(retjson,"pending",utxo->swappending); } else jaddstr(retjson,"method","quote"); @@ -356,7 +363,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } } if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) - retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee")); + retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee"),jbits256(argjson,"otherpubkey")); else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4acbd7645..240b0a8ca 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -61,10 +61,11 @@ struct LP_utxoinfo struct LP_cacheinfo { UT_hash_handle hh; + bits256 otherpub; uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(int32_t)]; double price; uint64_t satoshis,txfee,destsatoshis,desttxfee; - uint32_t timestamp; + uint32_t timestamp,reserved; } *LP_cacheinfos; int32_t LP_cachekey(uint8_t *key,char *base,char *rel,bits256 txid,int32_t vout) @@ -98,22 +99,30 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout return(ptr); } -double LP_pricecache(uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *base,char *rel,bits256 txid,int32_t vout) +double LP_pricecache(bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *base,char *rel,bits256 txid,int32_t vout) { struct LP_cacheinfo *ptr; if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) { if ( destsatoshisp != 0 ) { + *otherpubp = ptr->otherpub; *destsatoshisp = ptr->destsatoshis; *txfeep = ptr->txfee; *desttxfeep = ptr->desttxfee; + *reservedp = ptr->reserved; } //printf("found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } else if ( destsatoshisp != 0 ) + { + memset(otherpubp,0,sizeof(*otherpubp)); *destsatoshisp = 0; + *txfeep = 0; + *desttxfeep = 0; + *reservedp = 0; + } //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); return(0.); } From 005d96d4d23a8424a991044ab4a200eae890c97d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:29:34 +0300 Subject: [PATCH 0771/2705] Test --- iguana/exchanges/LP_rpc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index a3131ac93..f912440aa 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -144,9 +144,9 @@ int32_t LP_importaddress(char *symbol,char *address) return(1); } -uint64_t LP_getestimatedrate(char *symbol) +double LP_getestimatedrate(char *symbol) { - char buf[512],*retstr; uint64_t rate = 200; struct iguana_info *coin = LP_coinfind(symbol); + char buf[512],*retstr; double rate = 200; struct iguana_info *coin = LP_coinfind(symbol); if ( coin != 0 ) { sprintf(buf,"[%d]",3); @@ -155,7 +155,7 @@ uint64_t LP_getestimatedrate(char *symbol) if ( retstr[0] != '-' ) { rate = atof(retstr) / 1024.; - printf("estimated rate %s -> %llu\n",retstr,(long long)rate); + printf("estimated rate %s -> %.8f\n",retstr,rate); } free(retstr); } From 371375141d66d0cb4c82506a74cc675464a70c2e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:40:29 +0300 Subject: [PATCH 0772/2705] Test --- iguana/exchanges/LP_commands.c | 24 +++++++++++++++++++----- iguana/exchanges/LP_nativeDEX.c | 10 +++++++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index eb9d3f16e..236fa8675 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -35,9 +35,9 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } -double LP_pricequery(bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout) +double LP_pricequery(bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub) { - cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,pushsock = -1; double price = 0.; + cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; if ( ipaddr != 0 && port >= 1000 ) { if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),port)) == 0 ) @@ -51,12 +51,22 @@ double LP_pricequery(bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uin jaddnum(reqjson,"vout",vout); jaddstr(reqjson,"base",base); jaddstr(reqjson,"rel",rel); - jaddstr(reqjson,"method","price"); + if ( bits256_nonz(mypub) == 0 ) + jaddstr(reqjson,"method","price"); + else + { + flag = 1; + jaddstr(reqjson,"method","request"); + jaddbits256(reqjson,"mypub",mypub); + } LP_send(pushsock,jprint(reqjson,1),1); for (i=0; i<10; i++) { if ( (price= LP_pricecache(otherpubp,reservedp,txfeep,destsatoshisp,desttxfeep,base,rel,txid,vout)) != 0. ) - break; + { + if ( flag == 0 || bits256_nonz(*otherpubp) != 0 ) + break; + } usleep(250000); } } else printf("no pushsock for peer.%s:%u\n",ipaddr,port); @@ -137,6 +147,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { + static bits256 zero; int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; bits256 otherpubs[100]; uint32_t reserved[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; bestprice = 0.; if ( (array= LP_tradecandidates(utxo,base)) != 0 ) @@ -155,7 +166,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,i); if ( (price= jdouble(item,"price")) == 0. ) { - price = LP_pricequery(&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout")); + price = LP_pricequery(&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero); if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) price = (double)j64bits(item,"satoshis")/destsatoshis[i]; } @@ -186,6 +197,9 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) if ( besti >= 0 ) { bestitem = jduplicate(jitem(array,besti)); + i = besti; + item = bestitem; + price = LP_pricequery(&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),myutxo->pubkey); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"reserved",reserved[besti]); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 240b0a8ca..b970f4dce 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -48,7 +48,7 @@ struct LP_peerinfo struct LP_utxoinfo { UT_hash_handle hh; - bits256 txid,deposittxid,feetxid,otherpubkey; + bits256 txid,deposittxid,feetxid,otherpubkey,mypub; void *swap; uint64_t satoshis,depositsatoshis,feesatoshis; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; @@ -775,7 +775,7 @@ struct iguana_info *LP_coinfind(char *symbol) uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t amclient) { - char coinaddr[64],*script; cJSON *array,*item,*retjson; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + char coinaddr[64],*script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) { printf("cant add privkey for %s, coin not active\n",symbol); @@ -833,7 +833,11 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb values[i] = 0, used++; if ( amclient == 0 ) LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); - else LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coinaddr,"127.0.0.1",0,0); + else + { + if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coinaddr,"127.0.0.1",0,0)) != 0 ) + utxo->mypub = curve25519(privkey,curve25519_basepoint9()); + } total += value; } } From 9f159a1c43a0689382645749f88f48316ddffee6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:41:28 +0300 Subject: [PATCH 0773/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 236fa8675..98a9e938a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -199,7 +199,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) bestitem = jduplicate(jitem(array,besti)); i = besti; item = bestitem; - price = LP_pricequery(&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),myutxo->pubkey); + price = LP_pricequery(&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"reserved",reserved[besti]); From 93ddd65c94084f8641cf6d8940e339275168897f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:42:58 +0300 Subject: [PATCH 0774/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 98a9e938a..7039cbfa8 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -275,7 +275,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ if ( strcmp(method,"request") == 0 ) { utxo->swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); - utxo->otherpubkey = jbits256(argjson,"pubkey"); + utxo->otherpubkey = jbits256(argjson,"mypub"); jaddbits256(retjson,"otherpubkey",utxo->otherpubkey); jaddstr(retjson,"method","reserved"); jaddnum(retjson,"pending",utxo->swappending); From 700f42ee7e67ca90e9145c6f13378886a1ba1df9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 11:46:12 +0300 Subject: [PATCH 0775/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7039cbfa8..c61238235 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -172,7 +172,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; - printf("i.%d price %.8f bestprice %.8f: (%s)\n",i,price,bestprice,jprint(item,0)); + //printf("i.%d price %.8f bestprice %.8f: (%s)\n",i,price,bestprice,jprint(item,0)); } if ( bestprice != 0. ) { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b970f4dce..01a19cf07 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -980,7 +980,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i nn_freemsg(ptr), ptr = 0; } if ( nonz == 0 ) - sleep(1); + usleep(50000); } } } From e9af28aa079d764aac22660744c006dc5b089854 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 13:35:59 +0300 Subject: [PATCH 0776/2705] Test --- iguana/exchanges/LP_commands.c | 16 +++++++++------- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c61238235..c802b249a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -35,7 +35,7 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } -double LP_pricequery(bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub) +double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; if ( ipaddr != 0 && port >= 1000 ) @@ -51,14 +51,12 @@ double LP_pricequery(bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uin jaddnum(reqjson,"vout",vout); jaddstr(reqjson,"base",base); jaddstr(reqjson,"rel",rel); - if ( bits256_nonz(mypub) == 0 ) - jaddstr(reqjson,"method","price"); - else + if ( bits256_nonz(mypub) != 0 ) { flag = 1; - jaddstr(reqjson,"method","request"); jaddbits256(reqjson,"mypub",mypub); } + jaddstr(reqjson,"method",method); LP_send(pushsock,jprint(reqjson,1),1); for (i=0; i<10; i++) { @@ -166,7 +164,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,i); if ( (price= jdouble(item,"price")) == 0. ) { - price = LP_pricequery(&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero); + price = LP_query("price",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero); if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) price = (double)j64bits(item,"satoshis")/destsatoshis[i]; } @@ -199,7 +197,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) bestitem = jduplicate(jitem(array,besti)); i = besti; item = bestitem; - price = LP_pricequery(&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub); + price = LP_query("request",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"reserved",reserved[besti]); @@ -208,6 +206,10 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) jadd64bits(bestitem,"desttxfee",desttxfees[besti]); jadd64bits(bestitem,"destsatoshis",destsatoshis[besti]); jaddbits256(bestitem,"otherpub",otherpubs[besti]); + if ( LP_price(base,utxo->coin) > 0.975*price ) + { + price = LP_query("connect",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub); + } } } free_json(array); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 01a19cf07..d072833fd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -436,7 +436,7 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por { char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - //printf("send.(%s)\n",url); + printf("send.(%s)\n",url); retstr = issue_curl(url); //printf("GETPEERS.(%s)\n",retstr); return(retstr); From 9286f78fdd6d1b65ff57b5bdda9988e340c9dc2b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 13:37:26 +0300 Subject: [PATCH 0777/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d072833fd..81a16abf9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -436,7 +436,7 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por { char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - printf("send.(%s)\n",url); + //printf("send.(%s)\n",url); retstr = issue_curl(url); //printf("GETPEERS.(%s)\n",retstr); return(retstr); @@ -446,6 +446,7 @@ char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn, { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); + printf("getutxos.(%s)\n",url); return(issue_curl(url)); } From c9a2dc8626518783591e6808631420e227b74942 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 13:39:29 +0300 Subject: [PATCH 0778/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 81a16abf9..972f1829d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -446,7 +446,6 @@ char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn, { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); - printf("getutxos.(%s)\n",url); return(issue_curl(url)); } @@ -454,6 +453,7 @@ char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); + printf("getutxos.(%s)\n",url); return(issue_curl(url)); } From 76e37735d5e3676633ca88f0a63e0c3747c0b9de Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 13:46:22 +0300 Subject: [PATCH 0779/2705] Test --- iguana/exchanges/LP_commands.c | 2 ++ iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_prices.c | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c802b249a..cde261c53 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -380,6 +380,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee"),jbits256(argjson,"otherpubkey")); + else if ( IAMCLIENT == 0 && strcmp(method,"getprice") == 0 ) + retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 972f1829d..d06aaad8b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -453,7 +453,7 @@ char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); - printf("getutxos.(%s)\n",url); + //printf("getutxos.(%s)\n",url); return(issue_curl(url)); } diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 33bc6f897..3804bc029 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -41,3 +41,24 @@ double LP_price(char *base,char *rel) } return(0.); } + +char *LP_pricestr(char *base,char *rel) +{ + double price = 0.; cJSON *retjson; + if ( base != 0 && base[0] != 0 && rel != 0 && rel[0] != 0 ) + price = LP_price(base,rel); + if ( price != 0. ) + { + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","success"); + jaddnum(retjson,"price",price); + return(jprint(retjson,1)); + } else return(clonestr("{\"error\":\"cant find baserel pair\"}")); +} + + + + + + + From 29aaa66d452341715390c0692f5022f856c2afbf Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 13:47:58 +0300 Subject: [PATCH 0780/2705] Test --- iguana/exchanges/LP_prices.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 3804bc029..4d1fff738 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -51,6 +51,8 @@ char *LP_pricestr(char *base,char *rel) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); + jaddstr(retjson,"base",base); + jaddstr(retjson,"rel",rel); jaddnum(retjson,"price",price); return(jprint(retjson,1)); } else return(clonestr("{\"error\":\"cant find baserel pair\"}")); From 1d7ff64c9c9cd04a51273c9b71baec95c78acfd3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 14:01:43 +0300 Subject: [PATCH 0781/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index cde261c53..3a03be77d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -30,8 +30,8 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch rp->DEXselector = DEXselector; safecopy(rp->src,src,sizeof(rp->src)); safecopy(rp->dest,dest,sizeof(rp->dest)); - rp->quoteid = basilisk_quoteid(rp); rp->requestid = basilisk_requestid(rp); + rp->quoteid = basilisk_quoteid(rp); return(rp); } From 1b18065238f01be01a5a9caa53cbd3d40c405997 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 14:05:55 +0300 Subject: [PATCH 0782/2705] Test --- iguana/exchanges/LP_swap.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 2a1d96bef..fe2df8a7c 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -177,6 +177,14 @@ void basilisk_swap_finished(struct basilisk_swap *swap) swap->nummessages = 0; } +uint32_t basilisk_quoteid(struct basilisk_request *rp) +{ + struct basilisk_request R; + R = *rp; + R.unused = R.requestid = R.quoteid = R.DEXselector = 0; + return(calc_crc32(0,(void *)&R,sizeof(R))); +} + uint32_t basilisk_requestid(struct basilisk_request *rp) { struct basilisk_request R; @@ -184,25 +192,17 @@ uint32_t basilisk_requestid(struct basilisk_request *rp) R.requestid = R.quoteid = R.quotetime = R.DEXselector = 0; R.destamount = R.unused = 0; memset(R.desthash.bytes,0,sizeof(R.desthash.bytes)); - if ( 0 ) + if ( 1 ) { int32_t i; for (i=0; i %s %.8f %s crc.%u\n",R.timestamp,R.requestid,R.quoteid,R.src,dstr(R.srcamount),bits256_str(str,R.srchash),R.dest,dstr(R.destamount),bits256_str(str2,R.desthash),calc_crc32(0,(void *)&R,sizeof(R))); + char str[65],str2[65]; printf("B REQUESTID: t.%u r.%u q.%u %s %.8f %s -> %s %.8f %s crc.%u q%u\n",R.timestamp,R.requestid,R.quoteid,R.src,dstr(R.srcamount),bits256_str(str,R.srchash),R.dest,dstr(R.destamount),bits256_str(str2,R.desthash),calc_crc32(0,(void *)&R,sizeof(R)),basilisk_quoteid(&R)); } return(calc_crc32(0,(void *)&R,sizeof(R))); } -uint32_t basilisk_quoteid(struct basilisk_request *rp) -{ - struct basilisk_request R; - R = *rp; - R.requestid = R.quoteid = R.unused = R.DEXselector = 0; - return(calc_crc32(0,(void *)&R,sizeof(R))); -} - int32_t LP_pubkeys_data(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t i,datalen = 0; From d2a991f5ec624de1acaab275c32f74785ad54954 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 19:01:35 +0300 Subject: [PATCH 0783/2705] Test --- iguana/exchanges/LP_commands.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 3a03be77d..7d34bfe5d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -318,7 +318,22 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) == 0 ) { retjson = cJSON_CreateObject(); - jaddstr(retjson,"result","connected"); + jaddstr(retjson,"base",base); + jaddstr(retjson,"rel",rel); + jaddstr(retjson,"address",utxo->coinaddr); + jaddnum(retjson,"timestamp",timestamp); + jaddnum(retjson,"quotetime",quotetime); + jaddnum(retjson,"price",price); + jaddbits256(retjson,"txid",txid); + jaddnum(retjson,"vout",utxo->vout); + pubkey = LP_pubkey(LP_privkey(utxo->coinaddr)); + jaddbits256(retjson,"srchash",pubkey); + jadd64bits(retjson,"txfee",txfee); + jadd64bits(retjson,"desttxfee",desttxfee); + jadd64bits(retjson,"value",utxo->satoshis); + jadd64bits(retjson,"satoshis",utxo->satoshis - txfee); + jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee) + desttxfee); + jaddstr(retjson,"method","connected"); jaddstr(retjson,"pair",pairstr); jaddnum(retjson,"requestid",R.requestid); jaddnum(retjson,"quoteid",R.quoteid); @@ -380,6 +395,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee"),jbits256(argjson,"otherpubkey")); + else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) + retstr = jprint(argjson,0); else if ( IAMCLIENT == 0 && strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) From cc367abf4dcd605ae9df991578dbd67571e737a3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 19:12:52 +0300 Subject: [PATCH 0784/2705] Test --- iguana/exchanges/LP_commands.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7d34bfe5d..a914f0f46 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -35,7 +35,7 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } -double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub) +double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub,cJSON *argitem) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; if ( ipaddr != 0 && port >= 1000 ) @@ -55,6 +55,13 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx { flag = 1; jaddbits256(reqjson,"mypub",mypub); + if ( argitem != 0 ) + { + jadd64bits(reqjson,"satoshis",j64bits(argitem,"satoshis")); + jadd64bits(reqjson,"txfee",j64bits(argitem,"txfee")); + jadd64bits(reqjson,"desttxfee",j64bits(argitem,"desttxfee")); + jadd64bits(reqjson,"destsatoshis",j64bits(argitem,"destsatoshis")); + } } jaddstr(reqjson,"method",method); LP_send(pushsock,jprint(reqjson,1),1); @@ -164,7 +171,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,i); if ( (price= jdouble(item,"price")) == 0. ) { - price = LP_query("price",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero); + price = LP_query("price",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero,0); if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) price = (double)j64bits(item,"satoshis")/destsatoshis[i]; } @@ -192,12 +199,12 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } } } - if ( besti >= 0 ) + if ( besti >= 0 && bits256_cmp(utxo->mypub,otherpubs[besti]) == 0 ) { bestitem = jduplicate(jitem(array,besti)); i = besti; item = bestitem; - price = LP_query("request",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub); + price = LP_query("request",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,0); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"reserved",reserved[besti]); @@ -208,7 +215,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) jaddbits256(bestitem,"otherpub",otherpubs[besti]); if ( LP_price(base,utxo->coin) > 0.975*price ) { - price = LP_query("connect",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub); + price = LP_query("connect",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,item); } } } From 8c6aaa81eb65413769e284cf492043874c696fa0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 19:16:09 +0300 Subject: [PATCH 0785/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a914f0f46..1bc50c150 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -199,7 +199,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } } } - if ( besti >= 0 && bits256_cmp(utxo->mypub,otherpubs[besti]) == 0 ) + if ( besti >= 0 )//&& bits256_cmp(utxo->mypub,otherpubs[besti]) == 0 ) { bestitem = jduplicate(jitem(array,besti)); i = besti; From bf1aa24b309c6d39871d5963a2927b50f5e57dc2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 19:18:31 +0300 Subject: [PATCH 0786/2705] Test --- iguana/exchanges/LP_commands.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 1bc50c150..ff4c4f85a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -403,7 +403,10 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee"),jbits256(argjson,"otherpubkey")); else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) + { retstr = jprint(argjson,0); + printf("got connected! (%s)\n",retstr); + } else if ( IAMCLIENT == 0 && strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) From e0b3c1eed11de3463c33046ca2033593361decd4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 19:21:39 +0300 Subject: [PATCH 0787/2705] Test --- iguana/exchanges/LP_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index ff4c4f85a..616e5ddd2 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -400,6 +400,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } else LP_addpeer(amclient,LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); } } + printf("CMD.(%s)\n",jprint(argjson,0)); if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee"),jbits256(argjson,"otherpubkey")); else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) From 5e6e8424f140dfeb08d9e55b57dcf513e2d2d607 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 19:24:03 +0300 Subject: [PATCH 0788/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 616e5ddd2..c34c69a85 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -65,7 +65,7 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx } jaddstr(reqjson,"method",method); LP_send(pushsock,jprint(reqjson,1),1); - for (i=0; i<10; i++) + for (i=0; i<100; i++) { if ( (price= LP_pricecache(otherpubp,reservedp,txfeep,destsatoshisp,desttxfeep,base,rel,txid,vout)) != 0. ) { From a5eaae009075c465c447e43c8e9ec4f874aa3bb3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 19:58:12 +0300 Subject: [PATCH 0789/2705] Test --- iguana/exchanges/LP_commands.c | 8 ++++++-- iguana/exchanges/LP_nativeDEX.c | 9 ++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c34c69a85..4406189db 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -241,9 +241,9 @@ char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout, else return(clonestr("{\"error\":\"nullptr\"}")); } -void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) +int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; + char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,retval = -1,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; //LP_command.({"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"base":"KMD","rel":"BTC","method":"price"}) if ( (method= jstr(argjson,"method")) != 0 ) { @@ -255,6 +255,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ utxo->swappending = 0; if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) { + retval = 1; if ( utxo->swappending == 0 && utxo->pair < 0 ) { if ( utxo->pair >= 0 ) @@ -283,6 +284,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee) + desttxfee); if ( strcmp(method,"request") == 0 ) { + retval |= 2; utxo->swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); utxo->otherpubkey = jbits256(argjson,"mypub"); jaddbits256(retjson,"otherpubkey",utxo->otherpubkey); @@ -296,6 +298,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ } else if ( strcmp(method,"connect") == 0 ) { + retval = 4; if ( utxo->pair < 0 ) { if ( (price= LP_price(base,rel)) != 0. ) @@ -369,6 +372,7 @@ void LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_ } } } + return(retval); } char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d06aaad8b..a444540fa 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -973,7 +973,14 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { len = (int32_t)strlen((char *)ptr) + 1; portable_mutex_lock(&LP_commandmutex); - LP_command(mypeer,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin); + if ( LP_command(mypeer,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) == 0 ) + { + if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypubport)) != 0 ) + { + printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + free(retstr); + } + } portable_mutex_unlock(&LP_commandmutex); free_json(argjson); } From 68228f80eb3b52912a08d39e371cc66e8656b172 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 20:49:35 +0300 Subject: [PATCH 0790/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 4406189db..e45d792d6 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -256,9 +256,9 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) { retval = 1; - if ( utxo->swappending == 0 && utxo->pair < 0 ) + if ( utxo->swappending == 0 ) { - if ( utxo->pair >= 0 ) + if ( strcmp(method,"request") == 0 && utxo->pair >= 0 ) nn_close(utxo->pair), utxo->pair = -1; if ( (price= LP_price(base,rel)) != 0. ) { From eb2d06d9da03e937f45b2a5060d9eec28d214aa9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 21:47:02 +0300 Subject: [PATCH 0791/2705] Test --- iguana/exchanges/LP_commands.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index e45d792d6..0d4928eb4 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -54,7 +54,7 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx if ( bits256_nonz(mypub) != 0 ) { flag = 1; - jaddbits256(reqjson,"mypub",mypub); + jaddbits256(reqjson,"otherpub",mypub); if ( argitem != 0 ) { jadd64bits(reqjson,"satoshis",j64bits(argitem,"satoshis")); @@ -65,7 +65,7 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx } jaddstr(reqjson,"method",method); LP_send(pushsock,jprint(reqjson,1),1); - for (i=0; i<100; i++) + for (i=0; i<30; i++) { if ( (price= LP_pricecache(otherpubp,reservedp,txfeep,destsatoshisp,desttxfeep,base,rel,txid,vout)) != 0. ) { @@ -244,7 +244,6 @@ char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout, int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,retval = -1,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; - //LP_command.({"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"base":"KMD","rel":"BTC","method":"price"}) if ( (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); @@ -286,8 +285,8 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin { retval |= 2; utxo->swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); - utxo->otherpubkey = jbits256(argjson,"mypub"); - jaddbits256(retjson,"otherpubkey",utxo->otherpubkey); + utxo->otherpubkey = jbits256(argjson,"otherpub"); + jaddbits256(retjson,"otherpub",utxo->otherpubkey); jaddstr(retjson,"method","reserved"); jaddnum(retjson,"pending",utxo->swappending); } else jaddstr(retjson,"method","quote"); @@ -301,6 +300,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin retval = 4; if ( utxo->pair < 0 ) { + //LP_command.({"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"base":"KMD","rel":"BTC","mypub":"3b8f71015d644aaa4c9cceeee289b9a50dc9ec7fafab861c4d5872a8e3844466","satoshis":"0","txfee":"100000","desttxfee":"10000","destsatoshis":"2163363","method":"connect"}) if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); @@ -311,8 +311,8 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin destvout = jint(argjson,"destvout"); timestamp = juint(argjson,"timestamp"); privkey = LP_privkey(utxo->coinaddr); - pubkey = LP_pubkey(privkey); - srchash = jbits256(argjson,"srchash"); + srchash = LP_pubkey(privkey); + jaddbits256(argjson,"srchash",srchash); value = j64bits(argjson,"destsatoshis"); quotetime = juint(argjson,"quotetime"); //if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) @@ -323,7 +323,8 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin printf("error creating utxo->pair\n"); else if ( nn_connect(utxo->pair,pairstr) >= 0 ) { - desthash = jbits256(argjson,"desthash"); + desthash = jbits256(argjson,"otherpub"); + char str[65],str2[65]; printf("(%s) -> %s %s %s %.8f %s %.8f %u %u %d\n",jprint(argjson,0),bits256_str(str,srchash),bits256_str(str2,desthash),base,dstr(satoshis),rel,dstr(destsatoshis),timestamp,quotetime,DEXselector); LP_requestinit(&R,srchash,desthash,base,satoshis,rel,destsatoshis,timestamp,quotetime,DEXselector); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) == 0 ) { @@ -406,7 +407,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } printf("CMD.(%s)\n",jprint(argjson,0)); if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) - retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee"),jbits256(argjson,"otherpubkey")); + retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee"),jbits256(argjson,"otherpub")); else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) { retstr = jprint(argjson,0); From 0a17042d06b01433f94ee4309356579bdb382580 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 21:54:45 +0300 Subject: [PATCH 0792/2705] Test --- iguana/exchanges/LP_commands.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 0d4928eb4..9ff6fff5e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -57,6 +57,9 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx jaddbits256(reqjson,"otherpub",mypub); if ( argitem != 0 ) { + printf("ARGITEM.(%s)\n",jprint(argitem,0)); + jaddnum(reqjson,"timestamp",j64bits(argitem,"timestamp")); + jaddnum(reqjson,"quotetime",j64bits(argitem,"quotetime")); jadd64bits(reqjson,"satoshis",j64bits(argitem,"satoshis")); jadd64bits(reqjson,"txfee",j64bits(argitem,"txfee")); jadd64bits(reqjson,"desttxfee",j64bits(argitem,"desttxfee")); @@ -173,7 +176,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { price = LP_query("price",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero,0); if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) - price = (double)j64bits(item,"satoshis")/destsatoshis[i]; + price = (double)j64bits(item,"value")/destsatoshis[i]; } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; From 6219964c7cb188a3fbfe9fa078f29caea036ed8f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 22:01:11 +0300 Subject: [PATCH 0793/2705] Test --- iguana/exchanges/LP_commands.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9ff6fff5e..25a09714e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -20,6 +20,7 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srchash,bits256 desthash,char *src,uint64_t srcsatoshis,char *dest,uint64_t destsatoshis,uint32_t timestamp,uint32_t quotetime,int32_t DEXselector) { + struct basilisk_request R; memset(rp,0,sizeof(*rp)); rp->srchash = srchash; rp->desthash = desthash; @@ -30,7 +31,9 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch rp->DEXselector = DEXselector; safecopy(rp->src,src,sizeof(rp->src)); safecopy(rp->dest,dest,sizeof(rp->dest)); + R = *rp; rp->requestid = basilisk_requestid(rp); + *rp = R; rp->quoteid = basilisk_quoteid(rp); return(rp); } @@ -59,8 +62,8 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx { printf("ARGITEM.(%s)\n",jprint(argitem,0)); jaddnum(reqjson,"timestamp",j64bits(argitem,"timestamp")); - jaddnum(reqjson,"quotetime",j64bits(argitem,"quotetime")); - jadd64bits(reqjson,"satoshis",j64bits(argitem,"satoshis")); + jaddnum(reqjson,"quotetime",time(NULL)); + jadd64bits(reqjson,"satoshis",j64bits(argitem,"value")-j64bits(argitem,"txfee")); jadd64bits(reqjson,"txfee",j64bits(argitem,"txfee")); jadd64bits(reqjson,"desttxfee",j64bits(argitem,"desttxfee")); jadd64bits(reqjson,"destsatoshis",j64bits(argitem,"destsatoshis")); From dbce54481394febf36a7f9877cc3d7dd17a870a5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 22:05:40 +0300 Subject: [PATCH 0794/2705] Test --- iguana/exchanges/LP_commands.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 25a09714e..c7598222c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -159,7 +159,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { static bits256 zero; - int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; bits256 otherpubs[100]; uint32_t reserved[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; + int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; bits256 otherpubs[100]; uint32_t reserved[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; quoteinfo struct bestprice = 0.; if ( (array= LP_tradecandidates(utxo,base)) != 0 ) { @@ -177,6 +177,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,i); if ( (price= jdouble(item,"price")) == 0. ) { + horrible, pass in quoteinfo, utxo price = LP_query("price",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero,0); if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) price = (double)j64bits(item,"value")/destsatoshis[i]; @@ -221,6 +222,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) jaddbits256(bestitem,"otherpub",otherpubs[besti]); if ( LP_price(base,utxo->coin) > 0.975*price ) { + the same, cleanup price = LP_query("connect",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,item); } } @@ -268,6 +270,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); + horror show retjson = cJSON_CreateObject(); jaddstr(retjson,"base",base); jaddstr(retjson,"rel",rel); @@ -321,7 +324,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin jaddbits256(argjson,"srchash",srchash); value = j64bits(argjson,"destsatoshis"); quotetime = juint(argjson,"quotetime"); - //if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) + if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) { destsatoshis = value; nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); @@ -373,7 +376,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin nn_close(utxo->pair); utxo->pair = -1; } - } //else printf("dest %.8f < required %.8f\n",dstr(value),dstr(price*(utxo->satoshis-txfee))); + } else printf("dest %.8f < required %.8f\n",dstr(value),dstr(price*(utxo->satoshis-txfee))); } else printf("no price for %s/%s\n",base,rel); } else printf("utxo->pair.%d when connect came in (%s)\n",utxo->pair,jprint(argjson,0)); } From dc11d5c77bde52434b7a4d6b5248a087b2d28518 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 31 May 2017 22:06:58 +0300 Subject: [PATCH 0795/2705] Test --- iguana/exchanges/LP_commands.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c7598222c..96e9a9c1f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -159,7 +159,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { static bits256 zero; - int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; bits256 otherpubs[100]; uint32_t reserved[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; quoteinfo struct + int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; bits256 otherpubs[100]; uint32_t reserved[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; //quoteinfo struct bestprice = 0.; if ( (array= LP_tradecandidates(utxo,base)) != 0 ) { @@ -177,7 +177,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,i); if ( (price= jdouble(item,"price")) == 0. ) { - horrible, pass in quoteinfo, utxo +// horrible, pass in quoteinfo, utxo price = LP_query("price",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero,0); if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) price = (double)j64bits(item,"value")/destsatoshis[i]; @@ -222,7 +222,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) jaddbits256(bestitem,"otherpub",otherpubs[besti]); if ( LP_price(base,utxo->coin) > 0.975*price ) { - the same, cleanup +// the same, cleanup price = LP_query("connect",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,item); } } @@ -270,7 +270,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); - horror show +// horror show retjson = cJSON_CreateObject(); jaddstr(retjson,"base",base); jaddstr(retjson,"rel",rel); @@ -317,11 +317,12 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin desttxfee = j64bits(argjson,"desttxfee"); satoshis = j64bits(argjson,"satoshis"); desttxid = jbits256(argjson,"desttxid"); + srchash = jbits256(argjson,"srchash"); destvout = jint(argjson,"destvout"); timestamp = juint(argjson,"timestamp"); privkey = LP_privkey(utxo->coinaddr); - srchash = LP_pubkey(privkey); - jaddbits256(argjson,"srchash",srchash); + pubkey = LP_pubkey(privkey); + jaddbits256(argjson,"srchash",pubkey); value = j64bits(argjson,"destsatoshis"); quotetime = juint(argjson,"quotetime"); if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) From d7955ef7794c1c3dc7945f3c4f9a3b46b984c1c6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 07:43:31 +0300 Subject: [PATCH 0796/2705] Test --- iguana/exchanges/LP_commands.c | 266 +++++++++++++++++++------------- iguana/exchanges/LP_nativeDEX.c | 67 ++++---- 2 files changed, 192 insertions(+), 141 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 96e9a9c1f..60f201cc0 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -38,9 +38,10 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } -double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub,cJSON *argitem) +double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub,cJSON *argitem) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; + memset(qp,0,sizeof(*qp)); if ( ipaddr != 0 && port >= 1000 ) { if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),port)) == 0 ) @@ -57,7 +58,7 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx if ( bits256_nonz(mypub) != 0 ) { flag = 1; - jaddbits256(reqjson,"otherpub",mypub); + jaddbits256(reqjson,"desthash",mypub); if ( argitem != 0 ) { printf("ARGITEM.(%s)\n",jprint(argitem,0)); @@ -73,9 +74,9 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx LP_send(pushsock,jprint(reqjson,1),1); for (i=0; i<30; i++) { - if ( (price= LP_pricecache(otherpubp,reservedp,txfeep,destsatoshisp,desttxfeep,base,rel,txid,vout)) != 0. ) + if ( (price= LP_pricecache(qp,base,rel,txid,vout)) != 0. ) { - if ( flag == 0 || bits256_nonz(*otherpubp) != 0 ) + if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) break; } usleep(250000); @@ -86,19 +87,6 @@ double LP_query(char *method,bits256 *otherpubp,uint32_t *reservedp,uint64_t *tx return(price); } -/* - //5.9.253.196:7779 [{"ipaddr":"5.9.253.196","port":7779,"profit":0.01064000,"coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}] - - LP_send(peer->pushsock,jprint(reqjson,0),1); - jdelete(reqjson,"method"); - jaddstr(reqjson,"method","request"); - LP_send(peer->pushsock,jprint(reqjson,0),1); - jdelete(reqjson,"method"); - jaddstr(reqjson,"method","connect"); - LP_send(peer->pushsock,jprint(reqjson,0),1); - - //SENT.({"base":"KMD","rel":"BTC","timestamp":1496076137,"price":0.00021791,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"2fe57da347cd62431528daac5fbb290730fff684afc4cfc2ed90995f58cb3b74","txfee":"100000","satoshis":"9999900000","destsatoshis":"2179101","result":"reserved","pending":1496076197} -*/ int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) { if ( mysatoshis >= othersatoshis ) @@ -108,7 +96,7 @@ int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { - struct LP_peerinfo *peer,*tmp; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; bits256 otherpub; uint32_t reserved; int64_t estimatedbase; uint64_t txfee,destsatoshis,desttxfee; + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase; if ( (price= LP_price(base,myutxo->coin)) == .0 ) return(0); estimatedbase = myutxo->satoshis / price; @@ -132,9 +120,9 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) if ( strcmp(coinstr,base) == 0 && LP_sizematch(estimatedbase,j64bits(item,"satoshis")) == 0 ) { icopy = 0; - if ( (price= LP_pricecache(&otherpub,&reserved,&txfee,&destsatoshis,&desttxfee,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) + if ( (price= LP_pricecache(&Q,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) { - if ( LP_sizematch(myutxo->satoshis,destsatoshis) == 0 ) + if ( LP_sizematch(myutxo->satoshis,Q.destsatoshis) == 0 ) icopy = jduplicate(item); } else icopy = jduplicate(item); if ( icopy != 0 ) @@ -159,18 +147,14 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { static bits256 zero; - int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; bits256 otherpubs[100]; uint32_t reserved[100]; uint64_t txfees[100],destsatoshis[100],desttxfees[100]; //quoteinfo struct + int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; struct LP_quoteinfo Q[sizeof(prices)/sizeof(*prices)]; bestprice = 0.; if ( (array= LP_tradecandidates(utxo,base)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); - memset(reserved,0,sizeof(reserved)); - memset(otherpubs,0,sizeof(otherpubs)); - memset(txfees,0,sizeof(txfees)); - memset(destsatoshis,0,sizeof(destsatoshis)); - memset(desttxfees,0,sizeof(desttxfees)); + memset(Q,0,sizeof(Q)); //BTC 0.02500000 -> ([{"ipaddr":"5.9.253.196","port":7779,"profit":0.01035000,"base":"KMD","coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}]) for (i=0; icoin,jbits256(item,"txid"),jint(item,"vout"),zero,0); - if ( destsatoshis[i] != 0 && (double)j64bits(item,"value")/destsatoshis[i] > price ) - price = (double)j64bits(item,"value")/destsatoshis[i]; + price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),zero,0); + if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"value")/Q[i].destsatoshis > price ) + price = (double)j64bits(item,"value")/Q[i].destsatoshis; } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; @@ -192,12 +176,12 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) besti = -1; for (i=0; i 0.9 ) { - metric = destsatoshis[i] / metric * metric * metric; + metric = Q[i].destsatoshis / metric * metric * metric; if ( metric > bestmetric ) { besti = i; @@ -211,19 +195,18 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) bestitem = jduplicate(jitem(array,besti)); i = besti; item = bestitem; - price = LP_query("request",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,0); + price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,0); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); - jaddnum(bestitem,"reserved",reserved[besti]); jaddnum(bestitem,"price",prices[besti]); - jadd64bits(bestitem,"txfee",txfees[besti]); - jadd64bits(bestitem,"desttxfee",desttxfees[besti]); - jadd64bits(bestitem,"destsatoshis",destsatoshis[besti]); - jaddbits256(bestitem,"otherpub",otherpubs[besti]); + jadd64bits(bestitem,"txfee",Q[besti].txfee); + jadd64bits(bestitem,"desttxfee",Q[besti].desttxfee); + jadd64bits(bestitem,"destsatoshis",Q[besti].destsatoshis); + jaddbits256(bestitem,"desthash",Q[besti].desthash); if ( LP_price(base,utxo->coin) > 0.975*price ) { // the same, cleanup - price = LP_query("connect",&otherpubs[i],&reserved[i],&txfees[i],&destsatoshis[i],&desttxfees[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,item); + price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,item); } } } @@ -233,17 +216,130 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) return(bestitem); } -char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 otherpub) +cJSON *LP_quotejson(struct LP_quoteinfo *qp) { - struct LP_cacheinfo *ptr; - if ( (ptr= LP_cacheadd(base,rel,txid,vout,price,satoshis)) != 0 ) + double price; cJSON *retjson = cJSON_CreateObject(); + jaddstr(retjson,"base",qp->srccoin); + jaddstr(retjson,"rel",qp->destcoin); + jaddstr(retjson,"address",qp->coinaddr); + if ( qp->timestamp != 0 ) + jaddnum(retjson,"timestamp",qp->timestamp); + jaddbits256(retjson,"txid",qp->txid); + jaddnum(retjson,"vout",qp->vout); + jaddbits256(retjson,"srchash",qp->srchash); + jadd64bits(retjson,"txfee",qp->txfee); + if ( qp->quotetime != 0 ) + jaddnum(retjson,"quotetime",qp->quotetime); + jadd64bits(retjson,"satoshis",qp->satoshis); + if ( bits256_nonz(qp->desthash) != 0 ) + jaddbits256(retjson,"desthash",qp->desthash); + if ( bits256_nonz(qp->txid) != 0 ) + { + jaddbits256(retjson,"txid",qp->txid); + jaddnum(retjson,"vout",qp->vout); + } + if ( bits256_nonz(qp->txid2) != 0 ) + { + jaddbits256(retjson,"txid2",qp->txid2); + jaddnum(retjson,"vout2",qp->vout2); + jadd64bits(retjson,"satoshis2",qp->satoshis2); + } + if ( bits256_nonz(qp->desttxid) != 0 ) + { + jaddstr(retjson,"destaddr",qp->destaddr); + jaddbits256(retjson,"desttxid",qp->desttxid); + jaddnum(retjson,"destvout",qp->destvout); + } + jadd64bits(retjson,"destsatoshis",qp->destsatoshis); + jadd64bits(retjson,"desttxfee",qp->desttxfee); + if ( qp->change != 0 ) + jaddnum(retjson,"change",dstr(qp->change)); + price = (double)(qp->destsatoshis+qp->desttxfee) / qp->satoshis; + jaddnum(retjson,"price",price); + return(retjson); +} + +int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) +{ + safecopy(qp->srccoin,jstr(argjson,"base"),sizeof(qp->srccoin)); + safecopy(qp->coinaddr,jstr(argjson,"address"),sizeof(qp->coinaddr)); + safecopy(qp->destcoin,jstr(argjson,"rel"),sizeof(qp->destcoin)); + safecopy(qp->destaddr,jstr(argjson,"destaddr"),sizeof(qp->destaddr)); + qp->timestamp = juint(argjson,"timestamp"); + qp->quotetime = juint(argjson,"quotetime"); + qp->txid = jbits256(argjson,"txid"); + qp->txid2 = jbits256(argjson,"txid2"); + qp->vout = jint(argjson,"vout"); + qp->vout2 = jint(argjson,"vout2"); + qp->srchash = jbits256(argjson,"srchash"); + qp->desttxid = jbits256(argjson,"desttxid"); + qp->destvout = jint(argjson,"destvout"); + qp->desthash = jbits256(argjson,"desthash"); + qp->satoshis = j64bits(argjson,"satoshis"); + qp->destsatoshis = j64bits(argjson,"destsatoshis"); + qp->change = SATOSHIDEN * jdouble(argjson,"change"); + qp->satoshis2 = j64bits(argjson,"satoshis2"); + qp->txfee = j64bits(argjson,"txfee"); + qp->desttxfee = j64bits(argjson,"desttxfee"); + return(0); +} + +int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price) +{ + memset(qp,0,sizeof(*qp)); + qp->timestamp = (uint32_t)time(NULL); + if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) + qp->txfee = 10000; + if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->satoshis2 ) + return(-1); + qp->txid = utxo->txid; + qp->vout = utxo->vout; + qp->txid2 = utxo->txid2; + qp->vout2 = utxo->vout2; + qp->satoshis2 = utxo->satoshis2 - qp->txfee; + qp->satoshis = utxo->satoshis - qp->txfee; + qp->destsatoshis = qp->satoshis * price; + if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) + qp->desttxfee = 10000; + if ( qp->desttxfee >= qp->destsatoshis ) + return(-2); + qp->destsatoshis -= qp->desttxfee; + safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); + safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); + safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); + qp->srchash = LP_pubkey(LP_privkey(utxo->coinaddr)); + return(0); +} + +int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quotetime,uint64_t value,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 desttxid,int32_t destvout,bits256 desthash,char *destaddr) +{ + if ( txfee != qp->txfee ) + { + if ( txfee >= value ) + return(-1); + qp->txfee = txfee; + qp->satoshis = value - txfee; + } + qp->timestamp = timestamp; + qp->quotetime = quotetime; + qp->destsatoshis = destsatoshis; + qp->desttxfee = desttxfee; + qp->desttxid = desttxid; + qp->destvout = destvout; + qp->desthash = desthash; + safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr)); + return(0); +} + +char *LP_quote(cJSON *argjson) +{ + struct LP_cacheinfo *ptr; double price; struct LP_quoteinfo Q; + LP_quoteparse(&Q,argjson); + price = (double)(Q.destsatoshis + Q.desttxfee) / (Q.satoshis + Q.txfee); + if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) { //SENT.({"base":"KMD","rel":"BTC","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","timestamp":1496216835,"price":0.00021141,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"0bcabd875bfa724e26de5f35035ca3767c50b30960e23cbfcbd478cac9147412","txfee":"100000","desttxfee":"10000","value":"10000000000","satoshis":"9999900000","destsatoshis":"2124104","method":"quote"}) - ptr->reserved = reserved; - ptr->txfee = txfee; - ptr->destsatoshis = destsatoshis; - ptr->desttxfee = desttxfee; - ptr->otherpub = otherpub; + ptr->Q = Q; return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); @@ -251,7 +347,7 @@ char *LP_quote(uint32_t reserved,char *base,char *rel,bits256 txid,int32_t vout, int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 srchash,desthash,pubkey,privkey,txid,desttxid; struct LP_utxoinfo *utxo; uint32_t timestamp,quotetime; int32_t destvout,retval = -1,DEXselector = 0; uint64_t txfee,satoshis,desttxfee,destsatoshis,value; struct basilisk_request R; + char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey,txid; struct LP_utxoinfo *utxo; int32_t retval = -1,DEXselector = 0; uint64_t destvalue; struct basilisk_request R; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); @@ -270,34 +366,18 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); -// horror show - retjson = cJSON_CreateObject(); - jaddstr(retjson,"base",base); - jaddstr(retjson,"rel",rel); - jaddstr(retjson,"address",utxo->coinaddr); - jaddnum(retjson,"timestamp",time(NULL)); - jaddnum(retjson,"price",price); - jaddbits256(retjson,"txid",txid); - jaddnum(retjson,"vout",utxo->vout); - pubkey = LP_pubkey(LP_privkey(utxo->coinaddr)); - jaddbits256(retjson,"srchash",pubkey); - if ( (txfee= LP_getestimatedrate(base)*LP_AVETXSIZE) < 10000 ) - txfee = 10000; - jadd64bits(retjson,"txfee",txfee); - if ( (desttxfee= LP_getestimatedrate(rel) * LP_AVETXSIZE) < 10000 ) - desttxfee = 10000; - jadd64bits(retjson,"desttxfee",desttxfee); - jadd64bits(retjson,"value",utxo->satoshis); - jadd64bits(retjson,"satoshis",utxo->satoshis - txfee); - jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee) + desttxfee); + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + retjson = LP_quotejson(&Q); if ( strcmp(method,"request") == 0 ) { retval |= 2; utxo->swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); - utxo->otherpubkey = jbits256(argjson,"otherpub"); - jaddbits256(retjson,"otherpub",utxo->otherpubkey); - jaddstr(retjson,"method","reserved"); + utxo->otherpubkey = jbits256(argjson,"desthash"); + jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); jaddnum(retjson,"pending",utxo->swappending); + jaddbits256(retjson,"desthash",utxo->otherpubkey); + jaddstr(retjson,"method","reserved"); } else jaddstr(retjson,"method","quote"); retstr = jprint(retjson,1); LP_send(pubsock,retstr,1); @@ -313,47 +393,23 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); - txfee = j64bits(argjson,"txfee"); - desttxfee = j64bits(argjson,"desttxfee"); - satoshis = j64bits(argjson,"satoshis"); - desttxid = jbits256(argjson,"desttxid"); - srchash = jbits256(argjson,"srchash"); - destvout = jint(argjson,"destvout"); - timestamp = juint(argjson,"timestamp"); + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + if ( LP_quoteparse(&Q,argjson) < 0 ) + return(-2); privkey = LP_privkey(utxo->coinaddr); - pubkey = LP_pubkey(privkey); - jaddbits256(argjson,"srchash",pubkey); - value = j64bits(argjson,"destsatoshis"); - quotetime = juint(argjson,"quotetime"); - if ( timestamp == utxo->swappending-LP_RESERVETIME && quotetime >= timestamp && quotetime < utxo->swappending && bits256_cmp(pubkey,srchash) == 0 && (destsatoshis= LP_txvalue(rel,desttxid,destvout)) > price*(utxo->satoshis-txfee)+desttxfee && value <= destsatoshis-desttxfee ) + if ( bits256_nonz(privkey) != 0 && Q.timestamp == utxo->swappending-LP_RESERVETIME && Q.quotetime >= Q.timestamp && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { - destsatoshis = value; + Q.change = destvalue - (Q.destsatoshis+Q.desttxfee); nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) printf("error creating utxo->pair\n"); else if ( nn_connect(utxo->pair,pairstr) >= 0 ) { - desthash = jbits256(argjson,"otherpub"); - char str[65],str2[65]; printf("(%s) -> %s %s %s %.8f %s %.8f %u %u %d\n",jprint(argjson,0),bits256_str(str,srchash),bits256_str(str2,desthash),base,dstr(satoshis),rel,dstr(destsatoshis),timestamp,quotetime,DEXselector); - LP_requestinit(&R,srchash,desthash,base,satoshis,rel,destsatoshis,timestamp,quotetime,DEXselector); + LP_requestinit(&R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) == 0 ) { - retjson = cJSON_CreateObject(); - jaddstr(retjson,"base",base); - jaddstr(retjson,"rel",rel); - jaddstr(retjson,"address",utxo->coinaddr); - jaddnum(retjson,"timestamp",timestamp); - jaddnum(retjson,"quotetime",quotetime); - jaddnum(retjson,"price",price); - jaddbits256(retjson,"txid",txid); - jaddnum(retjson,"vout",utxo->vout); - pubkey = LP_pubkey(LP_privkey(utxo->coinaddr)); - jaddbits256(retjson,"srchash",pubkey); - jadd64bits(retjson,"txfee",txfee); - jadd64bits(retjson,"desttxfee",desttxfee); - jadd64bits(retjson,"value",utxo->satoshis); - jadd64bits(retjson,"satoshis",utxo->satoshis - txfee); - jadd64bits(retjson,"destsatoshis",price * (utxo->satoshis-txfee) + desttxfee); + retjson = LP_quotejson(&Q); jaddstr(retjson,"method","connected"); jaddstr(retjson,"pair",pairstr); jaddnum(retjson,"requestid",R.requestid); @@ -377,7 +433,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin nn_close(utxo->pair); utxo->pair = -1; } - } else printf("dest %.8f < required %.8f\n",dstr(value),dstr(price*(utxo->satoshis-txfee))); + } else printf("dest %.8f < required %.8f (%d %d %d %d %d %d)\n",dstr(Q.satoshis),dstr(price*(utxo->satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->swappending ,bits256_cmp(utxo->mypub,Q.srchash) == 0 , LP_txvalue(rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee); } else printf("no price for %s/%s\n",base,rel); } else printf("utxo->pair.%d when connect came in (%s)\n",utxo->pair,jprint(argjson,0)); } @@ -386,6 +442,8 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin return(retval); } +// add orderbook api + char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; @@ -417,7 +475,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } printf("CMD.(%s)\n",jprint(argjson,0)); if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) - retstr = LP_quote(juint(argjson,"pending"),jstr(argjson,"base"),jstr(argjson,"rel"),jbits256(argjson,"txid"),jint(argjson,"vout"),jdouble(argjson,"price"),j64bits(argjson,"satoshis"),j64bits(argjson,"txfee"),j64bits(argjson,"destsatoshis"),j64bits(argjson,"desttxfee"),jbits256(argjson,"otherpub")); + retstr = LP_quote(argjson); else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) { retstr = jprint(argjson,0); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a444540fa..b5668c9b6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -48,24 +48,31 @@ struct LP_peerinfo struct LP_utxoinfo { UT_hash_handle hh; - bits256 txid,deposittxid,feetxid,otherpubkey,mypub; + bits256 txid,txid2,feetxid,otherpubkey,mypub; void *swap; - uint64_t satoshis,depositsatoshis,feesatoshis; + uint64_t satoshis,satoshis2; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; - int32_t vout,depositvout,feevout,pair; uint32_t lasttime,errors,swappending; + int32_t vout,vout2,pair; uint32_t lasttime,errors,swappending; double profitmargin; char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; uint16_t port; } *LP_utxoinfos; +struct LP_quoteinfo +{ + bits256 srchash,desthash,txid,txid2,desttxid; + uint64_t satoshis,satoshis2,txfee,destsatoshis,desttxfee,change; + uint32_t timestamp,quotetime; int32_t vout,vout2,destvout; + char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; +}; + struct LP_cacheinfo { UT_hash_handle hh; - bits256 otherpub; + struct LP_quoteinfo Q; uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(int32_t)]; double price; - uint64_t satoshis,txfee,destsatoshis,desttxfee; - uint32_t timestamp,reserved; + uint32_t timestamp; } *LP_cacheinfos; int32_t LP_cachekey(uint8_t *key,char *base,char *rel,bits256 txid,int32_t vout) @@ -93,41 +100,28 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout { printf("expire price %.8f\n",ptr->price); ptr->price = 0.; - ptr->destsatoshis = ptr->txfee = ptr->desttxfee = 0; - ptr->timestamp = 0; + memset(&ptr->Q,0,sizeof(ptr->Q)); } return(ptr); } -double LP_pricecache(bits256 *otherpubp,uint32_t *reservedp,uint64_t *txfeep,uint64_t *destsatoshisp,uint64_t *desttxfeep,char *base,char *rel,bits256 txid,int32_t vout) +double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,int32_t vout) { struct LP_cacheinfo *ptr; if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) { - if ( destsatoshisp != 0 ) - { - *otherpubp = ptr->otherpub; - *destsatoshisp = ptr->destsatoshis; - *txfeep = ptr->txfee; - *desttxfeep = ptr->desttxfee; - *reservedp = ptr->reserved; - } + if ( qp != 0 ) + (*qp) = ptr->Q; //printf("found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } - else if ( destsatoshisp != 0 ) - { - memset(otherpubp,0,sizeof(*otherpubp)); - *destsatoshisp = 0; - *txfeep = 0; - *desttxfeep = 0; - *reservedp = 0; - } + else if ( qp != 0 ) + memset(qp,0,sizeof(*qp)); //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); return(0.); } -struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t satoshis) +struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout,double price,struct LP_quoteinfo *qp) { struct LP_cacheinfo *ptr=0; if ( (ptr= LP_cachefind(base,rel,txid,vout)) == 0 ) @@ -143,8 +137,7 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, //char str[65]; if ( price != ptr->price ) // printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)satoshis,price); ptr->price = price; - ptr->satoshis = satoshis; - ptr->destsatoshis = satoshis * price; + ptr->Q = *qp; ptr->timestamp = (uint32_t)time(NULL); return(ptr); } @@ -192,9 +185,9 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) jaddbits256(item,"txid",utxo->txid); jaddnum(item,"vout",utxo->vout); jaddnum(item,"value",dstr(utxo->satoshis)); - jaddbits256(item,"deposit",utxo->deposittxid); - jaddnum(item,"dvout",utxo->depositvout); - jaddnum(item,"dvalue",dstr(utxo->depositsatoshis)); + jaddbits256(item,"txid2",utxo->txid2); + jaddnum(item,"vout2",utxo->vout2); + jaddnum(item,"value2",dstr(utxo->satoshis2)); return(item); } @@ -311,10 +304,10 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 } if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { - if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->deposittxid) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->depositvout || depositsatoshis != utxo->depositsatoshis || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) + if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->txid2) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->vout2 || depositsatoshis != utxo->satoshis2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) { utxo->errors++; - char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->deposittxid) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->depositvout,depositsatoshis != utxo->depositsatoshis,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); + char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->txid2) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->vout2,depositsatoshis != utxo->satoshis2,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); } else if ( profitmargin != 0. ) utxo->profitmargin = profitmargin; @@ -332,9 +325,9 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 utxo->txid = txid; utxo->vout = vout; utxo->satoshis = satoshis; - utxo->deposittxid = deposittxid; - utxo->depositvout = depositvout; - utxo->depositsatoshis = depositsatoshis; + utxo->txid2 = deposittxid; + utxo->vout2 = depositvout; + utxo->satoshis2 = depositsatoshis; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); memcpy(utxo->key,key,sizeof(key)); @@ -467,7 +460,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&deposit=%s&dvout=%d&dvalue=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->deposittxid),utxo->depositvout,dstr(utxo->depositsatoshis),utxo->spendscript,utxo->coinaddr); + sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&deposit=%s&dvout=%d&dvalue=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->txid2),utxo->vout2,dstr(utxo->satoshis2),utxo->spendscript,utxo->coinaddr); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); From 15540f9a6f01e444f818ccb347d74ce13ea4f112 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:01:28 +0300 Subject: [PATCH 0797/2705] Test --- iguana/exchanges/LP_commands.c | 146 ++++++++++++++++----------------- 1 file changed, 71 insertions(+), 75 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 60f201cc0..5b97e4feb 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -38,6 +38,74 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch return(rp); } +cJSON *LP_quotejson(struct LP_quoteinfo *qp) +{ + double price; cJSON *retjson = cJSON_CreateObject(); + jaddstr(retjson,"base",qp->srccoin); + jaddstr(retjson,"rel",qp->destcoin); + jaddstr(retjson,"address",qp->coinaddr); + if ( qp->timestamp != 0 ) + jaddnum(retjson,"timestamp",qp->timestamp); + jaddbits256(retjson,"txid",qp->txid); + jaddnum(retjson,"vout",qp->vout); + jaddbits256(retjson,"srchash",qp->srchash); + jadd64bits(retjson,"txfee",qp->txfee); + if ( qp->quotetime != 0 ) + jaddnum(retjson,"quotetime",qp->quotetime); + jadd64bits(retjson,"satoshis",qp->satoshis); + if ( bits256_nonz(qp->desthash) != 0 ) + jaddbits256(retjson,"desthash",qp->desthash); + if ( bits256_nonz(qp->txid) != 0 ) + { + jaddbits256(retjson,"txid",qp->txid); + jaddnum(retjson,"vout",qp->vout); + } + if ( bits256_nonz(qp->txid2) != 0 ) + { + jaddbits256(retjson,"txid2",qp->txid2); + jaddnum(retjson,"vout2",qp->vout2); + jadd64bits(retjson,"satoshis2",qp->satoshis2); + } + if ( bits256_nonz(qp->desttxid) != 0 ) + { + jaddstr(retjson,"destaddr",qp->destaddr); + jaddbits256(retjson,"desttxid",qp->desttxid); + jaddnum(retjson,"destvout",qp->destvout); + } + jadd64bits(retjson,"destsatoshis",qp->destsatoshis); + jadd64bits(retjson,"desttxfee",qp->desttxfee); + if ( qp->change != 0 ) + jaddnum(retjson,"change",dstr(qp->change)); + price = (double)(qp->destsatoshis+qp->desttxfee) / qp->satoshis; + jaddnum(retjson,"price",price); + return(retjson); +} + +int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) +{ + safecopy(qp->srccoin,jstr(argjson,"base"),sizeof(qp->srccoin)); + safecopy(qp->coinaddr,jstr(argjson,"address"),sizeof(qp->coinaddr)); + safecopy(qp->destcoin,jstr(argjson,"rel"),sizeof(qp->destcoin)); + safecopy(qp->destaddr,jstr(argjson,"destaddr"),sizeof(qp->destaddr)); + qp->timestamp = juint(argjson,"timestamp"); + qp->quotetime = juint(argjson,"quotetime"); + qp->txid = jbits256(argjson,"txid"); + qp->txid2 = jbits256(argjson,"txid2"); + qp->vout = jint(argjson,"vout"); + qp->vout2 = jint(argjson,"vout2"); + qp->srchash = jbits256(argjson,"srchash"); + qp->desttxid = jbits256(argjson,"desttxid"); + qp->destvout = jint(argjson,"destvout"); + qp->desthash = jbits256(argjson,"desthash"); + qp->satoshis = j64bits(argjson,"satoshis"); + qp->destsatoshis = j64bits(argjson,"destsatoshis"); + qp->change = SATOSHIDEN * jdouble(argjson,"change"); + qp->satoshis2 = j64bits(argjson,"satoshis2"); + qp->txfee = j64bits(argjson,"txfee"); + qp->desttxfee = j64bits(argjson,"desttxfee"); + return(0); +} + double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub,cJSON *argitem) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; @@ -192,21 +260,17 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } if ( besti >= 0 )//&& bits256_cmp(utxo->mypub,otherpubs[besti]) == 0 ) { - bestitem = jduplicate(jitem(array,besti)); + item = jitem(array,besti); + bestitem = LP_quotejson(&Q[i]); i = besti; - item = bestitem; price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,0); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"price",prices[besti]); - jadd64bits(bestitem,"txfee",Q[besti].txfee); - jadd64bits(bestitem,"desttxfee",Q[besti].desttxfee); - jadd64bits(bestitem,"destsatoshis",Q[besti].destsatoshis); - jaddbits256(bestitem,"desthash",Q[besti].desthash); if ( LP_price(base,utxo->coin) > 0.975*price ) { // the same, cleanup - price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,item); + price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,bestitem); } } } @@ -216,74 +280,6 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) return(bestitem); } -cJSON *LP_quotejson(struct LP_quoteinfo *qp) -{ - double price; cJSON *retjson = cJSON_CreateObject(); - jaddstr(retjson,"base",qp->srccoin); - jaddstr(retjson,"rel",qp->destcoin); - jaddstr(retjson,"address",qp->coinaddr); - if ( qp->timestamp != 0 ) - jaddnum(retjson,"timestamp",qp->timestamp); - jaddbits256(retjson,"txid",qp->txid); - jaddnum(retjson,"vout",qp->vout); - jaddbits256(retjson,"srchash",qp->srchash); - jadd64bits(retjson,"txfee",qp->txfee); - if ( qp->quotetime != 0 ) - jaddnum(retjson,"quotetime",qp->quotetime); - jadd64bits(retjson,"satoshis",qp->satoshis); - if ( bits256_nonz(qp->desthash) != 0 ) - jaddbits256(retjson,"desthash",qp->desthash); - if ( bits256_nonz(qp->txid) != 0 ) - { - jaddbits256(retjson,"txid",qp->txid); - jaddnum(retjson,"vout",qp->vout); - } - if ( bits256_nonz(qp->txid2) != 0 ) - { - jaddbits256(retjson,"txid2",qp->txid2); - jaddnum(retjson,"vout2",qp->vout2); - jadd64bits(retjson,"satoshis2",qp->satoshis2); - } - if ( bits256_nonz(qp->desttxid) != 0 ) - { - jaddstr(retjson,"destaddr",qp->destaddr); - jaddbits256(retjson,"desttxid",qp->desttxid); - jaddnum(retjson,"destvout",qp->destvout); - } - jadd64bits(retjson,"destsatoshis",qp->destsatoshis); - jadd64bits(retjson,"desttxfee",qp->desttxfee); - if ( qp->change != 0 ) - jaddnum(retjson,"change",dstr(qp->change)); - price = (double)(qp->destsatoshis+qp->desttxfee) / qp->satoshis; - jaddnum(retjson,"price",price); - return(retjson); -} - -int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) -{ - safecopy(qp->srccoin,jstr(argjson,"base"),sizeof(qp->srccoin)); - safecopy(qp->coinaddr,jstr(argjson,"address"),sizeof(qp->coinaddr)); - safecopy(qp->destcoin,jstr(argjson,"rel"),sizeof(qp->destcoin)); - safecopy(qp->destaddr,jstr(argjson,"destaddr"),sizeof(qp->destaddr)); - qp->timestamp = juint(argjson,"timestamp"); - qp->quotetime = juint(argjson,"quotetime"); - qp->txid = jbits256(argjson,"txid"); - qp->txid2 = jbits256(argjson,"txid2"); - qp->vout = jint(argjson,"vout"); - qp->vout2 = jint(argjson,"vout2"); - qp->srchash = jbits256(argjson,"srchash"); - qp->desttxid = jbits256(argjson,"desttxid"); - qp->destvout = jint(argjson,"destvout"); - qp->desthash = jbits256(argjson,"desthash"); - qp->satoshis = j64bits(argjson,"satoshis"); - qp->destsatoshis = j64bits(argjson,"destsatoshis"); - qp->change = SATOSHIDEN * jdouble(argjson,"change"); - qp->satoshis2 = j64bits(argjson,"satoshis2"); - qp->txfee = j64bits(argjson,"txfee"); - qp->desttxfee = j64bits(argjson,"desttxfee"); - return(0); -} - int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price) { memset(qp,0,sizeof(*qp)); From b73b585916eba56327b7b1f0a40d0d48f4389b54 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:09:52 +0300 Subject: [PATCH 0798/2705] Test --- iguana/exchanges/LP_commands.c | 38 +++++++++++---------------------- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 5b97e4feb..9f25669ab 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -106,7 +106,7 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) return(0); } -double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 txid,int32_t vout,bits256 mypub,cJSON *argitem) +double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; memset(qp,0,sizeof(*qp)); @@ -118,31 +118,17 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port, { if ( (pushsock= peer->pushsock) >= 0 ) { - reqjson = cJSON_CreateObject(); - jaddbits256(reqjson,"txid",txid); - jaddnum(reqjson,"vout",vout); - jaddstr(reqjson,"base",base); - jaddstr(reqjson,"rel",rel); - if ( bits256_nonz(mypub) != 0 ) - { + qp->desthash = mypub; + strcpy(qp->srccoin,base); + strcpy(qp->destcoin,rel); + reqjson = LP_quotejson(qp); + if ( bits256_nonz(qp->desthash) != 0 ) flag = 1; - jaddbits256(reqjson,"desthash",mypub); - if ( argitem != 0 ) - { - printf("ARGITEM.(%s)\n",jprint(argitem,0)); - jaddnum(reqjson,"timestamp",j64bits(argitem,"timestamp")); - jaddnum(reqjson,"quotetime",time(NULL)); - jadd64bits(reqjson,"satoshis",j64bits(argitem,"value")-j64bits(argitem,"txfee")); - jadd64bits(reqjson,"txfee",j64bits(argitem,"txfee")); - jadd64bits(reqjson,"desttxfee",j64bits(argitem,"desttxfee")); - jadd64bits(reqjson,"destsatoshis",j64bits(argitem,"destsatoshis")); - } - } jaddstr(reqjson,"method",method); LP_send(pushsock,jprint(reqjson,1),1); for (i=0; i<30; i++) { - if ( (price= LP_pricecache(qp,base,rel,txid,vout)) != 0. ) + if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) != 0. ) { if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) break; @@ -223,14 +209,14 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { memset(prices,0,sizeof(prices)); memset(Q,0,sizeof(Q)); - //BTC 0.02500000 -> ([{"ipaddr":"5.9.253.196","port":7779,"profit":0.01035000,"base":"KMD","coin":"KMD","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","script":"76a914434009423522682bd7cc1b18a614c3096d19683188ac","txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"value":100,"deposit":"07902a65d11f0f577a0346432bcd2b6b53de5554c314209d1964693962524d69","dvout":1,"dvalue":120}]) for (i=0; icoin,jbits256(item,"txid"),jint(item,"vout"),zero,0); + LP_quoteparse(&Q[i],item); + price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,zero); if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"value")/Q[i].destsatoshis > price ) price = (double)j64bits(item,"value")/Q[i].destsatoshis; } @@ -263,14 +249,14 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,besti); bestitem = LP_quotejson(&Q[i]); i = besti; - price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,0); + price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,utxo->mypub); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"price",prices[besti]); if ( LP_price(base,utxo->coin) > 0.975*price ) { // the same, cleanup - price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,jbits256(item,"txid"),jint(item,"vout"),utxo->mypub,bestitem); + price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,utxo->mypub); } } } @@ -488,7 +474,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( IAMCLIENT == 0 && strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"deposit"),jint(argjson,"dvout"),SATOSHIDEN * jdouble(argjson,"dvalue"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),SATOSHIDEN * jdouble(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b5668c9b6..3d07f24cd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -405,7 +405,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"deposit"),jint(item,"dvout"),SATOSHIDEN * jdouble(item,"dvalue"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),SATOSHIDEN * jdouble(item,"value2"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } From b6aaf8e6740dec508da7164b35b431fa02583f02 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:16:38 +0300 Subject: [PATCH 0799/2705] Test --- iguana/exchanges/LP_commands.c | 6 +++--- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9f25669ab..a3bce4b39 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -214,11 +214,11 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,i); if ( (price= jdouble(item,"price")) == 0. ) { -// horrible, pass in quoteinfo, utxo + printf("i.%d of %d: (%s)\n",i,n,jprint(item,0)); LP_quoteparse(&Q[i],item); price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,zero); - if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"value")/Q[i].destsatoshis > price ) - price = (double)j64bits(item,"value")/Q[i].destsatoshis; + if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"satoshis")/Q[i].destsatoshis > price ) + price = (double)j64bits(item,"satoshis")/Q[i].destsatoshis; } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3d07f24cd..733661f3e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -460,7 +460,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&deposit=%s&dvout=%d&dvalue=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->txid2),utxo->vout2,dstr(utxo->satoshis2),utxo->spendscript,utxo->coinaddr); + sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&txid2=%s&vout2=%d&value2=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->txid2),utxo->vout2,dstr(utxo->satoshis2),utxo->spendscript,utxo->coinaddr); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); From 36cfcd80d3d615321e243c7502046c6ce8a019fa Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:26:37 +0300 Subject: [PATCH 0800/2705] Test --- iguana/exchanges/LP_commands.c | 45 ++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a3bce4b39..1a8382d3b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -43,16 +43,27 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) double price; cJSON *retjson = cJSON_CreateObject(); jaddstr(retjson,"base",qp->srccoin); jaddstr(retjson,"rel",qp->destcoin); - jaddstr(retjson,"address",qp->coinaddr); + if ( qp->coinaddr[0] != 0 ) + jaddstr(retjson,"address",qp->coinaddr); if ( qp->timestamp != 0 ) jaddnum(retjson,"timestamp",qp->timestamp); - jaddbits256(retjson,"txid",qp->txid); - jaddnum(retjson,"vout",qp->vout); - jaddbits256(retjson,"srchash",qp->srchash); - jadd64bits(retjson,"txfee",qp->txfee); + if ( bits256_nonz(qp->txid) != 0 ) + { + jaddbits256(retjson,"txid",qp->txid); + jaddnum(retjson,"vout",qp->vout); + } + if ( bits256_nonz(qp->srchash) != 0 ) + jaddbits256(retjson,"srchash",qp->srchash); + if ( qp->txfee != 0 ) + jadd64bits(retjson,"txfee",qp->txfee); if ( qp->quotetime != 0 ) jaddnum(retjson,"quotetime",qp->quotetime); - jadd64bits(retjson,"satoshis",qp->satoshis); + if ( qp->satoshis != 0 ) + { + jadd64bits(retjson,"satoshis",qp->satoshis); + price = (double)(qp->destsatoshis+qp->desttxfee) / qp->satoshis; + jaddnum(retjson,"price",price); + } if ( bits256_nonz(qp->desthash) != 0 ) jaddbits256(retjson,"desthash",qp->desthash); if ( bits256_nonz(qp->txid) != 0 ) @@ -64,20 +75,22 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) { jaddbits256(retjson,"txid2",qp->txid2); jaddnum(retjson,"vout2",qp->vout2); - jadd64bits(retjson,"satoshis2",qp->satoshis2); + if ( qp->satoshis2 != 0 ) + jadd64bits(retjson,"satoshis2",qp->satoshis2); } if ( bits256_nonz(qp->desttxid) != 0 ) { - jaddstr(retjson,"destaddr",qp->destaddr); + if ( qp->destaddr[0] != 0 ) + jaddstr(retjson,"destaddr",qp->destaddr); jaddbits256(retjson,"desttxid",qp->desttxid); jaddnum(retjson,"destvout",qp->destvout); } - jadd64bits(retjson,"destsatoshis",qp->destsatoshis); - jadd64bits(retjson,"desttxfee",qp->desttxfee); + if ( qp->destsatoshis != 0 ) + jadd64bits(retjson,"destsatoshis",qp->destsatoshis); + if ( qp->desttxfee != 0 ) + jadd64bits(retjson,"desttxfee",qp->desttxfee); if ( qp->change != 0 ) jaddnum(retjson,"change",dstr(qp->change)); - price = (double)(qp->destsatoshis+qp->desttxfee) / qp->satoshis; - jaddnum(retjson,"price",price); return(retjson); } @@ -97,10 +110,12 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) qp->desttxid = jbits256(argjson,"desttxid"); qp->destvout = jint(argjson,"destvout"); qp->desthash = jbits256(argjson,"desthash"); - qp->satoshis = j64bits(argjson,"satoshis"); + if ( (qp->satoshis= j64bits(argjson,"satoshis")) == 0 ) + qp->satoshis = j64bits(argjson,"value"); + if ( (qp->satoshis2= j64bits(argjson,"satoshis2")) == 0 ) + qp->satoshis2 = j64bits(argjson,"value2"); qp->destsatoshis = j64bits(argjson,"destsatoshis"); qp->change = SATOSHIDEN * jdouble(argjson,"change"); - qp->satoshis2 = j64bits(argjson,"satoshis2"); qp->txfee = j64bits(argjson,"txfee"); qp->desttxfee = j64bits(argjson,"desttxfee"); return(0); @@ -214,8 +229,8 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) item = jitem(array,i); if ( (price= jdouble(item,"price")) == 0. ) { - printf("i.%d of %d: (%s)\n",i,n,jprint(item,0)); LP_quoteparse(&Q[i],item); + char str[65]; printf("i.%d of %d: (%s) -> txid.%s\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid)); price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,zero); if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"satoshis")/Q[i].destsatoshis > price ) price = (double)j64bits(item,"satoshis")/Q[i].destsatoshis; From 8d3893da90308e8f6a060d5769cf99d6abd13d9e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:31:00 +0300 Subject: [PATCH 0801/2705] Test --- iguana/exchanges/LP_commands.c | 1 - 1 file changed, 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 1a8382d3b..eb0de5c11 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -124,7 +124,6 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; - memset(qp,0,sizeof(*qp)); if ( ipaddr != 0 && port >= 1000 ) { if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),port)) == 0 ) From 6b3b43ca651532a740bb3afbf8408303a8e55250 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:34:44 +0300 Subject: [PATCH 0802/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 1 + iguana/exchanges/LP_rpc.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index eb0de5c11..69b7452d5 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -236,7 +236,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; - //printf("i.%d price %.8f bestprice %.8f: (%s)\n",i,price,bestprice,jprint(item,0)); + printf("i.%d price %.8f bestprice %.8f: (%s)\n",i,price,bestprice,jprint(item,0)); } if ( bestprice != 0. ) { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 733661f3e..44c25270b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -100,6 +100,7 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout { printf("expire price %.8f\n",ptr->price); ptr->price = 0.; + ptr->timestamp = 0; memset(&ptr->Q,0,sizeof(ptr->Q)); } return(ptr); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index f912440aa..b30a303a4 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -155,7 +155,7 @@ double LP_getestimatedrate(char *symbol) if ( retstr[0] != '-' ) { rate = atof(retstr) / 1024.; - printf("estimated rate %s -> %.8f\n",retstr,rate); + printf("estimated rate.%s %s -> %.8f\n",coin->symbol,retstr,rate); } free(retstr); } From 52ae8865f88477a128f85e43b3deec0ce1ca2096 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:37:19 +0300 Subject: [PATCH 0803/2705] test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 44c25270b..c2305dc23 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -922,11 +922,11 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i while ( 1 ) { nonz = 0; - if ( (counter++ % 300) == 0 ) + if ( (counter++ % 2000) == 0 ) LP_privkey_updates(mypeer,pubsock,passphrase,amclient); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers != mypeer->numpeers || (rand() % 10) == 0 ) + if ( peer->numpeers != mypeer->numpeers || (rand() % 1000) == 0 ) { if ( peer->numpeers != mypeer->numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); From 46e91f04f141648dd144938c7797e1563fe29934 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:43:04 +0300 Subject: [PATCH 0804/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 5 +++-- iguana/exchanges/LP_rpc.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 69b7452d5..4c69954dd 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -284,6 +284,7 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * { memset(qp,0,sizeof(*qp)); qp->timestamp = (uint32_t)time(NULL); + safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) qp->txfee = 10000; if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->satoshis2 ) @@ -302,7 +303,6 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * qp->destsatoshis -= qp->desttxfee; safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); - safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); qp->srchash = LP_pubkey(LP_privkey(utxo->coinaddr)); return(0); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c2305dc23..01b57a821 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -113,7 +113,7 @@ double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,i { if ( qp != 0 ) (*qp) = ptr->Q; - //printf("found %s/%s %.8f\n",base,rel,ptr->price); + printf("found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } else if ( qp != 0 ) @@ -140,6 +140,7 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, ptr->price = price; ptr->Q = *qp; ptr->timestamp = (uint32_t)time(NULL); + printf("cacheadd %.8f\n",price); return(ptr); } @@ -926,7 +927,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_privkey_updates(mypeer,pubsock,passphrase,amclient); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers != mypeer->numpeers || (rand() % 1000) == 0 ) + if ( peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0 ) { if ( peer->numpeers != mypeer->numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index b30a303a4..d6a3dfeab 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -155,7 +155,7 @@ double LP_getestimatedrate(char *symbol) if ( retstr[0] != '-' ) { rate = atof(retstr) / 1024.; - printf("estimated rate.%s %s -> %.8f\n",coin->symbol,retstr,rate); + printf("estimated rate.(%s) %s -> %.8f\n",symbol,retstr,rate); } free(retstr); } From 6e5fa167ea57dab2108da3e9d2e15386e049f224 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:48:19 +0300 Subject: [PATCH 0805/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 01b57a821..6a68e716e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -113,6 +113,11 @@ double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,i { if ( qp != 0 ) (*qp) = ptr->Q; + if ( ptr->price == 0. && ptr->Q.satoshis != 0 ) + { + printf("null ptr->price? "); + ptr->price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; + } printf("found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } From 800c69d0aa56636a9cb324a1dbaabe479e01efbe Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:52:23 +0300 Subject: [PATCH 0806/2705] Test --- iguana/exchanges/LP_commands.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 4c69954dd..57ed4622a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -145,7 +145,10 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port, if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) != 0. ) { if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) + { + printf("break out of loop.%d price %.8f\n",i,price); break; + } } usleep(250000); } @@ -231,8 +234,12 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) LP_quoteparse(&Q[i],item); char str[65]; printf("i.%d of %d: (%s) -> txid.%s\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid)); price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,zero); + printf("price %.8f\n",price); if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"satoshis")/Q[i].destsatoshis > price ) + { + printf("adjustprice %.8f -> %.8f\n",price,(double)j64bits(item,"satoshis")/Q[i].destsatoshis); price = (double)j64bits(item,"satoshis")/Q[i].destsatoshis; + } } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; From b5c8c9b80f7fedc30aa2388bdfdf64e50377ae4f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:54:31 +0300 Subject: [PATCH 0807/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6a68e716e..eb07ecfe9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -123,7 +123,7 @@ double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,i } else if ( qp != 0 ) memset(qp,0,sizeof(*qp)); - //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); + char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); return(0.); } @@ -140,8 +140,8 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, portable_mutex_unlock(&LP_cachemutex); } else printf("LP_cacheadd keysize mismatch?\n"); } //else printf("CACHE hit!\n"); - //char str[65]; if ( price != ptr->price ) - // printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)satoshis,price); + char str[65]; if ( price != ptr->price ) + printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)qp->satoshis,price); ptr->price = price; ptr->Q = *qp; ptr->timestamp = (uint32_t)time(NULL); From 7740ae6d0e4ba05dc696481daf686e1e1f41e2a0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 08:55:57 +0300 Subject: [PATCH 0808/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index eb07ecfe9..687d17212 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -121,9 +121,7 @@ double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,i printf("found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } - else if ( qp != 0 ) - memset(qp,0,sizeof(*qp)); - char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); + //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); return(0.); } From 14a7a7296a632389278f6b624182570c6e066002 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 09:05:31 +0300 Subject: [PATCH 0809/2705] Test --- iguana/exchanges/LP_commands.c | 135 ++++++++++++++++---------------- iguana/exchanges/LP_nativeDEX.c | 4 +- 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 57ed4622a..a4461d6b3 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -121,6 +121,66 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) return(0); } +int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price) +{ + memset(qp,0,sizeof(*qp)); + qp->timestamp = (uint32_t)time(NULL); + safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); + if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) + qp->txfee = 10000; + if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->satoshis2 ) + return(-1); + qp->txid = utxo->txid; + qp->vout = utxo->vout; + qp->txid2 = utxo->txid2; + qp->vout2 = utxo->vout2; + qp->satoshis2 = utxo->satoshis2 - qp->txfee; + qp->satoshis = utxo->satoshis - qp->txfee; + qp->destsatoshis = qp->satoshis * price; + if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) + qp->desttxfee = 10000; + if ( qp->desttxfee >= qp->destsatoshis ) + return(-2); + qp->destsatoshis -= qp->desttxfee; + safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); + safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); + qp->srchash = LP_pubkey(LP_privkey(utxo->coinaddr)); + return(0); +} + +int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quotetime,uint64_t value,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 desttxid,int32_t destvout,bits256 desthash,char *destaddr) +{ + if ( txfee != qp->txfee ) + { + if ( txfee >= value ) + return(-1); + qp->txfee = txfee; + qp->satoshis = value - txfee; + } + qp->timestamp = timestamp; + qp->quotetime = quotetime; + qp->destsatoshis = destsatoshis; + qp->desttxfee = desttxfee; + qp->desttxid = desttxid; + qp->destvout = destvout; + qp->desthash = desthash; + safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr)); + return(0); +} + +char *LP_quote(cJSON *argjson) +{ + struct LP_cacheinfo *ptr; double price; struct LP_quoteinfo Q; + LP_quoteparse(&Q,argjson); + price = (double)(Q.destsatoshis + Q.desttxfee) / (Q.satoshis + Q.txfee); + if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) + { + ptr->Q = Q; + return(clonestr("{\"result\":\"updated\"}")); + } + else return(clonestr("{\"error\":\"nullptr\"}")); +} + double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; @@ -135,6 +195,8 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port, qp->desthash = mypub; strcpy(qp->srccoin,base); strcpy(qp->destcoin,rel); + if ( strcmp(method,"request") == 0 ) + qp->quotetime = (uint32_t)time(NULL); reqjson = LP_quotejson(qp); if ( bits256_nonz(qp->desthash) != 0 ) flag = 1; @@ -146,7 +208,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port, { if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) { - printf("break out of loop.%d price %.8f\n",i,price); + //printf("break out of loop.%d price %.8f\n",i,price); break; } } @@ -232,9 +294,8 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) if ( (price= jdouble(item,"price")) == 0. ) { LP_quoteparse(&Q[i],item); - char str[65]; printf("i.%d of %d: (%s) -> txid.%s\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid)); + //char str[65]; printf("i.%d of %d: (%s) -> txid.%s\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid)); price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,zero); - printf("price %.8f\n",price); if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"satoshis")/Q[i].destsatoshis > price ) { printf("adjustprice %.8f -> %.8f\n",price,(double)j64bits(item,"satoshis")/Q[i].destsatoshis); @@ -243,7 +304,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; - printf("i.%d price %.8f bestprice %.8f: (%s)\n",i,price,bestprice,jprint(item,0)); + //printf("i.%d price %.8f bestprice %.8f: (%s)\n",i,price,bestprice,jprint(item,0)); } if ( bestprice != 0. ) { @@ -287,67 +348,6 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) return(bestitem); } -int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price) -{ - memset(qp,0,sizeof(*qp)); - qp->timestamp = (uint32_t)time(NULL); - safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); - if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) - qp->txfee = 10000; - if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->satoshis2 ) - return(-1); - qp->txid = utxo->txid; - qp->vout = utxo->vout; - qp->txid2 = utxo->txid2; - qp->vout2 = utxo->vout2; - qp->satoshis2 = utxo->satoshis2 - qp->txfee; - qp->satoshis = utxo->satoshis - qp->txfee; - qp->destsatoshis = qp->satoshis * price; - if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) - qp->desttxfee = 10000; - if ( qp->desttxfee >= qp->destsatoshis ) - return(-2); - qp->destsatoshis -= qp->desttxfee; - safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); - safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); - qp->srchash = LP_pubkey(LP_privkey(utxo->coinaddr)); - return(0); -} - -int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quotetime,uint64_t value,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 desttxid,int32_t destvout,bits256 desthash,char *destaddr) -{ - if ( txfee != qp->txfee ) - { - if ( txfee >= value ) - return(-1); - qp->txfee = txfee; - qp->satoshis = value - txfee; - } - qp->timestamp = timestamp; - qp->quotetime = quotetime; - qp->destsatoshis = destsatoshis; - qp->desttxfee = desttxfee; - qp->desttxid = desttxid; - qp->destvout = destvout; - qp->desthash = desthash; - safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr)); - return(0); -} - -char *LP_quote(cJSON *argjson) -{ - struct LP_cacheinfo *ptr; double price; struct LP_quoteinfo Q; - LP_quoteparse(&Q,argjson); - price = (double)(Q.destsatoshis + Q.desttxfee) / (Q.satoshis + Q.txfee); - if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) - { - //SENT.({"base":"KMD","rel":"BTC","address":"RFQn4gNG555woQWQV1wPseR47spCduiJP5","timestamp":1496216835,"price":0.00021141,"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","srchash":"0bcabd875bfa724e26de5f35035ca3767c50b30960e23cbfcbd478cac9147412","txfee":"100000","desttxfee":"10000","value":"10000000000","satoshis":"9999900000","destsatoshis":"2124104","method":"quote"}) - ptr->Q = Q; - return(clonestr("{\"result\":\"updated\"}")); - } - else return(clonestr("{\"error\":\"nullptr\"}")); -} - int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey,txid; struct LP_utxoinfo *utxo; int32_t retval = -1,DEXselector = 0; uint64_t destvalue; struct basilisk_request R; struct LP_quoteinfo Q; @@ -371,6 +371,8 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); + if ( strcmp(method,"price") == 0 ) + Q.timestamp = (uint32_t)time(NULL); retjson = LP_quotejson(&Q); if ( strcmp(method,"request") == 0 ) { @@ -381,7 +383,8 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin jaddnum(retjson,"pending",utxo->swappending); jaddbits256(retjson,"desthash",utxo->otherpubkey); jaddstr(retjson,"method","reserved"); - } else jaddstr(retjson,"method","quote"); + } + else jaddstr(retjson,"method","quote"); retstr = jprint(retjson,1); LP_send(pubsock,retstr,1); } else printf("null price\n"); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 687d17212..c31d69ece 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -96,7 +96,7 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout HASH_FIND(hh,LP_cacheinfos,key,sizeof(key),ptr); portable_mutex_unlock(&LP_cachemutex); } else printf("LP_cachefind keysize mismatch?\n"); - if ( ptr != 0 && ptr->timestamp != 0 && ptr->timestamp < time(NULL)-LP_CACHEDURATION ) + if ( 0 && ptr != 0 && ptr->timestamp != 0 && ptr->timestamp < time(NULL)-LP_CACHEDURATION ) { printf("expire price %.8f\n",ptr->price); ptr->price = 0.; @@ -118,7 +118,7 @@ double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,i printf("null ptr->price? "); ptr->price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; } - printf("found %s/%s %.8f\n",base,rel,ptr->price); + //printf("found %s/%s %.8f\n",base,rel,ptr->price); return(ptr->price); } //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); From e036e7ea0022ec651022d28ffc20982a2b32f4ce Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 09:08:57 +0300 Subject: [PATCH 0810/2705] Test --- iguana/exchanges/LP_commands.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a4461d6b3..1ca121b80 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -404,6 +404,8 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( LP_quoteparse(&Q,argjson) < 0 ) return(-2); privkey = LP_privkey(utxo->coinaddr); + if ( bits256_nonz(utxo->mypub) == 0 ) + utxo->mypub = LP_pubkey(privkey); if ( bits256_nonz(privkey) != 0 && Q.timestamp == utxo->swappending-LP_RESERVETIME && Q.quotetime >= Q.timestamp && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { Q.change = destvalue - (Q.destsatoshis+Q.desttxfee); @@ -439,7 +441,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin nn_close(utxo->pair); utxo->pair = -1; } - } else printf("dest %.8f < required %.8f (%d %d %d %d %d %d)\n",dstr(Q.satoshis),dstr(price*(utxo->satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->swappending ,bits256_cmp(utxo->mypub,Q.srchash) == 0 , LP_txvalue(rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee); + } else printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->swappending ,bits256_cmp(utxo->mypub,Q.srchash) == 0 , LP_txvalue(rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); } else printf("no price for %s/%s\n",base,rel); } else printf("utxo->pair.%d when connect came in (%s)\n",utxo->pair,jprint(argjson,0)); } From 880f82174e619cf594cf705cf1cb16ed8ad278f7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 09:10:42 +0300 Subject: [PATCH 0811/2705] Test --- iguana/exchanges/LP_transaction.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index eea8a63fc..2d192ef5b 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -67,6 +67,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) uint64_t value = 0; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; if ( (txobj= LP_gettx(symbol,txid)) != 0 ) { + printf("%s txobj.(%s)\n",symbol,jprint(txobj,0)); if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 && vout < numvouts ) { utxoobj = jitem(vouts,vout); From 76b37edd3a9a38918ed58fb251f9992de3120077 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 09:21:36 +0300 Subject: [PATCH 0812/2705] Test --- iguana/exchanges/LP_commands.c | 16 +++++++++------- iguana/exchanges/LP_transaction.c | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 1ca121b80..34554aebb 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -277,12 +277,12 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) return(retarray); } -cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) +cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) { static bits256 zero; int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; struct LP_quoteinfo Q[sizeof(prices)/sizeof(*prices)]; bestprice = 0.; - if ( (array= LP_tradecandidates(utxo,base)) != 0 ) + if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { @@ -295,7 +295,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) { LP_quoteparse(&Q[i],item); //char str[65]; printf("i.%d of %d: (%s) -> txid.%s\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid)); - price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,zero); + price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,zero); if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"satoshis")/Q[i].destsatoshis > price ) { printf("adjustprice %.8f -> %.8f\n",price,(double)j64bits(item,"satoshis")/Q[i].destsatoshis); @@ -326,19 +326,21 @@ cJSON *LP_bestprice(struct LP_utxoinfo *utxo,char *base) } } } - if ( besti >= 0 )//&& bits256_cmp(utxo->mypub,otherpubs[besti]) == 0 ) + if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) { item = jitem(array,besti); bestitem = LP_quotejson(&Q[i]); i = besti; - price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,utxo->mypub); + Q[i].desttxid = myutxo->txid; + Q[i].destvout = myutxo->vout; + price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"price",prices[besti]); - if ( LP_price(base,utxo->coin) > 0.975*price ) + if ( LP_price(base,myutxo->coin) > 0.975*price ) { // the same, cleanup - price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,utxo->coin,utxo->mypub); + price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); } } } diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 2d192ef5b..c54336e74 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -67,7 +67,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) uint64_t value = 0; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; if ( (txobj= LP_gettx(symbol,txid)) != 0 ) { - printf("%s txobj.(%s)\n",symbol,jprint(txobj,0)); + char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 && vout < numvouts ) { utxoobj = jitem(vouts,vout); From 5f1ff2296736974a955bec23eeb665544a21c9b7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 09:26:21 +0300 Subject: [PATCH 0813/2705] Test --- iguana/exchanges/LP_commands.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 34554aebb..2d967fc8b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -66,11 +66,6 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) } if ( bits256_nonz(qp->desthash) != 0 ) jaddbits256(retjson,"desthash",qp->desthash); - if ( bits256_nonz(qp->txid) != 0 ) - { - jaddbits256(retjson,"txid",qp->txid); - jaddnum(retjson,"vout",qp->vout); - } if ( bits256_nonz(qp->txid2) != 0 ) { jaddbits256(retjson,"txid2",qp->txid2); @@ -339,7 +334,8 @@ cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) jaddnum(bestitem,"price",prices[besti]); if ( LP_price(base,myutxo->coin) > 0.975*price ) { -// the same, cleanup + Q[i].desttxid = myutxo->txid; + Q[i].destvout = myutxo->vout; price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); } } @@ -397,7 +393,6 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin retval = 4; if ( utxo->pair < 0 ) { - //LP_command.({"txid":"f5d5e2eb4ef85c78f95076d0d2d99af9e1b85968e57b3c7bdb282bd005f7c341","vout":1,"base":"KMD","rel":"BTC","mypub":"3b8f71015d644aaa4c9cceeee289b9a50dc9ec7fafab861c4d5872a8e3844466","satoshis":"0","txfee":"100000","desttxfee":"10000","destsatoshis":"2163363","method":"connect"}) if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); @@ -405,6 +400,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin return(-1); if ( LP_quoteparse(&Q,argjson) < 0 ) return(-2); + printf("connect with.(%s)\n",jprint(argjson,0)); privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); From c7d9eff67041bd41071ebdb5b88e71131aacb26d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 09:31:35 +0300 Subject: [PATCH 0814/2705] Test --- iguana/exchanges/LP_commands.c | 7 +++---- iguana/exchanges/LP_transaction.c | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2d967fc8b..39763fea1 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -23,17 +23,16 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch struct basilisk_request R; memset(rp,0,sizeof(*rp)); rp->srchash = srchash; - rp->desthash = desthash; rp->srcamount = srcsatoshis; - rp->destamount = destsatoshis; rp->timestamp = timestamp; - rp->quotetime = quotetime; rp->DEXselector = DEXselector; safecopy(rp->src,src,sizeof(rp->src)); safecopy(rp->dest,dest,sizeof(rp->dest)); R = *rp; rp->requestid = basilisk_requestid(rp); - *rp = R; + rp->quotetime = quotetime; + rp->desthash = desthash; + rp->destamount = destsatoshis; rp->quoteid = basilisk_quoteid(rp); return(rp); } diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index c54336e74..3a8d63120 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -67,7 +67,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) uint64_t value = 0; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; if ( (txobj= LP_gettx(symbol,txid)) != 0 ) { - char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); + //char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 && vout < numvouts ) { utxoobj = jitem(vouts,vout); From 45544ec6a5034c1a62703ca9124e14658dad0505 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 09:34:27 +0300 Subject: [PATCH 0815/2705] Test --- iguana/exchanges/LP_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 39763fea1..0f5c6a257 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -411,6 +411,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin printf("error creating utxo->pair\n"); else if ( nn_connect(utxo->pair,pairstr) >= 0 ) { + char str[65]; printf("destsatoshis %.8f %s t%u\n",dstr(Q.destsatoshis),bits256_str(str,Q.desthash),Q.quotetime); LP_requestinit(&R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) == 0 ) { From 209c02cefee13795c504e00d5ddf1c9575555b3d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 09:38:25 +0300 Subject: [PATCH 0816/2705] Test --- iguana/exchanges/LP_commands.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 0f5c6a257..af337b933 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -274,7 +274,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) { static bits256 zero; - int32_t i,n,besti; cJSON *array,*item,*bestitem=0; double bestmetric,metric,bestprice=0.,price,prices[100]; struct LP_quoteinfo Q[sizeof(prices)/sizeof(*prices)]; + int32_t i,n,besti,DEXselector=0; cJSON *array,*item,*bestitem=0; struct basilisk_request R; double bestmetric,metric,bestprice=0.,price,prices[100]; struct LP_quoteinfo Q[sizeof(prices)/sizeof(*prices)]; bestprice = 0.; if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { @@ -336,6 +336,8 @@ cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) Q[i].desttxid = myutxo->txid; Q[i].destvout = myutxo->vout; price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); + LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); + printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); } } } @@ -399,7 +401,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin return(-1); if ( LP_quoteparse(&Q,argjson) < 0 ) return(-2); - printf("connect with.(%s)\n",jprint(argjson,0)); + //printf("connect with.(%s)\n",jprint(argjson,0)); privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); @@ -411,7 +413,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin printf("error creating utxo->pair\n"); else if ( nn_connect(utxo->pair,pairstr) >= 0 ) { - char str[65]; printf("destsatoshis %.8f %s t%u\n",dstr(Q.destsatoshis),bits256_str(str,Q.desthash),Q.quotetime); + //char str[65]; printf("destsatoshis %.8f %s t%u\n",dstr(Q.destsatoshis),bits256_str(str,Q.desthash),Q.quotetime); LP_requestinit(&R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) == 0 ) { From 79b4f515f7f20c064f4ba8fbb98f85198f230af6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 10:19:25 +0300 Subject: [PATCH 0817/2705] Test --- iguana/exchanges/LP_swap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index fe2df8a7c..86f1d0a0c 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -192,7 +192,7 @@ uint32_t basilisk_requestid(struct basilisk_request *rp) R.requestid = R.quoteid = R.quotetime = R.DEXselector = 0; R.destamount = R.unused = 0; memset(R.desthash.bytes,0,sizeof(R.desthash.bytes)); - if ( 1 ) + if ( 0 ) { int32_t i; for (i=0; i Date: Thu, 1 Jun 2017 10:51:25 +0300 Subject: [PATCH 0818/2705] Test --- iguana/exchanges/LP_commands.c | 17 +++++++++++++++-- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_nativeDEX.c | 5 +++-- iguana/exchanges/LP_swap.c | 24 +++++++++++------------- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index af337b933..dc0b68a5c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -486,8 +486,21 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port retstr = LP_quote(argjson); else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) { - retstr = jprint(argjson,0); - printf("got connected! (%s)\n",retstr); + int32_t pairsock = -1; char *pairstr; + if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) + printf("error creating pairsock\n"); + else if ( nn_connect(pairsock,pairstr) >= 0 ) + { + struct LP_quoteinfo *qp; int32_t DEXselector = 0; + qp = calloc(1,sizeof(*qp)); + LP_quoteparse(qp,argjson); + qp->pair = pairsock; + qp->privkey = LP_privkey(qp->destaddr); + LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis,qp->destcoin,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)qp) == 0 ) + { + } + } } else if ( IAMCLIENT == 0 && strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index a7e239f2b..35c38051a 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -470,6 +470,7 @@ enum opcodetype void basilisk_dontforget_update(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx); uint32_t basilisk_requestid(struct basilisk_request *rp); uint32_t basilisk_quoteid(struct basilisk_request *rp); +struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); struct iguana_info *LP_coinfind(char *symbol); void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c31d69ece..29c81b18e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -60,9 +60,10 @@ struct LP_utxoinfo struct LP_quoteinfo { - bits256 srchash,desthash,txid,txid2,desttxid; + struct basilisk_request R; + bits256 srchash,desthash,txid,txid2,desttxid,privkey; uint64_t satoshis,satoshis2,txfee,destsatoshis,desttxfee,change; - uint32_t timestamp,quotetime; int32_t vout,vout2,destvout; + uint32_t timestamp,quotetime; int32_t vout,vout2,destvout,pair; char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; }; diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 86f1d0a0c..d70b78954 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -527,22 +527,21 @@ void LP_bobloop(void *_utxo) utxo->pair = -1; } -void LP_aliceloop(void *_utxo) +void LP_aliceloop(void *_qp) { - uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; - fprintf(stderr,"start swap iambob\n"); + uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = 0; struct LP_quoteinfo *qp = _qp; + fprintf(stderr,"start swap iamalice\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + 10; - while ( (swap= utxo->swap) == 0 && time(NULL) < expiration ) - sleep(1); - if ( (utxo->swap= swap) != 0 ) + swap = LP_swapinit(1,0,qp->privkey,&qp->R); + if ( swap != 0 ) { - if ( LP_sendwait("pubkeys",10,utxo->pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_sendwait("pubkeys",10,qp->pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); - else if ( LP_sendwait("choosei",10,utxo->pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + else if ( LP_sendwait("choosei",10,qp->pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); - else if ( LP_sendwait("mostprivs",10,utxo->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + else if ( LP_sendwait("mostprivs",10,qp->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error LP_sendwait mostprivs\n"); else if ( basilisk_alicetxs(swap,data,maxlen) != 0 ) printf("basilisk_alicetxs error\n"); @@ -558,10 +557,9 @@ void LP_aliceloop(void *_utxo) } } else printf("swap timed out\n"); basilisk_swap_finished(swap); - free(utxo->swap); - utxo->swap = 0; - nn_close(utxo->pair); - utxo->pair = -1; + free(swap); + nn_close(qp->pair); + free(qp); } #ifdef old From fc1c078bb7da07d3cb9c7e23cd20722eaf3781f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 10:53:26 +0300 Subject: [PATCH 0819/2705] Test --- iguana/exchanges/LP_commands.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index dc0b68a5c..611bf9aab 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -327,6 +327,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) i = besti; Q[i].desttxid = myutxo->txid; Q[i].destvout = myutxo->vout; + strcpy(Q[i].destaddr,myutxo->coinaddr); price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); @@ -335,6 +336,7 @@ cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) { Q[i].desttxid = myutxo->txid; Q[i].destvout = myutxo->vout; + strcpy(Q[i].destaddr,myutxo->coinaddr); price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); From d3ad3e546fd05566f926f7950fdef4bfffa7eefa Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 10:55:25 +0300 Subject: [PATCH 0820/2705] Test --- iguana/exchanges/LP_swap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index d70b78954..de851683d 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -534,7 +534,7 @@ void LP_aliceloop(void *_qp) maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + 10; - swap = LP_swapinit(1,0,qp->privkey,&qp->R); + swap = LP_swapinit(0,0,qp->privkey,&qp->R); if ( swap != 0 ) { if ( LP_sendwait("pubkeys",10,qp->pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) @@ -555,9 +555,9 @@ void LP_aliceloop(void *_qp) // alicespend // done } - } else printf("swap timed out\n"); - basilisk_swap_finished(swap); - free(swap); + basilisk_swap_finished(swap); + free(swap); + } nn_close(qp->pair); free(qp); } From ab8c9158afb57f3ed4e90031947b8b2177647405 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 10:56:40 +0300 Subject: [PATCH 0821/2705] Test --- iguana/exchanges/LP_swap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index de851683d..618597b29 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -443,11 +443,13 @@ int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basi int32_t datalen,sendlen,retval = -1; if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { + printf("waitsend waited\n"); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { retval = 0; + printf("sent success\n"); } else printf("send %s error\n",statename); } } else printf("didnt get pubkeys\n"); @@ -459,10 +461,14 @@ int32_t LP_sendwait(char *statename,int32_t timeout,int32_t pairsock,struct basi int32_t datalen,sendlen,retval = -1; if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { + printf("sendwait.%d\n",datalen); if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) + { retval = 0; + printf("waited success\n"); + } else printf("didnt get %s\n",statename); } else printf("send pubkeys error\n"); } From 2072e3a3b2a0eae2cbaadf63396aafe7ec1e4d4f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:06:14 +0300 Subject: [PATCH 0822/2705] Test --- iguana/exchanges/LP_commands.c | 1 + iguana/exchanges/LP_swap.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 611bf9aab..2c5c4d65c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -499,6 +499,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port qp->pair = pairsock; qp->privkey = LP_privkey(qp->destaddr); LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis,qp->destcoin,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); + printf("alice pairstr.(%s)\n",pairstr); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)qp) == 0 ) { } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 618597b29..707c2d3e1 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -441,6 +441,7 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; + printf("wait on pairsock.%d\n",pairsock); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { printf("waitsend waited\n"); @@ -525,9 +526,9 @@ void LP_bobloop(void *_utxo) // bobrefund // done } + basilisk_swap_finished(swap); + free(utxo->swap); } else printf("swap timed out\n"); - basilisk_swap_finished(swap); - free(utxo->swap); utxo->swap = 0; nn_close(utxo->pair); utxo->pair = -1; @@ -536,7 +537,7 @@ void LP_bobloop(void *_utxo) void LP_aliceloop(void *_qp) { uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = 0; struct LP_quoteinfo *qp = _qp; - fprintf(stderr,"start swap iamalice\n"); + fprintf(stderr,"start swap iamalice pair.%d\n",qp->pair); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + 10; From f32f4c3868166e0a11d1316d81b68eb7fcd365cb Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:11:46 +0300 Subject: [PATCH 0823/2705] Test --- iguana/exchanges/LP_swap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 707c2d3e1..2fab0961e 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -431,9 +431,10 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i { if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { + printf("got %d bytes\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); - } + } else printf("error nn_recv\n"); } return(retval); } @@ -453,7 +454,7 @@ int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basi printf("sent success\n"); } else printf("send %s error\n",statename); } - } else printf("didnt get pubkeys\n"); + } else printf("didnt get data\n"); return(retval); } From 0c238430b5de46e71ae0666316dbb15826f3f453 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:14:20 +0300 Subject: [PATCH 0824/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2c5c4d65c..8e9fdb623 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -413,7 +413,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) printf("error creating utxo->pair\n"); - else if ( nn_connect(utxo->pair,pairstr) >= 0 ) + else if ( nn_bind(utxo->pair,pairstr) >= 0 ) { //char str[65]; printf("destsatoshis %.8f %s t%u\n",dstr(Q.destsatoshis),bits256_str(str,Q.desthash),Q.quotetime); LP_requestinit(&R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); From 204bb261615a3f1f83dac20c2ee9f49a54714508 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:20:07 +0300 Subject: [PATCH 0825/2705] Test --- iguana/exchanges/LP_swap.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 2fab0961e..1fcef1467 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -216,10 +216,14 @@ int32_t LP_pubkeys_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datal int32_t i,len = 0; if ( datalen == sizeof(swap->otherdeck) ) { + printf("extract pubkeys\n"); for (i=0; iotherdeck)/sizeof(swap->otherdeck[0][0]); i++) len += iguana_rwnum(0,&data[len],sizeof(swap->otherdeck[i>>1][i&1]),&swap->otherdeck[i>>1][i&1]); + printf("done extract pubkeys\n"); return(0); - } else return(-1); + } + printf("pubkeys verify size mismatch %d != %d\n",datalen,(int32_t)sizeof(swap->otherdeck)); + return(-1); } int32_t LP_choosei_data(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) @@ -434,6 +438,7 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i printf("got %d bytes\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); + printf("retval.%d\n",retval); } else printf("error nn_recv\n"); } return(retval); @@ -454,7 +459,7 @@ int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basi printf("sent success\n"); } else printf("send %s error\n",statename); } - } else printf("didnt get data\n"); + } else printf("didnt get valid data\n"); return(retval); } From a1cf1dcf3a123052bff2c2c0b1490ab446da1eaf Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:22:03 +0300 Subject: [PATCH 0826/2705] Test --- iguana/exchanges/LP_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 1fcef1467..32af56b5e 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -439,6 +439,7 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i retval = (*verify)(swap,data,datalen); nn_freemsg(data); printf("retval.%d\n",retval); + return(retval); } else printf("error nn_recv\n"); } return(retval); From cdd9cca9e47b71940774bdbe7bcd6a2b23a6dc4b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:25:33 +0300 Subject: [PATCH 0827/2705] Test --- iguana/exchanges/LP_swap.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 32af56b5e..18b7eaa4f 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -435,10 +435,8 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i { if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { - printf("got %d bytes\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); - printf("retval.%d\n",retval); return(retval); } else printf("error nn_recv\n"); } @@ -448,17 +446,13 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; - printf("wait on pairsock.%d\n",pairsock); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { - printf("waitsend waited\n"); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) - { retval = 0; - printf("sent success\n"); - } else printf("send %s error\n",statename); + else printf("send %s error\n",statename); } } else printf("didnt get valid data\n"); return(retval); @@ -469,14 +463,10 @@ int32_t LP_sendwait(char *statename,int32_t timeout,int32_t pairsock,struct basi int32_t datalen,sendlen,retval = -1; if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { - printf("sendwait.%d\n",datalen); if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) - { retval = 0; - printf("waited success\n"); - } else printf("didnt get %s\n",statename); } else printf("send pubkeys error\n"); } From b3d19ef972f84733353b72315151e3763a1f44e4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:27:59 +0300 Subject: [PATCH 0828/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 3a8d63120..99bb86bfb 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -766,7 +766,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch return(0); if ( (utxoobj= LP_gettxout(symbol,utxotxid,vout)) == 0 ) { - printf("basilisk_swap_bobtxspend.%s utxo already spent or doesnt exist\n",name); + printf("basilisk_swap_bobtxspend.%s %s utxo.(%s) already spent or doesnt exist\n",name,symbol,bits256_str(str,utxotxid)); return(0); } if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) From f996a6d4a79f8d8d53f7218ece9861fb6a5d2fca Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:33:27 +0300 Subject: [PATCH 0829/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_include.h | 11 ++++++++++- iguana/exchanges/LP_nativeDEX.c | 9 --------- iguana/exchanges/LP_swap.c | 7 +++++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 8e9fdb623..9208a6006 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -426,7 +426,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin jaddnum(retjson,"quoteid",R.quoteid); retstr = jprint(retjson,1); LP_send(pubsock,retstr,1); - utxo->swap = LP_swapinit(1,0,privkey,&R); + utxo->swap = LP_swapinit(1,0,privkey,&R,&Q); } else { diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 35c38051a..a7ec599ed 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -199,6 +199,15 @@ struct basilisk_swap }; +struct LP_quoteinfo +{ + struct basilisk_request R; + bits256 srchash,desthash,txid,txid2,desttxid,privkey; + uint64_t satoshis,satoshis2,txfee,destsatoshis,desttxfee,change; + uint32_t timestamp,quotetime; int32_t vout,vout2,destvout,pair; + char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; +}; + static struct bitcoin_opcode { UT_hash_handle hh; uint8_t opcode,flags,stackitems; int8_t extralen; } *OPTABLE; static char *OPCODES[0x100]; static int32_t OPCODELENS[0x100]; #define SIGHASH_ALL 1 @@ -470,7 +479,7 @@ enum opcodetype void basilisk_dontforget_update(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx); uint32_t basilisk_requestid(struct basilisk_request *rp); uint32_t basilisk_quoteid(struct basilisk_request *rp); -struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp); +struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp,struct LP_quoteinfo *qp); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); struct iguana_info *LP_coinfind(char *symbol); void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 29c81b18e..90e56063e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -58,15 +58,6 @@ struct LP_utxoinfo uint16_t port; } *LP_utxoinfos; -struct LP_quoteinfo -{ - struct basilisk_request R; - bits256 srchash,desthash,txid,txid2,desttxid,privkey; - uint64_t satoshis,satoshis2,txfee,destsatoshis,desttxfee,change; - uint32_t timestamp,quotetime; int32_t vout,vout2,destvout,pair; - char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; -}; - struct LP_cacheinfo { UT_hash_handle hh; diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 18b7eaa4f..79df18dff 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -538,7 +538,7 @@ void LP_aliceloop(void *_qp) maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + 10; - swap = LP_swapinit(0,0,qp->privkey,&qp->R); + swap = LP_swapinit(0,0,qp->privkey,&qp->R,qp); if ( swap != 0 ) { if ( LP_sendwait("pubkeys",10,qp->pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) @@ -977,7 +977,7 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 return(swap); } -struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp) +struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp,struct LP_quoteinfo *qp) { struct basilisk_swap *swap; bits256 pubkey25519; uint8_t pubkey33[33]; swap = calloc(1,sizeof(*swap)); @@ -996,6 +996,9 @@ struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 free(swap); swap = 0; } + swap->bobpayment.utxotxid = qp->txid, swap->bobpayment.utxovout = qp->vout; + swap->bobdeposit.utxotxid = qp->txid2, swap->bobdeposit.utxovout = qp->vout2; + swap->alicepayment.utxotxid = qp->desttxid, swap->alicepayment.utxovout = qp->destvout; return(swap); } From b6293004cd31315b49b7395cde059fc9fbd0f453 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:37:35 +0300 Subject: [PATCH 0830/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 79df18dff..3837d1b7b 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -907,7 +907,7 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 return(0); } if ( (coin= LP_coinfind(swap->I.req.dest)) != 0 ) - swap->bobcoin = *coin; + swap->alicecoin = *coin; else { printf("missing bobcoin.%p or missing alicecoin.%p src.%p dest.%p\n",&swap->bobcoin,&swap->alicecoin,LP_coinfind(swap->I.req.src),LP_coinfind(swap->I.req.dest)); @@ -915,7 +915,7 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 return(0); } if ( (coin= LP_coinfind(swap->I.req.src)) != 0 ) - swap->alicecoin = *coin; + swap->bobcoin = *coin; else { printf("missing bobcoin.%p or missing alicecoin.%p src.%p dest.%p\n",&swap->bobcoin,&swap->alicecoin,LP_coinfind(swap->I.req.src),LP_coinfind(swap->I.req.dest)); From 25eee9e0b451cdf12d881e08ec1989114db0df8c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:41:01 +0300 Subject: [PATCH 0831/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 - 1 file changed, 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 90e56063e..4c8a8e28f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -751,7 +751,6 @@ struct iguana_info *LP_coinfind(char *symbol) } else { - cdata.isPoS = 1; cdata.pubtype = 60; cdata.p2shtype = 85; cdata.wiftype = 188; From 9b7ba324ca6d531b920c7e732c099596dc479620 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:43:08 +0300 Subject: [PATCH 0832/2705] Test --- iguana/exchanges/LP_transaction.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 99bb86bfb..ac40faa22 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -621,10 +621,11 @@ cJSON *LP_createvins(struct basilisk_rawtx *dest,struct vin_info *V,struct basil jaddbits256(item,"txid",rawtx->I.actualtxid); else jaddbits256(item,"txid",rawtx->I.signedtxid); jaddnum(item,"vout",0); - sobj = cJSON_CreateObject(); + //sobj = cJSON_CreateObject(); init_hexbytes_noT(hexstr,rawtx->spendscript,rawtx->I.spendlen); - jaddstr(sobj,"hex",hexstr); - jadd(item,"scriptPubKey",sobj); + //jaddstr(sobj,"hex",hexstr); + //jadd(item,"scriptPubKey",sobj); + jaddstr(item,"scriptPubKey",hexstr); jaddnum(item,"suppress",dest->I.suppress_pubkeys); jaddnum(item,"sequence",sequenceid); if ( (dest->I.redeemlen= rawtx->I.redeemlen) != 0 ) From cb49fee8ae18982eaf1ad85b18d17c99ab289371 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:44:49 +0300 Subject: [PATCH 0833/2705] Test --- iguana/exchanges/LP_transaction.c | 7 ++++--- iguana/exchanges/mm.c | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index ac40faa22..cca131464 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -810,7 +810,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } jaddbits256(item,"txid",utxotxid); jaddnum(item,"vout",vout); - sobj = cJSON_CreateObject(); + //sobj = cJSON_CreateObject(); bitcoin_address(destaddr,pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); /*int32_t i; @@ -826,8 +826,9 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf(" <- vs direct calc\n");*/ spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); - jaddstr(sobj,"hex",hexstr); - jadd(item,"scriptPubKey",sobj); + //jaddstr(sobj,"hex",hexstr); + //jadd(item,"scriptPubKey",sobj); + jaddstr(item,"scriptPubKey",hexstr); jaddnum(item,"suppress",suppress_pubkeys); jaddnum(item,"sequence",sequenceid); if ( redeemlen != 0 ) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 34312e13a..703f70dd7 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -833,7 +833,7 @@ int main(int argc, const char * argv[]) while ( 1 ) { theoretical = marketmaker_updateprice("komodo","KMD","BTC",theoretical,&incr); - sleep(30); + sleep(10); if ( jint(retjson,"client") != 0 ) { struct LP_utxoinfo *utxo,*utmp; @@ -843,6 +843,7 @@ int main(int argc, const char * argv[]) printf("bestprice (%s)\n",jprint(matchjson,1)); } } + sleep(1000); } profitmargin = jdouble(retjson,"profitmargin"); minask = jdouble(retjson,"minask"); From a69d5fc6f6c8aefed284ab6442fefc59bb48f7bc Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:46:48 +0300 Subject: [PATCH 0834/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index d6a3dfeab..904fe7a2b 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -208,7 +208,7 @@ printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); len = (int32_t)strlen(hexstr); signedtx = calloc(1,len+1); strcpy(signedtx,hexstr); - *completedp = jint(json,"completed"); + *completedp = is_cJSON_True(jobj(json,"complete")); data = malloc(len >> 1); decode_hex(data,len>>1,hexstr); *signedtxidp = bits256_doublesha256(0,data,len >> 1); From d4933ab98edebe76ab953125e7887e0e6a7431bf Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:56:17 +0300 Subject: [PATCH 0835/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_transaction.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 904fe7a2b..e36dc2b81 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -200,7 +200,7 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * //printf("signrawtransaction\n"); if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"signrawtransaction",paramstr)) != 0 ) { -printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); +//printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); if ( (json= cJSON_Parse(retstr)) != 0 ) { if ( (hexstr= jstr(json,"hex")) != 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index cca131464..eddcd4118 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -757,7 +757,7 @@ int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8 char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*sobj,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -844,10 +844,10 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch { //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) - printf("couldnt sign transaction\n"); + printf("couldnt sign transaction.%s\n",name); else if ( completed == 0 ) { - printf("incomplete signing\n"); + printf("incomplete signing %s\n",name); if ( signedtx != 0 ) free(signedtx), signedtx = 0; } else printf("%s -> %s\n",name,bits256_str(str,*signedtxidp)); @@ -1432,7 +1432,7 @@ int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) { - int32_t i,j; //char str[65]; + int32_t j; //char str[65]; if ( genflag != 0 && swap->I.iambob == 0 ) printf("basilisk_bobscripts_set WARNING: alice generating BOB tx\n"); if ( depositflag == 0 ) @@ -1444,7 +1444,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i //printf(" <- bobpayment.%d\n",i); if ( genflag != 0 && bits256_nonz(*(bits256 *)swap->I.secretBn256) != 0 && swap->bobpayment.I.datalen == 0 ) { - for (i=0; i<3; i++) + //for (i=0; i<3; i++) { //if ( swap->bobpayment.txbytes != 0 && swap->bobpayment.I.spendlen != 0 ) // break; @@ -1477,7 +1477,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) { - for (i=0; i<3; i++) + //for (i=0; i<3; i++) { //if ( swap->bobdeposit.txbytes != 0 && swap->bobdeposit.I.spendlen != 0 ) // break; From 942688e9290d085d335c55e7358b75a40d195955 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 11:58:48 +0300 Subject: [PATCH 0836/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index e36dc2b81..801954ceb 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -200,7 +200,6 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * //printf("signrawtransaction\n"); if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"signrawtransaction",paramstr)) != 0 ) { -//printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); if ( (json= cJSON_Parse(retstr)) != 0 ) { if ( (hexstr= jstr(json,"hex")) != 0 ) @@ -212,6 +211,7 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * data = malloc(len >> 1); decode_hex(data,len>>1,hexstr); *signedtxidp = bits256_doublesha256(0,data,len >> 1); + printf("%s signrawtransaction.(%s) params.(%s) -> \nsignedtx.(%s)\n",coin->symbol,retstr,paramstr,signedtx); } free_json(json); } From d73a608326b47c8ad7260a3e86c2288409bfa60d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 12:05:05 +0300 Subject: [PATCH 0837/2705] Test --- iguana/exchanges/LP_rpc.c | 3 +++ iguana/exchanges/LP_transaction.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 801954ceb..ee8bd29b2 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -191,7 +191,10 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * memset(signedtxidp,0,sizeof(*signedtxidp)); *completedp = 0; if ( coin == 0 ) + { + printf("LP_signrawtx cant find coin.(%s)\n",symbol); return(0); + } array = cJSON_CreateArray(); jaddistr(array,rawtx); jaddi(array,jduplicate(vins)); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index eddcd4118..bad3640f6 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -842,9 +842,12 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); if ( (rawtxbytes= bitcoin_json2hex(isPoS,&txid,txobj,V)) != 0 ) { + char str[65]; + completed = 0; + memset(signedtxidp,0,sizeof(*signedtxidp)); //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) - printf("couldnt sign transaction.%s\n",name); + printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); else if ( completed == 0 ) { printf("incomplete signing %s\n",name); From 2a0ba4b6762056a3eb5fd536be39ceedd0185676 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 12:08:35 +0300 Subject: [PATCH 0838/2705] Test --- iguana/exchanges/LP_rpc.c | 1 + iguana/exchanges/LP_transaction.c | 2 +- iguana/exchanges/mm.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index ee8bd29b2..c901bf1aa 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -221,5 +221,6 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * free(retstr); } free(paramstr); + printf("return signedtx.%p\n",signedtx); return(signedtx); } diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index bad3640f6..f0a002ee7 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1500,7 +1500,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i //printf(" <- redeem.%d\n",swap->bobdeposit.redeemlen); //printf("GENERATED BOB DEPOSIT\n"); LP_unspents_mark(swap->bobcoin.symbol,swap->bobdeposit.vins); - basilisk_bobdeposit_refund(swap,swap->I.putduration); + //basilisk_bobdeposit_refund(swap,swap->I.putduration); printf("bobscripts set completed\n"); return(0); } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 703f70dd7..ebcc50b5b 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -833,7 +833,7 @@ int main(int argc, const char * argv[]) while ( 1 ) { theoretical = marketmaker_updateprice("komodo","KMD","BTC",theoretical,&incr); - sleep(10); + sleep(3); if ( jint(retjson,"client") != 0 ) { struct LP_utxoinfo *utxo,*utmp; From 94ed5048cd1baad2c650d4d2e9f6b7634890b264 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 12:09:54 +0300 Subject: [PATCH 0839/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index ebcc50b5b..703f70dd7 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -833,7 +833,7 @@ int main(int argc, const char * argv[]) while ( 1 ) { theoretical = marketmaker_updateprice("komodo","KMD","BTC",theoretical,&incr); - sleep(3); + sleep(10); if ( jint(retjson,"client") != 0 ) { struct LP_utxoinfo *utxo,*utmp; From 29ee53b3b5be2ff95cf253df102664ed82e7fdd4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 12:21:02 +0300 Subject: [PATCH 0840/2705] Test --- iguana/exchanges/LP_commands.c | 11 +++++++++++ iguana/exchanges/LP_include.h | 4 ++-- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_swap.c | 5 ++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9208a6006..ca22231aa 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -79,6 +79,11 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) jaddbits256(retjson,"desttxid",qp->desttxid); jaddnum(retjson,"destvout",qp->destvout); } + if ( bits256_nonz(qp->feetxid) != 0 ) + { + jaddbits256(retjson,"feetxid",qp->feetxid); + jaddnum(retjson,"feevout",qp->feevout); + } if ( qp->destsatoshis != 0 ) jadd64bits(retjson,"destsatoshis",qp->destsatoshis); if ( qp->desttxfee != 0 ) @@ -100,8 +105,10 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) qp->txid2 = jbits256(argjson,"txid2"); qp->vout = jint(argjson,"vout"); qp->vout2 = jint(argjson,"vout2"); + qp->feevout = jint(argjson,"feevout"); qp->srchash = jbits256(argjson,"srchash"); qp->desttxid = jbits256(argjson,"desttxid"); + qp->feetxid = jbits256(argjson,"feetxid"); qp->destvout = jint(argjson,"destvout"); qp->desthash = jbits256(argjson,"desthash"); if ( (qp->satoshis= j64bits(argjson,"satoshis")) == 0 ) @@ -327,6 +334,8 @@ cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) i = besti; Q[i].desttxid = myutxo->txid; Q[i].destvout = myutxo->vout; + Q[i].feetxid = myutxo->txid2; + Q[i].feevout = myutxo->vout2; strcpy(Q[i].destaddr,myutxo->coinaddr); price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); if ( jobj(bestitem,"price") != 0 ) @@ -336,6 +345,8 @@ cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) { Q[i].desttxid = myutxo->txid; Q[i].destvout = myutxo->vout; + Q[i].feetxid = myutxo->txid2; + Q[i].feevout = myutxo->vout2; strcpy(Q[i].destaddr,myutxo->coinaddr); price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index a7ec599ed..5ee18b1a7 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -202,9 +202,9 @@ struct basilisk_swap struct LP_quoteinfo { struct basilisk_request R; - bits256 srchash,desthash,txid,txid2,desttxid,privkey; + bits256 srchash,desthash,txid,txid2,desttxid,feetxid,privkey; uint64_t satoshis,satoshis2,txfee,destsatoshis,desttxfee,change; - uint32_t timestamp,quotetime; int32_t vout,vout2,destvout,pair; + uint32_t timestamp,quotetime; int32_t vout,vout2,destvout,feevout,pair; char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; }; diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index c901bf1aa..7000057d5 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -214,8 +214,8 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * data = malloc(len >> 1); decode_hex(data,len>>1,hexstr); *signedtxidp = bits256_doublesha256(0,data,len >> 1); - printf("%s signrawtransaction.(%s) params.(%s) -> \nsignedtx.(%s)\n",coin->symbol,retstr,paramstr,signedtx); } + else printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); free_json(json); } free(retstr); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 3837d1b7b..92db527c8 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -410,7 +410,7 @@ int32_t LP_mostprivs_verify(struct basilisk_swap *swap,uint8_t *data,int32_t dat swap->I.secretAm[i] = data[len++]; for (i=0; i<32; i++) swap->I.secretAm256[i] = data[len++]; - basilisk_bobscripts_set(swap,1,1); + //basilisk_bobscripts_set(swap,1,1); } else { @@ -999,6 +999,9 @@ struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 swap->bobpayment.utxotxid = qp->txid, swap->bobpayment.utxovout = qp->vout; swap->bobdeposit.utxotxid = qp->txid2, swap->bobdeposit.utxovout = qp->vout2; swap->alicepayment.utxotxid = qp->desttxid, swap->alicepayment.utxovout = qp->destvout; + if ( iambob != 0 ) + swap->otherfee.utxotxid = qp->feetxid, swap->otherfee.utxovout = qp->feevout; + else swap->myfee.utxotxid = qp->feetxid, swap->myfee.utxovout = qp->feevout; return(swap); } From c4f561430344c8818394e1ba57228a372bd871a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 12:28:17 +0300 Subject: [PATCH 0841/2705] Test --- iguana/exchanges/LP_rpc.c | 1 - iguana/exchanges/LP_swap.c | 2 -- iguana/exchanges/LP_transaction.c | 6 +++--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 7000057d5..d35568d2d 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -221,6 +221,5 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * free(retstr); } free(paramstr); - printf("return signedtx.%p\n",signedtx); return(signedtx); } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 92db527c8..0bf13129d 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -216,10 +216,8 @@ int32_t LP_pubkeys_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datal int32_t i,len = 0; if ( datalen == sizeof(swap->otherdeck) ) { - printf("extract pubkeys\n"); for (i=0; iotherdeck)/sizeof(swap->otherdeck[0][0]); i++) len += iguana_rwnum(0,&data[len],sizeof(swap->otherdeck[i>>1][i&1]),&swap->otherdeck[i>>1][i&1]); - printf("done extract pubkeys\n"); return(0); } printf("pubkeys verify size mismatch %d != %d\n",datalen,(int32_t)sizeof(swap->otherdeck)); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index f0a002ee7..8b5e25291 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1715,15 +1715,15 @@ int32_t basilisk_alicetxs(struct basilisk_swap *swap,uint8_t *data,int32_t maxle } if ( swap->myfee.I.datalen == 0 ) { - printf("generate fee\n"); + //printf("generate fee\n"); if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey) == 0 ) { swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x80,data,maxlen,&swap->myfee,0x40,0); LP_unspents_mark(swap->I.iambob!=0?swap->bobcoin.symbol:swap->alicecoin.symbol,swap->myfee.vins); //basilisk_txlog(swap,&swap->myfee,-1); - for (i=0; imyfee.I.spendlen; i++) + for (i=0; imyfee.I.datalen; i++) printf("%02x",swap->myfee.txbytes[i]); - printf(" fee %p %x\n",swap->myfee.txbytes,swap->I.statebits); + printf(" <- fee state.%x\n",swap->I.statebits); swap->I.statebits |= 0x40; } else From 0987f2de40f496f5e2efa296fcdc1933d7162b19 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 12:57:28 +0300 Subject: [PATCH 0842/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_remember.c | 8 ++--- iguana/exchanges/LP_transaction.c | 55 +++++++++++++++++++++---------- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 319552e58..781a50930 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1279,7 +1279,7 @@ cJSON *bitcoin_txoutput(cJSON *txobj,uint8_t *paymentscript,int32_t len,uint64_t jaddstr(skey,"hex",hexstr); //printf("addoutput.(%s %s)\n",hexstr,jprint(skey,0)); free(hexstr); - jadd(item,"scriptPubkey",skey); + jadd(item,"scriptPubKey",skey); jaddi(vouts,item); jadd(txobj,"vout",vouts); return(txobj); diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 5ee18b1a7..39567a5fe 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -195,7 +195,7 @@ struct basilisk_swap struct basilisk_swapmessage *messages; int32_t nummessages; char Bdeposit[64],Bpayment[64]; uint64_t otherdeck[INSTANTDEX_DECKSIZE][2],deck[INSTANTDEX_DECKSIZE][2]; - uint8_t persistent_pubkey33[33],pad[15],verifybuf[65536]; + uint8_t persistent_pubkey33[33],changermd160[20],pad[15],verifybuf[65536]; }; diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index d8951c9a5..efa8e8a59 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -748,7 +748,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); printf("alicespend len.%d redeemlen.%d\n",len,redeemlen); - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND])) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } @@ -773,7 +773,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM])) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0)) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } @@ -849,7 +849,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM])) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0)) != 0 ) { int32_t z; for (z=0; z<20; z++) @@ -879,7 +879,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND])) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 8b5e25291..f4f3ca59b 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -755,9 +755,9 @@ int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8 } #endif -char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp) +char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount,change = 0; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -777,6 +777,8 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch return(0); } else free_json(utxoobj); *destamountp = destamount; + if ( satoshis != 0 && destamount > satoshis+txfee ) + change = destamount - (satoshis - txfee); if ( destamount > txfee ) destamount -= txfee; timestamp = (uint32_t)time(NULL); @@ -840,6 +842,13 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jdelete(txobj,"vin"); jadd(txobj,"vin",vins); txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); + if ( change != 0 ) + { + int32_t changelen; uint8_t changescript[1024],changetype,changermd160[20]; + bitcoin_addr2rmd160(&changetype,changermd160,changeaddr); + changelen = bitcoin_standardspend(changescript,0,changermd160); + txobj = bitcoin_txoutput(txobj,changescript,changelen,change); + } if ( (rawtxbytes= bitcoin_json2hex(isPoS,&txid,txobj,V)) != 0 ) { char str[65]; @@ -862,15 +871,20 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch return(signedtx); } -int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey) +int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160) { - int32_t retval=-1,len,iter; char *signedtx; struct iguana_info *coin; int64_t newtxfee=0,destamount; + int32_t retval=-1,len,iter; char *signedtx,*changeaddr = 0,_changeaddr[64]; struct iguana_info *coin; int64_t newtxfee=0,destamount; if ( (coin= rawtx->coin) == 0 ) return(-1); //return(_basilisk_rawtx_gen(str,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay,privkey)); + if ( changermd160 != 0 ) + { + changeaddr = _changeaddr; + bitcoin_address(changeaddr,coin->pubtype,changermd160,20); + } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,pubkey33,1,0,&destamount)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -892,18 +906,23 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub return(retval); } -int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) +int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160) { - char *signedtx; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; double estimatedrate; + char *signedtx,*changeaddr = 0,_changeaddr[64]; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; double estimatedrate; timestamp = swap->I.started; if ( dest == &swap->aliceclaim ) locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; else if ( dest == &swap->bobreclaim ) locktime = swap->bobpayment.I.locktime + 1, sequenceid = 0; txfee = strcmp("BTC",symbol) == 0 ? 0 : 10000; + if ( changermd160 != 0 ) + { + changeaddr = _changeaddr; + bitcoin_address(changeaddr,pubtype,changermd160,20); + } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,rawtx->pubkey33,1,0,&destamount)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,rawtx->pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -959,7 +978,7 @@ char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2sht for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ txfee = LP_txfee(symbol); - signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration,destamountp); + signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration,destamountp,0,0); } return(signedtx); } @@ -1314,7 +1333,7 @@ int32_t basilisk_bobpayment_reclaim(struct basilisk_swap *swap,int32_t delay) len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); memcpy(swap->I.userdata_bobreclaim,userdata,len); swap->I.userdata_bobreclaimlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1,swap->changermd160)) == 0 ) { for (i=0; ibobreclaim.I.datalen; i++) printf("%02x",swap->bobreclaim.txbytes[i]); @@ -1400,7 +1419,7 @@ int32_t basilisk_verify_bobpaid(void *ptr,uint8_t *data,int32_t datalen) memcpy(swap->I.userdata_alicespend,userdata,len); swap->I.userdata_alicespendlen = len; char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) { for (i=0; ibobpayment.I.datalen; i++) printf("%02x",swap->bobpayment.txbytes[i]); @@ -1422,7 +1441,7 @@ int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) len = basilisk_swapuserdata(userdata,swap->I.privBn,0,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_bobrefund,userdata,len); swap->I.userdata_bobrefundlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0,swap->changermd160)) == 0 ) { for (i=0; ibobrefund.I.datalen; i++) printf("%02x",swap->bobrefund.txbytes[i]); @@ -1451,7 +1470,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i { //if ( swap->bobpayment.txbytes != 0 && swap->bobpayment.I.spendlen != 0 ) // break; - basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey); + basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160); if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) { printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); @@ -1484,7 +1503,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i { //if ( swap->bobdeposit.txbytes != 0 && swap->bobdeposit.I.spendlen != 0 ) // break; - basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey); + basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160); if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) { printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); @@ -1624,7 +1643,7 @@ int32_t basilisk_verify_bobdeposit(void *ptr,uint8_t *data,int32_t datalen) len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_aliceclaim,userdata,len); swap->I.userdata_aliceclaimlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) { for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); @@ -1643,7 +1662,7 @@ int32_t basilisk_verify_bobdeposit(void *ptr,uint8_t *data,int32_t datalen) void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) { alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); - basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey); + basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160); } int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_rawtx *dest) @@ -1662,7 +1681,7 @@ int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_r memcpy(swap->I.userdata_bobspend,swap->alicepayment.redeemscript,swap->alicepayment.I.spendlen); swap->I.userdata_bobspendlen = swap->alicepayment.I.spendlen; } - if ( (retval= basilisk_rawtx_sign(swap->alicecoin.symbol,swap->alicecoin.pubtype,swap->alicecoin.p2shtype,swap->alicecoin.isPoS,swap->alicecoin.wiftype,swap,dest,&swap->alicepayment,swap->I.privAm,&swap->I.privBn,0,0,1)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->alicecoin.symbol,swap->alicecoin.pubtype,swap->alicecoin.p2shtype,swap->alicecoin.isPoS,swap->alicecoin.wiftype,swap,dest,&swap->alicepayment,swap->I.privAm,&swap->I.privBn,0,0,1,swap->changermd160)) == 0 ) { for (i=0; iI.datalen; i++) printf("%02x",dest->txbytes[i]); @@ -1716,7 +1735,7 @@ int32_t basilisk_alicetxs(struct basilisk_swap *swap,uint8_t *data,int32_t maxle if ( swap->myfee.I.datalen == 0 ) { //printf("generate fee\n"); - if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey) == 0 ) + if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160) == 0 ) { swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x80,data,maxlen,&swap->myfee,0x40,0); LP_unspents_mark(swap->I.iambob!=0?swap->bobcoin.symbol:swap->alicecoin.symbol,swap->myfee.vins); From 3a6220cd80bb92c6c6f8503389bb2367eb4d391b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 12:59:33 +0300 Subject: [PATCH 0843/2705] Test --- iguana/exchanges/LP_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 0bf13129d..11b41a792 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -988,6 +988,7 @@ struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 swap->persistent_pubkey = pubkey25519; swap->persistent_privkey = privkey; memcpy(swap->persistent_pubkey33,pubkey33,33); + calc_rmd160_sha256(swap->changermd160,pubkey33,33); if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,!iambob) == 0 ) { printf("error doing swapinit\n"); From 1d343f8bd36e1056658a5e78716b4cb7eef9e0e4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:08:28 +0300 Subject: [PATCH 0844/2705] Test --- iguana/exchanges/LP_swap.c | 149 ------------------------------ iguana/exchanges/LP_transaction.c | 13 ++- 2 files changed, 11 insertions(+), 151 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 11b41a792..2fffa34dd 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -1004,152 +1004,3 @@ struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 return(swap); } -#ifdef notanymore -struct basilisk_swap *basilisk_thread_start(bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) -{ - int32_t i,m,n,iter; uint8_t pubkey33[33]; bits256 pubkey25519; uint32_t channel,starttime; cJSON *retarray,*item,*msgobj; struct iguana_info *coin; double pending=0.; struct basilisk_swap *swap = 0; - // statebits 1 -> client, 0 -> LP - /*if ( myinfo->numswaps > 0 ) - { - if ( (coin= LP_coinfind(rp->src)) == 0 || coin->FULLNODE >= 0 ) - { - printf("dont have SRC coin.%s or not native and already swap pending\n",rp->src); - return(0); - } - if ( (coin= LP_coinfind(rp->dest)) == 0 || coin->FULLNODE >= 0 ) - { - printf("dont have DEST coin.%s or not native and already swap pending\n",rp->dest); - return(0); - } - } - portable_mutex_lock(&myinfo->DEX_swapmutex); - for (i=0; inumswaps; i++) - if ( myinfo->swaps[i]->I.req.requestid == rp->requestid ) - { - printf("basilisk_thread_start error trying to start requestid.%u which is already started\n",rp->requestid); - break; - } - if ( i == myinfo->numswaps && i < sizeof(myinfo->swaps)/sizeof(*myinfo->swaps) )*/ - { - swap = calloc(1,sizeof(*swap)); - swap->ctx = bitcoin_ctx(); - swap->subsock = swap->pushsock = -1; - vcalc_sha256(0,swap->I.orderhash.bytes,(uint8_t *)rp,sizeof(*rp)); - swap->I.req = *rp; - //swap->myinfoptr = myinfo; - printf("basilisk_thread_start request.%u statebits.%d (%s/%s) reinit.%d\n",rp->requestid,statebits,rp->src,rp->dest,reinit); - bitcoin_pubkey33(swap->ctx,pubkey33,privkey); - pubkey25519 = curve25519(privkey,curve25519_basepoint9()); - swap->persistent_pubkey = pubkey25519; - swap->persistent_privkey = privkey; - memcpy(swap->persistent_pubkey33,pubkey33,33); - m = n = 0; - if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,statebits,reinit) != 0 ) - { - for (iter=0; iter<16; iter++) - { - basilisk_psockinit(swap,statebits == 0); - sleep(3); - if ( swap->connected > 0 ) - break; - sleep(10); - /*basilisk_sendstate(swap,data,sizeof(data)); - basilisk_swapget(swap,0x80000000,data,sizeof(data),basilisk_verify_statebits); - if ( swap->connected > 0 ) - break; - printf("loopback didntwork with %d %d\n",swap->pushsock,swap->subsock);*/ - } - if ( reinit != 0 ) - { - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) - { - - } - //myinfo->swaps[myinfo->numswaps++] = swap; - } - else - { - starttime = (uint32_t)time(NULL); - printf("statebits.%x m.%d n.%d\n",statebits,m,n); - while ( statebits == 0 && m <= n/2 && time(NULL) < starttime+7*BASILISK_MSGDURATION ) - { - uint32_t msgid; uint8_t data[1024]; int32_t datalen; - m = n = 0; - sleep(DEX_SLEEP); - printf("waiting for offer to be accepted\n"); - channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); - datalen = basilisk_rwDEXquote(1,data,rp); - msgid = (uint32_t)time(NULL); - printf("other req.%d >>>>>>>>>>> send response (%llx -> %llx) r.%u quoteid.%u\n",i,(long long)rp->desthash.txid,(long long)rp->srchash.txid,rp->requestid,rp->quoteid); - LP_channelsend(rp->desthash,rp->srchash,channel,msgid,data,datalen); - if ( (retarray= basilisk_channelget(rp->srchash,rp->desthash,channel,0x4000000,30)) != 0 ) - { - if ( is_cJSON_Array(retarray) != 0 && (n= cJSON_GetArraySize(retarray)) > 0 ) - { - for (i=0; i 0 ) - { - item = jitem(msgobj,0); - if ( jobj(item,"data") != 0 && jobj(item,"key") != 0 ) - m++; - else printf("(%s)\n",jprint(item,0)); - } //else printf("msgobj.%p m.%d n.%d\n",msgobj,m,n); - } - } - } else printf("no retarray\n"); - } - printf("LAUNCH check.%d m.%d\n",statebits,m); - if ( statebits != 0 || m > 0 )//n/2 ) - { - //for (i=0; iI.req); i++) - // fprintf(stderr,"%02x",((uint8_t *)&swap->I.req)[i]); - if ( (swap->fp= basilisk_swap_save(swap,privkey,rp,statebits,optionduration,reinit)) != 0 ) - { - } - if ( reinit == 0 ) - { - static FILE *swapsfp; - if ( swapsfp == 0 ) - { - char fname[512]; - sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); - if ( (swapsfp= fopen(fname,"rb+")) == 0 ) - swapsfp = fopen(fname,"wb+"); - else fseek(swapsfp,0,SEEK_END); - printf("LIST fp.%p\n",swapsfp); - } - if ( swapsfp != 0 ) - { - fwrite(&rp->requestid,1,sizeof(rp->requestid),swapsfp); - fwrite(&rp->quoteid,1,sizeof(rp->quoteid),swapsfp); - fflush(swapsfp); - } - } - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) - { - - } - //myinfo->swaps[myinfo->numswaps++] = swap; - } - else - { - if ( statebits != 0 ) - { - if ( (coin= LP_coinfind(rp->src)) != 0 ) - { - - } - } - printf("%u/%u offer wasnt accepted statebits.%d m.%d n.%d pending %.8f\n",rp->requestid,rp->quoteid,statebits,m,n,pending); - } - } - } - } - //portable_mutex_unlock(&myinfo->DEX_swapmutex); - return(swap); -} -#endif - - diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index f4f3ca59b..8a27b4255 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -776,11 +776,17 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch free_json(utxoobj); return(0); } else free_json(utxoobj); + if ( satoshis != 0 ) + { + if ( destamount > satoshis+txfee ) + change = destamount - (satoshis - txfee); + printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(destamount),dstr(satoshis),dstr(change),dstr(txfee)); + destamount = satoshis; + } *destamountp = destamount; - if ( satoshis != 0 && destamount > satoshis+txfee ) - change = destamount - (satoshis - txfee); if ( destamount > txfee ) destamount -= txfee; + else printf("unexpected too small destamount %.8f txfee %.8f\n",dstr(destamount),dstr(txfee)); timestamp = (uint32_t)time(NULL); V = calloc(256,sizeof(*V)); privkeys = cJSON_CreateArray(); @@ -848,6 +854,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch bitcoin_addr2rmd160(&changetype,changermd160,changeaddr); changelen = bitcoin_standardspend(changescript,0,changermd160); txobj = bitcoin_txoutput(txobj,changescript,changelen,change); + printf("add change.(%s)\n",jprint(txobj,0)); } if ( (rawtxbytes= bitcoin_json2hex(isPoS,&txid,txobj,V)) != 0 ) { @@ -881,6 +888,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub { changeaddr = _changeaddr; bitcoin_address(changeaddr,coin->pubtype,changermd160,20); + printf("changeaddr.(%s)\n",changeaddr); } for (iter=0; iter<2; iter++) { @@ -919,6 +927,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ { changeaddr = _changeaddr; bitcoin_address(changeaddr,pubtype,changermd160,20); + printf("changeaddr.(%s)\n",changeaddr); } for (iter=0; iter<2; iter++) { From 22447b12ed6caa84e9e85f4636062403f41efd4b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:13:06 +0300 Subject: [PATCH 0845/2705] Test --- iguana/exchanges/LP_swap.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 2fffa34dd..f107203d3 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -873,14 +873,14 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 swap->I.putduration -= optionduration; else if ( optionduration > 0 ) swap->I.callduration += optionduration; - swap->I.bobsatoshis = swap->I.req.destamount; - swap->I.alicesatoshis = swap->I.req.srcamount; + swap->I.bobsatoshis = swap->I.req.srcamount; + swap->I.alicesatoshis = swap->I.req.destamount; if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) swap->I.bobinsurance = 50000; if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) swap->I.aliceinsurance = 50000; - strcpy(swap->I.bobstr,swap->I.req.dest); - strcpy(swap->I.alicestr,swap->I.req.src); + strcpy(swap->I.bobstr,swap->I.req.src); + strcpy(swap->I.alicestr,swap->I.req.dest); swap->I.started = (uint32_t)time(NULL); swap->I.expiration = swap->I.req.timestamp + swap->I.putduration + swap->I.callduration; OS_randombytes((uint8_t *)&swap->I.choosei,sizeof(swap->I.choosei)); @@ -904,7 +904,7 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 char str[65]; printf("couldnt generate privkeys %d %s\n",x,bits256_str(str,privkey)); return(0); } - if ( (coin= LP_coinfind(swap->I.req.dest)) != 0 ) + if ( (coin= LP_coinfind(swap->I.alicestr)) != 0 ) swap->alicecoin = *coin; else { @@ -912,7 +912,7 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 free(swap); return(0); } - if ( (coin= LP_coinfind(swap->I.req.src)) != 0 ) + if ( (coin= LP_coinfind(swap->I.bobstr)) != 0 ) swap->bobcoin = *coin; else { From 6128ac5b4f79d446c9f0d4fc9054f194391bbc6c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:15:29 +0300 Subject: [PATCH 0846/2705] Test --- iguana/exchanges/LP_include.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 39567a5fe..db85f0489 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -25,7 +25,7 @@ #define BASILISK_DISABLESENDTX #define LP_RESERVETIME 60 -#define LP_AVETXSIZE 500 +#define LP_AVETXSIZE 200 #define LP_CACHEDURATION 60 #define BASILISK_DEFAULT_NUMCONFIRMS 5 From cce067bc10123ea15e0bd93524acf8d2431a97e0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:23:33 +0300 Subject: [PATCH 0847/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 +-- iguana/exchanges/LP_remember.c | 8 ++++---- iguana/exchanges/LP_swap.c | 8 ++++---- iguana/exchanges/LP_transaction.c | 17 ++++++++++------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4c8a8e28f..312ae6468 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -18,7 +18,6 @@ // marketmaker // // jl777: fix price calcs based on specific txfees -// jl777: add change output #include #include "LP_include.h" @@ -809,7 +808,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb depositval = values[i]; values[i] = 0, used++; if ( amclient != 0 ) - targetval = (depositval / 777); + targetval = (depositval / 776) + 50000; else targetval = (depositval / 9) * 8; //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index efa8e8a59..d52a9838c 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -748,7 +748,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); printf("alicespend len.%d redeemlen.%d\n",len,redeemlen); - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } @@ -773,7 +773,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0)) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0)) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } @@ -849,7 +849,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0)) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0)) != 0 ) { int32_t z; for (z=0; z<20; z++) @@ -879,7 +879,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0)) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index f107203d3..a5b60731c 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -875,10 +875,10 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 swap->I.callduration += optionduration; swap->I.bobsatoshis = swap->I.req.srcamount; swap->I.alicesatoshis = swap->I.req.destamount; - if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) - swap->I.bobinsurance = 50000; - if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < 50000 ) - swap->I.aliceinsurance = 50000; + if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < 10000 ) + swap->I.bobinsurance = 10000; + if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < 10000 ) + swap->I.aliceinsurance = 10000; strcpy(swap->I.bobstr,swap->I.req.src); strcpy(swap->I.alicestr,swap->I.req.dest); swap->I.started = (uint32_t)time(NULL); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 8a27b4255..11b1c96b6 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -755,9 +755,9 @@ int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8 } #endif -char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) +char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount,change = 0; + char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount,change = 0; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -819,7 +819,11 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jaddbits256(item,"txid",utxotxid); jaddnum(item,"vout",vout); //sobj = cJSON_CreateObject(); - bitcoin_address(destaddr,pubtype,pubkey33,33); + if ( destaddr == 0 ) + { + destaddr = _destaddr; + bitcoin_address(destaddr,pubtype,pubkey33,33); + } bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); /*int32_t i; for (i=0; i<33; i++) @@ -854,7 +858,6 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch bitcoin_addr2rmd160(&changetype,changermd160,changeaddr); changelen = bitcoin_standardspend(changescript,0,changermd160); txobj = bitcoin_txoutput(txobj,changescript,changelen,change); - printf("add change.(%s)\n",jprint(txobj,0)); } if ( (rawtxbytes= bitcoin_json2hex(isPoS,&txid,txobj,V)) != 0 ) { @@ -892,7 +895,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -931,7 +934,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,rawtx->pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,rawtx->pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -987,7 +990,7 @@ char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2sht for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ txfee = LP_txfee(symbol); - signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,pubkey33,1,expiration,destamountp,0,0); + signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0); } return(signedtx); } From 4c4f0123d49ff4f0b65b97a66840a396285f0df0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:28:24 +0300 Subject: [PATCH 0848/2705] Test --- iguana/exchanges/LP_transaction.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 11b1c96b6..d386dffff 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -818,12 +818,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } jaddbits256(item,"txid",utxotxid); jaddnum(item,"vout",vout); - //sobj = cJSON_CreateObject(); - if ( destaddr == 0 ) - { - destaddr = _destaddr; - bitcoin_address(destaddr,pubtype,pubkey33,33); - } + bitcoin_address(destaddr,pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); /*int32_t i; for (i=0; i<33; i++) @@ -838,6 +833,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf(" <- vs direct calc\n");*/ spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); + //sobj = cJSON_CreateObject(); //jaddstr(sobj,"hex",hexstr); //jadd(item,"scriptPubKey",sobj); jaddstr(item,"scriptPubKey",hexstr); @@ -851,6 +847,12 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jaddi(vins,item); jdelete(txobj,"vin"); jadd(txobj,"vin",vins); + if ( destaddr == 0 ) + { + destaddr = _destaddr; + bitcoin_address(destaddr,pubtype,pubkey33,33); + } + bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); if ( change != 0 ) { From 53433db1a9f8968158c3822b04ec158eb6ca51d7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:30:10 +0300 Subject: [PATCH 0849/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index a5b60731c..23f4e8c7f 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -840,8 +840,8 @@ void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx * rawtx->coin = coin; strcpy(rawtx->I.coinstr,coin->symbol); rawtx->I.numconfirms = numconfirms; - if ( (rawtx->I.amount= satoshis) < 50000 ) - rawtx->I.amount = 50000; + if ( (rawtx->I.amount= satoshis) < 10000 ) + rawtx->I.amount = 10000; rawtx->I.vintype = vintype; // 0 -> std, 2 -> 2of2, 3 -> spend bobpayment, 4 -> spend bobdeposit rawtx->I.vouttype = vouttype; // 0 -> fee, 1 -> std, 2 -> 2of2, 3 -> bobpayment, 4 -> bobdeposit if ( rawtx->I.vouttype == 0 ) From 2bf1bc43a50c5f349355ffd65108236f0ccdc0cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:38:39 +0300 Subject: [PATCH 0850/2705] Test --- iguana/exchanges/LP_transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index d386dffff..04ae644ff 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -893,7 +893,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub { changeaddr = _changeaddr; bitcoin_address(changeaddr,coin->pubtype,changermd160,20); - printf("changeaddr.(%s)\n",changeaddr); + printf("changeaddr.(%s) vs destaddr.(%s)\n",changeaddr,rawtx->I.destaddr); } for (iter=0; iter<2; iter++) { @@ -936,7 +936,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,rawtx->pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) From b727ce72befd45c8acf6a12e0692fb8160f8bb5e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:41:36 +0300 Subject: [PATCH 0851/2705] Test --- iguana/exchanges/LP_transaction.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 04ae644ff..65ab7ea53 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -757,7 +757,7 @@ int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8 char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) { - char *rawtxbytes=0,*signedtx=0,str[65],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount,change = 0; + char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount,change = 0; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -818,8 +818,8 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } jaddbits256(item,"txid",utxotxid); jaddnum(item,"vout",vout); - bitcoin_address(destaddr,pubtype,pubkey33,33); - bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); + bitcoin_address(tmpaddr,pubtype,pubkey33,33); + bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); /*int32_t i; for (i=0; i<33; i++) printf("%02x",pubkey33[i]); From 39e812062f8c91092c2a80de548868db1fc331c9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:47:14 +0300 Subject: [PATCH 0852/2705] Test --- iguana/exchanges/LP_transaction.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 65ab7ea53..1340f11eb 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -757,7 +757,7 @@ int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8 char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) { - char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount,change = 0; + char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount,value,change = 0; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -770,7 +770,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf("basilisk_swap_bobtxspend.%s %s utxo.(%s) already spent or doesnt exist\n",name,symbol,bits256_str(str,utxotxid)); return(0); } - if ( (destamount= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (destamount= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + if ( (value= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) { printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); free_json(utxoobj); @@ -778,15 +778,13 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } else free_json(utxoobj); if ( satoshis != 0 ) { - if ( destamount > satoshis+txfee ) - change = destamount - (satoshis - txfee); - printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(destamount),dstr(satoshis),dstr(change),dstr(txfee)); - destamount = satoshis; - } - *destamountp = destamount; - if ( destamount > txfee ) - destamount -= txfee; - else printf("unexpected too small destamount %.8f txfee %.8f\n",dstr(destamount),dstr(txfee)); + if ( value > satoshis+txfee ) + change = value - (satoshis - txfee); + printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(change),dstr(txfee)); + } else if ( value > txfee ) + satoshis = value - txfee; + else printf("unexpected small value %.8f vs txfee %.8f\n",dstr(value),dstr(txfee)); + *destamountp = satoshis; timestamp = (uint32_t)time(NULL); V = calloc(256,sizeof(*V)); privkeys = cJSON_CreateArray(); @@ -853,7 +851,8 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch bitcoin_address(destaddr,pubtype,pubkey33,33); } bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); - txobj = bitcoin_txoutput(txobj,spendscript,spendlen,destamount); + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + txobj = bitcoin_txoutput(txobj,spendscript,spendlen,satoshis); if ( change != 0 ) { int32_t changelen; uint8_t changescript[1024],changetype,changermd160[20]; From 14f3da18f61b5176ad8000745efef45b88109e7b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 13:56:44 +0300 Subject: [PATCH 0853/2705] Test --- iguana/exchanges/LP_transaction.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 1340f11eb..637c14d82 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -757,7 +757,7 @@ int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8 char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) { - char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t destamount,value,change = 0; + char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -851,7 +851,9 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch bitcoin_address(destaddr,pubtype,pubkey33,33); } bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); - spendlen = bitcoin_standardspend(spendscript,0,rmd160); + if ( addrtype == p2shtype ) + spendlen = bitcoin_p2shspend(spendscript,0,rmd160); + else spendlen = bitcoin_standardspend(spendscript,0,rmd160); txobj = bitcoin_txoutput(txobj,spendscript,spendlen,satoshis); if ( change != 0 ) { From d95040f938ec6a7fc3ef45650bffe2474cc90b78 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:00:15 +0300 Subject: [PATCH 0854/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 23f4e8c7f..6a2f7ac89 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -269,7 +269,7 @@ int32_t LP_choosei_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datal vcalc_sha256(0,swap->I.secretBn256,swap->I.privBn.bytes,sizeof(swap->I.privBn)); swap->I.pubBn = bitcoin_pubkey33(swap->ctx,pubkey33,swap->I.privBn); printf("set privBn.%s %s\n",bits256_str(str,swap->I.privBn),bits256_str(str2,*(bits256 *)swap->I.secretBn256)); - basilisk_bobscripts_set(swap,1,1); + //basilisk_bobscripts_set(swap,1,1); } else { @@ -408,7 +408,7 @@ int32_t LP_mostprivs_verify(struct basilisk_swap *swap,uint8_t *data,int32_t dat swap->I.secretAm[i] = data[len++]; for (i=0; i<32; i++) swap->I.secretAm256[i] = data[len++]; - //basilisk_bobscripts_set(swap,1,1); + basilisk_bobscripts_set(swap,1,1); } else { From 3411112b0a4821b5d1f8c62d4a03c71593b45dd8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:01:31 +0300 Subject: [PATCH 0855/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 312ae6468..1a29d6e20 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -908,7 +908,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } } if ( nonz == 0 ) - sleep(1); + usleep(100000); } } else From d1776cc5219c6e5c5b45c7ee216051911b058c45 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:04:13 +0300 Subject: [PATCH 0856/2705] Test --- iguana/exchanges/LP_transaction.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 637c14d82..4b9b46f4b 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1476,6 +1476,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i { swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); //for (i=0; ibobpayment.redeemlen; i++) // printf("%02x",swap->bobpayment.redeemscript[i]); //printf(" <- bobpayment.%d\n",i); @@ -1512,6 +1513,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i { swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) { //for (i=0; i<3; i++) From b9abdc45d2e056694bcdd74112206051ca538040 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:09:56 +0300 Subject: [PATCH 0857/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 6a2f7ac89..3df11271e 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -373,8 +373,8 @@ int32_t basilisk_verify_privi(void *ptr,uint8_t *data,int32_t datalen) basilisk_dontforget_update(swap,0); char str[65]; printf("privi verified.(%s)\n",bits256_str(str,privkey)); return(0); - } - } + } else printf("pubpair doesnt verify privi\n"); + } else printf("verify privi size mismatch %d != %d\n",datalen,(int32_t)sizeof(bits256)); return(-1); } From 62dac5199f6882985823bd64c085af47eeb39c66 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:17:42 +0300 Subject: [PATCH 0858/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 3df11271e..0eeb78ca2 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -408,7 +408,7 @@ int32_t LP_mostprivs_verify(struct basilisk_swap *swap,uint8_t *data,int32_t dat swap->I.secretAm[i] = data[len++]; for (i=0; i<32; i++) swap->I.secretAm256[i] = data[len++]; - basilisk_bobscripts_set(swap,1,1); + //basilisk_bobscripts_set(swap,1,1); } else { @@ -508,7 +508,7 @@ void LP_bobloop(void *_utxo) printf("error waitsend choosei\n"); else if ( LP_waitsend("mostprivs",10,utxo->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error waitsend mostprivs\n"); - else if ( basilisk_bobscripts_set(swap,1,1) < 0 ) + else if ( basilisk_bobscripts_set(swap,1,1) < 0 || basilisk_bobscripts_set(swap,0,1) < 0 ) printf("error bobscripts\n"); else { From 6d081009c99c5d57cd298abf098cb42c72251b36 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:21:01 +0300 Subject: [PATCH 0859/2705] Test --- iguana/exchanges/LP_transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 4b9b46f4b..05133715a 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1502,8 +1502,8 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i //printf(" <- redeem.%d\n",swap->bobpayment.redeemlen); printf(" <- GENERATED BOB PAYMENT.%d\n",swap->bobpayment.I.datalen); LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); - basilisk_bobpayment_reclaim(swap,swap->I.callduration); - printf("bobscripts set completed\n"); + //basilisk_bobpayment_reclaim(swap,swap->I.callduration); + //printf("bobscripts set completed\n"); return(0); } } From bb81415e5876347e010e84af2447505568e8ae6e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:29:23 +0300 Subject: [PATCH 0860/2705] Test --- iguana/exchanges/LP_transaction.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 05133715a..aed68652c 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -64,7 +64,7 @@ bits256 LP_broadcast_tx(char *name,char *symbol,uint8_t *data,int32_t datalen) uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) { - uint64_t value = 0; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; + uint64_t value = 0; double interest; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; if ( (txobj= LP_gettx(symbol,txid)) != 0 ) { //char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); @@ -75,6 +75,11 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) { char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d/%d\n",symbol,bits256_str(str,txid),jprint(utxoobj,0),vout,numvouts); } + else if ( (interest= jdouble(txobj,"interest")) != 0. ) + { + printf("add interest of %.8f to %.8f\n",interest,dstr(value)); + value += SATOSHIDEN * interest; + } } free_json(txobj); } @@ -779,7 +784,10 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch if ( satoshis != 0 ) { if ( value > satoshis+txfee ) - change = value - (satoshis - txfee); + { + if ( strcmp(symbol,"BTC") == 0 || value > satoshis+txfee*5 ) + change = value - (satoshis + txfee); + } printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(change),dstr(txfee)); } else if ( value > txfee ) satoshis = value - txfee; From 9be441cc169ce35c03346fe5c9f449b5f639fb9c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:34:18 +0300 Subject: [PATCH 0861/2705] Test --- iguana/exchanges/LP_transaction.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index aed68652c..476e9b535 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -75,10 +75,18 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) { char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d/%d\n",symbol,bits256_str(str,txid),jprint(utxoobj,0),vout,numvouts); } - else if ( (interest= jdouble(txobj,"interest")) != 0. ) + else if ( strcmp(symbol,"KMD") == 0 ) { - printf("add interest of %.8f to %.8f\n",interest,dstr(value)); - value += SATOSHIDEN * interest; + if ( (utxoobj= LP_gettxout(symbol,txid,vout)) != 0 ) + { + printf("gettxout.(%s)\n",jprint(utxoobj,0)); + if ( (interest= jdouble(txobj,"interest")) != 0. ) + { + printf("add interest of %.8f to %.8f\n",interest,dstr(value)); + value += SATOSHIDEN * interest; + } + free_json(utxoobj); + } } } free_json(txobj); From 6ff841c083338c19e03755c4e9431c96d33adebc Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:40:53 +0300 Subject: [PATCH 0862/2705] Test --- iguana/exchanges/LP_transaction.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 476e9b535..1d160e1d9 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -770,7 +770,7 @@ int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8 char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) { - char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *utxoobj,*txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; + char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -778,17 +778,11 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 ) return(0); - if ( (utxoobj= LP_gettxout(symbol,utxotxid,vout)) == 0 ) + if ( (value= LP_txvalue(symbol,utxotxid,vout)) == 0 ) { printf("basilisk_swap_bobtxspend.%s %s utxo.(%s) already spent or doesnt exist\n",name,symbol,bits256_str(str,utxotxid)); return(0); } - if ( (value= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) - { - printf("%s %s basilisk_swap_bobtxspend.%s strange utxo.(%s)\n",symbol,bits256_str(str,utxotxid),name,jprint(utxoobj,0)); - free_json(utxoobj); - return(0); - } else free_json(utxoobj); if ( satoshis != 0 ) { if ( value > satoshis+txfee ) From 41fc7fbd11bdf1dfc2274bfbd52995f6b9a3a96c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:43:21 +0300 Subject: [PATCH 0863/2705] Test --- iguana/exchanges/LP_transaction.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 1d160e1d9..3c4e21298 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -79,8 +79,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) { if ( (utxoobj= LP_gettxout(symbol,txid,vout)) != 0 ) { - printf("gettxout.(%s)\n",jprint(utxoobj,0)); - if ( (interest= jdouble(txobj,"interest")) != 0. ) + if ( (interest= jdouble(utxoobj,"interest")) != 0. ) { printf("add interest of %.8f to %.8f\n",interest,dstr(value)); value += SATOSHIDEN * interest; @@ -786,10 +785,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch if ( satoshis != 0 ) { if ( value > satoshis+txfee ) - { - if ( strcmp(symbol,"BTC") == 0 || value > satoshis+txfee*5 ) - change = value - (satoshis + txfee); - } + change = value - (satoshis + txfee); printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(change),dstr(txfee)); } else if ( value > txfee ) satoshis = value - txfee; From 024e2a2c15d3362ad01596c38649d55675699526 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:46:20 +0300 Subject: [PATCH 0864/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1a29d6e20..e02ee5c12 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -578,7 +578,7 @@ void tradebot_pendingadd(cJSON *tradejson,char *base,double basevolume,char *rel // add to trades } -char GLOBAL_DBDIR[] = "."; +char GLOBAL_DBDIR[] = "DB"; #include "LP_secp.c" #include "LP_rpc.c" From 7c40aa18105afe34364a0ca8ab24d363989db2d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 14:57:40 +0300 Subject: [PATCH 0865/2705] Test --- iguana/exchanges/mm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 703f70dd7..4fc22eda1 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -833,7 +833,8 @@ int main(int argc, const char * argv[]) while ( 1 ) { theoretical = marketmaker_updateprice("komodo","KMD","BTC",theoretical,&incr); - sleep(10); + sleep(3); + LP_privkey_updates(0,-1,passphrase,1); if ( jint(retjson,"client") != 0 ) { struct LP_utxoinfo *utxo,*utmp; From 47e03ce8d02c5e9521394b2d9d5013fd02881e8f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 16:59:54 +0300 Subject: [PATCH 0866/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 10 +- iguana/exchanges/LP_remember.c | 2 +- iguana/exchanges/LP_statemachine.c | 189 +++++++++- iguana/exchanges/LP_swap.c | 104 +++++- iguana/exchanges/LP_transaction.c | 552 ++++++++--------------------- 7 files changed, 434 insertions(+), 426 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index db85f0489..77604a157 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -483,5 +483,6 @@ struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); struct iguana_info *LP_coinfind(char *symbol); void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3); +uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend); #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e02ee5c12..f651df270 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -585,7 +585,7 @@ char GLOBAL_DBDIR[] = "DB"; #include "LP_bitcoin.c" #include "LP_transaction.c" #include "LP_remember.c" -#include "LP_statemachine.c" +//#include "LP_statemachine.c" #include "LP_swap.c" #include "LP_commands.c" diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index bd6855e9d..45d25e403 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -144,7 +144,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) return(-1); } -uint32_t LP_swapsend(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits,uint32_t crcs[2]) +uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits,uint32_t crcs[2]) { uint8_t *buf; int32_t sentbytes,offset=0,i; buf = malloc(datalen + sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2); @@ -156,17 +156,11 @@ uint32_t LP_swapsend(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,i offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); if ( datalen > 0 ) memcpy(&buf[offset],data,datalen), offset += datalen; - if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) + if ( (sentbytes= nn_send(pairsock,buf,offset,0)) != offset ) { printf("sentbytes.%d vs offset.%d\n",sentbytes,offset); if ( sentbytes < 0 ) { - if ( swap->pushsock >= 0 ) - nn_close(swap->pushsock), swap->pushsock = -1; //, - if ( swap->subsock >= 0 ) // - nn_close(swap->subsock), swap->subsock = -1; - swap->connected = swap->I.iambob != 0 ? -1 : 0; - swap->aborted = (uint32_t)time(NULL); } } //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index d52a9838c..faea5b665 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -184,7 +184,7 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx fprintf(fp,"\",\"txid\":\"%s\"",bits256_str(str,bits256_doublesha256(0,rawtx->txbytes,rawtx->I.datalen))); if ( rawtx == &swap->bobdeposit || rawtx == &swap->bobpayment ) { - basilisk_swap_coinaddr(swap,&swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); + LP_swap_coinaddr(swap,&swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); if ( coinaddr[0] != 0 ) { LP_importaddress(swap->bobcoin.symbol,coinaddr); diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index 4cb663b99..950e22e88 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -17,6 +17,193 @@ // LP_statemachine.c // marketmaker // +int32_t basilisk_rawtx_return(struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) +{ + char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; + if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) + { + privkeyarray = cJSON_CreateArray(); + jaddistr(privkeyarray,wifstr); + if ( (signedtx= LP_signrawtx(rawtx->coin->symbol,&rawtx->I.signedtxid,&rawtx->I.completed,vins,txbytes,privkeyarray,V)) != 0 ) + { + if ( lockinputs != 0 ) + { + //printf("lockinputs\n"); + LP_unspentslock(rawtx->coin->symbol,vins); + if ( (n= cJSON_GetArraySize(vins)) != 0 ) + { + bits256 txid; int32_t vout; + for (i=0; iI.datalen = (int32_t)strlen(signedtx) >> 1; + //rawtx->txbytes = calloc(1,rawtx->I.datalen); + decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); + //printf("%s SIGNEDTX.(%s)\n",rawtx->name,signedtx); + free(signedtx); + retval = 0; + } else printf("error signrawtx\n"); //do a very short timeout so it finishes via local poll + free_json(privkeyarray); + } + return(retval); +} + +cJSON *LP_createvins(struct basilisk_rawtx *dest,struct vin_info *V,struct basilisk_rawtx *rawtx,uint8_t *userdata,int32_t userdatalen,uint32_t sequenceid) +{ + cJSON *vins,*item,*sobj; char hexstr[8192]; + vins = cJSON_CreateArray(); + item = cJSON_CreateObject(); + if ( userdata != 0 && userdatalen > 0 ) + { + memcpy(V[0].userdata,userdata,userdatalen); + V[0].userdatalen = userdatalen; + init_hexbytes_noT(hexstr,userdata,userdatalen); + jaddstr(item,"userdata",hexstr); +#ifdef DISABLE_CHECKSIG + needsig = 0; +#endif + } + //printf("rawtx B\n"); + if ( bits256_nonz(rawtx->I.actualtxid) != 0 ) + jaddbits256(item,"txid",rawtx->I.actualtxid); + else jaddbits256(item,"txid",rawtx->I.signedtxid); + jaddnum(item,"vout",0); + //sobj = cJSON_CreateObject(); + init_hexbytes_noT(hexstr,rawtx->spendscript,rawtx->I.spendlen); + //jaddstr(sobj,"hex",hexstr); + //jadd(item,"scriptPubKey",sobj); + jaddstr(item,"scriptPubKey",hexstr); + jaddnum(item,"suppress",dest->I.suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); + if ( (dest->I.redeemlen= rawtx->I.redeemlen) != 0 ) + { + init_hexbytes_noT(hexstr,rawtx->redeemscript,rawtx->I.redeemlen); + memcpy(dest->redeemscript,rawtx->redeemscript,rawtx->I.redeemlen); + jaddstr(item,"redeemScript",hexstr); + } + jaddi(vins,item); + return(vins); +} + +int32_t _basilisk_rawtx_gen(char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey) +{ + char scriptstr[1024],wifstr[256],coinaddr[64],*signedtx,*rawtxbytes; uint32_t basilisktag; int32_t retval = -1; cJSON *vins,*privkeys,*addresses,*valsobj; struct vin_info *V; + //bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,myinfo->persistent_pubkey33,33); + if ( rawtx->coin->changeaddr[0] == 0 ) + { + bitcoin_address(rawtx->coin->changeaddr,rawtx->coin->pubtype,pubkey33,33); + printf("set change address.(%s)\n",rawtx->coin->changeaddr); + } + init_hexbytes_noT(scriptstr,script,scriptlen); + basilisktag = (uint32_t)rand(); + valsobj = cJSON_CreateObject(); + jaddstr(valsobj,"coin",rawtx->coin->symbol); + jaddstr(valsobj,"spendscript",scriptstr); + jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); + jadd64bits(valsobj,"satoshis",rawtx->I.amount); + if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) + txfee = 50000; + jadd64bits(valsobj,"txfee",txfee); + jaddnum(valsobj,"minconf",minconf); + if ( locktime == 0 ) + locktime = (uint32_t)time(NULL) - 777; + jaddnum(valsobj,"locktime",locktime); + jaddnum(valsobj,"timeout",30000); + jaddnum(valsobj,"timestamp",swapstarted+delay); + addresses = cJSON_CreateArray(); + bitcoin_address(coinaddr,rawtx->coin->pubtype,pubkey33,33); + jaddistr(addresses,coinaddr); + jadd(valsobj,"addresses",addresses); + rawtx->I.locktime = locktime; + printf("%s locktime.%u\n",rawtx->name,locktime); + V = calloc(256,sizeof(*V)); + privkeys = cJSON_CreateArray(); + bitcoin_priv2wif(wifstr,privkey,rawtx->coin->wiftype); + jaddistr(privkeys,wifstr); + vins = LP_createvins(rawtx,V,rawtx,0,0,0xffffffff); + rawtx->vins = jduplicate(vins); + jdelete(valsobj,"vin"); + jadd(valsobj,"vin",vins); + if ( (rawtxbytes= bitcoin_json2hex(rawtx->coin->isPoS,&rawtx->I.txid,valsobj,V)) != 0 ) + { + //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); + if ( (signedtx= LP_signrawtx(rawtx->coin->symbol,&rawtx->I.signedtxid,&rawtx->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) + { + rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) + decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); + else printf("DEX tx is too big %d vs %d\n",rawtx->I.datalen,(int32_t)sizeof(rawtx->txbytes)); + if ( signedtx != rawtxbytes ) + free(signedtx); + if ( rawtx->I.completed != 0 ) + retval = 0; + else printf("couldnt complete sign transaction %s\n",rawtx->name); + } else printf("error signing\n"); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(valsobj); + free(V); + return(retval); +} + +int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,uint32_t timestamp,uint32_t locktime,uint32_t sequenceid,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) +{ + char *rawtxbytes=0,*signedtx=0,wifstr[128]; cJSON *txobj,*vins,*privkeys; int32_t needsig=1,retval = -1; struct vin_info *V; + V = calloc(256,sizeof(*V)); + V[0].signers[0].privkey = privkey; + bitcoin_pubkey33(swap->ctx,V[0].signers[0].pubkey,privkey); + privkeys = cJSON_CreateArray(); + bitcoin_priv2wif(wifstr,privkey,wiftype); + jaddistr(privkeys,wifstr); + if ( privkey2 != 0 ) + { + V[0].signers[1].privkey = *privkey2; + bitcoin_pubkey33(swap->ctx,V[0].signers[1].pubkey,*privkey2); + bitcoin_priv2wif(wifstr,*privkey2,wiftype); + jaddistr(privkeys,wifstr); + V[0].N = V[0].M = 2; + //char str[65]; printf("add second privkey.(%s) %s\n",jprint(privkeys,0),bits256_str(str,*privkey2)); + } else V[0].N = V[0].M = 1; + V[0].suppress_pubkeys = dest->I.suppress_pubkeys; + V[0].ignore_cltverr = ignore_cltverr; + if ( dest->I.redeemlen != 0 ) + memcpy(V[0].p2shscript,dest->redeemscript,dest->I.redeemlen), V[0].p2shlen = dest->I.redeemlen; + txobj = bitcoin_txcreate(symbol,isPoS,locktime,userdata == 0 ? 1 : 1,timestamp);//rawtx->coin->locktime_txversion); + vins = LP_createvins(dest,V,rawtx,userdata,userdatalen,sequenceid); + jdelete(txobj,"vin"); + jadd(txobj,"vin",vins); + //printf("basilisk_rawtx_sign locktime.%u/%u for %s spendscript.%s -> %s, suppress.%d\n",rawtx->I.locktime,dest->I.locktime,rawtx->name,hexstr,dest->name,dest->I.suppress_pubkeys); + txobj = bitcoin_txoutput(txobj,dest->spendscript,dest->I.spendlen,dest->I.amount); + if ( (rawtxbytes= bitcoin_json2hex(isPoS,&dest->I.txid,txobj,V)) != 0 ) + { + //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); + if ( needsig == 0 ) + signedtx = rawtxbytes; + if ( signedtx != 0 || (signedtx= LP_signrawtx(symbol,&dest->I.signedtxid,&dest->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) + { + dest->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( dest->I.datalen <= sizeof(dest->txbytes) ) + decode_hex(dest->txbytes,dest->I.datalen,signedtx); + else printf("DEX tx is too big %d vs %d\n",dest->I.datalen,(int32_t)sizeof(dest->txbytes)); + if ( signedtx != rawtxbytes ) + free(signedtx); + if ( dest->I.completed != 0 ) + retval = 0; + else printf("couldnt complete sign transaction %s\n",rawtx->name); + } else printf("error signing\n"); + free(rawtxbytes); + } else printf("error making rawtx\n"); + free_json(privkeys); + free_json(txobj); + free(V); + return(retval); +} int32_t basilisk_process_swapverify(void *ptr,int32_t (*internal_func)(void *ptr,uint8_t *data,int32_t datalen),uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen,uint32_t expiration,uint32_t duration) { @@ -26,8 +213,6 @@ int32_t basilisk_process_swapverify(void *ptr,int32_t (*internal_func)(void *ptr else return(0); } - - int32_t basilisk_priviextract(struct iguana_info *coin,char *name,bits256 *destp,uint8_t secret160[20],bits256 srctxid,int32_t srcvout) { /*bits256 txid; char str[65]; int32_t i,vini,scriptlen; uint8_t rmd160[20],scriptsig[IGUANA_MAXSCRIPTSIZE]; diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 0eeb78ca2..c066e3012 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -491,9 +491,62 @@ void LP_swapsfp_update(struct basilisk_request *rp) } } +struct basilisk_rawtx *LP_swapdata_rawtx(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx) +{ + if ( rawtx->I.datalen != 0 && rawtx->I.datalen <= maxlen ) + { + memcpy(data,rawtx->txbytes,rawtx->I.datalen); + return(rawtx); + } + return(0); +} + +uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) +{ + uint8_t sendbuf[32768]; int32_t sendlen; + if ( LP_swapdata_rawtx(swap,data,maxlen,rawtx) != 0 ) + { + if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + { + char str[65],str2[65]; + rawtx->I.actualtxid = LP_broadcast_tx(rawtx->name,rawtx->coin->symbol,rawtx->txbytes,rawtx->I.datalen); + if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) + { + printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); + rawtx->I.actualtxid = rawtx->I.signedtxid; + } + if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) + { + sendlen = 0; + sendbuf[sendlen++] = rawtx->I.datalen & 0xff; + sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; + sendbuf[sendlen++] = rawtx->I.redeemlen; + memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + { + memcpy(&sendbuf[sendlen],rawtx->redeemscript,rawtx->I.redeemlen); + sendlen += rawtx->I.redeemlen; + } + basilisk_dontforget_update(swap,rawtx); + //printf("sendlen.%d datalen.%d redeemlen.%d\n",sendlen,rawtx->datalen,rawtx->redeemlen); + if ( suppress_swapsend == 0 ) + return(LP_swapsend(pairsock,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs)); + else + { + printf("suppress swapsend %x\n",msgbits); + return(0); + } + } + } + return(nextbits); + } else if ( swap->I.iambob == 0 ) + printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); + return(0); +} + void LP_bobloop(void *_utxo) { - uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; + uint8_t *data; char *retstr; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; fprintf(stderr,"start swap iambob\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); @@ -513,13 +566,22 @@ void LP_bobloop(void *_utxo) else { LP_swapsfp_update(&swap->I.req); - // wait alicefee - // send bobdeposit - // wait alicepayment - // send bobpayment - // bobspend - // bobrefund - // done + if ( LP_waitfor(utxo->pair,swap,10,LP_verify_otherfee) < 0 ) + printf("error waiting for alicefee\n"); + else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0) == 0 ) + printf("error sending bobdeposit\n"); + else if ( LP_waitfor(utxo->pair,swap,10,LP_verify_alicepayment) < 0 ) + printf("error waiting for alicepayment\n"); + else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) + printf("error sending bobpayment\n"); + while ( 1 ) + { + if ( (retstr= basilisk_swaplist()) != 0 ) + { + printf("%s\n",retstr); + free(retstr); + } + } } basilisk_swap_finished(swap); free(utxo->swap); @@ -531,7 +593,7 @@ void LP_bobloop(void *_utxo) void LP_aliceloop(void *_qp) { - uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = 0; struct LP_quoteinfo *qp = _qp; + uint8_t *data; char *retstr; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = 0; struct LP_quoteinfo *qp = _qp; fprintf(stderr,"start swap iamalice pair.%d\n",qp->pair); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); @@ -545,17 +607,27 @@ void LP_aliceloop(void *_qp) printf("error LP_sendwait choosei\n"); else if ( LP_sendwait("mostprivs",10,qp->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error LP_sendwait mostprivs\n"); - else if ( basilisk_alicetxs(swap,data,maxlen) != 0 ) + else if ( basilisk_alicetxs(qp->pair,swap,data,maxlen) != 0 ) printf("basilisk_alicetxs error\n"); else { LP_swapsfp_update(&swap->I.req); - // send alicefee - // wait bobdeposit - // send alicepayment - // wait bobpayment - // alicespend - // done + if ( LP_swapdata_rawtxsend(qp->pair,swap,0x80,data,maxlen,&swap->myfee,0x40,0) == 0 ) + printf("error sending alicefee\n"); + else if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobdeposit) < 0 ) + printf("error waiting for bobdeposit\n"); + else if ( LP_swapdata_rawtxsend(qp->pair,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0) == 0 ) + printf("error sending alicepayment\n"); + else if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobpayment) < 0 ) + printf("error waiting for bobpayment\n"); + while ( 1 ) + { + if ( (retstr= basilisk_swaplist()) != 0 ) + { + printf("%s\n",retstr); + free(retstr); + } + } } basilisk_swap_finished(swap); free(swap); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 3c4e21298..29cda5305 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -577,194 +577,7 @@ int32_t iguana_signrawtransaction(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS return(complete); } -int32_t basilisk_rawtx_return(struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) -{ - char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; - if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) - { - privkeyarray = cJSON_CreateArray(); - jaddistr(privkeyarray,wifstr); - if ( (signedtx= LP_signrawtx(rawtx->coin->symbol,&rawtx->I.signedtxid,&rawtx->I.completed,vins,txbytes,privkeyarray,V)) != 0 ) - { - if ( lockinputs != 0 ) - { - //printf("lockinputs\n"); - LP_unspentslock(rawtx->coin->symbol,vins); - if ( (n= cJSON_GetArraySize(vins)) != 0 ) - { - bits256 txid; int32_t vout; - for (i=0; iI.datalen = (int32_t)strlen(signedtx) >> 1; - //rawtx->txbytes = calloc(1,rawtx->I.datalen); - decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); - //printf("%s SIGNEDTX.(%s)\n",rawtx->name,signedtx); - free(signedtx); - retval = 0; - } else printf("error signrawtx\n"); //do a very short timeout so it finishes via local poll - free_json(privkeyarray); - } - return(retval); -} -cJSON *LP_createvins(struct basilisk_rawtx *dest,struct vin_info *V,struct basilisk_rawtx *rawtx,uint8_t *userdata,int32_t userdatalen,uint32_t sequenceid) -{ - cJSON *vins,*item,*sobj; char hexstr[8192]; - vins = cJSON_CreateArray(); - item = cJSON_CreateObject(); - if ( userdata != 0 && userdatalen > 0 ) - { - memcpy(V[0].userdata,userdata,userdatalen); - V[0].userdatalen = userdatalen; - init_hexbytes_noT(hexstr,userdata,userdatalen); - jaddstr(item,"userdata",hexstr); -#ifdef DISABLE_CHECKSIG - needsig = 0; -#endif - } - //printf("rawtx B\n"); - if ( bits256_nonz(rawtx->I.actualtxid) != 0 ) - jaddbits256(item,"txid",rawtx->I.actualtxid); - else jaddbits256(item,"txid",rawtx->I.signedtxid); - jaddnum(item,"vout",0); - //sobj = cJSON_CreateObject(); - init_hexbytes_noT(hexstr,rawtx->spendscript,rawtx->I.spendlen); - //jaddstr(sobj,"hex",hexstr); - //jadd(item,"scriptPubKey",sobj); - jaddstr(item,"scriptPubKey",hexstr); - jaddnum(item,"suppress",dest->I.suppress_pubkeys); - jaddnum(item,"sequence",sequenceid); - if ( (dest->I.redeemlen= rawtx->I.redeemlen) != 0 ) - { - init_hexbytes_noT(hexstr,rawtx->redeemscript,rawtx->I.redeemlen); - memcpy(dest->redeemscript,rawtx->redeemscript,rawtx->I.redeemlen); - jaddstr(item,"redeemScript",hexstr); - } - jaddi(vins,item); - return(vins); -} - -int32_t _basilisk_rawtx_gen(char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey) -{ - char scriptstr[1024],wifstr[256],coinaddr[64],*signedtx,*rawtxbytes; uint32_t basilisktag; int32_t retval = -1; cJSON *vins,*privkeys,*addresses,*valsobj; struct vin_info *V; - //bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,myinfo->persistent_pubkey33,33); - if ( rawtx->coin->changeaddr[0] == 0 ) - { - bitcoin_address(rawtx->coin->changeaddr,rawtx->coin->pubtype,pubkey33,33); - printf("set change address.(%s)\n",rawtx->coin->changeaddr); - } - init_hexbytes_noT(scriptstr,script,scriptlen); - basilisktag = (uint32_t)rand(); - valsobj = cJSON_CreateObject(); - jaddstr(valsobj,"coin",rawtx->coin->symbol); - jaddstr(valsobj,"spendscript",scriptstr); - jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); - jadd64bits(valsobj,"satoshis",rawtx->I.amount); - if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) - txfee = 50000; - jadd64bits(valsobj,"txfee",txfee); - jaddnum(valsobj,"minconf",minconf); - if ( locktime == 0 ) - locktime = (uint32_t)time(NULL) - 777; - jaddnum(valsobj,"locktime",locktime); - jaddnum(valsobj,"timeout",30000); - jaddnum(valsobj,"timestamp",swapstarted+delay); - addresses = cJSON_CreateArray(); - bitcoin_address(coinaddr,rawtx->coin->pubtype,pubkey33,33); - jaddistr(addresses,coinaddr); - jadd(valsobj,"addresses",addresses); - rawtx->I.locktime = locktime; - printf("%s locktime.%u\n",rawtx->name,locktime); - V = calloc(256,sizeof(*V)); - privkeys = cJSON_CreateArray(); - bitcoin_priv2wif(wifstr,privkey,rawtx->coin->wiftype); - jaddistr(privkeys,wifstr); - vins = LP_createvins(rawtx,V,rawtx,0,0,0xffffffff); - rawtx->vins = jduplicate(vins); - jdelete(valsobj,"vin"); - jadd(valsobj,"vin",vins); - if ( (rawtxbytes= bitcoin_json2hex(rawtx->coin->isPoS,&rawtx->I.txid,valsobj,V)) != 0 ) - { - //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); - if ( (signedtx= LP_signrawtx(rawtx->coin->symbol,&rawtx->I.signedtxid,&rawtx->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) - { - rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; - if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) - decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); - else printf("DEX tx is too big %d vs %d\n",rawtx->I.datalen,(int32_t)sizeof(rawtx->txbytes)); - if ( signedtx != rawtxbytes ) - free(signedtx); - if ( rawtx->I.completed != 0 ) - retval = 0; - else printf("couldnt complete sign transaction %s\n",rawtx->name); - } else printf("error signing\n"); - free(rawtxbytes); - } else printf("error making rawtx\n"); - free_json(privkeys); - free_json(valsobj); - free(V); - return(retval); -} - - -int32_t _basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,uint32_t timestamp,uint32_t locktime,uint32_t sequenceid,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr) -{ - char *rawtxbytes=0,*signedtx=0,wifstr[128]; cJSON *txobj,*vins,*privkeys; int32_t needsig=1,retval = -1; struct vin_info *V; - V = calloc(256,sizeof(*V)); - V[0].signers[0].privkey = privkey; - bitcoin_pubkey33(swap->ctx,V[0].signers[0].pubkey,privkey); - privkeys = cJSON_CreateArray(); - bitcoin_priv2wif(wifstr,privkey,wiftype); - jaddistr(privkeys,wifstr); - if ( privkey2 != 0 ) - { - V[0].signers[1].privkey = *privkey2; - bitcoin_pubkey33(swap->ctx,V[0].signers[1].pubkey,*privkey2); - bitcoin_priv2wif(wifstr,*privkey2,wiftype); - jaddistr(privkeys,wifstr); - V[0].N = V[0].M = 2; - //char str[65]; printf("add second privkey.(%s) %s\n",jprint(privkeys,0),bits256_str(str,*privkey2)); - } else V[0].N = V[0].M = 1; - V[0].suppress_pubkeys = dest->I.suppress_pubkeys; - V[0].ignore_cltverr = ignore_cltverr; - if ( dest->I.redeemlen != 0 ) - memcpy(V[0].p2shscript,dest->redeemscript,dest->I.redeemlen), V[0].p2shlen = dest->I.redeemlen; - txobj = bitcoin_txcreate(symbol,isPoS,locktime,userdata == 0 ? 1 : 1,timestamp);//rawtx->coin->locktime_txversion); - vins = LP_createvins(dest,V,rawtx,userdata,userdatalen,sequenceid); - jdelete(txobj,"vin"); - jadd(txobj,"vin",vins); - //printf("basilisk_rawtx_sign locktime.%u/%u for %s spendscript.%s -> %s, suppress.%d\n",rawtx->I.locktime,dest->I.locktime,rawtx->name,hexstr,dest->name,dest->I.suppress_pubkeys); - txobj = bitcoin_txoutput(txobj,dest->spendscript,dest->I.spendlen,dest->I.amount); - if ( (rawtxbytes= bitcoin_json2hex(isPoS,&dest->I.txid,txobj,V)) != 0 ) - { - //printf("rawtx.(%s) vins.%p\n",rawtxbytes,vins); - if ( needsig == 0 ) - signedtx = rawtxbytes; - if ( signedtx != 0 || (signedtx= LP_signrawtx(symbol,&dest->I.signedtxid,&dest->I.completed,vins,rawtxbytes,privkeys,V)) != 0 ) - { - dest->I.datalen = (int32_t)strlen(signedtx) >> 1; - if ( dest->I.datalen <= sizeof(dest->txbytes) ) - decode_hex(dest->txbytes,dest->I.datalen,signedtx); - else printf("DEX tx is too big %d vs %d\n",dest->I.datalen,(int32_t)sizeof(dest->txbytes)); - if ( signedtx != rawtxbytes ) - free(signedtx); - if ( dest->I.completed != 0 ) - retval = 0; - else printf("couldnt complete sign transaction %s\n",rawtx->name); - } else printf("error signing\n"); - free(rawtxbytes); - } else printf("error making rawtx\n"); - free_json(privkeys); - free_json(txobj); - free(V); - return(retval); -} #endif char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) @@ -1365,97 +1178,6 @@ int32_t basilisk_bobpayment_reclaim(struct basilisk_swap *swap,int32_t delay) return(-1); } -int32_t basilisk_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) -{ - int32_t datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; bits256 txid; - datalen = recvbuf[0]; - datalen += (int32_t)recvbuf[1] << 8; - if ( datalen > 65536 ) - return(-1); - rawtx->I.redeemlen = recvbuf[2]; - data = &recvbuf[3]; - if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) - memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); - //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); - if ( rawtx->I.datalen == 0 ) - { - //rawtx->txbytes = calloc(1,datalen); - memcpy(rawtx->txbytes,data,datalen); - rawtx->I.datalen = datalen; - } - else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) - { - int32_t i; for (i=0; iI.datalen; i++) - printf("%02x",rawtx->txbytes[i]); - printf(" <- rawtx\n"); - printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); - return(-1); - } - txid = bits256_doublesha256(0,data,datalen); - char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); - if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) - rawtx->I.actualtxid = txid; - if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) - { - rawtx->I.actualtxid = rawtx->I.signedtxid; - //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,rawtx->signedtxid),jprint(txobj,0)); - rawtx->I.locktime = rawtx->msgtx.lock_time; - if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) - { - vout = jitem(vouts,v); - if ( j64bits(vout,"satoshis") == rawtx->I.amount && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) - { - if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) - { - decode_hex(rawtx->spendscript,hexlen,hexstr); - rawtx->I.spendlen = hexlen; - bitcoin_address(rawtx->p2shaddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); - //if ( swap != 0 ) - // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment - retval = 0; - } - } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); - } - free_json(txobj); - } - return(retval); -} - -int32_t basilisk_verify_bobpaid(void *ptr,uint8_t *data,int32_t datalen) -{ - uint8_t userdata[512]; int32_t i,retval,len = 0; bits256 revAm; struct basilisk_swap *swap = ptr; - memset(revAm.bytes,0,sizeof(revAm)); - if ( basilisk_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) - { - swap->bobpayment.I.signedtxid = LP_broadcast_tx(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); - if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) - swap->paymentunconf = 1; - basilisk_dontforget_update(swap,&swap->bobpayment); - for (i=0; i<32; i++) - revAm.bytes[i] = swap->I.privAm.bytes[31-i]; - len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); - memcpy(swap->I.userdata_alicespend,userdata,len); - swap->I.userdata_alicespendlen = len; - char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) - { - for (i=0; ibobpayment.I.datalen; i++) - printf("%02x",swap->bobpayment.txbytes[i]); - printf(" <- bobpayment\n"); - for (i=0; ialicespend.I.datalen; i++) - printf("%02x",swap->alicespend.txbytes[i]); - printf(" <- alicespend\n\n"); - swap->I.alicespent = 1; - //basilisk_txlog(swap,&swap->alicespend,-1); - return(retval); - } - } - return(-1); -} - int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) { uint8_t userdata[512]; int32_t i,retval,len = 0; char str[65]; @@ -1557,60 +1279,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i /**/ -struct basilisk_rawtx *LP_swapdata_rawtx(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx) -{ - if ( rawtx->I.datalen != 0 && rawtx->I.datalen <= maxlen ) - { - memcpy(data,rawtx->txbytes,rawtx->I.datalen); - return(rawtx); - } - return(0); -} - -uint32_t LP_swapdata_rawtxsend(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) -{ - uint8_t sendbuf[32768]; int32_t sendlen; - if ( LP_swapdata_rawtx(swap,data,maxlen,rawtx) != 0 ) - { - if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) - { - char str[65],str2[65]; - rawtx->I.actualtxid = LP_broadcast_tx(rawtx->name,rawtx->coin->symbol,rawtx->txbytes,rawtx->I.datalen); - if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) - { - printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); - rawtx->I.actualtxid = rawtx->I.signedtxid; - } - if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) - { - sendlen = 0; - sendbuf[sendlen++] = rawtx->I.datalen & 0xff; - sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; - sendbuf[sendlen++] = rawtx->I.redeemlen; - memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; - if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) - { - memcpy(&sendbuf[sendlen],rawtx->redeemscript,rawtx->I.redeemlen); - sendlen += rawtx->I.redeemlen; - } - basilisk_dontforget_update(swap,rawtx); - //printf("sendlen.%d datalen.%d redeemlen.%d\n",sendlen,rawtx->datalen,rawtx->redeemlen); - if ( suppress_swapsend == 0 ) - return(LP_swapsend(swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs)); - else - { - printf("suppress swapsend %x\n",msgbits); - return(0); - } - } - } - return(nextbits); - } else if ( swap->I.iambob == 0 ) - printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); - return(0); -} - -void basilisk_swap_coinaddr(struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) +void LP_swap_coinaddr(struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) { cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; if ( (txobj= bitcoin_data2json(coin->pubtype,coin->p2shtype,coin->isPoS,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) @@ -1635,59 +1304,6 @@ void basilisk_swap_coinaddr(struct basilisk_swap *swap,struct iguana_info *coin, } } -int32_t basilisk_verify_otherfee(void *ptr,uint8_t *data,int32_t datalen) -{ - struct basilisk_swap *swap = ptr; - // add verification and broadcast - //swap->otherfee.txbytes = calloc(1,datalen); - memcpy(swap->otherfee.txbytes,data,datalen); - swap->otherfee.I.datalen = datalen; - swap->otherfee.I.actualtxid = swap->otherfee.I.signedtxid = bits256_doublesha256(0,data,datalen); - //basilisk_txlog(swap,&swap->otherfee,-1); - return(0); -} - -/* Bob deposit: - OP_IF - OP_CLTV OP_DROP OP_CHECKSIG - OP_ELSE - OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG - OP_ENDIF*/ - -int32_t basilisk_verify_bobdeposit(void *ptr,uint8_t *data,int32_t datalen) -{ - uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; struct basilisk_swap *swap = ptr; - if ( basilisk_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) - { - swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); - if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) - swap->depositunconf = 1; - basilisk_dontforget_update(swap,&swap->bobdeposit); - len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); - memcpy(swap->I.userdata_aliceclaim,userdata,len); - swap->I.userdata_aliceclaimlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) - { - for (i=0; ibobdeposit.I.datalen; i++) - printf("%02x",swap->bobdeposit.txbytes[i]); - printf(" <- bobdeposit\n"); - for (i=0; ialiceclaim.I.datalen; i++) - printf("%02x",swap->aliceclaim.txbytes[i]); - printf(" <- aliceclaim\n"); - //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); - return(retval); - } - } - printf("error with bobdeposit\n"); - return(-1); -} - -void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) -{ - alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); - basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160); -} - int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_rawtx *dest) { int32_t i,retval; @@ -1717,21 +1333,13 @@ int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_r return(-1); } -int32_t basilisk_verify_alicepaid(void *ptr,uint8_t *data,int32_t datalen) +void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) { - struct basilisk_swap *swap = ptr; - if ( basilisk_rawtx_spendscript(swap,swap->alicecoin.longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) - { - swap->alicepayment.I.signedtxid = LP_broadcast_tx(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); - if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) - swap->aliceunconf = 1; - basilisk_dontforget_update(swap,&swap->alicepayment); - return(0); - } - else return(-1); + alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); + basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160); } -int32_t basilisk_alicetxs(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) +int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t i,retval = -1; printf("alicetxs\n"); @@ -1760,7 +1368,7 @@ int32_t basilisk_alicetxs(struct basilisk_swap *swap,uint8_t *data,int32_t maxle //printf("generate fee\n"); if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160) == 0 ) { - swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x80,data,maxlen,&swap->myfee,0x40,0); + swap->I.statebits |= LP_swapdata_rawtxsend(pairsock,swap,0x80,data,maxlen,&swap->myfee,0x40,0); LP_unspents_mark(swap->I.iambob!=0?swap->bobcoin.symbol:swap->alicecoin.symbol,swap->myfee.vins); //basilisk_txlog(swap,&swap->myfee,-1); for (i=0; imyfee.I.datalen; i++) @@ -1778,3 +1386,151 @@ int32_t basilisk_alicetxs(struct basilisk_swap *swap,uint8_t *data,int32_t maxle return(0); return(-1); } + +int32_t LP_verify_otherfee(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) +{ + // add verification and broadcast + memcpy(swap->otherfee.txbytes,data,datalen); + swap->otherfee.I.datalen = datalen; + swap->otherfee.I.actualtxid = swap->otherfee.I.signedtxid = bits256_doublesha256(0,data,datalen); + return(0); +} + +int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) +{ + int32_t datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; bits256 txid; + datalen = recvbuf[0]; + datalen += (int32_t)recvbuf[1] << 8; + if ( datalen > 65536 ) + return(-1); + rawtx->I.redeemlen = recvbuf[2]; + data = &recvbuf[3]; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); + //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); + if ( rawtx->I.datalen == 0 ) + { + //rawtx->txbytes = calloc(1,datalen); + memcpy(rawtx->txbytes,data,datalen); + rawtx->I.datalen = datalen; + } + else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) + { + int32_t i; for (i=0; iI.datalen; i++) + printf("%02x",rawtx->txbytes[i]); + printf(" <- rawtx\n"); + printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); + return(-1); + } + txid = bits256_doublesha256(0,data,datalen); + char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); + if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + rawtx->I.actualtxid = txid; + if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + rawtx->I.actualtxid = rawtx->I.signedtxid; + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,rawtx->signedtxid),jprint(txobj,0)); + rawtx->I.locktime = rawtx->msgtx.lock_time; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) + { + vout = jitem(vouts,v); + if ( j64bits(vout,"satoshis") == rawtx->I.amount && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) + { + if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) + { + decode_hex(rawtx->spendscript,hexlen,hexstr); + rawtx->I.spendlen = hexlen; + bitcoin_address(rawtx->p2shaddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); + //if ( swap != 0 ) + // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment + retval = 0; + } + } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); + } + free_json(txobj); + } + return(retval); +} + +/* Bob deposit: + OP_IF + OP_CLTV OP_DROP OP_CHECKSIG + OP_ELSE + OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG + OP_ENDIF*/ + +int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; + if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) + { + swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) + swap->depositunconf = 1; + basilisk_dontforget_update(swap,&swap->bobdeposit); + len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_aliceclaim,userdata,len); + swap->I.userdata_aliceclaimlen = len; + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) + { + for (i=0; ibobdeposit.I.datalen; i++) + printf("%02x",swap->bobdeposit.txbytes[i]); + printf(" <- bobdeposit\n"); + for (i=0; ialiceclaim.I.datalen; i++) + printf("%02x",swap->aliceclaim.txbytes[i]); + printf(" <- aliceclaim\n"); + //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); + return(retval); + } + } + printf("error with bobdeposit\n"); + return(-1); +} + +int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) +{ + if ( LP_rawtx_spendscript(swap,swap->alicecoin.longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) + { + swap->alicepayment.I.signedtxid = LP_broadcast_tx(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) + swap->aliceunconf = 1; + basilisk_dontforget_update(swap,&swap->alicepayment); + return(0); + } + else return(-1); +} + +int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) +{ + uint8_t userdata[512]; int32_t i,retval,len = 0; bits256 revAm; + memset(revAm.bytes,0,sizeof(revAm)); + if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) + { + swap->bobpayment.I.signedtxid = LP_broadcast_tx(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) + swap->paymentunconf = 1; + basilisk_dontforget_update(swap,&swap->bobpayment); + for (i=0; i<32; i++) + revAm.bytes[i] = swap->I.privAm.bytes[31-i]; + len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + memcpy(swap->I.userdata_alicespend,userdata,len); + swap->I.userdata_alicespendlen = len; + char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) + { + for (i=0; ibobpayment.I.datalen; i++) + printf("%02x",swap->bobpayment.txbytes[i]); + printf(" <- bobpayment\n"); + for (i=0; ialicespend.I.datalen; i++) + printf("%02x",swap->alicespend.txbytes[i]); + printf(" <- alicespend\n\n"); + swap->I.alicespent = 1; + //basilisk_txlog(swap,&swap->alicespend,-1); + return(retval); + } + } + return(-1); +} From 1b97251bc675529d248edd6b89704ba6e1737f50 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:05:34 +0300 Subject: [PATCH 0867/2705] Test --- iguana/exchanges/LP_statemachine.c | 219 ++++++++++++++++++++++++++++ iguana/exchanges/LP_swap.c | 222 +---------------------------- 2 files changed, 221 insertions(+), 220 deletions(-) diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index 950e22e88..9b4604c25 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -724,6 +724,225 @@ cJSON *basilisk_privkeyarray(struct iguana_info *coin,cJSON *vins) #endif +#ifdef old +void basilisk_swaploop(void *_utxo) +{ + uint8_t *data; uint32_t expiration,savestatebits=0,saveotherbits=0; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; + swap = utxo->swap; + fprintf(stderr,"start swap iambob.%d\n",swap->I.iambob); + maxlen = 1024*1024 + sizeof(*swap); + data = malloc(maxlen); + expiration = (uint32_t)time(NULL) + 300; + //myinfo->DEXactive = expiration; + channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); + while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) + { + LP_channelsend(swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); + if ( swap->connected == 0 ) + basilisk_psockinit(swap,swap->I.iambob != 0); + if ( swap->connected > 0 ) + { + printf("A r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); + basilisk_sendstate(swap,data,maxlen); + basilisk_sendpubkeys(swap,data,maxlen); // send pubkeys + if ( basilisk_checkdeck(swap,data,maxlen) == 0) // check for other deck 0x02 + basilisk_sendchoosei(swap,data,maxlen); + basilisk_waitchoosei(swap,data,maxlen); // wait for choosei 0x08 + if ( (swap->I.statebits & (0x08|0x02)) == (0x08|0x02) ) + break; + } + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + } + if ( swap->connected == 0 ) + { + printf("couldnt establish connection\n"); + retval = -1; + } + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 ) + { + if ( swap->connected == 0 ) + basilisk_psockinit(swap,swap->I.iambob != 0); + printf("B r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); + basilisk_sendstate(swap,data,maxlen); + basilisk_sendchoosei(swap,data,maxlen); + basilisk_sendmostprivs(swap,data,maxlen); + if ( basilisk_swapget(swap,0x20,data,maxlen,basilisk_verify_privkeys) == 0 ) + { + swap->I.statebits |= 0x20; + break; + } + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + if ( time(NULL) > expiration ) + break; + } + //myinfo->DEXactive = swap->I.expiration; + if ( time(NULL) >= expiration ) + { + retval = -1; + //myinfo->DEXactive = 0; + } + if ( swap->aborted != 0 ) + { + printf("swap aborted before tx sent\n"); + retval = -1; + } + printf("C r%u/q%u swapstate.%x retval.%d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,retval); + iters = 0; + while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x40) == 0 && iters++ < 10 ) // send fee + { + if ( swap->connected == 0 ) + basilisk_psockinit(swap,swap->I.iambob != 0); + //printf("sendstate.%x\n",swap->I.statebits); + basilisk_sendstate(swap,data,maxlen); + //printf("swapget\n"); + basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + //printf("after swapget\n"); + if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) + { + printf("bobscripts set\n"); + if ( basilisk_bobscripts_set(swap,1,1) < 0 ) + { + sleep(DEX_SLEEP); + printf("bobscripts set error\n"); + continue; + } + } + if ( swap->I.iambob == 0 ) + { + /*for (i=0; i<20; i++) + printf("%02x",swap->secretAm[i]); + printf(" <- secretAm\n"); + for (i=0; i<32; i++) + printf("%02x",swap->secretAm256[i]); + printf(" <- secretAm256\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubAm.bytes[i]); + printf(" <- pubAm\n"); + for (i=0; i<20; i++) + printf("%02x",swap->secretBn[i]); + printf(" <- secretBn\n"); + for (i=0; i<32; i++) + printf("%02x",swap->secretBn256[i]); + printf(" <- secretBn256\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubBn.bytes[i]); + printf(" <- pubBn\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubA0.bytes[i]); + printf(" <- pubA0\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubA1.bytes[i]); + printf(" <- pubA1\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubB0.bytes[i]); + printf(" <- pubB0\n"); + for (i=0; i<32; i++) + printf("%02x",swap->pubB1.bytes[i]); + printf(" <- pubB1\n");*/ + if ( (retval= basilisk_alicetxs(swap,data,maxlen)) != 0 ) + { + printf("basilisk_alicetxs error\n"); + break; + } + } + } + if ( swap->I.iambob == 0 && (swap->I.statebits & 0x40) == 0 ) + { + printf("couldnt send fee\n"); + retval = -8; + } + if ( retval == 0 ) + { + if ( swap->I.iambob == 0 && (swap->myfee.I.datalen == 0 || swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.datalen == 0) ) + { + printf("ALICE's error %d %d %d\n",swap->myfee.I.datalen,swap->alicepayment.I.datalen,swap->alicepayment.I.datalen); + retval = -7; + } + else if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) //swap->bobpayment.I.datalen == 0 + { + printf("BOB's error %d %d %d\n",swap->myfee.I.datalen,swap->bobpayment.I.datalen,swap->bobdeposit.I.datalen); + retval = -7; + } + } + while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(swap,data,maxlen) == 0 ) + { + if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) + sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); + savestatebits = swap->I.statebits; + saveotherbits = swap->I.otherstatebits; + basilisk_sendstate(swap,data,maxlen); + basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); + basilisk_swap_saveupdate(swap); + if ( time(NULL) > swap->I.expiration ) + break; + } + if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen != 0 && bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) + { + printf("BOB waiting for confirm state.%x\n",swap->I.statebits); + sleep(60); // wait for confirm/propagation of msig + printf("BOB reclaims refund\n"); + basilisk_bobdeposit_refund(swap,0); + if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobrefund,0x40000000,0) == 0 ) // use secretBn + { + printf("Bob submit error getting refund of deposit\n"); + } + else + { + // maybe wait for bobrefund to be confirmed + for (j=datalen=0; j<32; j++) + data[datalen++] = swap->I.privBn.bytes[j]; + LP_swapsend(swap,0x40000000,data,datalen,0x40000000,swap->I.crcs_mypriv); + } + basilisk_swap_saveupdate(swap); + } + if ( retval != 0 ) + basilisk_swap_sendabort(swap); + printf("end of atomic swap\n"); + if ( swapcompleted(swap) > 0 ) // only if swap completed + { + if ( swap->I.iambob != 0 ) + tradebot_pendingadd(swapjson(swap),swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); + else tradebot_pendingadd(swapjson(swap),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.src,dstr(swap->I.req.srcamount)); + } + printf("%s swap finished statebits %x\n",swap->I.iambob!=0?"BOB":"ALICE",swap->I.statebits); + //basilisk_swap_purge(swap); + free(data); +} +#endif + +int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct iguana_info **alicecoinp,char *src,char *dest,bits256 srchash,bits256 desthash) +{ + struct iguana_info *coin = LP_coinfind(src); + if ( coin == 0 || LP_coinfind(dest) == 0 ) + return(0); + *bobcoinp = *alicecoinp = 0; + *bobcoinp = LP_coinfind(dest); + *alicecoinp = LP_coinfind(src); + if ( bits256_cmp(pubkey,srchash) == 0 ) + { + if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) + return(1); + else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) + return(-1); + else return(0); + } + else if ( bits256_cmp(pubkey,desthash) == 0 ) + { + if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) + return(-1); + else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) + return(1); + else return(0); + } + return(0); +} + /*void basilisk_swap_purge(struct basilisk_swap *swap) { int32_t i,n; diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index c066e3012..55b48fe66 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -119,33 +119,6 @@ */ -int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct iguana_info **alicecoinp,char *src,char *dest,bits256 srchash,bits256 desthash) -{ - struct iguana_info *coin = LP_coinfind(src); - if ( coin == 0 || LP_coinfind(dest) == 0 ) - return(0); - *bobcoinp = *alicecoinp = 0; - *bobcoinp = LP_coinfind(dest); - *alicecoinp = LP_coinfind(src); - if ( bits256_cmp(pubkey,srchash) == 0 ) - { - if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) - return(1); - else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) - return(-1); - else return(0); - } - else if ( bits256_cmp(pubkey,desthash) == 0 ) - { - if ( strcmp(src,(*bobcoinp)->symbol) == 0 ) - return(-1); - else if ( strcmp(dest,(*alicecoinp)->symbol) == 0 ) - return(1); - else return(0); - } - return(0); -} - void basilisk_rawtx_purge(struct basilisk_rawtx *rawtx) { if ( rawtx->vins != 0 ) @@ -498,6 +471,7 @@ struct basilisk_rawtx *LP_swapdata_rawtx(struct basilisk_swap *swap,uint8_t *dat memcpy(data,rawtx->txbytes,rawtx->I.datalen); return(rawtx); } + printf("swapdata rawtx has null txbytes\n"); return(0); } @@ -539,7 +513,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 } } return(nextbits); - } else if ( swap->I.iambob == 0 ) + } //else if ( swap->I.iambob == 0 ) printf("error from basilisk_swapdata_rawtx.%s %p len.%d\n",rawtx->name,rawtx->txbytes,rawtx->I.datalen); return(0); } @@ -636,198 +610,6 @@ void LP_aliceloop(void *_qp) free(qp); } -#ifdef old -void basilisk_swaploop(void *_utxo) -{ - uint8_t *data; uint32_t expiration,savestatebits=0,saveotherbits=0; uint32_t channel; int32_t iters,retval=0,j,datalen,maxlen; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; - swap = utxo->swap; - fprintf(stderr,"start swap iambob.%d\n",swap->I.iambob); - maxlen = 1024*1024 + sizeof(*swap); - data = malloc(maxlen); - expiration = (uint32_t)time(NULL) + 300; - //myinfo->DEXactive = expiration; - channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); - while ( swap->aborted == 0 && (swap->I.statebits & (0x08|0x02)) != (0x08|0x02) && time(NULL) < expiration ) - { - LP_channelsend(swap->I.req.srchash,swap->I.req.desthash,channel,0x4000000,(void *)&swap->I.req.requestid,sizeof(swap->I.req.requestid)); //,60); - if ( swap->connected == 0 ) - basilisk_psockinit(swap,swap->I.iambob != 0); - if ( swap->connected > 0 ) - { - printf("A r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); - basilisk_sendstate(swap,data,maxlen); - basilisk_sendpubkeys(swap,data,maxlen); // send pubkeys - if ( basilisk_checkdeck(swap,data,maxlen) == 0) // check for other deck 0x02 - basilisk_sendchoosei(swap,data,maxlen); - basilisk_waitchoosei(swap,data,maxlen); // wait for choosei 0x08 - if ( (swap->I.statebits & (0x08|0x02)) == (0x08|0x02) ) - break; - } - if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) - sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); - savestatebits = swap->I.statebits; - saveotherbits = swap->I.otherstatebits; - } - if ( swap->connected == 0 ) - { - printf("couldnt establish connection\n"); - retval = -1; - } - while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x20) == 0 ) - { - if ( swap->connected == 0 ) - basilisk_psockinit(swap,swap->I.iambob != 0); - printf("B r%u/q%u swapstate.%x\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits); - basilisk_sendstate(swap,data,maxlen); - basilisk_sendchoosei(swap,data,maxlen); - basilisk_sendmostprivs(swap,data,maxlen); - if ( basilisk_swapget(swap,0x20,data,maxlen,basilisk_verify_privkeys) == 0 ) - { - swap->I.statebits |= 0x20; - break; - } - if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) - sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); - savestatebits = swap->I.statebits; - saveotherbits = swap->I.otherstatebits; - if ( time(NULL) > expiration ) - break; - } - //myinfo->DEXactive = swap->I.expiration; - if ( time(NULL) >= expiration ) - { - retval = -1; - //myinfo->DEXactive = 0; - } - if ( swap->aborted != 0 ) - { - printf("swap aborted before tx sent\n"); - retval = -1; - } - printf("C r%u/q%u swapstate.%x retval.%d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,retval); - iters = 0; - while ( swap->aborted == 0 && retval == 0 && (swap->I.statebits & 0x40) == 0 && iters++ < 10 ) // send fee - { - if ( swap->connected == 0 ) - basilisk_psockinit(swap,swap->I.iambob != 0); - //printf("sendstate.%x\n",swap->I.statebits); - basilisk_sendstate(swap,data,maxlen); - //printf("swapget\n"); - basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); - //printf("after swapget\n"); - if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) - { - printf("bobscripts set\n"); - if ( basilisk_bobscripts_set(swap,1,1) < 0 ) - { - sleep(DEX_SLEEP); - printf("bobscripts set error\n"); - continue; - } - } - if ( swap->I.iambob == 0 ) - { - /*for (i=0; i<20; i++) - printf("%02x",swap->secretAm[i]); - printf(" <- secretAm\n"); - for (i=0; i<32; i++) - printf("%02x",swap->secretAm256[i]); - printf(" <- secretAm256\n"); - for (i=0; i<32; i++) - printf("%02x",swap->pubAm.bytes[i]); - printf(" <- pubAm\n"); - for (i=0; i<20; i++) - printf("%02x",swap->secretBn[i]); - printf(" <- secretBn\n"); - for (i=0; i<32; i++) - printf("%02x",swap->secretBn256[i]); - printf(" <- secretBn256\n"); - for (i=0; i<32; i++) - printf("%02x",swap->pubBn.bytes[i]); - printf(" <- pubBn\n"); - for (i=0; i<32; i++) - printf("%02x",swap->pubA0.bytes[i]); - printf(" <- pubA0\n"); - for (i=0; i<32; i++) - printf("%02x",swap->pubA1.bytes[i]); - printf(" <- pubA1\n"); - for (i=0; i<32; i++) - printf("%02x",swap->pubB0.bytes[i]); - printf(" <- pubB0\n"); - for (i=0; i<32; i++) - printf("%02x",swap->pubB1.bytes[i]); - printf(" <- pubB1\n");*/ - if ( (retval= basilisk_alicetxs(swap,data,maxlen)) != 0 ) - { - printf("basilisk_alicetxs error\n"); - break; - } - } - } - if ( swap->I.iambob == 0 && (swap->I.statebits & 0x40) == 0 ) - { - printf("couldnt send fee\n"); - retval = -8; - } - if ( retval == 0 ) - { - if ( swap->I.iambob == 0 && (swap->myfee.I.datalen == 0 || swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.datalen == 0) ) - { - printf("ALICE's error %d %d %d\n",swap->myfee.I.datalen,swap->alicepayment.I.datalen,swap->alicepayment.I.datalen); - retval = -7; - } - else if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen == 0 ) //swap->bobpayment.I.datalen == 0 - { - printf("BOB's error %d %d %d\n",swap->myfee.I.datalen,swap->bobpayment.I.datalen,swap->bobdeposit.I.datalen); - retval = -7; - } - } - while ( swap->aborted == 0 && retval == 0 && basilisk_swapiteration(swap,data,maxlen) == 0 ) - { - if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) - sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); - savestatebits = swap->I.statebits; - saveotherbits = swap->I.otherstatebits; - basilisk_sendstate(swap,data,maxlen); - basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); - basilisk_swap_saveupdate(swap); - if ( time(NULL) > swap->I.expiration ) - break; - } - if ( swap->I.iambob != 0 && swap->bobdeposit.I.datalen != 0 && bits256_nonz(swap->bobdeposit.I.actualtxid) != 0 ) - { - printf("BOB waiting for confirm state.%x\n",swap->I.statebits); - sleep(60); // wait for confirm/propagation of msig - printf("BOB reclaims refund\n"); - basilisk_bobdeposit_refund(swap,0); - if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobrefund,0x40000000,0) == 0 ) // use secretBn - { - printf("Bob submit error getting refund of deposit\n"); - } - else - { - // maybe wait for bobrefund to be confirmed - for (j=datalen=0; j<32; j++) - data[datalen++] = swap->I.privBn.bytes[j]; - LP_swapsend(swap,0x40000000,data,datalen,0x40000000,swap->I.crcs_mypriv); - } - basilisk_swap_saveupdate(swap); - } - if ( retval != 0 ) - basilisk_swap_sendabort(swap); - printf("end of atomic swap\n"); - if ( swapcompleted(swap) > 0 ) // only if swap completed - { - if ( swap->I.iambob != 0 ) - tradebot_pendingadd(swapjson(swap),swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount)); - else tradebot_pendingadd(swapjson(swap),swap->I.req.dest,dstr(swap->I.req.destamount),swap->I.req.src,dstr(swap->I.req.srcamount)); - } - printf("%s swap finished statebits %x\n",swap->I.iambob!=0?"BOB":"ALICE",swap->I.statebits); - //basilisk_swap_purge(swap); - free(data); -} -#endif - bits256 instantdex_derivekeypair(void *ctx,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash) { bits256 sharedsecret; From 3472fab226e87b30879dad9103bca882bd2c644b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:14:29 +0300 Subject: [PATCH 0868/2705] Test --- iguana/exchanges/LP_swap.c | 2 ++ iguana/exchanges/LP_transaction.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 55b48fe66..46d05fbe7 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -555,6 +555,7 @@ void LP_bobloop(void *_utxo) printf("%s\n",retstr); free(retstr); } + sleep(10); } } basilisk_swap_finished(swap); @@ -601,6 +602,7 @@ void LP_aliceloop(void *_qp) printf("%s\n",retstr); free(retstr); } + sleep(10); } } basilisk_swap_finished(swap); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 29cda5305..f51844127 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1432,7 +1432,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { rawtx->I.actualtxid = rawtx->I.signedtxid; - //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,rawtx->signedtxid),jprint(txobj,0)); + char str[65]; printf("got %s txid.%s (%s)\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),jprint(txobj,0)); rawtx->I.locktime = rawtx->msgtx.lock_time; if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) { @@ -1484,7 +1484,7 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da printf(" <- aliceclaim\n"); //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); return(retval); - } + } else printf("error signing aliceclaim\n"); } printf("error with bobdeposit\n"); return(-1); @@ -1500,7 +1500,8 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t basilisk_dontforget_update(swap,&swap->alicepayment); return(0); } - else return(-1); + printf("error validating alicepayment\n"); + return(-1); } int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) @@ -1532,5 +1533,6 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da return(retval); } } + printf("error validating bobpayment\n"); return(-1); } From 38d1b559356aea6d1f1cca5945259f4f48ae9381 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:16:37 +0300 Subject: [PATCH 0869/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index ca22231aa..46f5cb8ee 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -418,7 +418,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); - if ( bits256_nonz(privkey) != 0 && Q.timestamp == utxo->swappending-LP_RESERVETIME && Q.quotetime >= Q.timestamp && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + if ( bits256_nonz(privkey) != 0 && Q.timestamp == utxo->swappending-LP_RESERVETIME && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { Q.change = destvalue - (Q.destsatoshis+Q.desttxfee); nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); From 399475b7f439a24b292ad96d2b09edfb3569546e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:19:59 +0300 Subject: [PATCH 0870/2705] Test --- iguana/exchanges/LP_network.c | 1 + iguana/exchanges/LP_swap.c | 1 + 2 files changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 45d25e403..faf6137f3 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -163,6 +163,7 @@ uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbit { } } + printf("sent %d bytes\n",sentbytes); //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); free(buf); return(nextbits); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 46d05fbe7..4bfb92b1a 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -406,6 +406,7 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i { if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { + printf("received %d bytes\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); return(retval); From 87f3c78047258ac3496de02afc3f4612bf3b1489 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:25:15 +0300 Subject: [PATCH 0871/2705] Test --- iguana/exchanges/LP_swap.c | 2 +- iguana/exchanges/LP_transaction.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 4bfb92b1a..ed3191e13 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -487,7 +487,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 rawtx->I.actualtxid = LP_broadcast_tx(rawtx->name,rawtx->coin->symbol,rawtx->txbytes,rawtx->I.datalen); if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) { - printf("%s rawtxsend %s vs %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); + printf("%s rawtxsend.[%d] %s vs %s\n",rawtx->name,rawtx->I.datalen,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); rawtx->I.actualtxid = rawtx->I.signedtxid; } if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index f51844127..c6de0c949 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1401,8 +1401,11 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba int32_t datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; bits256 txid; datalen = recvbuf[0]; datalen += (int32_t)recvbuf[1] << 8; - if ( datalen > 65536 ) + if ( datalen > 1024 ) + { + printf("LP_rawtx_spendscript %s datalen.%d too big\n",rawtx->name,datalen); return(-1); + } rawtx->I.redeemlen = recvbuf[2]; data = &recvbuf[3]; if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) From de4837a6e8e680b64d7d32ab8d244772fead97d1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:27:29 +0300 Subject: [PATCH 0872/2705] test --- iguana/exchanges/LP_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index ed3191e13..9acbc9f67 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -496,6 +496,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 sendbuf[sendlen++] = rawtx->I.datalen & 0xff; sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; sendbuf[sendlen++] = rawtx->I.redeemlen; + printf("datalen.%d redeemlen.%d\n",rawtx->I.datalen,rawtx->I.redeemlen); memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) { From ad8e91a832b4c68906853a96bfcbadd932bc137e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:33:18 +0300 Subject: [PATCH 0873/2705] Test --- iguana/exchanges/LP_transaction.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index c6de0c949..c9f50cfda 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1398,16 +1398,22 @@ int32_t LP_verify_otherfee(struct basilisk_swap *swap,uint8_t *data,int32_t data int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) { - int32_t datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; bits256 txid; - datalen = recvbuf[0]; - datalen += (int32_t)recvbuf[1] << 8; + bits256 otherhash,myhash,txid; int32_t i,offset=0,datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; uint32_t quoteid,msgbits; + for (i=0; i<32; i++) + otherhash.bytes[i] = recvbuf[offset++]; + for (i=0; i<32; i++) + myhash.bytes[i] = recvbuf[offset++]; + offset += iguana_rwnum(0,&recvbuf[offset],sizeof(quoteid),"eid); + offset += iguana_rwnum(0,&recvbuf[offset],sizeof(msgbits),&msgbits); + datalen = recvbuf[offset++]; + datalen += (int32_t)recvbuf[offset++] << 8; if ( datalen > 1024 ) { printf("LP_rawtx_spendscript %s datalen.%d too big\n",rawtx->name,datalen); return(-1); } - rawtx->I.redeemlen = recvbuf[2]; - data = &recvbuf[3]; + rawtx->I.redeemlen = recvbuf[offset++]; + data = &recvbuf[offset++]; if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); From f6fbdba6b44aeca77d92cd62cf39bd71b06ee7ba Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:55:30 +0300 Subject: [PATCH 0874/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f651df270..bc691ce86 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -334,7 +334,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0); + char str[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid)); } return(utxo); } From 8d39f92ae210f0176c93a973c99d1d41fd5a7444 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 17:57:57 +0300 Subject: [PATCH 0875/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index bc691ce86..d4197a969 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -820,6 +820,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { value = values[i]; values[i] = 0, used++; + printf("addutxo.(%s)\n",jprint(item,0)); if ( amclient == 0 ) LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); else From 0aaea83995f9e3b214343777f003953e879eccf9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:00:52 +0300 Subject: [PATCH 0876/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d4197a969..ff9efa048 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -820,7 +820,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { value = values[i]; values[i] = 0, used++; - printf("addutxo.(%s)\n",jprint(item,0)); + char str[65],str2[65]; printf("addutxo.(%s) %s %s\n",jprint(item,0),bits256_str(str,txid),bits256_str(str2,jbits256(item,"txid2"))); if ( amclient == 0 ) LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); else From b12e3cd10d15e5c3ef9c7f1b513fe9ab7950d541 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:09:20 +0300 Subject: [PATCH 0877/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ff9efa048..eadcee992 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -292,7 +292,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) { - struct LP_utxoinfo *utxo = 0; uint8_t key[sizeof(txid) + sizeof(vout)]; + struct LP_utxoinfo *utxo = 0; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); @@ -324,17 +324,16 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 utxo->txid2 = deposittxid; utxo->vout2 = depositvout; utxo->satoshis2 = depositsatoshis; - memcpy(key,txid.bytes,sizeof(txid)); - memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - memcpy(utxo->key,key,sizeof(key)); + memcpy(utxo->key,txid.bytes,sizeof(txid)); + memcpy(&utxo->key[sizeof(txid)],&vout,sizeof(vout)); portable_mutex_lock(&LP_utxomutex); - HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(key),utxo); + HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - char str[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid)); + char str[65],str2[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); } return(utxo); } @@ -820,9 +819,12 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { value = values[i]; values[i] = 0, used++; - char str[65],str2[65]; printf("addutxo.(%s) %s %s\n",jprint(item,0),bits256_str(str,txid),bits256_str(str2,jbits256(item,"txid2"))); + char str[65],str2[65]; printf("addutxo.(%s) %s %s\n",jprint(item,0),bits256_str(str,txid),bits256_str(str2,deposittxid)); if ( amclient == 0 ) - LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin); + { + if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) + utxo->mypub = curve25519(privkey,curve25519_basepoint9()); + } else { if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coinaddr,"127.0.0.1",0,0)) != 0 ) From 2e5cd278ab85913825cf7ed6919d52a8ae0dbd6e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:12:33 +0300 Subject: [PATCH 0878/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index eadcee992..3c6320504 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -802,6 +802,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { item = jitem(array,i); deposittxid = jbits256(item,"txid"); + char str[65],str2[65]; printf("addutxo.(%s) %s\n",jprint(item,0),bits256_str(str,deposittxid)); depositvout = juint(item,"vout"); script = jstr(item,"scriptPubKey"); depositval = values[i]; @@ -819,7 +820,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { value = values[i]; values[i] = 0, used++; - char str[65],str2[65]; printf("addutxo.(%s) %s %s\n",jprint(item,0),bits256_str(str,txid),bits256_str(str2,deposittxid)); + printf("addutxo.(%s) %s %s\n",jprint(item,0),bits256_str(str,txid),bits256_str(str2,deposittxid)); if ( amclient == 0 ) { if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) From d66a5ac9a786632d0c462715cf03a4a28fd40a89 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:15:57 +0300 Subject: [PATCH 0879/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3c6320504..7fc8a2733 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -802,7 +802,6 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { item = jitem(array,i); deposittxid = jbits256(item,"txid"); - char str[65],str2[65]; printf("addutxo.(%s) %s\n",jprint(item,0),bits256_str(str,deposittxid)); depositvout = juint(item,"vout"); script = jstr(item,"scriptPubKey"); depositval = values[i]; @@ -810,17 +809,17 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb if ( amclient != 0 ) targetval = (depositval / 776) + 50000; else targetval = (depositval / 9) * 8; - //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); + printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) { item = jitem(array,i); txid = jbits256(item,"txid"); vout = juint(item,"vout"); + printf("j.%d %.8f target %.8f\n",i,dstr(values[i]),dstr(targetval)); if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 ) { value = values[i]; values[i] = 0, used++; - printf("addutxo.(%s) %s %s\n",jprint(item,0),bits256_str(str,txid),bits256_str(str2,deposittxid)); if ( amclient == 0 ) { if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) From 9ef56e6143bfc3d6e022aa6e57c21dc8fc963bdb Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:22:33 +0300 Subject: [PATCH 0880/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7fc8a2733..98c509d7b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -518,7 +518,7 @@ void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock { if ( i++ < firsti ) continue; - if ( utxo->lasttime != now ) + if ( utxo->lasttime != now && strcmp(utxo->ipaddr,"127.0.0.1") != 0 ) { char str[65]; printf("{%s:%u %s} ",utxo->ipaddr,utxo->port,bits256_str(str,utxo->txid)); flag++; From 1e1c4e3098be3d2c065f650dd3354ee503ee9ae7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:30:44 +0300 Subject: [PATCH 0881/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 98c509d7b..cfedfab1e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -410,8 +410,8 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs { if ( destpeer->numutxos < n ) { - destpeer->numutxos = n; - printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); + //destpeer->numutxos = n; + //printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); } } } From c87311d4155022e444749ea4f1c1a6b680ff321e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:38:19 +0300 Subject: [PATCH 0882/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index cfedfab1e..d846074f4 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -298,6 +298,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); return(0); } + if ( amclient == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) + { + printf("LP node got localhost utxo\n"); + return(0); + } if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->txid2) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->vout2 || depositsatoshis != utxo->satoshis2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) From 47d38bd91cf8a3e10ed33db0e2651cb355ecc802 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:43:35 +0300 Subject: [PATCH 0883/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d846074f4..c056d38d8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -935,7 +935,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) LP_peersquery(amclient,mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); } - if ( peer->numutxos != mypeer->numutxos ) + if ( peer->numutxos > mypeer->numutxos ) { lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; if ( lastn < 0 ) From c28396d4b592587709eb8584f978616a1fd0c713 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:57:30 +0300 Subject: [PATCH 0884/2705] Test --- iguana/exchanges/LP_swap.c | 5 ++--- iguana/exchanges/LP_transaction.c | 26 ++++++++++++++------------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 9acbc9f67..01aa3d3e2 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -483,11 +483,10 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 { if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) { - char str[65],str2[65]; rawtx->I.actualtxid = LP_broadcast_tx(rawtx->name,rawtx->coin->symbol,rawtx->txbytes,rawtx->I.datalen); if ( bits256_cmp(rawtx->I.actualtxid,rawtx->I.signedtxid) != 0 ) { - printf("%s rawtxsend.[%d] %s vs %s\n",rawtx->name,rawtx->I.datalen,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); + //printf("%s rawtxsend.[%d] %s vs %s\n",rawtx->name,rawtx->I.datalen,bits256_str(str,rawtx->I.signedtxid),bits256_str(str2,rawtx->I.actualtxid)); rawtx->I.actualtxid = rawtx->I.signedtxid; } if ( bits256_nonz(rawtx->I.actualtxid) != 0 && msgbits != 0 ) @@ -496,7 +495,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 sendbuf[sendlen++] = rawtx->I.datalen & 0xff; sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; sendbuf[sendlen++] = rawtx->I.redeemlen; - printf("datalen.%d redeemlen.%d\n",rawtx->I.datalen,rawtx->I.redeemlen); + //printf("datalen.%d redeemlen.%d\n",rawtx->I.datalen,rawtx->I.redeemlen); memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index c9f50cfda..78be11aaf 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1473,7 +1473,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { - uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; + uint8_t userdata[512]; int32_t i,retval=-1,len = 0; static bits256 zero; if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); @@ -1483,20 +1483,21 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_aliceclaim,userdata,len); swap->I.userdata_aliceclaimlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) + retval = 0; + //if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) { for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); printf(" <- bobdeposit\n"); - for (i=0; ialiceclaim.I.datalen; i++) - printf("%02x",swap->aliceclaim.txbytes[i]); - printf(" <- aliceclaim\n"); + //for (i=0; ialiceclaim.I.datalen; i++) + // printf("%02x",swap->aliceclaim.txbytes[i]); + //printf(" <- aliceclaim\n"); //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); return(retval); - } else printf("error signing aliceclaim\n"); + } //else printf("error signing aliceclaim\n"); } printf("error with bobdeposit\n"); - return(-1); + return(retval); } int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) @@ -1515,7 +1516,7 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { - uint8_t userdata[512]; int32_t i,retval,len = 0; bits256 revAm; + uint8_t userdata[512]; int32_t i,retval=-1,len = 0; bits256 revAm; memset(revAm.bytes,0,sizeof(revAm)); if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { @@ -1528,15 +1529,16 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); memcpy(swap->I.userdata_alicespend,userdata,len); swap->I.userdata_alicespendlen = len; + retval = 0; char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) + //if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) { for (i=0; ibobpayment.I.datalen; i++) printf("%02x",swap->bobpayment.txbytes[i]); printf(" <- bobpayment\n"); - for (i=0; ialicespend.I.datalen; i++) - printf("%02x",swap->alicespend.txbytes[i]); - printf(" <- alicespend\n\n"); + //for (i=0; ialicespend.I.datalen; i++) + // printf("%02x",swap->alicespend.txbytes[i]); + //printf(" <- alicespend\n\n"); swap->I.alicespent = 1; //basilisk_txlog(swap,&swap->alicespend,-1); return(retval); From c0ae01e5a507feabbf1a56c571c93e1e586b4a92 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 18:58:55 +0300 Subject: [PATCH 0885/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 46f5cb8ee..8c0ee8730 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -418,7 +418,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); - if ( bits256_nonz(privkey) != 0 && Q.timestamp == utxo->swappending-LP_RESERVETIME && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { Q.change = destvalue - (Q.destsatoshis+Q.desttxfee); nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); From 238e74d443ed16fe7ade22cb68b403942ab2b0b9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 19:20:25 +0300 Subject: [PATCH 0886/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- iguana/exchanges/mm.c | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 01aa3d3e2..72a1804d6 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -556,7 +556,7 @@ void LP_bobloop(void *_utxo) printf("%s\n",retstr); free(retstr); } - sleep(10); + sleep(100); } } basilisk_swap_finished(swap); @@ -603,7 +603,7 @@ void LP_aliceloop(void *_qp) printf("%s\n",retstr); free(retstr); } - sleep(10); + sleep(100); } } basilisk_swap_finished(swap); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 4fc22eda1..f2dffc4de 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -829,6 +829,12 @@ int main(int argc, const char * argv[]) printf("error launching LP_main (%s)\n",jprint(retjson,0)); exit(-1); } else printf("(%s) launched.(%s)\n",argv[1],passphrase); + if ( (retstr= basilisk_swaplist()) != 0 ) + { + printf("%s\ngetchar to continue\n",retstr); + getchar(); + free(retstr); + } incr = 100.; while ( 1 ) { From dc3ae44f6828dd905f3ca4ecd79a55780551e7b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 19:24:15 +0300 Subject: [PATCH 0887/2705] Test --- iguana/exchanges/LP_remember.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index faea5b665..db1f55f9b 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -559,13 +559,13 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( bits256_nonz(privkey) != 0 ) { privAm = privkey; - //printf("set privAm <- %s\n",bits256_str(str,privAm)); + printf("set privAm <- %s\n",bits256_str(str,privAm)); } privkey = jbits256(item,"privBn"); if ( bits256_nonz(privkey) != 0 ) { privBn = privkey; - //printf("set privBn <- %s\n",bits256_str(str,privBn)); + printf("set privBn <- %s\n",bits256_str(str,privBn)); } expiration = juint(item,"expiration"); state = jint(item,"state"); From 0475f88c370f52aaf9027375b276d77e4211fb19 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 19:42:42 +0300 Subject: [PATCH 0888/2705] Test --- iguana/exchanges/LP_transaction.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 78be11aaf..a63f971f7 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -637,6 +637,9 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jaddnum(item,"vout",vout); bitcoin_address(tmpaddr,pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); + if ( addrtype == p2shtype ) + spendlen = bitcoin_p2shspend(spendscript,0,rmd160); + else spendlen = bitcoin_standardspend(spendscript,0,rmd160); /*int32_t i; for (i=0; i<33; i++) printf("%02x",pubkey33[i]); @@ -648,11 +651,8 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" <- vs direct calc\n");*/ - spendlen = bitcoin_standardspend(spendscript,0,rmd160); + //spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); - //sobj = cJSON_CreateObject(); - //jaddstr(sobj,"hex",hexstr); - //jadd(item,"scriptPubKey",sobj); jaddstr(item,"scriptPubKey",hexstr); jaddnum(item,"suppress",suppress_pubkeys); jaddnum(item,"sequence",sequenceid); From 6ede6c7e9dea6398d3a574664c7ac2c47bace4ae Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 19:45:21 +0300 Subject: [PATCH 0889/2705] Test --- iguana/exchanges/LP_transaction.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index a63f971f7..72ff0e45d 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -637,9 +637,6 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jaddnum(item,"vout",vout); bitcoin_address(tmpaddr,pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); - if ( addrtype == p2shtype ) - spendlen = bitcoin_p2shspend(spendscript,0,rmd160); - else spendlen = bitcoin_standardspend(spendscript,0,rmd160); /*int32_t i; for (i=0; i<33; i++) printf("%02x",pubkey33[i]); @@ -652,15 +649,16 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf("%02x",rmd160[i]); printf(" <- vs direct calc\n");*/ //spendlen = bitcoin_standardspend(spendscript,0,rmd160); - init_hexbytes_noT(hexstr,spendscript,spendlen); - jaddstr(item,"scriptPubKey",hexstr); - jaddnum(item,"suppress",suppress_pubkeys); - jaddnum(item,"sequence",sequenceid); if ( redeemlen != 0 ) { init_hexbytes_noT(hexstr,redeemscript,redeemlen); jaddstr(item,"redeemScript",hexstr); - } + spendlen = bitcoin_p2shspend(spendscript,0,rmd160); + } else spendlen = bitcoin_standardspend(spendscript,0,rmd160); + init_hexbytes_noT(hexstr,spendscript,spendlen); + jaddstr(item,"scriptPubKey",hexstr); + jaddnum(item,"suppress",suppress_pubkeys); + jaddnum(item,"sequence",sequenceid); jaddi(vins,item); jdelete(txobj,"vin"); jadd(txobj,"vin",vins); From c27a08b8c4d7ce2fa0e1c0b58a6b305443412f2e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 19:46:44 +0300 Subject: [PATCH 0890/2705] Test --- iguana/exchanges/LP_transaction.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 72ff0e45d..464fa16d1 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -654,6 +654,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch init_hexbytes_noT(hexstr,redeemscript,redeemlen); jaddstr(item,"redeemScript",hexstr); spendlen = bitcoin_p2shspend(spendscript,0,rmd160); + printf("P2SH path\n"); } else spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); jaddstr(item,"scriptPubKey",hexstr); From d69dcef42da623d183fc56762e7c56cd668843a1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 19:48:38 +0300 Subject: [PATCH 0891/2705] Test --- iguana/exchanges/LP_transaction.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 464fa16d1..0a0a59cfb 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -635,8 +635,6 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } jaddbits256(item,"txid",utxotxid); jaddnum(item,"vout",vout); - bitcoin_address(tmpaddr,pubtype,pubkey33,33); - bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); /*int32_t i; for (i=0; i<33; i++) printf("%02x",pubkey33[i]); @@ -653,9 +651,16 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch { init_hexbytes_noT(hexstr,redeemscript,redeemlen); jaddstr(item,"redeemScript",hexstr); + calc_rmd160_sha256(rmd160,redeemscript,redeemlen); spendlen = bitcoin_p2shspend(spendscript,0,rmd160); printf("P2SH path\n"); - } else spendlen = bitcoin_standardspend(spendscript,0,rmd160); + } + else + { + bitcoin_address(tmpaddr,pubtype,pubkey33,33); + bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + } init_hexbytes_noT(hexstr,spendscript,spendlen); jaddstr(item,"scriptPubKey",hexstr); jaddnum(item,"suppress",suppress_pubkeys); From 71d82f76bdc7f7c90909da0eb4b2286eac18b15d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 20:08:44 +0300 Subject: [PATCH 0892/2705] Test --- iguana/exchanges/LP_remember.c | 22 +++++++++++------ iguana/exchanges/LP_transaction.c | 39 ++++++++++++++++--------------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index db1f55f9b..c9c766449 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -501,9 +501,10 @@ int32_t basilisk_swap_isfinished(int32_t iambob,bits256 *txids,int32_t *sentflag cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requestid,uint32_t quoteid) { static void *ctx; - FILE *fp; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,n,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[1024],userdata[1024]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*txname,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)],signedtxid; struct iguana_info *bob=0,*alice=0; uint64_t txfee = 10000; + FILE *fp; int32_t sentflags[sizeof(txnames)/sizeof(*txnames)],i,n,j,len,needflag,secretstart,redeemlen,addflag,origfinishedflag = 0,finishedflag = 0,iambob = -1; int64_t srcamount,destamount=0,value,values[sizeof(txnames)/sizeof(*txnames)]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],pubkey33[33],redeemscript[1024],userdata[1024]; uint32_t plocktime,dlocktime,expiration=0,r,q,state,otherstate; char *secretstr,*srcstr,*deststr,str[65],src[64],dest[64],fname[512],*fstr,*dest33,*symbol,*txname,*Adest,*Bdest,*AAdest,*ABdest,destaddr[64],Adestaddr[64],alicepaymentaddr[64],bobpaymentaddr[64],bobdepositaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; long fsize; cJSON *txobj,*item,*sentobj,*array; bits256 checktxid,txid,pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,zero,privkey,rev,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)],signedtxid; struct iguana_info *bob=0,*alice=0; uint64_t txfee = 10000; if ( ctx == 0 ) ctx = bitcoin_ctx(); + bobpaymentaddr[0] = bobdepositaddr[0] = alicepaymentaddr[0] = 0; memset(values,0,sizeof(values)); memset(txids,0,sizeof(txids)); memset(secretAm,0,sizeof(secretAm)); @@ -640,6 +641,12 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( bits256_nonz(txid) == 0 ) continue; txids[i] = txid; + if ( jstr(txobj,"Apayment") != 0 ) + strcpy(alicepaymentaddr,jstr(txobj,"Apayment")); + if ( jstr(txobj,"Bpayment") != 0 ) + strcpy(bobpaymentaddr,jstr(txobj,"Bpayment")); + if ( jstr(txobj,"Bdeposit") != 0 ) + strcpy(bobdepositaddr,jstr(txobj,"Bdeposit")); if ( jobj(txobj,"tx") != 0 ) { txbytes[i] = clonestr(jstr(txobj,"tx")); @@ -680,6 +687,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } else if ( finishedflag == 0 ) printf("%s not finished\n",fname); } + printf("alicepayment.%s bobpayment.%s bobdeposit.%s\n",alicepaymentaddr,bobpaymentaddr,bobdepositaddr); //printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); Adestaddr[0] = destaddr[0] = 0; Adest = Bdest = AAdest = ABdest = 0; @@ -748,7 +756,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); printf("alicespend len.%d redeemlen.%d\n",len,redeemlen); - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } @@ -773,7 +781,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0)) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0,bobdepositaddr)) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } @@ -795,7 +803,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti privBn = basilisk_swap_privBn_extract(&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",alicecoin,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM])) != 0 ) + if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",alicecoin,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM],alicepaymentaddr)) != 0 ) printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); } } @@ -825,7 +833,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",alicecoin,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND])) != 0 ) + if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",alicecoin,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND],alicepaymentaddr)) != 0 ) printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); } } @@ -849,7 +857,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0)) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0,bobpaymentaddr)) != 0 ) { int32_t z; for (z=0; z<20; z++) @@ -879,7 +887,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0)) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0,bobdepositaddr)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 0a0a59cfb..e4722fd1f 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -580,7 +580,7 @@ int32_t iguana_signrawtransaction(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS #endif -char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr) +char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr) { char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; *destamountp = 0; @@ -647,20 +647,17 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf("%02x",rmd160[i]); printf(" <- vs direct calc\n");*/ //spendlen = bitcoin_standardspend(spendscript,0,rmd160); + bitcoin_address(tmpaddr,pubtype,pubkey33,33); + bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); if ( redeemlen != 0 ) { init_hexbytes_noT(hexstr,redeemscript,redeemlen); jaddstr(item,"redeemScript",hexstr); - calc_rmd160_sha256(rmd160,redeemscript,redeemlen); + if ( vinaddr != 0 ) + bitcoin_addr2rmd160(&addrtype,rmd160,vinaddr); spendlen = bitcoin_p2shspend(spendscript,0,rmd160); printf("P2SH path\n"); - } - else - { - bitcoin_address(tmpaddr,pubtype,pubkey33,33); - bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); - spendlen = bitcoin_standardspend(spendscript,0,rmd160); - } + } else spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); jaddstr(item,"scriptPubKey",hexstr); jaddnum(item,"suppress",suppress_pubkeys); @@ -707,7 +704,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch return(signedtx); } -int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160) +int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160,char *vinaddr) { int32_t retval=-1,len,iter; char *signedtx,*changeaddr = 0,_changeaddr[64]; struct iguana_info *coin; int64_t newtxfee=0,destamount; if ( (coin= rawtx->coin) == 0 ) @@ -721,7 +718,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -743,7 +740,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub return(retval); } -int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160) +int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160,char *vinaddr) { char *signedtx,*changeaddr = 0,_changeaddr[64]; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; double estimatedrate; timestamp = swap->I.started; @@ -760,7 +757,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -797,7 +794,7 @@ int32_t basilisk_alicescript(uint8_t *redeemscript,int32_t *redeemlenp,uint8_t * return(n); } -char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp) +char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp,char *vinaddr) { char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn,signedtxid; uint64_t txfee; if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) @@ -816,7 +813,7 @@ char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2sht for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ txfee = LP_txfee(symbol); - signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0); + signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr); } return(signedtx); } @@ -1157,6 +1154,7 @@ int32_t basilisk_swapuserdata(uint8_t *userdata,bits256 privkey,int32_t ifpath,b return(len); } +#ifdef old /*Bob paytx: OP_IF OP_CLTV OP_DROP OP_CHECKSIG @@ -1198,6 +1196,7 @@ int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) } return(-1); } +#endif int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) { @@ -1218,7 +1217,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i { //if ( swap->bobpayment.txbytes != 0 && swap->bobpayment.I.spendlen != 0 ) // break; - basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160); + basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) { printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); @@ -1252,7 +1251,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i { //if ( swap->bobdeposit.txbytes != 0 && swap->bobdeposit.I.spendlen != 0 ) // break; - basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160); + basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) { printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); @@ -1308,6 +1307,7 @@ void LP_swap_coinaddr(struct basilisk_swap *swap,struct iguana_info *coin,char * } } +#ifdef old int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_rawtx *dest) { int32_t i,retval; @@ -1336,11 +1336,12 @@ int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_r } return(-1); } +#endif void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) { alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); - basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160); + basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); } int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) @@ -1370,7 +1371,7 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d if ( swap->myfee.I.datalen == 0 ) { //printf("generate fee\n"); - if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160) == 0 ) + if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0) == 0 ) { swap->I.statebits |= LP_swapdata_rawtxsend(pairsock,swap,0x80,data,maxlen,&swap->myfee,0x40,0); LP_unspents_mark(swap->I.iambob!=0?swap->bobcoin.symbol:swap->alicecoin.symbol,swap->myfee.vins); From a572ba12d13308aaac09f6ea2e6af6fe6f203ff4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 20:14:47 +0300 Subject: [PATCH 0893/2705] Test --- iguana/exchanges/LP_transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index e4722fd1f..0a9250112 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -656,7 +656,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch if ( vinaddr != 0 ) bitcoin_addr2rmd160(&addrtype,rmd160,vinaddr); spendlen = bitcoin_p2shspend(spendscript,0,rmd160); - printf("P2SH path\n"); + printf("P2SH path.%s\n",vinaddr!=0?vinaddr:0); } else spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); jaddstr(item,"scriptPubKey",hexstr); @@ -692,7 +692,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); else if ( completed == 0 ) { - printf("incomplete signing %s\n",name); + printf("incomplete signing %s (%s)\n",name,jprint(vins,0)); if ( signedtx != 0 ) free(signedtx), signedtx = 0; } else printf("%s -> %s\n",name,bits256_str(str,*signedtxidp)); From 4f5b42c5e94682d0adf3e85b78d575092599d68a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 20:15:59 +0300 Subject: [PATCH 0894/2705] Test --- iguana/exchanges/LP_rpc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index d35568d2d..d3742e5e0 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -215,7 +215,8 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * decode_hex(data,len>>1,hexstr); *signedtxidp = bits256_doublesha256(0,data,len >> 1); } - else printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); + //else + printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); free_json(json); } free(retstr); From fe55e3def76c8fbff23ed0b580113fe37ab56ed0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 20:43:34 +0300 Subject: [PATCH 0895/2705] Test --- iguana/exchanges/LP_remember.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index c9c766449..41f425b18 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -755,7 +755,12 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); - printf("alicespend len.%d redeemlen.%d\n",len,redeemlen); + { + char privaddr[64]; uint8_t privpub33[33]; + bitcoin_pubkey33(ctx,privpub33,myprivs[0]); + bitcoin_address(privaddr,60,privpub33,33); + printf("alicespend len.%d redeemlen.%d priv0addr.(%s)\n",len,redeemlen,privaddr); + } if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } From 351728c71323b6e7ef83911de0e3fd8197981210 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 20:56:17 +0300 Subject: [PATCH 0896/2705] Test --- iguana/exchanges/LP_transaction.c | 286 +++++++++++++++--------------- 1 file changed, 142 insertions(+), 144 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 0a9250112..3da97beb8 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -107,8 +107,6 @@ int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) return(numconfirms); } - -#ifdef later int32_t iguana_msgtx_Vset(uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,struct vin_info *V) { int32_t vini,j,scriptlen,p2shlen,userdatalen,siglen,plen,need_op0=0,len = 0; uint8_t *script,*redeemscript=0,*userdata=0; struct vin_info *vp; @@ -204,139 +202,7 @@ int32_t iguana_msgtx_Vset(uint8_t *serialized,int32_t maxlen,struct iguana_msgtx return(len); } -int32_t bitcoin_verifyvins(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxlen,struct vin_info *V,uint32_t sighash,int32_t signtx,int32_t suppress_pubkeys) -{ - bits256 sigtxid; uint8_t *sig,*script; struct vin_info *vp; char vpnstr[64]; int32_t scriptlen,complete=0,j,vini=0,flag=0,siglen,numvouts,numsigs; - numvouts = msgtx->tx_out; - vpnstr[0] = 0; - *signedtx = 0; - memset(signedtxidp,0,sizeof(*signedtxidp)); - for (vini=0; vinitx_in; vini++) - { - if ( V->p2shscript[0] != 0 && V->p2shlen != 0 ) - { - script = V->p2shscript; - scriptlen = V->p2shlen; - //printf("V->p2shlen.%d\n",V->p2shlen); - } - else - { - script = msgtx->vins[vini].spendscript; - scriptlen = msgtx->vins[vini].spendlen; - } - sigtxid = bitcoin_sigtxid(pubtype,p2shtype,isPoS,height,serialized,maxlen,msgtx,vini,script,scriptlen,sighash,vpnstr,suppress_pubkeys); - if ( bits256_nonz(sigtxid) != 0 ) - { - vp = &V[vini]; - vp->sigtxid = sigtxid; - for (j=numsigs=0; jN; j++) - { - sig = vp->signers[j].sig; - siglen = vp->signers[j].siglen; - if ( signtx != 0 && bits256_nonz(vp->signers[j].privkey) != 0 ) - { - siglen = bitcoin_sign(swap->ctx,sig,sigtxid,vp->signers[j].privkey,0); - //if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) <= 0 ) - bitcoin_pubkey33(swap->ctx,vp->signers[j].pubkey,vp->signers[j].privkey); - sig[siglen++] = sighash; - vp->signers[j].siglen = siglen; - /*char str[65]; printf("SIGTXID.(%s) ",bits256_str(str,sigtxid)); - int32_t i; for (i=0; isigners[j].pubkey[i]); - // s2 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1; - printf(" SIGNEDTX.[%02x] siglen.%d priv.%s\n",sig[siglen-1],siglen,bits256_str(str,vp->signers[j].privkey));*/ - } - if ( sig == 0 || siglen == 0 ) - { - memset(vp->signers[j].pubkey,0,sizeof(vp->signers[j].pubkey)); - continue; - } - if ( bitcoin_verify(sig,siglen-1,sigtxid,vp->signers[j].pubkey,bitcoin_pubkeylen(vp->signers[j].pubkey)) < 0 ) - { - int32_t k; for (k=0; ksigners[j].pubkey); k++) - printf("%02x",vp->signers[j].pubkey[k]); - printf(" SIG.%d.%d ERROR siglen.%d\n",vini,j,siglen); - } - else - { - flag++; - numsigs++; - /*int32_t z; - for (z=0; zsigners[j].pubkey[z]); - printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M);*/ - } - } - if ( numsigs >= vp->M ) - complete = 1; - } - } - iguana_msgtx_Vset(serialized,maxlen,msgtx,V); - cJSON *txobj = cJSON_CreateObject(); - *signedtx = iguana_rawtxbytes(pubtype,p2shtype,isPoS,height,txobj,msgtx,suppress_pubkeys); - //printf("SIGNEDTX.(%s)\n",jprint(txobj,1)); - *signedtxidp = msgtx->txid; - return(complete); -} - -int32_t iguana_vininfo_create(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msgtx,cJSON *vins,int32_t numinputs,struct vin_info *V) -{ - int32_t i,plen,finalized = 1,len = 0; struct vin_info *vp; //struct iguana_waccount *wacct; struct iguana_waddress *waddr; uint32_t sigsize,pubkeysize,p2shsize,userdatalen; - msgtx->tx_in = numinputs; - maxsize -= (sizeof(struct iguana_msgvin) * msgtx->tx_in); - msgtx->vins = (struct iguana_msgvin *)&serialized[maxsize]; - memset(msgtx->vins,0,sizeof(struct iguana_msgvin) * msgtx->tx_in); - if ( msgtx->tx_in > 0 && msgtx->tx_in*sizeof(struct iguana_msgvin) < maxsize ) - { - for (i=0; itx_in; i++) - { - vp = &V[i]; - //printf("VINS.(%s)\n",jprint(jitem(vins,i),0)); - len += iguana_parsevinobj(&serialized[len],maxsize,&msgtx->vins[i],jitem(vins,i),vp); - if ( msgtx->vins[i].sequence < IGUANA_SEQUENCEID_FINAL ) - finalized = 0; - if ( msgtx->vins[i].spendscript == 0 ) - { - /*if ( iguana_RTunspentindfind(coin,&outpt,vp->coinaddr,vp->spendscript,&vp->spendlen,&vp->amount,&vp->height,msgtx->vins[i].prev_hash,msgtx->vins[i].prev_vout,coin->bundlescount-1,0) == 0 ) - { - vp->unspentind = outpt.unspentind; - msgtx->vins[i].spendscript = vp->spendscript; - msgtx->vins[i].spendlen = vp->spendlen; - vp->hashtype = iguana_vinscriptparse(coin,vp,&sigsize,&pubkeysize,&p2shsize,&userdatalen,vp->spendscript,vp->spendlen); - vp->userdatalen = userdatalen; - printf("V %.8f (%s) spendscript.[%d] userdatalen.%d\n",dstr(vp->amount),vp->coinaddr,vp->spendlen,userdatalen); - }*/ - } - else - { - memcpy(vp->spendscript,msgtx->vins[i].spendscript,msgtx->vins[i].spendlen); - vp->spendlen = msgtx->vins[i].spendlen; - _iguana_calcrmd160(pubtype,p2shtype,vp); - if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) > 0 ) - bitcoin_address(vp->coinaddr,pubtype,vp->signers[0].pubkey,plen); - } - if ( vp->M == 0 && vp->N == 0 ) - vp->M = vp->N = 1; - /*if ( vp->coinaddr[i] != 0 && (waddr= iguana_waddresssearch(&wacct,vp->coinaddr)) != 0 ) - { - vp->signers[0].privkey = waddr->privkey; - if ( (plen= bitcoin_pubkeylen(waddr->pubkey)) != vp->spendscript[1] || vp->spendscript[vp->spendlen-1] != 0xac ) - { - if ( plen > 0 && plen < sizeof(vp->signers[0].pubkey) ) - memcpy(vp->signers[0].pubkey,waddr->pubkey,plen); - } - }*/ - } - } - return(finalized); -} - +#ifdef adfafds void iguana_ensure_privkey(struct iguana_info *coin,bits256 privkey) { uint8_t pubkey33[33]; struct iguana_waccount *wacct; struct iguana_waddress *waddr,addr; char coinaddr[128]; @@ -427,6 +293,7 @@ int32_t iguana_interpreter(struct iguana_info *coin,cJSON *logarray,int64_t nLoc } return(0); } +#endif bits256 iguana_str2priv(char *str) { @@ -447,7 +314,140 @@ bits256 iguana_str2priv(char *str) return(privkey); } -int32_t iguana_signrawtransaction(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,struct iguana_msgtx *msgtx,char **signedtxp,bits256 *signedtxidp,struct vin_info *V,int32_t numinputs,char *rawtx,cJSON *vins,cJSON *privkeysjson) +int32_t iguana_vininfo_create(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msgtx,cJSON *vins,int32_t numinputs,struct vin_info *V) +{ + int32_t i,plen,finalized = 1,len = 0; struct vin_info *vp; //struct iguana_waccount *wacct; struct iguana_waddress *waddr; uint32_t sigsize,pubkeysize,p2shsize,userdatalen; + msgtx->tx_in = numinputs; + maxsize -= (sizeof(struct iguana_msgvin) * msgtx->tx_in); + msgtx->vins = (struct iguana_msgvin *)&serialized[maxsize]; + memset(msgtx->vins,0,sizeof(struct iguana_msgvin) * msgtx->tx_in); + if ( msgtx->tx_in > 0 && msgtx->tx_in*sizeof(struct iguana_msgvin) < maxsize ) + { + for (i=0; itx_in; i++) + { + vp = &V[i]; + //printf("VINS.(%s)\n",jprint(jitem(vins,i),0)); + len += iguana_parsevinobj(&serialized[len],maxsize,&msgtx->vins[i],jitem(vins,i),vp); + if ( msgtx->vins[i].sequence < IGUANA_SEQUENCEID_FINAL ) + finalized = 0; + if ( msgtx->vins[i].spendscript == 0 ) + { + /*if ( iguana_RTunspentindfind(coin,&outpt,vp->coinaddr,vp->spendscript,&vp->spendlen,&vp->amount,&vp->height,msgtx->vins[i].prev_hash,msgtx->vins[i].prev_vout,coin->bundlescount-1,0) == 0 ) + { + vp->unspentind = outpt.unspentind; + msgtx->vins[i].spendscript = vp->spendscript; + msgtx->vins[i].spendlen = vp->spendlen; + vp->hashtype = iguana_vinscriptparse(coin,vp,&sigsize,&pubkeysize,&p2shsize,&userdatalen,vp->spendscript,vp->spendlen); + vp->userdatalen = userdatalen; + printf("V %.8f (%s) spendscript.[%d] userdatalen.%d\n",dstr(vp->amount),vp->coinaddr,vp->spendlen,userdatalen); + }*/ + } + else + { + memcpy(vp->spendscript,msgtx->vins[i].spendscript,msgtx->vins[i].spendlen); + vp->spendlen = msgtx->vins[i].spendlen; + _iguana_calcrmd160(pubtype,p2shtype,vp); + if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) > 0 ) + bitcoin_address(vp->coinaddr,pubtype,vp->signers[0].pubkey,plen); + } + if ( vp->M == 0 && vp->N == 0 ) + vp->M = vp->N = 1; + /*if ( vp->coinaddr[i] != 0 && (waddr= iguana_waddresssearch(&wacct,vp->coinaddr)) != 0 ) + { + vp->signers[0].privkey = waddr->privkey; + if ( (plen= bitcoin_pubkeylen(waddr->pubkey)) != vp->spendscript[1] || vp->spendscript[vp->spendlen-1] != 0xac ) + { + if ( plen > 0 && plen < sizeof(vp->signers[0].pubkey) ) + memcpy(vp->signers[0].pubkey,waddr->pubkey,plen); + } + }*/ + } + } + return(finalized); +} + +int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxlen,struct vin_info *V,uint32_t sighash,int32_t signtx,int32_t suppress_pubkeys) +{ + bits256 sigtxid; uint8_t *sig,*script; struct vin_info *vp; char vpnstr[64]; int32_t scriptlen,complete=0,j,vini=0,flag=0,siglen,numvouts,numsigs; + numvouts = msgtx->tx_out; + vpnstr[0] = 0; + *signedtx = 0; + memset(signedtxidp,0,sizeof(*signedtxidp)); + for (vini=0; vinitx_in; vini++) + { + if ( V->p2shscript[0] != 0 && V->p2shlen != 0 ) + { + script = V->p2shscript; + scriptlen = V->p2shlen; + //printf("V->p2shlen.%d\n",V->p2shlen); + } + else + { + script = msgtx->vins[vini].spendscript; + scriptlen = msgtx->vins[vini].spendlen; + } + sigtxid = bitcoin_sigtxid(pubtype,p2shtype,isPoS,height,serialized,maxlen,msgtx,vini,script,scriptlen,sighash,vpnstr,suppress_pubkeys); + if ( bits256_nonz(sigtxid) != 0 ) + { + vp = &V[vini]; + vp->sigtxid = sigtxid; + for (j=numsigs=0; jN; j++) + { + sig = vp->signers[j].sig; + siglen = vp->signers[j].siglen; + if ( signtx != 0 && bits256_nonz(vp->signers[j].privkey) != 0 ) + { + siglen = bitcoin_sign(ctx,symbol,sig,sigtxid,vp->signers[j].privkey,0); + //if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) <= 0 ) + bitcoin_pubkey33(ctx,vp->signers[j].pubkey,vp->signers[j].privkey); + sig[siglen++] = sighash; + vp->signers[j].siglen = siglen; + /*char str[65]; printf("SIGTXID.(%s) ",bits256_str(str,sigtxid)); + int32_t i; for (i=0; isigners[j].pubkey[i]); + // s2 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1; + printf(" SIGNEDTX.[%02x] siglen.%d priv.%s\n",sig[siglen-1],siglen,bits256_str(str,vp->signers[j].privkey));*/ + } + if ( sig == 0 || siglen == 0 ) + { + memset(vp->signers[j].pubkey,0,sizeof(vp->signers[j].pubkey)); + continue; + } + if ( bitcoin_verify(ctx,sig,siglen-1,sigtxid,vp->signers[j].pubkey,bitcoin_pubkeylen(vp->signers[j].pubkey)) < 0 ) + { + int32_t k; for (k=0; ksigners[j].pubkey); k++) + printf("%02x",vp->signers[j].pubkey[k]); + printf(" SIG.%d.%d ERROR siglen.%d\n",vini,j,siglen); + } + else + { + flag++; + numsigs++; + /*int32_t z; + for (z=0; zsigners[j].pubkey[z]); + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M);*/ + } + } + if ( numsigs >= vp->M ) + complete = 1; + } + } + iguana_msgtx_Vset(serialized,maxlen,msgtx,V); + cJSON *txobj = cJSON_CreateObject(); + *signedtx = iguana_rawtxbytes(pubtype,p2shtype,isPoS,height,txobj,msgtx,suppress_pubkeys); + //printf("SIGNEDTX.(%s)\n",jprint(txobj,1)); + *signedtxidp = msgtx->txid; + return(complete); +} + +int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,struct iguana_msgtx *msgtx,char **signedtxp,bits256 *signedtxidp,struct vin_info *V,int32_t numinputs,char *rawtx,cJSON *vins,cJSON *privkeysjson) { uint8_t *serialized,*serialized2,*serialized3,*serialized4,*extraspace,pubkeys[64][33]; int32_t finalized,i,len,n,z,plen,maxsize,complete = 0,extralen = 65536; char *privkeystr,*signedtx = 0; bits256 privkeys[64],privkey,txid; cJSON *item; cJSON *txobj = 0; maxsize = 1000000; @@ -483,7 +483,7 @@ int32_t iguana_signrawtransaction(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS if ( privkeystr == 0 || privkeystr[0] == 0 ) continue; privkeys[i] = privkey = iguana_str2priv(privkeystr); - bitcoin_pubkey33(swap->ctx,pubkeys[i],privkey); + bitcoin_pubkey33(ctx,pubkeys[i],privkey); //if ( bits256_nonz(privkey) != 0 ) // iguana_ensure_privkey(coin,privkey); } @@ -557,7 +557,7 @@ int32_t iguana_signrawtransaction(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS } finalized = iguana_vininfo_create(pubtype,p2shtype,isPoS,serialized2,maxsize,msgtx,vins,numinputs,V); //printf("finalized.%d\n",finalized); - if ( (complete= bitcoin_verifyvins(pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) + if ( (complete= bitcoin_verifyvins(ctx,symbol,pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) { /*int32_t tmp; //char str[65]; if ( (tmp= iguana_interpreter(coin,0,iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) @@ -577,12 +577,9 @@ int32_t iguana_signrawtransaction(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS return(complete); } - -#endif - char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr) { - char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info *V; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; + char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info V[16]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -605,7 +602,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch else printf("unexpected small value %.8f vs txfee %.8f\n",dstr(value),dstr(txfee)); *destamountp = satoshis; timestamp = (uint32_t)time(NULL); - V = calloc(256,sizeof(*V)); + memset(V,0,sizeof(V)); privkeys = cJSON_CreateArray(); if ( privkey2p != 0 ) { @@ -688,7 +685,8 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch completed = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); - if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) + if ( iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys) <= 0 ) + //if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); else if ( completed == 0 ) { From 8a940e9b221c7795a98719a1833d21414f1b0be1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 20:59:10 +0300 Subject: [PATCH 0897/2705] Test --- iguana/exchanges/LP_transaction.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 3da97beb8..8de54beb1 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -426,13 +426,13 @@ int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shty { flag++; numsigs++; - /*int32_t z; + int32_t z; for (z=0; zsigners[j].pubkey[z]); - printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M);*/ + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M); } } if ( numsigs >= vp->M ) @@ -556,7 +556,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t } } finalized = iguana_vininfo_create(pubtype,p2shtype,isPoS,serialized2,maxsize,msgtx,vins,numinputs,V); - //printf("finalized.%d\n",finalized); + printf("finalized.%d\n",finalized); if ( (complete= bitcoin_verifyvins(ctx,symbol,pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) { /*int32_t tmp; //char str[65]; @@ -698,7 +698,6 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } else printf("error making rawtx\n"); free_json(privkeys); free_json(txobj); - free(V); return(signedtx); } From 2462138338bfa7a5c38ad5f735396335137e8554 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:02:48 +0300 Subject: [PATCH 0898/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 8de54beb1..8dc6c7e6b 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -685,7 +685,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch completed = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); - if ( iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys) <= 0 ) + if ( (completed= iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) //if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); else if ( completed == 0 ) From 3dab4329c9f7b373bba8372fe16a2f997a3ed175 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:17:36 +0300 Subject: [PATCH 0899/2705] Test --- iguana/exchanges/LP_remember.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 41f425b18..a28f5b32f 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -751,8 +751,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti // alicespend for (j=0; j<32; j++) rev.bytes[j] = privAm.bytes[31 - j]; - revcalc_rmd160_sha256(secretAm,rev);//privAm); - vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); + //revcalc_rmd160_sha256(secretAm,rev);//privAm); + //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { From bc01e248c27337b4b35d9da7dc1c086b6871af88 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:18:45 +0300 Subject: [PATCH 0900/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index a28f5b32f..5b6b7e32c 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -754,7 +754,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + len = basilisk_swapuserdata(userdata,privAm/*rev*/,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From 88e13effa7e90a697804be8e1e771e2811aa2479 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:21:42 +0300 Subject: [PATCH 0901/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- iguana/exchanges/LP_transaction.c | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 5b6b7e32c..a28f5b32f 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -754,7 +754,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,privAm/*rev*/,0,myprivs[0],redeemscript,redeemlen); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 8dc6c7e6b..8b31806fb 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -426,13 +426,14 @@ int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shty { flag++; numsigs++; - int32_t z; - for (z=0; zsigners[j].pubkey[z]); - printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d\n",vini,j,numsigs,vp->M); + int32_t z; char tmpaddr[64]; + for (z=0; zsigners[j].pubkey[z]); + bitcoin_address(tmpaddr,60,vp->signers[j].pubkey,33); + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d %s\n",vini,j,numsigs,vp->M,tmpaddr); } } if ( numsigs >= vp->M ) From f8ee4b8762d66f1879124f286aa21ab448c38d80 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:25:02 +0300 Subject: [PATCH 0902/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index a28f5b32f..621795f6f 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -759,7 +759,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); bitcoin_address(privaddr,60,privpub33,33); - printf("alicespend len.%d redeemlen.%d priv0addr.(%s)\n",len,redeemlen,privaddr); + printf("alicespend len.%d redeemlen.%d priv0addr.(%s) priv0.(%s)\n",len,redeemlen,privaddr,bits256_str(str,myprivs[0])); } if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); From 2992320dd9f749c1948cefbad1ef2b572b6ab24a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:30:18 +0300 Subject: [PATCH 0903/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 621795f6f..931e7abac 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -754,7 +754,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + len = basilisk_swapuserdata(userdata,privAm/*rev*/,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From 6f7aaa1b49a908328cc73783f0a0c3ce9bd40c60 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:31:22 +0300 Subject: [PATCH 0904/2705] Test --- iguana/exchanges/LP_remember.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 931e7abac..36bc245e8 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,8 +753,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,privAm/*rev*/,0,myprivs[0],redeemscript,redeemlen); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm/*rev*/,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From 72b53252b30d675570a331ed4149ba0b35644563 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:32:26 +0300 Subject: [PATCH 0905/2705] Test --- iguana/exchanges/LP_transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 8b31806fb..f8384b9d5 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -686,8 +686,8 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch completed = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); - if ( (completed= iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) - //if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) + //if ( (completed= iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) + if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); else if ( completed == 0 ) { From e534091c2b48dfcf6f13c0b18de30532ecf0a3a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:48:18 +0300 Subject: [PATCH 0906/2705] Test --- iguana/exchanges/LP_bitcoin.c | 1131 ++++++++++++++++++++++++++++- iguana/exchanges/LP_include.h | 16 + iguana/exchanges/LP_transaction.c | 28 +- 3 files changed, 1152 insertions(+), 23 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 781a50930..7b403117d 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -395,6 +395,19 @@ void iguana_optableinit() } } +int32_t bitcoin_pubkeylen(const uint8_t *pubkey) +{ + if ( pubkey[0] == 2 || pubkey[0] == 3 ) + return(33); + else if ( pubkey[0] == 4 ) + return(65); + else + { + //printf("illegal pubkey.[%02x] %llx\n",pubkey[0],*(long long *)pubkey); + return(-1); + } +} + int32_t iguana_expandscript(char *asmstr,int32_t maxlen,uint8_t *script,int32_t scriptlen) { int32_t len,n,j,i = 0; uint8_t opcode; uint32_t val,extraflag; @@ -470,6 +483,1111 @@ int32_t iguana_expandscript(char *asmstr,int32_t maxlen,uint8_t *script,int32_t return(len); } +static inline int32_t is_delim(int32_t c) +{ + if ( c == 0 || c == ' ' || c == '\t' || c == '\r' || c == '\n' ) + return(1); + else return(0); +} + +static struct iguana_stackdata iguana_pop(struct iguana_interpreter *stacks) +{ + struct iguana_stackdata Snum; + Snum = stacks->stack[--stacks->stackdepth]; + memset(&stacks->stack[stacks->stackdepth],0,sizeof(Snum)); + return(Snum); +} + +static int32_t iguana_altpush(struct iguana_interpreter *stacks,struct iguana_stackdata Snum) +{ + stacks->stack[2*IGUANA_MAXSTACKITEMS - ++stacks->altstackdepth] = Snum; + return(stacks->altstackdepth); +} + +static struct iguana_stackdata iguana_altpop(struct iguana_interpreter *stacks) +{ + struct iguana_stackdata Snum,*ptr; + ptr = &stacks->stack[2*IGUANA_MAXSTACKITEMS - --stacks->altstackdepth]; + Snum = *ptr; + memset(ptr,0,sizeof(Snum)); + return(Snum); +} + +static struct iguana_stackdata iguana_clone(struct iguana_stackdata Snum) +{ + struct iguana_stackdata clone; + clone = Snum; + if ( Snum.data != 0 ) + { + clone.data = malloc(Snum.size); + memcpy(clone.data,Snum.data,Snum.size); + } + return(clone); +} + +static int32_t iguana_isnonz(struct iguana_stackdata Snum) +{ + uint8_t *buf; int32_t i; + if ( Snum.size == sizeof(int32_t) ) + return(Snum.U.val != 0); + else if ( Snum.size == sizeof(int64_t) ) + return(Snum.U.val64 != 0); + else if ( Snum.size == 20 ) + buf = Snum.U.rmd160; + else if ( Snum.size == sizeof(bits256) ) + buf = Snum.U.hash2.bytes; + else if ( Snum.size == 33 ) + buf = Snum.U.pubkey; + else if ( Snum.size < 74 ) + buf = Snum.U.sig; + else buf = Snum.data; + for (i=0; ilastpath[stacks->ifdepth] < 0 ) + return(0); + //printf("PUSH.(%lld %p %d)\n",(long long)num64,numbuf,numlen); + if ( stacks->maxstackdepth > 0 ) + { + /*if ( numbuf != 0 ) + { + int32_t i; for (i=0; istackdepth < stacks->maxstackdepth ) + { + if ( stacks->logarray != 0 ) + item = cJSON_CreateObject(); + memset(&Snum,0,sizeof(Snum)); + if ( numbuf != 0 ) + { + if ( numlen <= sizeof(int32_t) ) + { + iguana_rwnum(1,(void *)&num,numlen,numbuf); + numlen = sizeof(num); + Snum.U.val = num; + } + else if ( numlen <= sizeof(int64_t) ) + { + iguana_rwnum(1,(void *)&num64,numlen,numbuf); + numlen = sizeof(num64); + Snum.U.val64 = num64; + } + else if ( numlen == 20 ) + memcpy(Snum.U.rmd160,numbuf,20); + else if ( numlen == sizeof(bits256) ) + iguana_rwbignum(1,Snum.U.hash2.bytes,sizeof(Snum.U.hash2),numbuf); + else if ( numlen == 33 ) + memcpy(Snum.U.pubkey,numbuf,numlen); + else if ( numlen < 74 ) + memcpy(Snum.U.sig,numbuf,numlen); + else + { + Snum.data = malloc(numlen); + memcpy(Snum.data,numbuf,numlen); + if ( item != 0 ) + jaddnum(item,"push",numlen); + } + Snum.size = numlen; + if ( item != 0 ) + { + init_hexbytes_noT(tmpstr,numbuf,numlen); + jaddstr(item,"push",tmpstr); + } + } + else if ( num64 <= 0xffffffff ) // what about negative numbers? + { + Snum.U.val = num, Snum.size = sizeof(num); + if ( item != 0 ) + jaddnum(item,"push",Snum.U.val); + } + else + { + Snum.U.val64 = num64, Snum.size = sizeof(num64); + if ( item != 0 ) + jaddnum(item,"push",Snum.U.val64); + } + if ( item != 0 ) + { + jaddnum(item,"depth",stacks->stackdepth); + if ( stacks->logarray != 0 ) + jaddi(stacks->logarray,item); + } + stacks->stack[stacks->stackdepth++] = Snum; + } else return(-1); + } else stacks->stackdepth++; + return(0); +} + +int32_t iguana_databuf(uint8_t *databuf,struct iguana_stackdata Snum) +{ + if ( Snum.size == 4 ) + memcpy(databuf,&Snum.U.val,4); + else if ( Snum.size == 8 ) + memcpy(databuf,&Snum.U.val64,8); + else if ( Snum.size == 20 ) + memcpy(databuf,&Snum.U.rmd160,20); + else if ( Snum.size == 32 ) + memcpy(databuf,&Snum.U.hash2.bytes,32); + else if ( Snum.size == 33 ) + memcpy(databuf,&Snum.U.pubkey,33); + else if ( Snum.size < 74 ) + memcpy(databuf,&Snum.U.sig,Snum.size); + else memcpy(databuf,&Snum.data,Snum.size); + return(Snum.size); +} + +static int32_t iguana_cmp(struct iguana_stackdata *a,struct iguana_stackdata *b) +{ + if ( a->size == b->size ) + { + if ( a->size == 4 ) + return(a->U.val != b->U.val); + else if ( a->size == 8 ) + return(a->U.val64 != b->U.val64); + else if ( a->size == 20 ) + return(memcmp(a->U.rmd160,b->U.rmd160,sizeof(a->U.rmd160))); + else if ( a->size == 32 ) + return(memcmp(a->U.hash2.bytes,b->U.hash2.bytes,sizeof(a->U.hash2))); + else if ( a->size == 33 ) + return(memcmp(a->U.pubkey,b->U.pubkey,33)); + else if ( a->size < 74 ) + return(memcmp(a->U.sig,b->U.sig,a->size)); + else return(memcmp(a->data,b->data,sizeof(a->size))); + } + return(-1); +} + +static int32_t iguana_dataparse(struct iguana_interpreter *stacks,uint8_t *script,int32_t k,char *str,int32_t *lenp) +{ + int32_t n,c,len; char tmp[4]; + *lenp = 0; + c = str[0]; + n = is_hexstr(str,0); + if ( n > 0 ) + { + if ( (n & 1) != 0 ) + len = (n+1) >> 1; + else len = n >> 1; + if ( len > 0 && len < 76 ) + { + if ( len == 1 ) + { + if ( n == 1 ) + { + tmp[0] = '0'; + tmp[1] = c; + tmp[2] = 0; + decode_hex(&script[k],1,tmp), (*lenp) = 1; + iguana_pushdata(stacks,script[k],0,0); + if ( script[k] != 0 ) + script[k++] += (IGUANA_OP_1 - 1); + return(k); + } + else if ( n == 2 && c == '1' && str[1] == '0' && is_delim(str[2]) != 0 ) + { + script[k++] = (IGUANA_OP_1 - 1) + 0x10, (*lenp) = 2; + iguana_pushdata(stacks,0x10,0,0); + return(k); + } + else if ( n == 2 && c == '8' && is_delim(str[2]) != 0 ) + { + if ( str[1] == '1' ) + { + script[k++] = IGUANA_OP_1NEGATE, (*lenp) = 2; + iguana_pushdata(stacks,-1,0,0); + return(k); + } + else if ( str[1] == '0' ) + { + script[k++] = IGUANA_OP_0, (*lenp) = 2; + iguana_pushdata(stacks,0,0,0); + return(k); + } + } + } + if ( len != 0 ) + script[k++] = len; + } + else if ( len <= 0xff ) + { + script[k++] = IGUANA_OP_PUSHDATA1; + script[k++] = len; + } + else if ( len <= 0xffff ) + { + if ( len <= MAX_SCRIPT_ELEMENT_SIZE ) + { + script[k++] = IGUANA_OP_PUSHDATA2; + script[k++] = (len & 0xff); + script[k++] = ((len >> 8) & 0xff); + } + else + { + printf("len.%d > MAX_SCRIPT_ELEMENT_SIZE.%d, offset.%d\n",len,MAX_SCRIPT_ELEMENT_SIZE,k); + return(-1); + } + } + else + { + printf("len.%d > MAX_SCRIPT_ELEMENT_SIZE.%d, offset.%d\n",len,MAX_SCRIPT_ELEMENT_SIZE,k); + return(-1); + } + if ( len != 0 ) + { + uint8_t *numstart; int32_t numlen; + numstart = &script[k], numlen = len; + if ( (n & 1) != 0 ) + { + tmp[0] = '0'; + tmp[1] = c; + tmp[2] = 0; + decode_hex(&script[k++],1,tmp), *lenp = 1; + len--; + } + if ( len != 0 ) + { + decode_hex(&script[k],len,str), (*lenp) += (len << 1); + k += len; + } + iguana_pushdata(stacks,0,numstart,numlen); + } + return(k); + } + return(0); +} + +void iguana_stack(struct iguana_interpreter *stacks,struct iguana_stackdata *args,int32_t num,char *pushstr,char *clonestr) +{ + int32_t i,c; + while ( (c= *pushstr++) != 0 ) + stacks->stack[stacks->stackdepth++] = args[c - '0']; + while ( (c= *clonestr++) != 0 ) + stacks->stack[stacks->stackdepth++] = iguana_clone(args[c - '0']); + if ( num > 0 ) + { + for (i=0; i 0 && siglen > 0 && siglen < 74 ) + { + if ( (retval= (bitcoin_verify(ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0)) == 0 ) + { + } + if ( (0) ) + { + int32_t i; char str[65]; + for (i=0; i 0 && privlen == 32 ) + { + bitcoin_pubkey33(ctx,checkpub,*(bits256 *)privkey); + return(memcmp(checkpub,pubkey,33) == 0); + } + return(0); +} + +int32_t iguana_checkschnorrsig(void *ctx,int64_t M,struct iguana_stackdata pubkeyarg,struct iguana_stackdata sigarg,bits256 sigtxid) +{ + /*uint8_t combined_pub[MAX_SCRIPT_ELEMENT_SIZE],sig[MAX_SCRIPT_ELEMENT_SIZE]; int32_t plen,siglen; + plen = iguana_databuf(combined_pub,pubkeyarg); + siglen = iguana_databuf(sig,sigarg); + if ( bitcoin_pubkeylen(combined_pub) == 33 && siglen == 64 ) + return(bitcoin_schnorr_verify(ctx,sig,sigtxid,combined_pub,33) == 0);*/ + return(0); +} + +int32_t iguana_checkmultisig(void *ctx,struct iguana_interpreter *stacks,int32_t M,int32_t N,bits256 txhash2) +{ + int32_t i,j=0,len,n,m,valid=0,numsigners = 0,siglens[MAX_PUBKEYS_PER_MULTISIG]; uint8_t pubkeys[MAX_PUBKEYS_PER_MULTISIG][MAX_SCRIPT_ELEMENT_SIZE],sigs[MAX_PUBKEYS_PER_MULTISIG][MAX_SCRIPT_ELEMENT_SIZE]; + if ( M <= N && N <= MAX_PUBKEYS_PER_MULTISIG ) + { + if ( stacks->stackdepth <= 0 ) + return(0); + n = (int32_t)iguana_num(iguana_pop(stacks)); + if ( n != N ) + { + printf("iguana_checkmultisig n.%d != N.%d\n",n,N); + return(0); + } + //printf("n.%d stackdepth.%d\n",n,stacks->stackdepth); + for (i=0; istackdepth <= 0 ) + return(0); + len = iguana_databuf(pubkeys[i],iguana_pop(stacks)); + if ( len == bitcoin_pubkeylen(pubkeys[i]) ) + { + numsigners++; + //for (j=0; j<33; j++) + // printf("%02x",pubkeys[i][j]); + //printf(" <- pubkey.[%d]\n",i); + } + else + { + printf("nonpubkey on stack\n"); + return(0); + memcpy(sigs[0],pubkeys[i],len); + siglens[0] = len; + break; + } + } + if ( stacks->stackdepth <= 0 ) + return(0); + m = (int32_t)iguana_num(iguana_pop(stacks)); + //printf("m.%d stackdepth.%d\n",m,stacks->stackdepth); + + if ( m != M ) + { + printf("iguana_checkmultisig m.%d != M.%d\n",m,M); + return(0); + } + for (i=0; istackdepth <= 0 ) + return(0); + siglens[i] = iguana_databuf(sigs[i],iguana_pop(stacks)); + if ( siglens[i] <= 0 || siglens[i] > 74 ) + break; + //for (j=0; jstackdepth,bits256_str(str,txhash2)); + if ( stacks->stackdepth > 0 ) + iguana_pop(stacks); // for backward compatibility + j = numsigners-1; + for (i=numsigners-1; i>=0; i--) + { + for (; j>=0; j--) + { + if ( bitcoin_verify(ctx,sigs[i],siglens[i]-1,txhash2,pubkeys[j],bitcoin_pubkeylen(pubkeys[j])) == 0 ) + { + if ( ++valid >= M ) + return(1); + j--; + break; + } + } + } + } + } + printf("checkmultisig: valid.%d j.%d M.%d N.%d numsigners.%d\n",valid,j,M,N,numsigners); + return(0); +} + +#define LOCKTIME_THRESHOLD 500000000 +int32_t iguana_checklocktimeverify(void *ctx,int64_t tx_lockval,uint32_t nSequence,struct iguana_stackdata Snum) +{ + int64_t nLockTime = iguana_num(Snum); + if ( nLockTime < 0 || tx_lockval < 0 ) + { + printf("CLTV.0 nLockTime.%lld tx_lockval.%lld\n",(long long)nLockTime,(long long)tx_lockval); + return(-1); + } + else if ( ((tx_lockval < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) || + (tx_lockval >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)) == 0 ) + { + printf("CLTV.1 nLockTime.%lld tx_lockval.%lld\n",(long long)nLockTime,(long long)tx_lockval); + return(-1); + } + else if ( nLockTime > tx_lockval ) + { + printf("CLTV.2 nLockTime.%lld tx_lockval.%lld\n",(long long)nLockTime,(long long)tx_lockval); + return(-1); + } + return(0); +} + +int32_t iguana_checksequenceverify(void *ctx,int64_t nLockTime,uint32_t nSequence,struct iguana_stackdata Snum) +{ + return(0); +} + +cJSON *iguana_spendasm(uint8_t *spendscript,int32_t spendlen) +{ + char asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; cJSON *spendasm = cJSON_CreateObject(); + iguana_expandscript(asmstr,sizeof(asmstr),spendscript,spendlen); + //int32_t i; for (i=0; i (%s)\n",asmstr); + jaddstr(spendasm,"interpreter",asmstr); + return(spendasm); +} + +int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCRIPTSIZE],cJSON *interpreter,int32_t interpret,int64_t nLockTime,struct vin_info *V) +{ + struct bitcoin_opcode *op; cJSON *array = 0; struct iguana_interpreter STACKS,*stacks = &STACKS; + struct iguana_stackdata args[MAX_PUBKEYS_PER_MULTISIG]; + uint8_t databuf[MAX_SCRIPT_ELEMENT_SIZE]; char *asmstr,*str,*hexstr; cJSON *item; + int32_t c,numops,dlen,plen,numvars,numused,numargs=0,i,j,k,n=0,len,datalen,errs=0; int64_t val; + iguana_optableinit(); + if ( (asmstr= jstr(interpreter,"interpreter")) == 0 || asmstr[0] == 0 ) + return(0); + if ( (numvars= juint(interpreter,"numvars")) > 0 ) + { + if ( (array= jarray(&n,interpreter,"args")) == 0 || (interpret != 0 && n != numvars) ) + return(-2); + } + str = asmstr; + if ( interpret != 0 ) + { + stacks = calloc(1,sizeof(*stacks) + sizeof(*stacks->stack)*2*IGUANA_MAXSTACKITEMS); + stacks->maxstackdepth = IGUANA_MAXSTACKITEMS; + if ( (stacks->logarray= logarray) != 0 ) + item = cJSON_CreateObject(); + else item = 0; + if ( V->M == 0 && V->N == 0 ) + V->N = V->M = 1; + for (i=0; iN; i++) + { + if ( V->signers[i].siglen != 0 ) + { + iguana_pushdata(stacks,0,V->signers[i].sig,V->signers[i].siglen); + if ( bitcoin_pubkeylen(V->signers[i].pubkey) <= 0 ) + { + printf("missing pubkey.[%d]\n",i); + free(stacks); + return(-1); + } + //printf("pushdata siglen.%d depth.%d\n",V->signers[i].siglen,stacks->stackdepth); + } + } + for (i=0; iN; i++) + { + if ( V->signers[i].siglen != 0 ) + { + plen = bitcoin_pubkeylen(V->signers[i].pubkey); + if ( V->suppress_pubkeys == 0 && (V->spendscript[0] != plen || V->spendscript[V->spendlen - 1] != IGUANA_OP_CHECKSIG || bitcoin_pubkeylen(&V->spendscript[1]) <= 0) ) + { + iguana_pushdata(stacks,0,V->signers[i].pubkey,plen); + //printf(">>>>>>>>> suppress.%d pushdata [%02x %02x] plen.%d depth.%d\n",V->suppress_pubkeys,V->signers[i].pubkey[0],V->signers[i].pubkey[1],plen,stacks->stackdepth); + } // else printf("<<<<<<<<<< skip pubkey push %d script[0].%d spendlen.%d depth.%d\n",plen,V->spendscript[0],V->spendlen,stacks->stackdepth); + } + } + if ( V->userdatalen != 0 ) + { + len = 0; + while ( len < V->userdatalen ) + { + dlen = V->userdata[len++]; + if ( dlen > 0 && dlen < 76 ) + iguana_pushdata(stacks,0,&V->userdata[len],dlen), len += dlen; + else if ( dlen >= IGUANA_OP_1 && dlen <= IGUANA_OP_16 ) + { + dlen -= (IGUANA_OP_1 - 1); + iguana_pushdata(stacks,dlen,0,0); + } + else if ( dlen == IGUANA_OP_PUSHDATA1 ) + { + iguana_pushdata(stacks,V->userdata[len++],0,0); + } + else if ( dlen == IGUANA_OP_PUSHDATA2 ) + { + iguana_pushdata(stacks,V->userdata[len] + ((int32_t)V->userdata[len+1]<<8),0,0); + len += 2; + } + else if ( dlen == IGUANA_OP_0 ) + iguana_pushdata(stacks,0,0,0); + else if ( dlen == IGUANA_OP_1NEGATE ) + iguana_pushdata(stacks,-1,0,0); + else + { + printf("invalid data opcode %02x\n",dlen); + free(stacks); + return(-1); + } + //printf("user data stackdepth.%d dlen.%d\n",stacks->stackdepth,dlen); + } + if ( len != V->userdatalen ) + { + printf("mismatched userdatalen %d vs %d\n",len,V->userdatalen); + free(stacks); + return(-1); + } + } + if ( item != 0 && stacks->logarray != 0 ) + { + jaddstr(item,"spendasm",asmstr); + jaddi(stacks->logarray,item); + } + if ( V->extras != 0 ) + { + if ( (n= cJSON_GetArraySize(V->extras)) > 0 ) + { + for (i=0; iextras,i),0)) != 0 && (len= is_hexstr(hexstr,0)) > 0 ) + { + len >>= 1; + decode_hex(databuf,len,hexstr); + iguana_pushdata(stacks,0,databuf,len); + } + } + } + } + } else memset(stacks,0,sizeof(*stacks)); + stacks->lastpath[0] = 1; + k = numops = numused = 0; + script[k] = 0; + while ( (c= *str++) != 0 ) + { + if ( is_delim(c) != 0 ) + { + //if ( c == 0 ) + // break; + continue; + } + if ( c == '/' && *str == '/' ) // support // + break; + else if ( c == '-' && *str == '1' && is_delim(str[1]) != 0 ) + { + script[k++] = IGUANA_OP_1NEGATE, str += 3; // OP_1NEGATE; + iguana_pushdata(stacks,-1,0,0); + continue; + } + else if ( c == '%' && *str == 's' ) + { + str++; + if ( numused < numvars && (hexstr= jstr(jitem(array,numused++),0)) != 0 ) + { + if ( (n= iguana_dataparse(stacks,script,k,str,&len)) > 0 ) + { + k += n; + continue; + } + } + printf("dataparse error.%d, numused.%d >= numvars.%d\n",n,numused,numvars); + errs++; + break; + } + else + { + str--; + if ( (n= iguana_dataparse(stacks,script,k,str,&len)) > 0 ) + { + k = n; + str += len; + continue; + } + else if ( n < 0 ) + { + printf("dataparse negative n.%d\n",n); + errs++; + break; + } + } + for (j=0; j<32; j++) + if ( is_delim(str[j]) != 0 ) + break; + if ( j == 32 ) + { + printf("too long opcode.%s at offset.%ld\n",str,(long)str-(long)asmstr); + errs++; + break; + } + HASH_FIND(hh,OPTABLE,str,j,op); + //printf("{%s}\n",str); + str += j; + if ( op != 0 ) + { + if ( numargs > 0 ) + { + for (i=0; iopcode; + if ( (op->flags & IGUANA_CONTROLFLAG) != 0 ) + { + //printf("control opcode depth.%d\n",stacks->stackdepth); + switch ( op->opcode ) + { + case IGUANA_OP_IF: case IGUANA_OP_NOTIF: + if ( stacks->ifdepth >= IGUANA_MAXSTACKDEPTH ) + { + printf("ifdepth.%d >= MAXSTACKDEPTH.%d\n",stacks->ifdepth,IGUANA_MAXSTACKDEPTH); + errs++; + } + else + { + if ( stacks->stackdepth <= 0 ) + { + printf("if invalid stackdepth %d\n",stacks->stackdepth); + errs++; + } + else + { + args[0] = iguana_pop(stacks); + if ( iguana_isnonz(args[0]) == (op->opcode == IGUANA_OP_IF) ) + { + val = 1; + //printf("OP_IF enabled depth.%d\n",stacks->stackdepth); + } + else + { + val = -1; + //printf("OP_IF disabled depth.%d\n",stacks->stackdepth); + } + stacks->lastpath[++stacks->ifdepth] = val; + } + } + break; + case IGUANA_OP_ELSE: + /*if ( stacks->stackdepth <= 0 ) + { + printf("else invalid stackdepth %d\n",stacks->stackdepth); + errs++; + } + else*/ + { + if ( stacks->ifdepth <= stacks->elsedepth ) + { + printf("unhandled opcode.%02x stacks->ifdepth %d <= %d stacks->elsedepth\n",op->opcode,stacks->ifdepth,stacks->elsedepth); + errs++; + } + stacks->lastpath[stacks->ifdepth] *= -1; + //printf("OP_ELSE status.%d depth.%d\n",stacks->lastpath[stacks->ifdepth],stacks->stackdepth); + } + break; + case IGUANA_OP_ENDIF: + if ( stacks->ifdepth <= 0 ) + { + printf("endif without if offset.%ld\n",(long)str-(long)asmstr); + errs++; + } + stacks->ifdepth--; + //printf("OP_ENDIF status.%d depth.%d\n",stacks->lastpath[stacks->ifdepth],stacks->stackdepth); + break; + case IGUANA_OP_VERIFY: + break; + case IGUANA_OP_RETURN: + iguana_pushdata(stacks,0,0,0); + errs++; + break; + } + if ( errs != 0 ) + break; + continue; + } + if ( stacks->lastpath[stacks->ifdepth] != 0 ) + { + if ( stacks->lastpath[stacks->ifdepth] < 0 ) + { + //printf("SKIP opcode.%02x depth.%d\n",op->opcode,stacks->stackdepth); + if ( stacks->logarray ) + jaddistr(stacks->logarray,"skip"); + continue; + } + //printf("conditional opcode.%02x stackdepth.%d\n",op->opcode,stacks->stackdepth); + } + if ( op->opcode <= IGUANA_OP_16 || ++numops <= MAX_OPS_PER_SCRIPT ) + { + if ( (op->flags & IGUANA_ALWAYSILLEGAL) != 0 ) + { + printf("disabled opcode.%s at offset.%ld\n",str,(long)str-(long)asmstr); + errs++; + break; + } + else if ( op->extralen > 0 ) + { + if ( is_delim(*str) != 0 ) + str++; + if ( is_hexstr(str,0) != (op->extralen<<1) ) + { + printf("expected extralen.%d of hex, got.(%s) at offset.%ld\n",op->extralen,str,(long)str-(long)asmstr); + errs++; + break; + } + decode_hex(&script[k],op->extralen,str), str += (op->extralen << 1); + if ( op->extralen == 1 ) + iguana_pushdata(stacks,script[k],0,0); + else if ( op->extralen == 2 ) + iguana_pushdata(stacks,script[k] + ((uint32_t)script[k]<<8),0,0); + k += op->extralen; + continue; + } + if ( interpret == 0 || V == 0 ) + continue; + if ( (op->flags & IGUANA_NOPFLAG) != 0 ) + continue; + if ( (numargs= op->stackitems) > 0 ) + { + if ( stacks->stackdepth < op->stackitems ) + { + //printf("stackdepth.%d needed.%d (%s) at offset.%ld\n",stacks->stackdepth,op->stackitems,str,(long)str-(long)asmstr); + errs++; + break; + } + for (i=0; iopcode,numargs,stacks->stackdepth); + if ( stacks->logarray != 0 ) + { + char tmpstr[1096]; + item = cJSON_CreateObject(); + array = cJSON_CreateArray(); + for (i=0; ihh.key,array); + jaddi(stacks->logarray,item); + } + if ( (op->flags & IGUANA_EXECUTIONILLEGAL) != 0 ) + { + printf("opcode not allowed to run.%s at %ld\n",(char *)op->hh.key,(long)str-(long)asmstr); + errs++; + break; + } + else if ( op->opcode == IGUANA_OP_EQUALVERIFY || op->opcode == IGUANA_OP_EQUAL ) + { + if ( iguana_cmp(&args[0],&args[1]) == 0 ) + iguana_pushdata(stacks,1,0,0); + else + { + iguana_pushdata(stacks,0,0,0); + for (i=0; iopcode,args[0].size,args[1].size); + } + } + else if ( (op->flags & IGUANA_CRYPTOFLAG) != 0 ) + { + uint8_t rmd160[20],revdatabuf[MAX_SCRIPT_ELEMENT_SIZE]; bits256 hash; + datalen = iguana_databuf(databuf,args[0]); + for (i=0; iopcode ) + { + case IGUANA_OP_RIPEMD160: + calc_rmd160(0,rmd160,databuf,datalen); + iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); + break; + case IGUANA_OP_SHA1: + calc_sha1(0,rmd160,databuf,datalen); + iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); + break; + case IGUANA_OP_HASH160: + /*if ( datalen == 32 ) + { + revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); + printf("SPECIAL CASE REVERSE\n"); + } else + for (i=0; i<32; i++) + printf("%02x",databuf[i]); + printf(" <- databuf\n"); + for (i=0; i<32; i++) + printf("%02x",revdatabuf[i]); + printf(" <- revdatabuf\n"); + calc_rmd160_sha256(rmd160,revdatabuf,datalen); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 revdatabuf\n"); + revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 special\n"); + calc_rmd160_sha256(rmd160,databuf,datalen); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 databuf\n");*/ + if ( datalen == 32 ) + calc_rmd160_sha256(rmd160,revdatabuf,datalen); + else calc_rmd160_sha256(rmd160,databuf,datalen); + iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); + break; + case IGUANA_OP_SHA256: + vcalc_sha256(0,hash.bytes,databuf,datalen); + for (i=0; i sha256 %s\n",bits256_str(str,hash)); + iguana_pushdata(stacks,0,hash.bytes,sizeof(hash)); + break; + case IGUANA_OP_HASH256: + hash = bits256_doublesha256(0,databuf,datalen); + iguana_pushdata(stacks,0,hash.bytes,sizeof(hash)); + break; + case IGUANA_OP_CHECKSIG: case IGUANA_OP_CHECKSIGVERIFY: + iguana_pushdata(stacks,iguana_checksig(ctx,args[1],args[0],V->sigtxid),0,0); + break; + case IGUANA_OP_CHECKMULTISIG: case IGUANA_OP_CHECKMULTISIGVERIFY: + iguana_pushdata(stacks,iguana_checkmultisig(ctx,stacks,V->M,V->N,V->sigtxid),0,0); + break; + case IGUANA_OP_CHECKSCHNORR: case IGUANA_OP_CHECKSCHNORRVERIFY: + iguana_pushdata(stacks,iguana_checkschnorrsig(ctx,iguana_num(args[2]),args[1],args[0],V->sigtxid),0,0); + break; + case IGUANA_OP_CHECKPRIVATEKEY: case IGUANA_OP_CHECKPRIVATEKEYVERIFY: + iguana_pushdata(stacks,iguana_checkprivatekey(ctx,args[1],args[0]),0,0); + break; + } + } + else if ( op->opcode == IGUANA_OP_CHECKLOCKTIMEVERIFY ) // former OP_NOP2 + { + if ( V->ignore_cltverr == 0 && iguana_checklocktimeverify(ctx,nLockTime,V->sequence,args[0]) < 0 ) + { + iguana_stack(stacks,args,1,"0",""); + errs++; + break; + } + iguana_stack(stacks,args,1,"0",""); + continue; + } + else if ( op->opcode == IGUANA_OP_CHECKSEQUENCEVERIFY ) // former OP_NOP3 + { + if ( iguana_checksequenceverify(ctx,nLockTime,V->sequence,args[0]) < 0 ) + { + iguana_stack(stacks,args,1,"0",""); + errs++; + break; + } + iguana_stack(stacks,args,1,"0",""); + continue; + } + else if ( (op->flags & IGUANA_STACKFLAG) != 0 ) + { + val = 0; + if ( op->opcode == IGUANA_OP_PICK || op->opcode == IGUANA_OP_ROLL ) + { + if ( interpret != 0 && stacks->stackdepth < (val= iguana_num(args[0])) ) + { + printf("stack not deep enough %d < %lld\n",stacks->stackdepth,(long long)iguana_num(args[0])); + errs++; + break; + } + if ( op->opcode == IGUANA_OP_PICK ) + { + stacks->stack[stacks->stackdepth] = iguana_clone(stacks->stack[stacks->stackdepth - 1 - val]); + stacks->stackdepth++; + } + else + { + args[1] = stacks->stack[stacks->stackdepth - 1 - val]; + for (i=(int32_t)(stacks->stackdepth-1-val); istackdepth-1; i++) + stacks->stack[i] = stacks->stack[i+1]; + stacks->stack[stacks->stackdepth - 1] = args[1]; + } + } + else + { + switch ( op->opcode ) + { + case IGUANA_OP_TOALTSTACK: + if ( stacks->altstackdepth < stacks->maxstackdepth ) + { + iguana_altpush(stacks,args[0]); + memset(&args[0],0,sizeof(args[0])); + } + else + { + printf("altstack overflow %d vs %d\n",stacks->altstackdepth,stacks->maxstackdepth); + errs++; + } + break; + case IGUANA_OP_FROMALTSTACK: + stacks->stack[stacks->stackdepth++] = iguana_altpop(stacks); + break; + case IGUANA_OP_DEPTH: iguana_pushdata(stacks,stacks->stackdepth,0,0); break; + case IGUANA_OP_DROP: case IGUANA_OP_2DROP: break; + case IGUANA_OP_3DUP: iguana_stack(stacks,args,3,"012","012"); break; + case IGUANA_OP_2OVER: iguana_stack(stacks,args,4,"0123","01"); break; + case IGUANA_OP_2ROT: iguana_stack(stacks,args,6,"234501",""); break; + case IGUANA_OP_2SWAP: iguana_stack(stacks,args,4,"2301",""); break; + case IGUANA_OP_IFDUP: + if ( iguana_isnonz(args[0]) != 0 ) + iguana_stack(stacks,args,0,"","0"); + iguana_stack(stacks,args,1,"0",""); + break; + case IGUANA_OP_DUP: iguana_stack(stacks,args,1,"0","0"); break; + case IGUANA_OP_2DUP: iguana_stack(stacks,args,2,"01","01"); break; + case IGUANA_OP_NIP: + if ( args[0].data != 0 ) + free(args[0].data); + iguana_stack(stacks,args,2,"1",""); + break; + case IGUANA_OP_OVER: iguana_stack(stacks,args,2,"01","0"); break; + case IGUANA_OP_ROT: iguana_stack(stacks,args,3,"120",""); break; + case IGUANA_OP_SWAP: iguana_stack(stacks,args,2,"10",""); break; + case IGUANA_OP_TUCK: iguana_stack(stacks,args,2,"10","1"); break; + } + } + } + else if ( (op->flags & IGUANA_MATHFLAG) != 0 ) + { + int64_t numA=0,numB=0,numC=0; + for (i=0; istackitems; i++) + { + if ( args[i].size != sizeof(int32_t) ) + break; + if ( i == 0 ) + numA = iguana_num(args[i]); + else if ( i == 1 ) + numB = iguana_num(args[i]); + else if ( i == 2 ) + numC = iguana_num(args[i]); + } + if ( i != op->stackitems ) + { + printf("math script non-int32_t arg[%d] of %d\n",i,op->stackitems); + errs++; + break; + } + switch ( op->opcode ) + { + case IGUANA_OP_1ADD: iguana_pushdata(stacks,numA + 1,0,0); break; + case IGUANA_OP_1SUB: iguana_pushdata(stacks,numA - 1,0,0); break; + case IGUANA_OP_NEGATE: iguana_pushdata(stacks,-numA,0,0); break; + case IGUANA_OP_ABS: iguana_pushdata(stacks,numA<0?-numA:numA,0,0); break; + case IGUANA_OP_NOT: iguana_pushdata(stacks,numA == 0,0,0); break; + case IGUANA_OP_0NOTEQUAL: iguana_pushdata(stacks,numA != 0,0,0); break; + case IGUANA_OP_ADD: iguana_pushdata(stacks,numA + numB,0,0); break; + case IGUANA_OP_SUB: iguana_pushdata(stacks,numA - numB,0,0); break; + case IGUANA_OP_BOOLAND:iguana_pushdata(stacks,numA != 0 && numB != 0,0,0); break; + case IGUANA_OP_BOOLOR: iguana_pushdata(stacks,numA != 0 || numB != 0,0,0); break; + case IGUANA_OP_NUMEQUAL: case IGUANA_OP_NUMEQUALVERIFY: + iguana_pushdata(stacks,numA == numB,0,0); break; + case IGUANA_OP_NUMNOTEQUAL:iguana_pushdata(stacks,numA != numB,0,0); break; + case IGUANA_OP_LESSTHAN: iguana_pushdata(stacks,numA < numB,0,0); break; + case IGUANA_OP_GREATERTHAN:iguana_pushdata(stacks,numA > numB,0,0); break; + case IGUANA_OP_LESSTHANOREQUAL:iguana_pushdata(stacks,numA <= numB,0,0); break; + case IGUANA_OP_GREATERTHANOREQUAL:iguana_pushdata(stacks,numA >= numB,0,0); break; + case IGUANA_OP_MIN: iguana_pushdata(stacks,numA <= numB ? numA : numB,0,0); break; + case IGUANA_OP_MAX: iguana_pushdata(stacks,numA >= numB ? numA : numB,0,0); break; + case IGUANA_OP_WITHIN: iguana_pushdata(stacks,numB <= numA && numA < numC,0,0); break; + } + } + else if ( op->opcode == IGUANA_OP_CODESEPARATOR ) + { + if ( stacks != 0 ) + stacks->codeseparator = k; + continue; + } + else + { + printf("unhandled opcode.%02x (%s)\n",op->opcode,str); + errs++; + break; + } + if ( (op->flags & IGUANA_POSTVERIFY) != 0 ) + { + if ( stacks->stackdepth < 1 ) + { + printf("empty stack at offset.%ld\n",(long)str - (long)asmstr); + errs++; + break; + } + if ( iguana_isnonz(stacks->stack[stacks->stackdepth-1]) == 0 ) + break; + iguana_pop(stacks); + } + } + else + { + printf("too many ops opcode.%s at offset.%ld\n",str,(long)str - (long)asmstr); + errs++; + break; + } + } + else + { + printf("unknown opcode.%s at offset.%ld\n",str,(long)str - (long)asmstr); + errs++; + break; + } + } + if ( stacks != &STACKS ) + { + if ( jobj(interpreter,"result") != 0 ) + jdelete(interpreter,"result"); + if ( stacks->stackdepth <= 0 ) + { + errs++; + printf("empty stack error\n"); + jaddstr(interpreter,"error","empty stack"); + jadd(interpreter,"result",jfalse()); + } + else if ( iguana_isnonz(stacks->stack[--stacks->stackdepth]) != 0 ) + { + //printf("Evaluate true, depth.%d errs.%d k.%d\n",stacks->stackdepth,errs,k); + if ( errs == 0 ) + jadd(interpreter,"result",jtrue()); + else jadd(interpreter,"result",jfalse()); + } + else + { + jadd(interpreter,"result",jfalse()); + printf("Evaluate FALSE, depth.%d errs.%d [0] size.%d num.%d\n",stacks->stackdepth,errs,stacks->stack[0].size,stacks->stack[0].U.val); + if ( stacks->logarray != 0 ) + printf("LOG.(%s)\n\n",jprint(stacks->logarray,0)); + } + if ( numargs > 0 ) + { + for (i=0; isuppress_pubkeys)) > 0 && signedtx != 0 ) { - /*int32_t tmp; //char str[65]; - if ( (tmp= iguana_interpreter(coin,0,iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) - { - printf("iguana_interpreter %d error.(%s)\n",tmp,signedtx); - complete = 0; - } */ + int32_t tmp; //char str[65]; + if ( (tmp= iguana_interpreter(ctx,0,iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) + { + printf("iguana_interpreter %d error.(%s)\n",tmp,signedtx); + complete = 0; + } else printf("interpreter passed\n"); } else printf("complete.%d\n",complete); } else printf("rwmsgtx error\n"); } else fprintf(stderr,"no inputs in vins.(%s)\n",vins!=0?jprint(vins,0):"null"); @@ -686,8 +694,8 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch completed = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); - //if ( (completed= iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) - if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) + if ( (completed= iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) + //if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); else if ( completed == 0 ) { From 5f6065a18be7e0393c42c12dca0357d1933f38d7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:49:27 +0300 Subject: [PATCH 0907/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 36bc245e8..621795f6f 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,7 +753,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm/*rev*/,privBn,secretAm,secretAm256,secretBn,secretBn256); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; From daee179a4e01efd7024a2a7f9603f57d47bc72d1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:52:46 +0300 Subject: [PATCH 0908/2705] Test --- iguana/exchanges/LP_bitcoin.c | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 7b403117d..c7c5fe8fa 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1321,29 +1321,29 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); break; case IGUANA_OP_HASH160: - /*if ( datalen == 32 ) - { - revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); - printf("SPECIAL CASE REVERSE\n"); - } else - for (i=0; i<32; i++) - printf("%02x",databuf[i]); - printf(" <- databuf\n"); - for (i=0; i<32; i++) - printf("%02x",revdatabuf[i]); - printf(" <- revdatabuf\n"); - calc_rmd160_sha256(rmd160,revdatabuf,datalen); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" <- rmd160 revdatabuf\n"); - revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" <- rmd160 special\n"); - calc_rmd160_sha256(rmd160,databuf,datalen); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" <- rmd160 databuf\n");*/ + if ( datalen == 32 ) + { + revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); + printf("SPECIAL CASE REVERSE\n"); + } else + for (i=0; i<32; i++) + printf("%02x",databuf[i]); + printf(" <- databuf\n"); + for (i=0; i<32; i++) + printf("%02x",revdatabuf[i]); + printf(" <- revdatabuf\n"); + calc_rmd160_sha256(rmd160,revdatabuf,datalen); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 revdatabuf\n"); + revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 special\n"); + calc_rmd160_sha256(rmd160,databuf,datalen); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 databuf\n"); if ( datalen == 32 ) calc_rmd160_sha256(rmd160,revdatabuf,datalen); else calc_rmd160_sha256(rmd160,databuf,datalen); From 7d99eddcf9963f717bea76a4be5a1b56c7c50113 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:55:52 +0300 Subject: [PATCH 0909/2705] Test --- iguana/exchanges/LP_bitcoin.c | 48 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index c7c5fe8fa..b8d92440d 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1321,30 +1321,30 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); break; case IGUANA_OP_HASH160: - if ( datalen == 32 ) - { - revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); - printf("SPECIAL CASE REVERSE\n"); - } else - for (i=0; i<32; i++) - printf("%02x",databuf[i]); - printf(" <- databuf\n"); - for (i=0; i<32; i++) - printf("%02x",revdatabuf[i]); - printf(" <- revdatabuf\n"); - calc_rmd160_sha256(rmd160,revdatabuf,datalen); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" <- rmd160 revdatabuf\n"); - revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" <- rmd160 special\n"); - calc_rmd160_sha256(rmd160,databuf,datalen); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" <- rmd160 databuf\n"); - if ( datalen == 32 ) + /*if ( datalen == 32 ) + { + revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); + printf("SPECIAL CASE REVERSE\n"); + } else + for (i=0; i<32; i++) + printf("%02x",databuf[i]); + printf(" <- databuf\n"); + for (i=0; i<32; i++) + printf("%02x",revdatabuf[i]); + printf(" <- revdatabuf\n"); + calc_rmd160_sha256(rmd160,revdatabuf,datalen); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 revdatabuf\n"); + revcalc_rmd160_sha256(rmd160,*(bits256 *)databuf); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 special\n"); + calc_rmd160_sha256(rmd160,databuf,datalen); + for (i=0; i<20; i++) + printf("%02x",rmd160[i]); + printf(" <- rmd160 databuf\n");*/ + if ( 0 && datalen == 32 ) calc_rmd160_sha256(rmd160,revdatabuf,datalen); else calc_rmd160_sha256(rmd160,databuf,datalen); iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); From cd9d08c40256e1b02a9aa8898b1280050d638f6b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:56:40 +0300 Subject: [PATCH 0910/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index b8d92440d..7b403117d 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1344,7 +1344,7 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" <- rmd160 databuf\n");*/ - if ( 0 && datalen == 32 ) + if ( datalen == 32 ) calc_rmd160_sha256(rmd160,revdatabuf,datalen); else calc_rmd160_sha256(rmd160,databuf,datalen); iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); From d4f93281ad587970b5671b34625927abb1161b01 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:58:15 +0300 Subject: [PATCH 0911/2705] Test --- iguana/exchanges/LP_remember.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 621795f6f..dd37a8573 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,8 +753,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm/*rev*/,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,privAm/*rev*/,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From b4f31059657f36cd399dc1c864814f7822aaf199 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 21:59:54 +0300 Subject: [PATCH 0912/2705] Test --- iguana/exchanges/LP_remember.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index dd37a8573..6f0c7fea0 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -751,10 +751,10 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti // alicespend for (j=0; j<32; j++) rev.bytes[j] = privAm.bytes[31 - j]; - //revcalc_rmd160_sha256(secretAm,rev);//privAm); - //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm/*rev*/,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,privAm/*rev*/,0,myprivs[0],redeemscript,redeemlen); + revcalc_rmd160_sha256(secretAm,rev);//privAm); + vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From 3aebe5264debfe9d49a1b3c48dc598d56c4fe090 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:02:16 +0300 Subject: [PATCH 0913/2705] Test --- iguana/exchanges/LP_bitcoin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 7b403117d..f475d2cc1 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1295,14 +1295,14 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR else { iguana_pushdata(stacks,0,0,0); - for (i=0; iopcode,args[0].size,args[1].size); - } + } else if ( (op->flags & IGUANA_CRYPTOFLAG) != 0 ) { From 49e72c521f432a936e482a9b74e69923e0f79905 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:03:46 +0300 Subject: [PATCH 0914/2705] Test --- iguana/exchanges/LP_bitcoin.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index f475d2cc1..dd6cf585b 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -797,7 +797,7 @@ int32_t iguana_checksig(void *ctx,struct iguana_stackdata pubkeyarg,struct iguan if ( (retval= (bitcoin_verify(ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0)) == 0 ) { } - if ( (0) ) + if ( (1) ) { int32_t i; char str[65]; for (i=0; iopcode,args[0].size,args[1].size); - + } } else if ( (op->flags & IGUANA_CRYPTOFLAG) != 0 ) { From 43a8954ebd1d1b96d87785f723115c0ea15d200d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:04:37 +0300 Subject: [PATCH 0915/2705] Test --- iguana/exchanges/LP_bitcoin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index dd6cf585b..c6ac462d6 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -792,6 +792,7 @@ int32_t iguana_checksig(void *ctx,struct iguana_stackdata pubkeyarg,struct iguan uint8_t pubkey[MAX_SCRIPT_ELEMENT_SIZE],sig[MAX_SCRIPT_ELEMENT_SIZE]; int32_t retval,plen,siglen; plen = iguana_databuf(pubkey,pubkeyarg); siglen = iguana_databuf(sig,sigarg); + printf("checksig\n"); if ( bitcoin_pubkeylen(pubkey) == plen && plen > 0 && siglen > 0 && siglen < 74 ) { if ( (retval= (bitcoin_verify(ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0)) == 0 ) From df4374fc28dea9983444bb43d723d3fa754f9710 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:07:47 +0300 Subject: [PATCH 0916/2705] Test --- iguana/exchanges/LP_bitcoin.c | 1 - iguana/exchanges/LP_transaction.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index c6ac462d6..dd6cf585b 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -792,7 +792,6 @@ int32_t iguana_checksig(void *ctx,struct iguana_stackdata pubkeyarg,struct iguan uint8_t pubkey[MAX_SCRIPT_ELEMENT_SIZE],sig[MAX_SCRIPT_ELEMENT_SIZE]; int32_t retval,plen,siglen; plen = iguana_databuf(pubkey,pubkeyarg); siglen = iguana_databuf(sig,sigarg); - printf("checksig\n"); if ( bitcoin_pubkeylen(pubkey) == plen && plen > 0 && siglen > 0 && siglen < 74 ) { if ( (retval= (bitcoin_verify(ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0)) == 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index d7f2f3f05..e3db71fe8 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -379,7 +379,7 @@ int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shty { script = V->p2shscript; scriptlen = V->p2shlen; - //printf("V->p2shlen.%d\n",V->p2shlen); + printf("V->p2shlen.%d\n",V->p2shlen); } else { From 17bb635e6b96487e3b15eac7176a254deda1f91b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:09:09 +0300 Subject: [PATCH 0917/2705] Test --- iguana/exchanges/LP_transaction.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index e3db71fe8..777ee155d 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -379,7 +379,9 @@ int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shty { script = V->p2shscript; scriptlen = V->p2shlen; - printf("V->p2shlen.%d\n",V->p2shlen); + for (j=0; jp2shlen.%d\n",V->p2shlen); } else { From 4160744795ab2cda09b0098ce7e71c91c7b18207 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:16:26 +0300 Subject: [PATCH 0918/2705] Test --- iguana/exchanges/LP_remember.c | 4 ++-- iguana/exchanges/LP_transaction.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 6f0c7fea0..621795f6f 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -751,8 +751,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti // alicespend for (j=0; j<32; j++) rev.bytes[j] = privAm.bytes[31 - j]; - revcalc_rmd160_sha256(secretAm,rev);//privAm); - vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); + //revcalc_rmd160_sha256(secretAm,rev);//privAm); + //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 777ee155d..a7315d8f3 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -379,9 +379,9 @@ int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shty { script = V->p2shscript; scriptlen = V->p2shlen; - for (j=0; jp2shlen.%d\n",V->p2shlen); + //for (j=0; jp2shlen.%d\n",V->p2shlen); } else { From 3bb4fbf4f57b52e3e9119ed600172b4296aa8590 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:18:08 +0300 Subject: [PATCH 0919/2705] Test --- iguana/exchanges/LP_bitcoin.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index dd6cf585b..95d6db4fa 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -797,7 +797,7 @@ int32_t iguana_checksig(void *ctx,struct iguana_stackdata pubkeyarg,struct iguan if ( (retval= (bitcoin_verify(ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0)) == 0 ) { } - if ( (1) ) + if ( (0) ) { int32_t i; char str[65]; for (i=0; iopcode,args[0].size,args[1].size); - } + //} } else if ( (op->flags & IGUANA_CRYPTOFLAG) != 0 ) { From 94861a0c68190b6b3fbda6b110a8a167c2a45f06 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:19:01 +0300 Subject: [PATCH 0920/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 95d6db4fa..df28e1bce 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1344,7 +1344,7 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" <- rmd160 databuf\n");*/ - if ( datalen == 32 ) + if ( 0 && datalen == 32 ) calc_rmd160_sha256(rmd160,revdatabuf,datalen); else calc_rmd160_sha256(rmd160,databuf,datalen); iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); From 5c3c0d559221c735a79baecb8d8038c689663397 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:20:03 +0300 Subject: [PATCH 0921/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 621795f6f..36bc245e8 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,7 +753,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm/*rev*/,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; From c01b014d13a127b7bc38de51660dc28ef524e2dd Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:21:11 +0300 Subject: [PATCH 0922/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 36bc245e8..dd37a8573 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -754,7 +754,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm/*rev*/,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + len = basilisk_swapuserdata(userdata,privAm/*rev*/,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From 3e2709c07c310e338acbcd510bcfc213982aa1e5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:37:45 +0300 Subject: [PATCH 0923/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- iguana/exchanges/LP_remember.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index df28e1bce..95d6db4fa 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1344,7 +1344,7 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" <- rmd160 databuf\n");*/ - if ( 0 && datalen == 32 ) + if ( datalen == 32 ) calc_rmd160_sha256(rmd160,revdatabuf,datalen); else calc_rmd160_sha256(rmd160,databuf,datalen); iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index dd37a8573..621795f6f 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,8 +753,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm/*rev*/,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,privAm/*rev*/,0,myprivs[0],redeemscript,redeemlen); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From 6be5e9404762a9388d11e3b661a9217e6113466b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:39:12 +0300 Subject: [PATCH 0924/2705] Test --- iguana/exchanges/LP_remember.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 621795f6f..dcf45c3db 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,8 +753,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,privAm,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From c88de3feb5fcf7b0c75b53ae2ffa7d3fa1730d04 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:40:08 +0300 Subject: [PATCH 0925/2705] Test --- iguana/exchanges/LP_remember.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index dcf45c3db..0e2cba2d1 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -761,7 +761,9 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti bitcoin_address(privaddr,60,privpub33,33); printf("alicespend len.%d redeemlen.%d priv0addr.(%s) priv0.(%s)\n",len,redeemlen,privaddr,bits256_str(str,myprivs[0])); } - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr)) != 0 ) + for (j=0; j<32; j++) + rev.bytes[j] = myprivs[0].bytes[31 - j]; + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,rev/*myprivs[0]*/,0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } From 49847eb688a17fbba36951eee5acaf1f183d5d06 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:49:54 +0300 Subject: [PATCH 0926/2705] Test --- iguana/exchanges/LP_bitcoin.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 95d6db4fa..4b84e137c 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1569,6 +1569,7 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR { jadd(interpreter,"result",jfalse()); printf("Evaluate FALSE, depth.%d errs.%d [0] size.%d num.%d\n",stacks->stackdepth,errs,stacks->stack[0].size,stacks->stack[0].U.val); + errs++; if ( stacks->logarray != 0 ) printf("LOG.(%s)\n\n",jprint(stacks->logarray,0)); } From 8b17d32b2ee189a3a8cf31ec2c7702733f324ff8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:56:48 +0300 Subject: [PATCH 0927/2705] Test --- iguana/exchanges/LP_bitcoin.c | 20 ++++++++++---------- iguana/exchanges/LP_transaction.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 4b84e137c..4b6309ac7 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -564,12 +564,12 @@ static int32_t iguana_pushdata(struct iguana_interpreter *stacks,int64_t num64,u //printf("PUSH.(%lld %p %d)\n",(long long)num64,numbuf,numlen); if ( stacks->maxstackdepth > 0 ) { - /*if ( numbuf != 0 ) - { - int32_t i; for (i=0; istackdepth < stacks->maxstackdepth ) { if ( stacks->logarray != 0 ) @@ -1127,7 +1127,7 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR break; } HASH_FIND(hh,OPTABLE,str,j,op); - //printf("{%s}\n",str); + printf("{%s}\n",str); str += j; if ( op != 0 ) { @@ -1295,14 +1295,14 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR else { iguana_pushdata(stacks,0,0,0); - } for (i=0; iopcode,args[0].size,args[1].size); - //} + } } else if ( (op->flags & IGUANA_CRYPTOFLAG) != 0 ) { @@ -1568,7 +1568,7 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR else { jadd(interpreter,"result",jfalse()); - printf("Evaluate FALSE, depth.%d errs.%d [0] size.%d num.%d\n",stacks->stackdepth,errs,stacks->stack[0].size,stacks->stack[0].U.val); + printf("Evaluate FALSE, depth.%d errs.%d [0] size.%d val.%d\n",stacks->stackdepth,errs,stacks->stack[0].size,stacks->stack[0].U.val); errs++; if ( stacks->logarray != 0 ) printf("LOG.(%s)\n\n",jprint(stacks->logarray,0)); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index a7315d8f3..2b7429640 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -571,7 +571,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t if ( (complete= bitcoin_verifyvins(ctx,symbol,pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) { int32_t tmp; //char str[65]; - if ( (tmp= iguana_interpreter(ctx,0,iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) + if ( (tmp= iguana_interpreter(ctx,cJSON_CreateArray(),iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) { printf("iguana_interpreter %d error.(%s)\n",tmp,signedtx); complete = 0; From 8f5e8b5cca2b58cc85a40000bca309a46d0b327e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 22:58:49 +0300 Subject: [PATCH 0928/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 0e2cba2d1..b93b8ee95 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -763,7 +763,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } for (j=0; j<32; j++) rev.bytes[j] = myprivs[0].bytes[31 - j]; - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,rev/*myprivs[0]*/,0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } From 8f29ff4babaa6545e86814e884d8cd7bb9bd7c2e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 23:01:31 +0300 Subject: [PATCH 0929/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- iguana/exchanges/LP_remember.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 4b6309ac7..fb1b2f13c 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1344,7 +1344,7 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" <- rmd160 databuf\n");*/ - if ( datalen == 32 ) + if ( 0 && datalen == 32 ) calc_rmd160_sha256(rmd160,revdatabuf,datalen); else calc_rmd160_sha256(rmd160,databuf,datalen); iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index b93b8ee95..dec78b521 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,8 +753,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,privAm,0,myprivs[0],redeemscript,redeemlen); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From 29cbde9ee20fdc5c54687755e56efcc6a0658391 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 23:03:09 +0300 Subject: [PATCH 0930/2705] Test --- iguana/exchanges/LP_remember.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index dec78b521..b93b8ee95 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,8 +753,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,privAm,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From a54b729addc0a93c1124cf38e4d0fa469bd8bab2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 23:04:05 +0300 Subject: [PATCH 0931/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index fb1b2f13c..4b6309ac7 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -1344,7 +1344,7 @@ int32_t bitcoin_assembler(void *ctx,cJSON *logarray,uint8_t script[IGUANA_MAXSCR for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" <- rmd160 databuf\n");*/ - if ( 0 && datalen == 32 ) + if ( datalen == 32 ) calc_rmd160_sha256(rmd160,revdatabuf,datalen); else calc_rmd160_sha256(rmd160,databuf,datalen); iguana_pushdata(stacks,0,rmd160,sizeof(rmd160)); From d92a0edcc28d86059b0e8908029b4bc275d26982 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 23:10:11 +0300 Subject: [PATCH 0932/2705] Test --- iguana/exchanges/LP_transaction.c | 12 ------------ iguana/exchanges/mm.c | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 2b7429640..1990ca089 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -643,18 +643,6 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } jaddbits256(item,"txid",utxotxid); jaddnum(item,"vout",vout); - /*int32_t i; - for (i=0; i<33; i++) - printf("%02x",pubkey33[i]); - printf(" pubkey33 ->\n"); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" destaddr.(%s)\n",destaddr); - calc_rmd160_sha256(rmd160,pubkey33,33); - for (i=0; i<20; i++) - printf("%02x",rmd160[i]); - printf(" <- vs direct calc\n");*/ - //spendlen = bitcoin_standardspend(spendscript,0,rmd160); bitcoin_address(tmpaddr,pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); if ( redeemlen != 0 ) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index f2dffc4de..060e85014 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -829,7 +829,7 @@ int main(int argc, const char * argv[]) printf("error launching LP_main (%s)\n",jprint(retjson,0)); exit(-1); } else printf("(%s) launched.(%s)\n",argv[1],passphrase); - if ( (retstr= basilisk_swaplist()) != 0 ) + if ( (0) && (retstr= basilisk_swaplist()) != 0 ) { printf("%s\ngetchar to continue\n",retstr); getchar(); From 5ecdd9bd6929a2e3dee2d40478ccd93ba22eb369 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 1 Jun 2017 23:13:04 +0300 Subject: [PATCH 0933/2705] Test --- iguana/exchanges/LP_remember.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index b93b8ee95..dec78b521 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -753,8 +753,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti rev.bytes[j] = privAm.bytes[31 - j]; //revcalc_rmd160_sha256(secretAm,rev);//privAm); //vcalc_sha256(0,secretAm256,rev.bytes,sizeof(rev)); - redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); - len = basilisk_swapuserdata(userdata,privAm,0,myprivs[0],redeemscript,redeemlen); + redeemlen = basilisk_swap_bobredeemscript(0,&secretstart,redeemscript,plocktime,pubA0,pubB0,pubB1,rev,privBn,secretAm,secretAm256,secretBn,secretBn256); + len = basilisk_swapuserdata(userdata,rev,0,myprivs[0],redeemscript,redeemlen); { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); From 326d4e99957f059666c8c13d58ad9022585464d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 2 Jun 2017 08:53:56 +0300 Subject: [PATCH 0934/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_remember.c | 6 ++++++ iguana/exchanges/LP_transaction.c | 10 +++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c056d38d8..634fca3fd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -781,7 +781,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { char tmpstr[128]; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - //printf("%s coinaddr.(%s) %d wif.(%s) passphrase.(%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); + printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } @@ -814,7 +814,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb if ( amclient != 0 ) targetval = (depositval / 776) + 50000; else targetval = (depositval / 9) * 8; - printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); + //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) { item = jitem(array,i); diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index dec78b521..52f511e77 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -212,6 +212,12 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx LP_importaddress(swap->alicecoin.symbol,coinaddr); fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); } + if ( rawtx->I.redeemlen > 0 ) + { + char scriptstr[2049]; + init_hexbytes_noT(scriptstr,rawtx->redeemscript,rawtx->I.redeemlen); + fprintf(fp,",\"redeem\":\"%s\"",scriptstr); + } /*basilisk_dontforget_userdata("Aclaim",fp,swap->I.userdata_aliceclaim,swap->I.userdata_aliceclaimlen); basilisk_dontforget_userdata("Areclaim",fp,swap->I.userdata_alicereclaim,swap->I.userdata_alicereclaimlen); basilisk_dontforget_userdata("Aspend",fp,swap->I.userdata_alicespend,swap->I.userdata_alicespendlen); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 1990ca089..8c8a2def2 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1223,11 +1223,11 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i { for (j=0; jbobpayment.I.datalen; j++) printf("%02x",swap->bobpayment.txbytes[j]); - //printf(" <- bobpayment.%d\n",swap->bobpayment.datalen); - //for (j=0; jbobpayment.redeemlen; j++) - // printf("%02x",swap->bobpayment.redeemscript[j]); - //printf(" <- redeem.%d\n",swap->bobpayment.redeemlen); - printf(" <- GENERATED BOB PAYMENT.%d\n",swap->bobpayment.I.datalen); + printf(" <- bobpayment.%d\n",swap->bobpayment.I.datalen); + for (j=0; jbobpayment.I.redeemlen; j++) + printf("%02x",swap->bobpayment.redeemscript[j]); + printf(" <- redeem.%d\n",swap->bobpayment.I.redeemlen); + printf(" <- GENERATED BOB PAYMENT.%d destaddr.(%s)\n",swap->bobpayment.I.datalen,swap->bobpayment.I.destaddr); LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); //basilisk_bobpayment_reclaim(swap,swap->I.callduration); //printf("bobscripts set completed\n"); From d1c3c246d7b1bfcd8594363919bea11dd77dc465 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 2 Jun 2017 09:15:14 +0300 Subject: [PATCH 0935/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +- iguana/exchanges/LP_swap.c | 6 +- iguana/exchanges/LP_transaction.c | 106 +++++++++++++----------------- 3 files changed, 52 insertions(+), 64 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 634fca3fd..ce8a3b97c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -25,7 +25,7 @@ #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid -char *activecoins[] = { "BTC", "KMD", };//"LTC", "USD", "REVS", "JUMBLR" }; +char *activecoins[] = { "BTC", "KMD", "REVS", "JUMBLR" };//"LTC", "USD", }; char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; @@ -338,7 +338,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - char str[65],str2[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); + //char str[65],str2[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); } return(utxo); } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 72a1804d6..5d4a085d8 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -536,8 +536,8 @@ void LP_bobloop(void *_utxo) printf("error waitsend choosei\n"); else if ( LP_waitsend("mostprivs",10,utxo->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error waitsend mostprivs\n"); - else if ( basilisk_bobscripts_set(swap,1,1) < 0 || basilisk_bobscripts_set(swap,0,1) < 0 ) - printf("error bobscripts\n"); + else if ( basilisk_bobscripts_set(swap,1,1) < 0 ) + printf("error bobscripts deposit\n"); else { LP_swapsfp_update(&swap->I.req); @@ -547,6 +547,8 @@ void LP_bobloop(void *_utxo) printf("error sending bobdeposit\n"); else if ( LP_waitfor(utxo->pair,swap,10,LP_verify_alicepayment) < 0 ) printf("error waiting for alicepayment\n"); + else if ( basilisk_bobscripts_set(swap,0,1) < 0 ) + printf("error bobscripts payment\n"); else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) printf("error sending bobpayment\n"); while ( 1 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 8c8a2def2..6ee6499f7 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1150,7 +1150,6 @@ int32_t basilisk_swapuserdata(uint8_t *userdata,bits256 privkey,int32_t ifpath,b return(len); } -#ifdef old /*Bob paytx: OP_IF OP_CLTV OP_DROP OP_CHECKSIG @@ -1165,7 +1164,7 @@ int32_t basilisk_bobpayment_reclaim(struct basilisk_swap *swap,int32_t delay) len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); memcpy(swap->I.userdata_bobreclaim,userdata,len); swap->I.userdata_bobreclaimlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1,swap->changermd160)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1,swap->changermd160,swap->bobpayment.I.destaddr)) == 0 ) { for (i=0; ibobreclaim.I.datalen; i++) printf("%02x",swap->bobreclaim.txbytes[i]); @@ -1182,7 +1181,7 @@ int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) len = basilisk_swapuserdata(userdata,swap->I.privBn,0,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_bobrefund,userdata,len); swap->I.userdata_bobrefundlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0,swap->changermd160)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) { for (i=0; ibobrefund.I.datalen; i++) printf("%02x",swap->bobrefund.txbytes[i]); @@ -1192,7 +1191,6 @@ int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) } return(-1); } -#endif int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) { @@ -1204,35 +1202,31 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); - //for (i=0; ibobpayment.redeemlen; i++) - // printf("%02x",swap->bobpayment.redeemscript[i]); - //printf(" <- bobpayment.%d\n",i); + int32_t i; for (i=0; ibobpayment.I.redeemlen; i++) + printf("%02x",swap->bobpayment.redeemscript[i]); + printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); if ( genflag != 0 && bits256_nonz(*(bits256 *)swap->I.secretBn256) != 0 && swap->bobpayment.I.datalen == 0 ) { - //for (i=0; i<3; i++) + basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); + if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) { - //if ( swap->bobpayment.txbytes != 0 && swap->bobpayment.I.spendlen != 0 ) - // break; - basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); - if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) - { - printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); - sleep(DEX_SLEEP); - } - else - { - for (j=0; jbobpayment.I.datalen; j++) - printf("%02x",swap->bobpayment.txbytes[j]); - printf(" <- bobpayment.%d\n",swap->bobpayment.I.datalen); - for (j=0; jbobpayment.I.redeemlen; j++) - printf("%02x",swap->bobpayment.redeemscript[j]); - printf(" <- redeem.%d\n",swap->bobpayment.I.redeemlen); - printf(" <- GENERATED BOB PAYMENT.%d destaddr.(%s)\n",swap->bobpayment.I.datalen,swap->bobpayment.I.destaddr); - LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); - //basilisk_bobpayment_reclaim(swap,swap->I.callduration); - //printf("bobscripts set completed\n"); - return(0); - } + printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); + sleep(DEX_SLEEP); + } + else + { + for (j=0; jbobpayment.I.datalen; j++) + printf("%02x",swap->bobpayment.txbytes[j]); + printf(" <- bobpayment.%d\n",swap->bobpayment.I.datalen); + for (j=0; jbobpayment.I.redeemlen; j++) + printf("%02x",swap->bobpayment.redeemscript[j]); + printf(" <- redeem.%d\n",swap->bobpayment.I.redeemlen); + printf(" <- GENERATED BOB PAYMENT.%d destaddr.(%s)\n",swap->bobpayment.I.datalen,swap->bobpayment.I.destaddr); + LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); + if ( swap->I.iambob != 0 ) + basilisk_bobpayment_reclaim(swap,swap->I.callduration); + //printf("bobscripts set completed\n"); + return(0); } } } @@ -1241,37 +1235,29 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); + int32_t i; for (i=0; ibobdeposit.I.redeemlen; i++) + printf("%02x",swap->bobdeposit.redeemscript[i]); + printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) { - //for (i=0; i<3; i++) + basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); + if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) { - //if ( swap->bobdeposit.txbytes != 0 && swap->bobdeposit.I.spendlen != 0 ) - // break; - basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); - if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) - { - printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); - sleep(DEX_SLEEP); - } - else - { - for (j=0; jbobdeposit.I.datalen; j++) - printf("%02x",swap->bobdeposit.txbytes[j]); - printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); - //for (j=0; jbobdeposit.redeemlen; j++) - // printf("%02x",swap->bobdeposit.redeemscript[j]); - //printf(" <- redeem.%d\n",swap->bobdeposit.redeemlen); - //printf("GENERATED BOB DEPOSIT\n"); - LP_unspents_mark(swap->bobcoin.symbol,swap->bobdeposit.vins); - //basilisk_bobdeposit_refund(swap,swap->I.putduration); - printf("bobscripts set completed\n"); - return(0); - } + printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); + sleep(DEX_SLEEP); + } + else + { + for (j=0; jbobdeposit.I.datalen; j++) + printf("%02x",swap->bobdeposit.txbytes[j]); + printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); + LP_unspents_mark(swap->bobcoin.symbol,swap->bobdeposit.vins); + if ( swap->I.iambob != 0 ) + basilisk_bobdeposit_refund(swap,swap->I.putduration); + printf("bobscripts set completed\n"); + return(0); } } - //for (i=0; ibobdeposit.redeemlen; i++) - // printf("%02x",swap->bobdeposit.redeemscript[i]); - //printf(" <- bobdeposit.%d\n",i); } return(0); } @@ -1532,14 +1518,14 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da swap->I.userdata_alicespendlen = len; retval = 0; char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); - //if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->alicepayment.I.destaddr)) == 0 ) { for (i=0; ibobpayment.I.datalen; i++) printf("%02x",swap->bobpayment.txbytes[i]); printf(" <- bobpayment\n"); - //for (i=0; ialicespend.I.datalen; i++) - // printf("%02x",swap->alicespend.txbytes[i]); - //printf(" <- alicespend\n\n"); + for (i=0; ialicespend.I.datalen; i++) + printf("%02x",swap->alicespend.txbytes[i]); + printf(" <- alicespend\n\n"); swap->I.alicespent = 1; //basilisk_txlog(swap,&swap->alicespend,-1); return(retval); From 71ea567ca40419a51b775f8721c86ce094b18eab Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 2 Jun 2017 11:21:12 +0300 Subject: [PATCH 0936/2705] batch17 --- iguana/main.c | 6 +- iguana/tests/KMD.batch17 | 433 +++++++++++++++++++++++++++ iguana/tests/KMD.batch17.listunspent | 345 +++++++++++++++++++++ iguana/tests/REVS.batch17 | 5 + 4 files changed, 787 insertions(+), 2 deletions(-) create mode 100755 iguana/tests/KMD.batch17 create mode 100755 iguana/tests/KMD.batch17.listunspent create mode 100755 iguana/tests/REVS.batch17 diff --git a/iguana/main.c b/iguana/main.c index 9a224d3d2..335d68baa 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -2056,10 +2056,12 @@ FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase) void komodo_ICO_batch(cJSON *array,int32_t batchid) { int32_t i,n,iter; cJSON *item; uint64_t kmdamount,revsamount; char *coinaddr,cmd[512]; double totalKMD,totalREVS; struct supernet_info *myinfo = SuperNET_MYINFO(0); + if ( myinfo->rpcport == 0 ) + myinfo->rpcport = 7778; if ( (n= cJSON_GetArraySize(array)) > 0 ) { totalKMD = totalREVS = 0; - for (iter=3; iter<4; iter++) + for (iter=0; iter<1; iter++) for (i=0; i Date: Fri, 2 Jun 2017 11:50:16 +0300 Subject: [PATCH 0937/2705] sleep --- iguana/tests/KMD.batch17 | 1 + iguana/tests/KMD.batch17.listunspent | 1 + 2 files changed, 2 insertions(+) diff --git a/iguana/tests/KMD.batch17 b/iguana/tests/KMD.batch17 index 6f08faea9..2b5513271 100755 --- a/iguana/tests/KMD.batch17 +++ b/iguana/tests/KMD.batch17 @@ -1,3 +1,4 @@ +sleep 9999999 # RCJHEogA7SW6PxuctPLtaVnXwiu49PyZY8 KMD 108998.28313606 ./komodo-cli sendtoaddress RCJHEogA7SW6PxuctPLtaVnXwiu49PyZY8 108998.28313606 sleep 3 diff --git a/iguana/tests/KMD.batch17.listunspent b/iguana/tests/KMD.batch17.listunspent index a59ac7f3b..bffaab46a 100755 --- a/iguana/tests/KMD.batch17.listunspent +++ b/iguana/tests/KMD.batch17.listunspent @@ -1,3 +1,4 @@ +sleep 999999 # RCJHEogA7SW6PxuctPLtaVnXwiu49PyZY8 KMD 108998.28313606 curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RCJHEogA7SW6PxuctPLtaVnXwiu49PyZY8\",\"symbol\":\"KMD\"}" echo "108998.28313606 <- expected amount RCJHEogA7SW6PxuctPLtaVnXwiu49PyZY8" From ac3d4780316697a99c16f719b9b5cb1c09df38e6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 2 Jun 2017 16:26:02 +0300 Subject: [PATCH 0938/2705] Test --- iguana/exchanges/LP_bitcoin.c | 307 +++++++++++ iguana/exchanges/LP_coins.c | 196 +++++++ iguana/exchanges/LP_commands.c | 35 +- iguana/exchanges/LP_include.h | 375 ++----------- iguana/exchanges/LP_nativeDEX.c | 839 +---------------------------- iguana/exchanges/LP_network.c | 229 -------- iguana/exchanges/LP_peers.c | 188 +++++++ iguana/exchanges/LP_prices.c | 162 +++++- iguana/exchanges/LP_remember.c | 139 ----- iguana/exchanges/LP_rpc.c | 50 +- iguana/exchanges/LP_statemachine.c | 311 +++++++++++ iguana/exchanges/LP_transaction.c | 31 -- iguana/exchanges/LP_utxos.c | 327 +++++++++++ iguana/exchanges/mm.c | 2 +- 14 files changed, 1617 insertions(+), 1574 deletions(-) create mode 100644 iguana/exchanges/LP_coins.c create mode 100644 iguana/exchanges/LP_peers.c create mode 100644 iguana/exchanges/LP_utxos.c diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 4b6309ac7..c7ee8b218 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -18,6 +18,313 @@ // marketmaker // +union iguana_stacknum { int32_t val; int64_t val64; uint8_t rmd160[20]; bits256 hash2; uint8_t pubkey[33]; uint8_t sig[74]; }; +struct iguana_stackdata { uint8_t *data; uint16_t size; union iguana_stacknum U; }; + +char *bitcoin_base58encode(char *coinaddr,uint8_t *data,int32_t datalen); +int32_t bitcoin_base58decode(uint8_t *data,char *coinaddr); + +#define IGUANA_MAXSCRIPTSIZE 10001 +#define IGUANA_SEQUENCEID_FINAL 0xfffffffe + +#define IGUANA_SCRIPT_NULL 0 +#define IGUANA_SCRIPT_76AC 1 +#define IGUANA_SCRIPT_76A988AC 2 +#define IGUANA_SCRIPT_P2SH 3 +#define IGUANA_SCRIPT_OPRETURN 4 +#define IGUANA_SCRIPT_3of3 5 +#define IGUANA_SCRIPT_2of3 6 +#define IGUANA_SCRIPT_1of3 7 +#define IGUANA_SCRIPT_2of2 8 +#define IGUANA_SCRIPT_1of2 9 +#define IGUANA_SCRIPT_MSIG 10 +#define IGUANA_SCRIPT_DATA 11 +#define IGUANA_SCRIPT_AC 12 +#define IGUANA_SCRIPT_1of1 13 +#define IGUANA_SCRIPT_STRANGE 15 + +#define MAX_SCRIPT_ELEMENT_SIZE 520 +#define MAX_OPS_PER_SCRIPT 201 // Maximum number of non-push operations per script +#define MAX_PUBKEYS_PER_MULTISIG 20 // Maximum number of public keys per multisig + +#define IGUANA_MAXSTACKITEMS ((int32_t)(IGUANA_MAXSCRIPTSIZE / sizeof(uint32_t))) +#define IGUANA_MAXSTACKDEPTH 128 +struct iguana_interpreter +{ + int32_t active,ifdepth,elsedepth,codeseparator,stackdepth,altstackdepth,maxstackdepth; + int8_t lastpath[IGUANA_MAXSTACKDEPTH]; + cJSON *logarray; + struct iguana_stackdata stack[]; +}; +static struct bitcoin_opcode { UT_hash_handle hh; uint8_t opcode,flags,stackitems; int8_t extralen; } *OPTABLE; static char *OPCODES[0x100]; static int32_t OPCODELENS[0x100]; + +#define SIGHASH_ALL 1 +#define SIGHASH_NONE 2 +#define SIGHASH_SINGLE 3 +#define SIGHASH_ANYONECANPAY 0x80 + +#define SCRIPT_OP_NOP 0x00 +#define SCRIPT_OP_TRUE 0x51 +#define SCRIPT_OP_2 0x52 +#define SCRIPT_OP_3 0x53 +#define SCRIPT_OP_4 0x54 +#define SCRIPT_OP_IF 0x63 +#define SCRIPT_OP_ELSE 0x67 +#define SCRIPT_OP_RETURN 0x6a +#define SCRIPT_OP_DUP 0x76 +#define SCRIPT_OP_ENDIF 0x68 +#define SCRIPT_OP_DROP 0x75 +#define SCRIPT_OP_EQUALVERIFY 0x88 +#define SCRIPT_OP_SHA256 0xa8 +#define SCRIPT_OP_HASH160 0xa9 + +#define SCRIPT_OP_EQUAL 0x87 +#define SCRIPT_OP_CHECKSIG 0xac +#define SCRIPT_OP_CHECKMULTISIG 0xae +#define SCRIPT_OP_CHECKSEQUENCEVERIFY 0xb2 +#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 +#define IGUANA_OP_0 0x00 +#define IGUANA_OP_PUSHDATA1 0x4c +#define IGUANA_OP_PUSHDATA2 0x4d +#define IGUANA_OP_PUSHDATA4 0x4e +#define IGUANA_OP_1NEGATE 0x4f +#define IGUANA_OP_1 0x51 +#define IGUANA_OP_16 0x60 +#define IGUANA_OP_NOP 0x61 +#define IGUANA_OP_IF 0x63 +#define IGUANA_OP_NOTIF 0x64 +#define IGUANA_OP_ELSE 0x67 +#define IGUANA_OP_ENDIF 0x68 +#define IGUANA_OP_VERIFY 0x69 +#define IGUANA_OP_RETURN 0x6a + +#define IGUANA_OP_TOALTSTACK 0x6b +#define IGUANA_OP_FROMALTSTACK 0x6c +#define IGUANA_OP_2DROP 0x6d +#define IGUANA_OP_2DUP 0x6e +#define IGUANA_OP_3DUP 0x6f +#define IGUANA_OP_2OVER 0x70 +#define IGUANA_OP_2ROT 0x71 +#define IGUANA_OP_2SWAP 0x72 +#define IGUANA_OP_IFDUP 0x73 +#define IGUANA_OP_DEPTH 0x74 +#define IGUANA_OP_DROP 0x75 +#define IGUANA_OP_DUP 0x76 +#define IGUANA_OP_NIP 0x77 +#define IGUANA_OP_OVER 0x78 +#define IGUANA_OP_PICK 0x79 +#define IGUANA_OP_ROLL 0x7a +#define IGUANA_OP_ROT 0x7b +#define IGUANA_OP_SWAP 0x7c +#define IGUANA_OP_TUCK 0x7d + +#define IGUANA_OP_EQUAL 0x87 +#define IGUANA_OP_EQUALVERIFY 0x88 + +#define IGUANA_OP_1ADD 0x8b +#define IGUANA_OP_1SUB 0x8c +#define IGUANA_OP_NEGATE 0x8f +#define IGUANA_OP_ABS 0x90 +#define IGUANA_OP_NOT 0x91 +#define IGUANA_OP_0NOTEQUAL 0x92 +#define IGUANA_OP_ADD 0x93 +#define IGUANA_OP_SUB 0x94 + +#define IGUANA_OP_BOOLAND 0x9a +#define IGUANA_OP_BOOLOR 0x9b +#define IGUANA_OP_NUMEQUAL 0x9c +#define IGUANA_OP_NUMEQUALVERIFY 0x9d +#define IGUANA_OP_NUMNOTEQUAL 0x9e +#define IGUANA_OP_LESSTHAN 0x9f +#define IGUANA_OP_GREATERTHAN 0xa0 +#define IGUANA_OP_LESSTHANOREQUAL 0xa1 +#define IGUANA_OP_GREATERTHANOREQUAL 0xa2 +#define IGUANA_OP_MIN 0xa3 +#define IGUANA_OP_MAX 0xa4 +#define IGUANA_OP_WITHIN 0xa5 + +#define IGUANA_OP_RIPEMD160 0xa6 +#define IGUANA_OP_SHA1 0xa7 +#define IGUANA_OP_SHA256 0xa8 +#define IGUANA_OP_HASH160 0xa9 +#define IGUANA_OP_HASH256 0xaa +#define IGUANA_OP_CODESEPARATOR 0xab +#define IGUANA_OP_CHECKSIG 0xac +#define IGUANA_OP_CHECKSIGVERIFY 0xad +#define IGUANA_OP_CHECKMULTISIG 0xae +#define IGUANA_OP_CHECKMULTISIGVERIFY 0xaf + +#define IGUANA_OP_NOP1 0xb0 +#define IGUANA_OP_CHECKLOCKTIMEVERIFY 0xb1 +#define IGUANA_OP_CHECKSEQUENCEVERIFY 0xb2 +#define IGUANA_OP_NOP10 0xb9 + +#define IGUANA_OP_COMBINEPUBKEYS 0xc0 +#define IGUANA_OP_CHECKSCHNORR 0xc1 +#define IGUANA_OP_CHECKSCHNORRVERIFY 0xc2 + +// https://github.com/TierNolan/bips/blob/cpkv/bip-cprkv.mediawiki +#define IGUANA_OP_CHECKPRIVATEKEY 0xc3 +#define IGUANA_OP_CHECKPRIVATEKEYVERIFY 0xc4 + +#define IGUANA_NOPFLAG 1 +#define IGUANA_ALWAYSILLEGAL 2 +#define IGUANA_EXECUTIONILLEGAL 4 +#define IGUANA_POSTVERIFY 8 +#define IGUANA_CRYPTOFLAG 16 +#define IGUANA_MATHFLAG 32 +#define IGUANA_CONTROLFLAG 64 +#define IGUANA_STACKFLAG 128 + +enum opcodetype +{ + // push value + OP_0 = 0x00, + OP_FALSE = OP_0, + OP_PUSHDATA1 = 0x4c, + OP_PUSHDATA2 = 0x4d, + OP_PUSHDATA4 = 0x4e, + OP_1NEGATE = 0x4f, + OP_RESERVED = 0x50, + OP_1 = 0x51, + OP_TRUE=OP_1, + OP_2 = 0x52, + OP_3 = 0x53, + OP_4 = 0x54, + OP_5 = 0x55, + OP_6 = 0x56, + OP_7 = 0x57, + OP_8 = 0x58, + OP_9 = 0x59, + OP_10 = 0x5a, + OP_11 = 0x5b, + OP_12 = 0x5c, + OP_13 = 0x5d, + OP_14 = 0x5e, + OP_15 = 0x5f, + OP_16 = 0x60, + + // control + OP_NOP = 0x61, + OP_VER = 0x62, + OP_IF = 0x63, + OP_NOTIF = 0x64, + OP_VERIF = 0x65, + OP_VERNOTIF = 0x66, + OP_ELSE = 0x67, + OP_ENDIF = 0x68, + OP_VERIFY = 0x69, + OP_RETURN = 0x6a, + + // stack ops + OP_TOALTSTACK = 0x6b, + OP_FROMALTSTACK = 0x6c, + OP_2DROP = 0x6d, + OP_2DUP = 0x6e, + OP_3DUP = 0x6f, + OP_2OVER = 0x70, + OP_2ROT = 0x71, + OP_2SWAP = 0x72, + OP_IFDUP = 0x73, + OP_DEPTH = 0x74, + OP_DROP = 0x75, + OP_DUP = 0x76, + OP_NIP = 0x77, + OP_OVER = 0x78, + OP_PICK = 0x79, + OP_ROLL = 0x7a, + OP_ROT = 0x7b, + OP_SWAP = 0x7c, + OP_TUCK = 0x7d, + + // splice ops + OP_CAT = 0x7e, + OP_SUBSTR = 0x7f, + OP_LEFT = 0x80, + OP_RIGHT = 0x81, + OP_SIZE = 0x82, + + // bit logic + OP_INVERT = 0x83, + OP_AND = 0x84, + OP_OR = 0x85, + OP_XOR = 0x86, + OP_EQUAL = 0x87, + OP_EQUALVERIFY = 0x88, + OP_RESERVED1 = 0x89, + OP_RESERVED2 = 0x8a, + + // numeric + OP_1ADD = 0x8b, + OP_1SUB = 0x8c, + OP_2MUL = 0x8d, + OP_2DIV = 0x8e, + OP_NEGATE = 0x8f, + OP_ABS = 0x90, + OP_NOT = 0x91, + OP_0NOTEQUAL = 0x92, + + OP_ADD = 0x93, + OP_SUB = 0x94, + OP_MUL = 0x95, + OP_DIV = 0x96, + OP_MOD = 0x97, + OP_LSHIFT = 0x98, + OP_RSHIFT = 0x99, + + OP_BOOLAND = 0x9a, + OP_BOOLOR = 0x9b, + OP_NUMEQUAL = 0x9c, + OP_NUMEQUALVERIFY = 0x9d, + OP_NUMNOTEQUAL = 0x9e, + OP_LESSTHAN = 0x9f, + OP_GREATERTHAN = 0xa0, + OP_LESSTHANOREQUAL = 0xa1, + OP_GREATERTHANOREQUAL = 0xa2, + OP_MIN = 0xa3, + OP_MAX = 0xa4, + + OP_WITHIN = 0xa5, + + // crypto + OP_RIPEMD160 = 0xa6, + OP_SHA1 = 0xa7, + OP_SHA256 = 0xa8, + OP_HASH160 = 0xa9, + OP_HASH256 = 0xaa, + OP_CODESEPARATOR = 0xab, + OP_CHECKSIG = 0xac, + OP_CHECKSIGVERIFY = 0xad, + OP_CHECKMULTISIG = 0xae, + OP_CHECKMULTISIGVERIFY = 0xaf, + + // expansion + OP_NOP1 = 0xb0, + OP_CHECKLOCKTIMEVERIFY = 0xb1, + OP_CHECKSEQUENCEVERIFY = 0xb2, + OP_NOP4 = 0xb3, + OP_NOP5 = 0xb4, + OP_NOP6 = 0xb5, + OP_NOP7 = 0xb6, + OP_NOP8 = 0xb7, + OP_NOP9 = 0xb8, + OP_NOP10 = 0xb9, + + OP_COMBINEPUBKEYS = 0xc0, + OP_CHECKSCHNORR = 0xc1, + OP_CHECKSCHNORRVERIFY = 0xc2, + OP_CHECKPRIVATEKEY = 0xc3, + OP_CHECKPRIVATEKEYVERIFY = 0xc4, + + // template matching params + //OP_SMALLINTEGER = 0xfa, + //OP_PUBKEYS = 0xfb, + //OP_PUBKEYHASH = 0xfd, + //OP_PUBKEY = 0xfe, + + OP_INVALIDOPCODE = 0xff, +}; + struct { bits256 privkey; uint8_t rmd160[20]; } LP_privkeys[100]; int32_t LP_numprivkeys; bits256 LP_privkeyfind(uint8_t rmd160[20]) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c new file mode 100644 index 000000000..d3f136c00 --- /dev/null +++ b/iguana/exchanges/LP_coins.c @@ -0,0 +1,196 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_coins.c +// marketmaker +// + + +char *parse_conf_line(char *line,char *field) +{ + line += strlen(field); + for (; *line!='='&&*line!=0; line++) + break; + if ( *line == 0 ) + return(0); + if ( *line == '=' ) + line++; + while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n' || line[strlen(line)-1] == ' ' ) + line[strlen(line)-1] = 0; + //printf("LINE.(%s)\n",line); + _stripwhite(line,0); + return(clonestr(line)); +} + +void LP_userpassfp(char *username,char *password,FILE *fp) +{ + char *rpcuser,*rpcpassword,*str,line[8192]; + rpcuser = rpcpassword = 0; + username[0] = password[0] = 0; + while ( fgets(line,sizeof(line),fp) != 0 ) + { + if ( line[0] == '#' ) + continue; + //printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword")); + if ( (str= strstr(line,(char *)"rpcuser")) != 0 ) + rpcuser = parse_conf_line(str,(char *)"rpcuser"); + else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 ) + rpcpassword = parse_conf_line(str,(char *)"rpcpassword"); + } + if ( rpcuser != 0 && rpcpassword != 0 ) + { + strcpy(username,rpcuser); + strcpy(password,rpcpassword); + } + //printf("rpcuser.(%s) rpcpassword.(%s) KMDUSERPASS.(%s) %u\n",rpcuser,rpcpassword,KMDUSERPASS,port); + if ( rpcuser != 0 ) + free(rpcuser); + if ( rpcpassword != 0 ) + free(rpcpassword); +} + +void LP_statefname(char *fname,char *symbol,char *assetname,char *str) +{ + sprintf(fname,"%s",LP_getdatadir()); +#ifdef WIN32 + strcat(fname,"\\"); +#else + strcat(fname,"/"); +#endif + if ( strcmp(symbol,"BTC") == 0 ) + strcat(fname,".bitcoin"); + else if ( strcmp(symbol,"LTC") == 0 ) + strcat(fname,".litecoin"); + else + { + strcat(fname,".komodo"); + if ( strcmp(symbol,"KMD") != 0 ) + { +#ifdef WIN32 + strcat(fname,"\\"); +#else + strcat(fname,"/"); +#endif + strcat(fname,assetname); + } + } +#ifdef WIN32 + strcat(fname,"\\"); +#else + strcat(fname,"/"); +#endif + strcat(fname,str); + printf("LP_statefname.(%s) <- %s %s %s\n",fname,symbol,assetname,str); +} + +int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) +{ + FILE *fp; char fname[512],username[512],password[512],confname[16]; + userpass[0] = 0; + sprintf(confname,"%s.conf",confroot); +#ifdef __APPLE__ + confname[0] = toupper(confname[0]); +#endif + LP_statefname(fname,symbol,assetname,confname); + if ( (fp= fopen(fname,"rb")) != 0 ) + { + LP_userpassfp(username,password,fp); + sprintf(userpass,"%s:%s",username,password); + fclose(fp); + return((int32_t)strlen(userpass)); + } + return(-1); +} + +uint32_t LP_assetmagic(char *symbol,uint64_t supply) +{ + uint8_t buf[512]; int32_t len = 0; + if ( strcmp(symbol,"KMD") == 0 ) + return(0x8de4eef9); + len = iguana_rwnum(1,&buf[len],sizeof(supply),(void *)&supply); + strcpy((char *)&buf[len],symbol); + len += strlen(symbol); + return(calc_crc32(0,buf,len)); +} + +uint16_t LP_assetport(uint32_t magic) +{ + if ( magic == 0x8de4eef9 ) + return(7771); + else return(8000 + (magic % 7777)); +} + +uint16_t LP_rpcport(char *symbol,uint64_t supply,uint32_t *magicp) +{ + if ( symbol == 0 || symbol[0] == 0 || strcmp("KMD",symbol) == 0 ) + { + *magicp = 0x8de4eef9; + return(7771); + } + else if ( strcmp("BTC",symbol) == 0 ) + return(8332); + else if ( strcmp("LTC",symbol) == 0 ) + return(9332); + *magicp = LP_assetmagic(symbol,supply); + return(LP_assetport(*magicp)+1); +} + +struct iguana_info *LP_coinfind(char *symbol) +{ + static struct iguana_info *LP_coins; static int32_t LP_numcoins; + struct iguana_info *coin,cdata; int32_t i; uint32_t magic; uint16_t port; + for (i=0; iQ = Q; return(clonestr("{\"result\":\"updated\"}")); - } - else return(clonestr("{\"error\":\"nullptr\"}")); + } else return(clonestr("{\"error\":\"nullptr\"}")); } double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub) @@ -213,7 +212,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port, break; } } - usleep(250000); + usleep(100000); } } else printf("no pushsock for peer.%s:%u\n",ipaddr,port); } else printf("cant find/create peer.%s:%u\n",ipaddr,port); @@ -360,6 +359,27 @@ cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) return(bestitem); } +int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin) +{ + double price; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; + if ( (now= (uint32_t)time(NULL)) > utxo->swappending ) + utxo->swappending = 0; + if ( now > utxo->published+60 && utxo->swappending == 0 && utxo->pair < 0 && utxo->swap == 0 && (price= LP_price(utxo->coin,rel)) != 0. ) + { + price *= (1. + profitmargin); + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + Q.timestamp = (uint32_t)time(NULL); + retjson = LP_quotejson(&Q); + jaddstr(retjson,"method","quote"); + retstr = jprint(retjson,1); + LP_send(pubsock,retstr,1); + utxo->published = now; + return(0); + } + return(-1); +} + int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey,txid; struct LP_utxoinfo *utxo; int32_t retval = -1,DEXselector = 0; uint64_t destvalue; struct basilisk_request R; struct LP_quoteinfo Q; @@ -368,7 +388,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(txid,jint(argjson,"vout"))) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { - printf("LP_command.(%s)\n",jprint(argjson,0)); + //printf("LP_command.(%s)\n",jprint(argjson,0)); if ( time(NULL) > utxo->swappending ) utxo->swappending = 0; if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) @@ -399,6 +419,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin else jaddstr(retjson,"method","quote"); retstr = jprint(retjson,1); LP_send(pubsock,retstr,1); + utxo->published = (uint32_t)time(NULL); } else printf("null price\n"); } else printf("swappending.%u pair.%d\n",utxo->swappending,utxo->pair); } @@ -496,7 +517,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } printf("CMD.(%s)\n",jprint(argjson,0)); if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) - retstr = LP_quote(argjson); + retstr = LP_quotereceived(argjson); else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) { int32_t pairsock = -1; char *pairstr; @@ -518,6 +539,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } else if ( IAMCLIENT == 0 && strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); + else if ( strcmp(method,"orderbook") == 0 ) + retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 568a65511..4cfacff3f 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -21,70 +21,30 @@ #ifndef LP_INCLUDE_H #define LP_INCLUDE_H +#define INSTANTDEX_DECKSIZE 1000 +#define INSTANTDEX_LOCKTIME (3600*2 + 300*2) +#define INSTANTDEX_INSURANCEDIV 777 +#define INSTANTDEX_PUBKEY "03bc2c7ba671bae4a6fc835244c9762b41647b9827d4780a89a949b984a8ddcc06" +#define INSTANTDEX_RMD160 "ca1e04745e8ca0c60d8c5881531d51bec470743f" +#define JUMBLR_RMD160 "5177f8b427e5f47342a4b8ab5dac770815d4389e" +#define TIERNOLAN_RMD160 "daedddd8dbe7a2439841ced40ba9c3d375f98146" +#define INSTANTDEX_BTC "1KRhTPvoxyJmVALwHFXZdeeWFbcJSbkFPu" +#define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" + #define BASILISK_DISABLEWAITTX #define BASILISK_DISABLESENDTX +#define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 #define LP_AVETXSIZE 200 #define LP_CACHEDURATION 60 - #define BASILISK_DEFAULT_NUMCONFIRMS 5 #define DEX_SLEEP 3 -#define BASILISK_DEXDURATION 300 -#define BASILISK_MSGDURATION 30 -#define BASILISK_AUCTION_DURATION 5 - -#define BASILISK_MAXFUTUREBLOCK 60 #define BASILISK_KEYSIZE ((int32_t)(2*sizeof(bits256)+sizeof(uint32_t)*2)) extern char GLOBAL_DBDIR[]; extern int32_t IAMCLIENT; -void *bitcoin_ctx(); -int32_t bitcoin_verify(void *ctx,uint8_t *sig,int32_t siglen,bits256 txhash2,uint8_t *pubkey,int32_t plen); -int32_t bitcoin_recoververify(void *ctx,char *symbol,uint8_t *sig,bits256 messagehash2,uint8_t *pubkey,size_t plen); -int32_t bitcoin_sign(void *ctx,char *symbol,uint8_t *sig,bits256 txhash2,bits256 privkey,int32_t recoverflag); -bits256 bitcoin_pubkey33(void *ctx,uint8_t *data,bits256 privkey); -bits256 bitcoin_pub256(void *ctx,bits256 *privkeyp,uint8_t odd_even); - -char *bitcoin_base58encode(char *coinaddr,uint8_t *data,int32_t datalen); -int32_t bitcoin_base58decode(uint8_t *data,char *coinaddr); - -#define IGUANA_MAXSCRIPTSIZE 10001 -#define IGUANA_SEQUENCEID_FINAL 0xfffffffe - -#define IGUANA_SCRIPT_NULL 0 -#define IGUANA_SCRIPT_76AC 1 -#define IGUANA_SCRIPT_76A988AC 2 -#define IGUANA_SCRIPT_P2SH 3 -#define IGUANA_SCRIPT_OPRETURN 4 -#define IGUANA_SCRIPT_3of3 5 -#define IGUANA_SCRIPT_2of3 6 -#define IGUANA_SCRIPT_1of3 7 -#define IGUANA_SCRIPT_2of2 8 -#define IGUANA_SCRIPT_1of2 9 -#define IGUANA_SCRIPT_MSIG 10 -#define IGUANA_SCRIPT_DATA 11 -#define IGUANA_SCRIPT_AC 12 -#define IGUANA_SCRIPT_1of1 13 -#define IGUANA_SCRIPT_STRANGE 15 - -#define BASILISK_TIMEOUT 3000 -#define BASILISK_MINFANOUT 8 -#define BASILISK_MAXFANOUT 64 -#define BASILISK_DEFAULTDIFF 0x1effffff -#define BASILISK_HDROFFSET ((int32_t)(sizeof(bits256)+sizeof(struct iguana_msghdr)+sizeof(uint32_t))) - -#define INSTANTDEX_DECKSIZE 1000 -#define INSTANTDEX_LOCKTIME (3600*2 + 300*2) -#define INSTANTDEX_INSURANCEDIV 777 -#define INSTANTDEX_PUBKEY "03bc2c7ba671bae4a6fc835244c9762b41647b9827d4780a89a949b984a8ddcc06" -#define INSTANTDEX_RMD160 "ca1e04745e8ca0c60d8c5881531d51bec470743f" -#define JUMBLR_RMD160 "5177f8b427e5f47342a4b8ab5dac770815d4389e" -#define TIERNOLAN_RMD160 "daedddd8dbe7a2439841ced40ba9c3d375f98146" -#define INSTANTDEX_BTC "1KRhTPvoxyJmVALwHFXZdeeWFbcJSbkFPu" -#define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" - struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }; struct iguana_msgvout { uint64_t value; uint32_t pk_scriptlen; uint8_t *pk_script; }; @@ -107,7 +67,7 @@ struct vin_info struct iguana_msgvin vin; uint64_t amount; cJSON *extras; bits256 sigtxid; int32_t M,N,validmask,spendlen,type,p2shlen,numpubkeys,numsigs,height,hashtype,userdatalen,suppress_pubkeys,ignore_cltverr; uint32_t sequence,unspentind; struct vin_signer signers[16]; char coinaddr[65]; - uint8_t rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE],userdata[IGUANA_MAXSCRIPTSIZE]; + uint8_t rmd160[20],spendscript[10000],p2shscript[10000],userdata[10000]; }; struct basilisk_swapmessage @@ -199,6 +159,31 @@ struct basilisk_swap }; +struct LP_utxoinfo +{ + UT_hash_handle hh; + bits256 txid,txid2,feetxid,otherpubkey,mypub; + void *swap; + uint64_t satoshis,satoshis2; + uint8_t key[sizeof(bits256) + sizeof(int32_t)]; + int32_t vout,vout2,pair; + uint32_t lasttime,errors,swappending,published; + double profitmargin; + char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; + uint16_t port; +}; + +struct LP_peerinfo +{ + UT_hash_handle hh; + uint64_t ip_port; + double profitmargin; + uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected; + int32_t pushsock,subsock; + uint16_t port; + char ipaddr[64]; +}; + struct LP_quoteinfo { struct basilisk_request R; @@ -208,297 +193,11 @@ struct LP_quoteinfo char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; }; -union iguana_stacknum { int32_t val; int64_t val64; uint8_t rmd160[20]; bits256 hash2; uint8_t pubkey[33]; uint8_t sig[74]; }; -struct iguana_stackdata { uint8_t *data; uint16_t size; union iguana_stacknum U; }; - -#define MAX_SCRIPT_ELEMENT_SIZE 520 -#define MAX_OPS_PER_SCRIPT 201 // Maximum number of non-push operations per script -#define MAX_PUBKEYS_PER_MULTISIG 20 // Maximum number of public keys per multisig - -#define IGUANA_MAXSTACKITEMS ((int32_t)(IGUANA_MAXSCRIPTSIZE / sizeof(uint32_t))) -#define IGUANA_MAXSTACKDEPTH 128 -struct iguana_interpreter -{ - int32_t active,ifdepth,elsedepth,codeseparator,stackdepth,altstackdepth,maxstackdepth; - int8_t lastpath[IGUANA_MAXSTACKDEPTH]; - cJSON *logarray; - struct iguana_stackdata stack[]; -}; -static struct bitcoin_opcode { UT_hash_handle hh; uint8_t opcode,flags,stackitems; int8_t extralen; } *OPTABLE; static char *OPCODES[0x100]; static int32_t OPCODELENS[0x100]; - -#define SIGHASH_ALL 1 -#define SIGHASH_NONE 2 -#define SIGHASH_SINGLE 3 -#define SIGHASH_ANYONECANPAY 0x80 - -#define SCRIPT_OP_NOP 0x00 -#define SCRIPT_OP_TRUE 0x51 -#define SCRIPT_OP_2 0x52 -#define SCRIPT_OP_3 0x53 -#define SCRIPT_OP_4 0x54 -#define SCRIPT_OP_IF 0x63 -#define SCRIPT_OP_ELSE 0x67 -#define SCRIPT_OP_RETURN 0x6a -#define SCRIPT_OP_DUP 0x76 -#define SCRIPT_OP_ENDIF 0x68 -#define SCRIPT_OP_DROP 0x75 -#define SCRIPT_OP_EQUALVERIFY 0x88 -#define SCRIPT_OP_SHA256 0xa8 -#define SCRIPT_OP_HASH160 0xa9 - -#define SCRIPT_OP_EQUAL 0x87 -#define SCRIPT_OP_CHECKSIG 0xac -#define SCRIPT_OP_CHECKMULTISIG 0xae -#define SCRIPT_OP_CHECKSEQUENCEVERIFY 0xb2 -#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 -#define IGUANA_OP_0 0x00 -#define IGUANA_OP_PUSHDATA1 0x4c -#define IGUANA_OP_PUSHDATA2 0x4d -#define IGUANA_OP_PUSHDATA4 0x4e -#define IGUANA_OP_1NEGATE 0x4f -#define IGUANA_OP_1 0x51 -#define IGUANA_OP_16 0x60 -#define IGUANA_OP_NOP 0x61 -#define IGUANA_OP_IF 0x63 -#define IGUANA_OP_NOTIF 0x64 -#define IGUANA_OP_ELSE 0x67 -#define IGUANA_OP_ENDIF 0x68 -#define IGUANA_OP_VERIFY 0x69 -#define IGUANA_OP_RETURN 0x6a - -#define IGUANA_OP_TOALTSTACK 0x6b -#define IGUANA_OP_FROMALTSTACK 0x6c -#define IGUANA_OP_2DROP 0x6d -#define IGUANA_OP_2DUP 0x6e -#define IGUANA_OP_3DUP 0x6f -#define IGUANA_OP_2OVER 0x70 -#define IGUANA_OP_2ROT 0x71 -#define IGUANA_OP_2SWAP 0x72 -#define IGUANA_OP_IFDUP 0x73 -#define IGUANA_OP_DEPTH 0x74 -#define IGUANA_OP_DROP 0x75 -#define IGUANA_OP_DUP 0x76 -#define IGUANA_OP_NIP 0x77 -#define IGUANA_OP_OVER 0x78 -#define IGUANA_OP_PICK 0x79 -#define IGUANA_OP_ROLL 0x7a -#define IGUANA_OP_ROT 0x7b -#define IGUANA_OP_SWAP 0x7c -#define IGUANA_OP_TUCK 0x7d - -#define IGUANA_OP_EQUAL 0x87 -#define IGUANA_OP_EQUALVERIFY 0x88 - -#define IGUANA_OP_1ADD 0x8b -#define IGUANA_OP_1SUB 0x8c -#define IGUANA_OP_NEGATE 0x8f -#define IGUANA_OP_ABS 0x90 -#define IGUANA_OP_NOT 0x91 -#define IGUANA_OP_0NOTEQUAL 0x92 -#define IGUANA_OP_ADD 0x93 -#define IGUANA_OP_SUB 0x94 - -#define IGUANA_OP_BOOLAND 0x9a -#define IGUANA_OP_BOOLOR 0x9b -#define IGUANA_OP_NUMEQUAL 0x9c -#define IGUANA_OP_NUMEQUALVERIFY 0x9d -#define IGUANA_OP_NUMNOTEQUAL 0x9e -#define IGUANA_OP_LESSTHAN 0x9f -#define IGUANA_OP_GREATERTHAN 0xa0 -#define IGUANA_OP_LESSTHANOREQUAL 0xa1 -#define IGUANA_OP_GREATERTHANOREQUAL 0xa2 -#define IGUANA_OP_MIN 0xa3 -#define IGUANA_OP_MAX 0xa4 -#define IGUANA_OP_WITHIN 0xa5 - -#define IGUANA_OP_RIPEMD160 0xa6 -#define IGUANA_OP_SHA1 0xa7 -#define IGUANA_OP_SHA256 0xa8 -#define IGUANA_OP_HASH160 0xa9 -#define IGUANA_OP_HASH256 0xaa -#define IGUANA_OP_CODESEPARATOR 0xab -#define IGUANA_OP_CHECKSIG 0xac -#define IGUANA_OP_CHECKSIGVERIFY 0xad -#define IGUANA_OP_CHECKMULTISIG 0xae -#define IGUANA_OP_CHECKMULTISIGVERIFY 0xaf - -#define IGUANA_OP_NOP1 0xb0 -#define IGUANA_OP_CHECKLOCKTIMEVERIFY 0xb1 -#define IGUANA_OP_CHECKSEQUENCEVERIFY 0xb2 -#define IGUANA_OP_NOP10 0xb9 - -#define IGUANA_OP_COMBINEPUBKEYS 0xc0 -#define IGUANA_OP_CHECKSCHNORR 0xc1 -#define IGUANA_OP_CHECKSCHNORRVERIFY 0xc2 - -// https://github.com/TierNolan/bips/blob/cpkv/bip-cprkv.mediawiki -#define IGUANA_OP_CHECKPRIVATEKEY 0xc3 -#define IGUANA_OP_CHECKPRIVATEKEYVERIFY 0xc4 - -#define IGUANA_NOPFLAG 1 -#define IGUANA_ALWAYSILLEGAL 2 -#define IGUANA_EXECUTIONILLEGAL 4 -#define IGUANA_POSTVERIFY 8 -#define IGUANA_CRYPTOFLAG 16 -#define IGUANA_MATHFLAG 32 -#define IGUANA_CONTROLFLAG 64 -#define IGUANA_STACKFLAG 128 - -enum opcodetype -{ - // push value - OP_0 = 0x00, - OP_FALSE = OP_0, - OP_PUSHDATA1 = 0x4c, - OP_PUSHDATA2 = 0x4d, - OP_PUSHDATA4 = 0x4e, - OP_1NEGATE = 0x4f, - OP_RESERVED = 0x50, - OP_1 = 0x51, - OP_TRUE=OP_1, - OP_2 = 0x52, - OP_3 = 0x53, - OP_4 = 0x54, - OP_5 = 0x55, - OP_6 = 0x56, - OP_7 = 0x57, - OP_8 = 0x58, - OP_9 = 0x59, - OP_10 = 0x5a, - OP_11 = 0x5b, - OP_12 = 0x5c, - OP_13 = 0x5d, - OP_14 = 0x5e, - OP_15 = 0x5f, - OP_16 = 0x60, - - // control - OP_NOP = 0x61, - OP_VER = 0x62, - OP_IF = 0x63, - OP_NOTIF = 0x64, - OP_VERIF = 0x65, - OP_VERNOTIF = 0x66, - OP_ELSE = 0x67, - OP_ENDIF = 0x68, - OP_VERIFY = 0x69, - OP_RETURN = 0x6a, - - // stack ops - OP_TOALTSTACK = 0x6b, - OP_FROMALTSTACK = 0x6c, - OP_2DROP = 0x6d, - OP_2DUP = 0x6e, - OP_3DUP = 0x6f, - OP_2OVER = 0x70, - OP_2ROT = 0x71, - OP_2SWAP = 0x72, - OP_IFDUP = 0x73, - OP_DEPTH = 0x74, - OP_DROP = 0x75, - OP_DUP = 0x76, - OP_NIP = 0x77, - OP_OVER = 0x78, - OP_PICK = 0x79, - OP_ROLL = 0x7a, - OP_ROT = 0x7b, - OP_SWAP = 0x7c, - OP_TUCK = 0x7d, - - // splice ops - OP_CAT = 0x7e, - OP_SUBSTR = 0x7f, - OP_LEFT = 0x80, - OP_RIGHT = 0x81, - OP_SIZE = 0x82, - - // bit logic - OP_INVERT = 0x83, - OP_AND = 0x84, - OP_OR = 0x85, - OP_XOR = 0x86, - OP_EQUAL = 0x87, - OP_EQUALVERIFY = 0x88, - OP_RESERVED1 = 0x89, - OP_RESERVED2 = 0x8a, - - // numeric - OP_1ADD = 0x8b, - OP_1SUB = 0x8c, - OP_2MUL = 0x8d, - OP_2DIV = 0x8e, - OP_NEGATE = 0x8f, - OP_ABS = 0x90, - OP_NOT = 0x91, - OP_0NOTEQUAL = 0x92, - - OP_ADD = 0x93, - OP_SUB = 0x94, - OP_MUL = 0x95, - OP_DIV = 0x96, - OP_MOD = 0x97, - OP_LSHIFT = 0x98, - OP_RSHIFT = 0x99, - - OP_BOOLAND = 0x9a, - OP_BOOLOR = 0x9b, - OP_NUMEQUAL = 0x9c, - OP_NUMEQUALVERIFY = 0x9d, - OP_NUMNOTEQUAL = 0x9e, - OP_LESSTHAN = 0x9f, - OP_GREATERTHAN = 0xa0, - OP_LESSTHANOREQUAL = 0xa1, - OP_GREATERTHANOREQUAL = 0xa2, - OP_MIN = 0xa3, - OP_MAX = 0xa4, - - OP_WITHIN = 0xa5, - - // crypto - OP_RIPEMD160 = 0xa6, - OP_SHA1 = 0xa7, - OP_SHA256 = 0xa8, - OP_HASH160 = 0xa9, - OP_HASH256 = 0xaa, - OP_CODESEPARATOR = 0xab, - OP_CHECKSIG = 0xac, - OP_CHECKSIGVERIFY = 0xad, - OP_CHECKMULTISIG = 0xae, - OP_CHECKMULTISIGVERIFY = 0xaf, - - // expansion - OP_NOP1 = 0xb0, - OP_CHECKLOCKTIMEVERIFY = 0xb1, - OP_CHECKSEQUENCEVERIFY = 0xb2, - OP_NOP4 = 0xb3, - OP_NOP5 = 0xb4, - OP_NOP6 = 0xb5, - OP_NOP7 = 0xb6, - OP_NOP8 = 0xb7, - OP_NOP9 = 0xb8, - OP_NOP10 = 0xb9, - - OP_COMBINEPUBKEYS = 0xc0, - OP_CHECKSCHNORR = 0xc1, - OP_CHECKSCHNORRVERIFY = 0xc2, - OP_CHECKPRIVATEKEY = 0xc3, - OP_CHECKPRIVATEKEYVERIFY = 0xc4, - - // template matching params - //OP_SMALLINTEGER = 0xfa, - //OP_PUBKEYS = 0xfb, - //OP_PUBKEYHASH = 0xfd, - //OP_PUBKEY = 0xfe, - - OP_INVALIDOPCODE = 0xff, -}; void basilisk_dontforget_update(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx); uint32_t basilisk_requestid(struct basilisk_request *rp); uint32_t basilisk_quoteid(struct basilisk_request *rp); struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp,struct LP_quoteinfo *qp); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); -struct iguana_info *LP_coinfind(char *symbol); -void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3); uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend); #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ce8a3b97c..68915cd7a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -23,549 +23,21 @@ #include "LP_include.h" #include "LP_network.c" -#define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid +struct LP_utxoinfo *LP_utxoinfos; +struct LP_peerinfo *LP_peerinfos,*LP_mypeer; char *activecoins[] = { "BTC", "KMD", "REVS", "JUMBLR" };//"LTC", "USD", }; +char GLOBAL_DBDIR[] = "DB"; char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", + portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; int32_t LP_mypubsock = -1; int32_t Client_connections; int32_t IAMCLIENT = 0; -struct LP_peerinfo -{ - UT_hash_handle hh; - uint64_t ip_port; - double profitmargin; - uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected; - int32_t pushsock,subsock; - uint16_t port; - char ipaddr[64]; -} *LP_peerinfos,*LP_mypeer; - -struct LP_utxoinfo -{ - UT_hash_handle hh; - bits256 txid,txid2,feetxid,otherpubkey,mypub; - void *swap; - uint64_t satoshis,satoshis2; - uint8_t key[sizeof(bits256) + sizeof(int32_t)]; - int32_t vout,vout2,pair; uint32_t lasttime,errors,swappending; - double profitmargin; - char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; - uint16_t port; -} *LP_utxoinfos; - -struct LP_cacheinfo -{ - UT_hash_handle hh; - struct LP_quoteinfo Q; - uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(int32_t)]; - double price; - uint32_t timestamp; -} *LP_cacheinfos; - -int32_t LP_cachekey(uint8_t *key,char *base,char *rel,bits256 txid,int32_t vout) -{ - uint64_t basebits,relbits; int32_t offset = 0; - basebits = stringbits(base); - relbits = stringbits(rel); - memcpy(&key[offset],&basebits,sizeof(basebits)), offset += sizeof(basebits); - memcpy(&key[offset],&relbits,sizeof(relbits)), offset += sizeof(relbits); - memcpy(&key[offset],&txid,sizeof(txid)), offset += sizeof(txid); - memcpy(&key[offset],&vout,sizeof(vout)), offset += sizeof(vout); - return(offset); -} - -struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout) -{ - struct LP_cacheinfo *ptr=0; uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(vout)]; - if ( LP_cachekey(key,base,rel,txid,vout) == sizeof(key) ) - { - portable_mutex_lock(&LP_cachemutex); - HASH_FIND(hh,LP_cacheinfos,key,sizeof(key),ptr); - portable_mutex_unlock(&LP_cachemutex); - } else printf("LP_cachefind keysize mismatch?\n"); - if ( 0 && ptr != 0 && ptr->timestamp != 0 && ptr->timestamp < time(NULL)-LP_CACHEDURATION ) - { - printf("expire price %.8f\n",ptr->price); - ptr->price = 0.; - ptr->timestamp = 0; - memset(&ptr->Q,0,sizeof(ptr->Q)); - } - return(ptr); -} - -double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,int32_t vout) -{ - struct LP_cacheinfo *ptr; - if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) - { - if ( qp != 0 ) - (*qp) = ptr->Q; - if ( ptr->price == 0. && ptr->Q.satoshis != 0 ) - { - printf("null ptr->price? "); - ptr->price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; - } - //printf("found %s/%s %.8f\n",base,rel,ptr->price); - return(ptr->price); - } - //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); - return(0.); -} - -struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout,double price,struct LP_quoteinfo *qp) -{ - struct LP_cacheinfo *ptr=0; - if ( (ptr= LP_cachefind(base,rel,txid,vout)) == 0 ) - { - ptr = calloc(1,sizeof(*ptr)); - if ( LP_cachekey(ptr->key,base,rel,txid,vout) == sizeof(ptr->key) ) - { - portable_mutex_lock(&LP_cachemutex); - HASH_ADD(hh,LP_cacheinfos,key,sizeof(ptr->key),ptr); - portable_mutex_unlock(&LP_cachemutex); - } else printf("LP_cacheadd keysize mismatch?\n"); - } //else printf("CACHE hit!\n"); - char str[65]; if ( price != ptr->price ) - printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)qp->satoshis,price); - ptr->price = price; - ptr->Q = *qp; - ptr->timestamp = (uint32_t)time(NULL); - printf("cacheadd %.8f\n",price); - return(ptr); -} - -struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) -{ - struct LP_peerinfo *peer=0; uint64_t ip_port; - ip_port = ((uint64_t)port << 32) | ipbits; - portable_mutex_lock(&LP_peermutex); - HASH_FIND(hh,LP_peerinfos,&ip_port,sizeof(ip_port),peer); - portable_mutex_unlock(&LP_peermutex); - return(peer); -} - -struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) -{ - struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; - memcpy(key,txid.bytes,sizeof(txid)); - memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - portable_mutex_lock(&LP_utxomutex); - HASH_FIND(hh,LP_utxoinfos,key,sizeof(key),utxo); - portable_mutex_unlock(&LP_utxomutex); - return(utxo); -} - -cJSON *LP_peerjson(struct LP_peerinfo *peer) -{ - cJSON *item = cJSON_CreateObject(); - jaddstr(item,"ipaddr",peer->ipaddr); - jaddnum(item,"port",peer->port); - jaddnum(item,"profit",peer->profitmargin); - return(item); -} - -cJSON *LP_utxojson(struct LP_utxoinfo *utxo) -{ - cJSON *item = cJSON_CreateObject(); - jaddstr(item,"ipaddr",utxo->ipaddr); - jaddnum(item,"port",utxo->port); - jaddnum(item,"profit",utxo->profitmargin); - jaddstr(item,"base",utxo->coin); - jaddstr(item,"coin",utxo->coin); - jaddstr(item,"address",utxo->coinaddr); - jaddstr(item,"script",utxo->spendscript); - jaddbits256(item,"txid",utxo->txid); - jaddnum(item,"vout",utxo->vout); - jaddnum(item,"value",dstr(utxo->satoshis)); - jaddbits256(item,"txid2",utxo->txid2); - jaddnum(item,"vout2",utxo->vout2); - jaddnum(item,"value2",dstr(utxo->satoshis2)); - return(item); -} - -char *LP_peers() -{ - struct LP_peerinfo *peer,*tmp; cJSON *peersjson = cJSON_CreateArray(); - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - jaddi(peersjson,LP_peerjson(peer)); - } - return(jprint(peersjson,1)); -} - -char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) -{ - int32_t i,firsti; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); - i = 0; - if ( lastn >= mypeer->numutxos ) - firsti = -1; - else firsti = (mypeer->numutxos - lastn); - HASH_ITER(hh,LP_utxoinfos,utxo,tmp) - { - if ( i++ < firsti ) - continue; - if ( coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0 ) - { - jaddi(utxosjson,LP_utxojson(utxo)); - } - } - return(jprint(utxosjson,1)); -} - -struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) -{ - uint32_t ipbits; int32_t pushsock,subsock,timeout,enabled; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; - ipbits = (uint32_t)calc_ipbits(ipaddr); - expand_ipbits(checkip,ipbits); - if ( strcmp(checkip,ipaddr) == 0 ) - { - if ( (peer= LP_peerfind(ipbits,port)) != 0 ) - { - if ( peer->profitmargin == 0. ) - peer->profitmargin = profitmargin; - if ( numpeers > peer->numpeers ) - peer->numpeers = numpeers; - if ( numutxos > peer->numutxos ) - peer->numutxos = numutxos; - } - else - { - //printf("LPaddpeer %s\n",ipaddr); - peer = calloc(1,sizeof(*peer)); - peer->pushsock = peer->subsock = pushsock = subsock = -1; - strcpy(peer->ipaddr,ipaddr); - if ( amclient == 0 ) - enabled = 1; - else enabled = 1;//(rand() % (1 << Client_connections)) == 0; - if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) - { - timeout = 1000; - nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); - if ( nn_connect(pushsock,pushaddr) >= 0 ) - { - printf("connected to push.(%s) %d\n",pushaddr,pushsock); - peer->connected = (uint32_t)time(NULL); - peer->pushsock = pushsock; - if ( enabled != 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) - { - timeout = 1; - nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - nanomsg_tcpname(subaddr,peer->ipaddr,subport); - if ( nn_connect(subsock,subaddr) >= 0 ) - { - peer->subsock = subsock; - printf("connected to sub.(%s) %d\n",subaddr,peer->subsock); - Client_connections += amclient; - } else nn_close(subsock); - } - } - else - { - nn_close(pushsock); - printf("error connecting to push.(%s)\n",pushaddr); - } - } else printf("%s pushport.%u subport.%u pushsock.%d\n",ipaddr,pushport,subport,pushsock); - peer->profitmargin = profitmargin; - peer->ipbits = ipbits; - peer->port = port; - peer->ip_port = ((uint64_t)port << 32) | ipbits; - portable_mutex_lock(&LP_peermutex); - HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer); - if ( mypeer != 0 ) - { - mypeer->numpeers++; - printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d other.(%d %d)\n",ipaddr,mypeer->numpeers,mypubsock,numpeers,numutxos); - } else peer->numpeers = 1; // will become mypeer - portable_mutex_unlock(&LP_peermutex); - if ( mypubsock >= 0 ) - LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); - } - } else printf("LP_addpeer: checkip.(%s) vs (%s)\n",checkip,ipaddr); - return(peer); -} - -struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) -{ - struct LP_utxoinfo *utxo = 0; - if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) - { - printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); - return(0); - } - if ( amclient == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) - { - printf("LP node got localhost utxo\n"); - return(0); - } - if ( (utxo= LP_utxofind(txid,vout)) != 0 ) - { - if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->txid2) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->vout2 || depositsatoshis != utxo->satoshis2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) - { - utxo->errors++; - char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->txid2) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->vout2,depositsatoshis != utxo->satoshis2,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); - } - else if ( profitmargin != 0. ) - utxo->profitmargin = profitmargin; - } - else - { - utxo = calloc(1,sizeof(*utxo)); - utxo->pair = -1; - utxo->profitmargin = profitmargin; - strcpy(utxo->ipaddr,ipaddr); - utxo->port = port; - safecopy(utxo->coin,coin,sizeof(utxo->coin)); - safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); - safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); - utxo->txid = txid; - utxo->vout = vout; - utxo->satoshis = satoshis; - utxo->txid2 = deposittxid; - utxo->vout2 = depositvout; - utxo->satoshis2 = depositsatoshis; - memcpy(utxo->key,txid.bytes,sizeof(txid)); - memcpy(&utxo->key[sizeof(txid)],&vout,sizeof(vout)); - portable_mutex_lock(&LP_utxomutex); - HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); - if ( mypeer != 0 ) - mypeer->numutxos++; - portable_mutex_unlock(&LP_utxomutex); - if ( mypubsock >= 0 ) - LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - //char str[65],str2[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); - } - return(utxo); -} - -int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) -{ - struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; - if ( (array= cJSON_Parse(retstr)) != 0 ) - { - if ( (n= cJSON_GetArraySize(array)) > 0 ) - { - for (i=0; ilasttime = now; - if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers != n ) - peer->numpeers = n; - } - } - } - } - free_json(array); - } - return(n); -} - -int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) -{ - struct LP_peerinfo *peer,*destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; - if ( amclient != 0 ) - { - printf("LP_utxosparse not for clientside\n"); - return(-1); - } - if ( (array= cJSON_Parse(retstr)) != 0 ) - { - if ( (n= cJSON_GetArraySize(array)) > 0 ) - { - for (i=0; ilasttime = now; - } - } - } - if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) - { - if ( destpeer->numutxos < n ) - { - //destpeer->numutxos = n; - //printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); - } - } - } - free_json(array); - } - return(n); -} - -char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) -{ - char url[512],*retstr; - sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - //printf("send.(%s)\n",url); - retstr = issue_curl(url); - //printf("GETPEERS.(%s)\n",retstr); - return(retstr); -} - -char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) -{ - char url[512]; - sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curl(url)); -} - -char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t lastn) -{ - char url[512]; - sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); - //printf("getutxos.(%s)\n",url); - return(issue_curl(url)); -} - -char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) -{ - char url[512]; - sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curl(url)); -} - -char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) -{ - char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&txid2=%s&vout2=%d&value2=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->txid2),utxo->vout2,dstr(utxo->satoshis2),utxo->spendscript,utxo->coinaddr); - if ( strlen(url) > 1024 ) - printf("WARNING long url.(%s)\n",url); - return(issue_curl(url)); -} - -void LP_peersquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) -{ - char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; - peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); - if ( peer != 0 && peer->errors > 0 ) - return; - if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer!=0?mypeer->numpeers:0,mypeer!=0?mypeer->numutxos:0)) != 0 ) - { - //printf("got.(%s)\n",retstr); - now = (uint32_t)time(NULL); - LP_peersparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); - free(retstr); - if ( amclient == 0 ) - { - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - if ( peer->lasttime != now ) - { - printf("{%s:%u %.6f}.%d ",peer->ipaddr,peer->port,peer->profitmargin,peer->lasttime - now); - flag++; - if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->profitmargin,peer->numpeers,0)) != 0 ) - free(retstr); - } - } - if ( flag != 0 ) - printf(" <- missing peers\n"); - } - } else if ( peer != 0 ) - peer->errors++; -} - -void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) -{ - char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; - if ( amclient != 0 ) - { - printf("LP_utxosquery not for clientside\n"); - return; - } - peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); - if ( (peer != 0 && peer->errors > 0) || mypeer == 0 ) - return; - if ( coin == 0 ) - coin = ""; - if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) - { - now = (uint32_t)time(NULL); - LP_utxosparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); - free(retstr); - i = 0; - if ( lastn >= mypeer->numutxos ) - firsti = -1; - else firsti = (mypeer->numutxos - lastn); - HASH_ITER(hh,LP_utxoinfos,utxo,tmp) - { - if ( i++ < firsti ) - continue; - if ( utxo->lasttime != now && strcmp(utxo->ipaddr,"127.0.0.1") != 0 ) - { - char str[65]; printf("{%s:%u %s} ",utxo->ipaddr,utxo->port,bits256_str(str,utxo->txid)); - flag++; - if ( (retstr= issue_LP_notifyutxo(destipaddr,destport,utxo)) != 0 ) - free(retstr); - } - } - if ( flag != 0 ) - printf(" <- missing utxos\n"); - } else if ( peer != 0 ) - peer->errors++; -} - -int32_t LP_maxvalue(uint64_t *values,int32_t n) -{ - int32_t i,maxi = -1; uint64_t maxval = 0; - for (i=0; i maxval ) - { - maxi = i; - maxval = values[i]; - } - return(maxi); -} - -int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) -{ - int32_t i,mini = -1; int64_t dist; uint64_t mindist = (1 << 31); - for (i=0; i= 0 && dist < mindist ) - { - mini = i; - mindist = dist; - } - } - return(mini); -} +// stubs int32_t basilisk_istrustedbob(struct basilisk_swap *swap) { // for BTC and if trusted LP @@ -581,283 +53,32 @@ void tradebot_pendingadd(cJSON *tradejson,char *base,double basevolume,char *rel { // add to trades } +char *LP_getdatadir() +{ + return("/root"); +} -char GLOBAL_DBDIR[] = "DB"; +char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) +{ + return(0); +} #include "LP_secp.c" -#include "LP_rpc.c" #include "LP_bitcoin.c" +#include "LP_coins.c" +#include "LP_rpc.c" +#include "LP_prices.c" #include "LP_transaction.c" #include "LP_remember.c" -//#include "LP_statemachine.c" #include "LP_swap.c" +#include "LP_peers.c" +#include "LP_utxos.c" #include "LP_commands.c" -char *parse_conf_line(char *line,char *field) -{ - line += strlen(field); - for (; *line!='='&&*line!=0; line++) - break; - if ( *line == 0 ) - return(0); - if ( *line == '=' ) - line++; - while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n' || line[strlen(line)-1] == ' ' ) - line[strlen(line)-1] = 0; - //printf("LINE.(%s)\n",line); - _stripwhite(line,0); - return(clonestr(line)); -} - -void LP_userpassfp(char *username,char *password,FILE *fp) -{ - char *rpcuser,*rpcpassword,*str,line[8192]; - rpcuser = rpcpassword = 0; - username[0] = password[0] = 0; - while ( fgets(line,sizeof(line),fp) != 0 ) - { - if ( line[0] == '#' ) - continue; - //printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword")); - if ( (str= strstr(line,(char *)"rpcuser")) != 0 ) - rpcuser = parse_conf_line(str,(char *)"rpcuser"); - else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 ) - rpcpassword = parse_conf_line(str,(char *)"rpcpassword"); - } - if ( rpcuser != 0 && rpcpassword != 0 ) - { - strcpy(username,rpcuser); - strcpy(password,rpcpassword); - } - //printf("rpcuser.(%s) rpcpassword.(%s) KMDUSERPASS.(%s) %u\n",rpcuser,rpcpassword,KMDUSERPASS,port); - if ( rpcuser != 0 ) - free(rpcuser); - if ( rpcpassword != 0 ) - free(rpcpassword); -} - -void LP_statefname(char *fname,char *symbol,char *assetname,char *str) -{ - sprintf(fname,"%s",LP_getdatadir()); -#ifdef WIN32 - strcat(fname,"\\"); -#else - strcat(fname,"/"); -#endif - if ( strcmp(symbol,"BTC") == 0 ) - strcat(fname,".bitcoin"); - else if ( strcmp(symbol,"LTC") == 0 ) - strcat(fname,".litecoin"); - else - { - strcat(fname,".komodo"); - if ( strcmp(symbol,"KMD") != 0 ) - { -#ifdef WIN32 - strcat(fname,"\\"); -#else - strcat(fname,"/"); -#endif - strcat(fname,assetname); - } - } -#ifdef WIN32 - strcat(fname,"\\"); -#else - strcat(fname,"/"); -#endif - strcat(fname,str); - printf("LP_statefname.(%s) <- %s %s %s\n",fname,symbol,assetname,str); -} - -int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) -{ - FILE *fp; char fname[512],username[512],password[512],confname[16]; - userpass[0] = 0; - sprintf(confname,"%s.conf",confroot); -#ifdef __APPLE__ - confname[0] = toupper(confname[0]); -#endif - LP_statefname(fname,symbol,assetname,confname); - if ( (fp= fopen(fname,"rb")) != 0 ) - { - LP_userpassfp(username,password,fp); - sprintf(userpass,"%s:%s",username,password); - fclose(fp); - return((int32_t)strlen(userpass)); - } - return(-1); -} - -uint32_t LP_assetmagic(char *symbol,uint64_t supply) -{ - uint8_t buf[512]; int32_t len = 0; - if ( strcmp(symbol,"KMD") == 0 ) - return(0x8de4eef9); - len = iguana_rwnum(1,&buf[len],sizeof(supply),(void *)&supply); - strcpy((char *)&buf[len],symbol); - len += strlen(symbol); - return(calc_crc32(0,buf,len)); -} - -uint16_t LP_assetport(uint32_t magic) -{ - if ( magic == 0x8de4eef9 ) - return(7771); - else return(8000 + (magic % 7777)); -} - -uint16_t LP_rpcport(char *symbol,uint64_t supply,uint32_t *magicp) -{ - if ( symbol == 0 || symbol[0] == 0 || strcmp("KMD",symbol) == 0 ) - { - *magicp = 0x8de4eef9; - return(7771); - } - else if ( strcmp("BTC",symbol) == 0 ) - return(8332); - else if ( strcmp("LTC",symbol) == 0 ) - return(9332); - *magicp = LP_assetmagic(symbol,supply); - return(LP_assetport(*magicp)+1); -} - -struct iguana_info *LP_coinfind(char *symbol) -{ - static struct iguana_info *LP_coins; static int32_t LP_numcoins; - struct iguana_info *coin,cdata; int32_t i; uint32_t magic; uint16_t port; - for (i=0; ipubtype); - { - char tmpstr[128]; - bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); - if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) - printf("importprivkey -> (%s)\n",jprint(retjson,1)); - } - bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); - LP_privkeyadd(privkey,rmd160); - if ( (array= LP_listunspent(symbol,coinaddr)) != 0 ) - { - if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) - { - values = calloc(n,sizeof(*values)); - for (i=0; i= 0 ) - { - item = jitem(array,i); - deposittxid = jbits256(item,"txid"); - depositvout = juint(item,"vout"); - script = jstr(item,"scriptPubKey"); - depositval = values[i]; - values[i] = 0, used++; - if ( amclient != 0 ) - targetval = (depositval / 776) + 50000; - else targetval = (depositval / 9) * 8; - //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); - if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) - { - item = jitem(array,i); - txid = jbits256(item,"txid"); - vout = juint(item,"vout"); - printf("j.%d %.8f target %.8f\n",i,dstr(values[i]),dstr(targetval)); - if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 ) - { - value = values[i]; - values[i] = 0, used++; - if ( amclient == 0 ) - { - if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) - utxo->mypub = curve25519(privkey,curve25519_basepoint9()); - } - else - { - if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coinaddr,"127.0.0.1",0,0)) != 0 ) - utxo->mypub = curve25519(privkey,curve25519_basepoint9()); - } - total += value; - } - } - } else break; - } - free(values); - } - free_json(array); - } - return(total); -} - -void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphrase,int32_t amclient) -{ - int32_t i; - for (i=0; icoin,"KMD") == 0 ) + LP_priceping(pubsock,utxo,"BTC",profitmargin); + else LP_priceping(pubsock,utxo,"KMD",profitmargin); + } + } HASH_ITER(hh,LP_peerinfos,peer,tmp) { n++; @@ -1052,16 +282,3 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } LP_mainloop(mypeer,mypubport,pubsock,pullsock,myport,amclient,passphrase,profitmargin); } - -/*#ifdef __APPLE__ -int32_t nn_bind() { return(-1); } -int32_t nn_close() { return(-1); } -int32_t nn_connect() { return(-1); } -int32_t nn_freemsg() { return(-1); } -int32_t nn_poll() { return(-1); } -int32_t nn_recv() { return(-1); } -int32_t nn_send() { return(-1); } -int32_t nn_setsockopt() { return(-1); } -int32_t nn_socket() { return(-1); } - -#endif*/ diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index faf6137f3..84a7cb512 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -18,94 +18,6 @@ // marketmaker // -void basilisk_psockinit(struct basilisk_swap *swap,int32_t amlp) -{ -/* char keystr[64],databuf[1024],pubkeystr[128],*retstr,*retstr2,*datastr,*pushaddr=0,*subaddr=0; cJSON *retjson,*addrjson; uint8_t data[512]; int32_t datalen,timeout,pushsock = -1,subsock = -1; - if ( swap->connected == 1 ) - return; - if ( swap->pushsock < 0 && swap->subsock < 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) - { - timeout = 1000; - nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - timeout = 1; - nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - swap->pushsock = pushsock; - swap->subsock = subsock; - } - if ( (subsock= swap->subsock) < 0 || (pushsock= swap->pushsock) < 0 ) - { - printf("error getting nn_sockets\n"); - return; - } - sprintf(keystr,"%08x-%08x",swap->I.req.requestid,swap->I.req.quoteid); - if ( swap->connected == 0 && (retstr= _dex_kvsearch("KV",keystr)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (datastr= jstr(retjson,"value")) != 0 ) - { - datalen = (int32_t)strlen(datastr) >> 1; - decode_hex((uint8_t *)databuf,datalen,datastr); - if ( (addrjson= cJSON_Parse(databuf)) != 0 ) - { - pushaddr = jstr(addrjson,"push"); - subaddr = jstr(addrjson,"sub"); - if ( pushaddr != 0 && subaddr != 0 ) - { - printf("KV decoded (%s and %s) %d %d\n",pushaddr,subaddr,swap->pushsock,swap->subsock); - if ( nn_connect(swap->pushsock,pushaddr) >= 0 && nn_connect(swap->subsock,subaddr) >= 0 ) - swap->connected = 1; - } - free_json(addrjson); - } - } - free_json(retjson); - } - printf("KVsearch.(%s) -> (%s) connected.%d socks.(%d %d) amlp.%d\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock,amlp); - free(retstr); - } - printf("connected.%d amlp.%d subsock.%d pushsock.%d\n",swap->connected,amlp,subsock,pushsock); - if ( swap->connected <= 0 && amlp != 0 && subsock >= 0 && pushsock >= 0 ) - { - if ( (retstr= _dex_psock("{}")) != 0 ) - { - printf("psock returns.(%s)\n",retstr); - // {"result":"success","pushaddr":"tcp://5.9.102.210:30002","subaddr":"tcp://5.9.102.210:30003","randipbits":3606291758,"coin":"KMD","tag":"6952562460568228137"} - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - pushaddr = jstr(retjson,"pushaddr"); - subaddr = jstr(retjson,"subaddr"); - if ( pushaddr != 0 && subaddr != 0 ) - { - if ( nn_connect(pushsock,pushaddr) >= 0 ) - { - printf("connected to %d pushaddr.(%s)\n",pushsock,pushaddr); - if ( nn_connect(subsock,subaddr) >= 0 ) - { - swap->connected = 1; - init_hexbytes_noT(pubkeystr,myinfo->persistent_pubkey33,33); - sprintf((char *)data,"{\"push\":\"%s\",\"sub\":\"%s\",\"trade\":[\"%s\", %.8f, \"%s\", %.8f],\"pub\":\"%s\"}",pushaddr,subaddr,swap->I.req.src,dstr(swap->I.req.srcamount),swap->I.req.dest,dstr(swap->I.req.destamount),pubkeystr); - datalen = (int32_t)strlen((char *)data) + 1; - printf("datalen.%d (%s)\n",datalen,(char *)data); - init_hexbytes_noT(databuf,data,datalen); - printf("%s -> %s\n",keystr,databuf); - if ( (retstr2= _dex_kvupdate("KV",keystr,databuf,1)) != 0 ) - { - printf("KVupdate.(%s)\n",retstr2); - free(retstr2); - } - } else printf("nn_connect error to %d subaddr.(%s)\n",subsock,subaddr); - } else printf("nn_connect error to %d pushaddr.(%s)\n",pushsock,pushaddr); - } - else printf("missing addr (%p) (%p) (%s)\n",pushaddr,subaddr,jprint(retjson,0)); - free_json(retjson); - } else printf("Error parsing psock.(%s)\n",retstr); - free(retstr); - } else printf("error issuing _dex_psock\n"); - }*/ -} - char *nanomsg_tcpname(char *str,char *ipaddr,uint16_t port) { sprintf(str,"tcp://%s:%u",ipaddr,port); @@ -168,144 +80,3 @@ uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbit free(buf); return(nextbits); } - -void basilisk_swap_sendabort(struct basilisk_swap *swap) -{ - uint32_t msgbits = 0; uint8_t buf[sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2]; int32_t sentbytes,offset=0; - memset(buf,0,sizeof(buf)); - offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); - offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); - if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) - { - if ( sentbytes < 0 ) - { - if ( swap->pushsock >= 0 ) // - nn_close(swap->pushsock), swap->pushsock = -1; - if ( swap->subsock >= 0 ) // - nn_close(swap->subsock), swap->subsock = -1; - swap->connected = 0; - } - } else printf("basilisk_swap_sendabort\n"); -} - -void basilisk_psockinit(struct basilisk_swap *swap,int32_t amlp); - -void basilisk_swapgotdata(struct basilisk_swap *swap,uint32_t crc32,bits256 srchash,bits256 desthash,uint32_t quoteid,uint32_t msgbits,uint8_t *data,int32_t datalen,int32_t reinit) -{ - int32_t i; struct basilisk_swapmessage *mp; - for (i=0; inummessages; i++) - if ( crc32 == swap->messages[i].crc32 && msgbits == swap->messages[i].msgbits && bits256_cmp(srchash,swap->messages[i].srchash) == 0 && bits256_cmp(desthash,swap->messages[i].desthash) == 0 ) - return; - //printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); - swap->messages = realloc(swap->messages,sizeof(*swap->messages) * (swap->nummessages + 1)); - mp = &swap->messages[swap->nummessages++]; - mp->crc32 = crc32; - mp->srchash = srchash; - mp->desthash = desthash; - mp->msgbits = msgbits; - mp->quoteid = quoteid; - mp->data = malloc(datalen); - mp->datalen = datalen; - memcpy(mp->data,data,datalen); - if ( reinit == 0 && swap->fp != 0 ) - { - fwrite(mp,1,sizeof(*mp),swap->fp); - fwrite(data,1,datalen,swap->fp); - fflush(swap->fp); - } -} - -int32_t basilisk_swapget(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(void *ptr,uint8_t *data,int32_t datalen)) -{ - uint8_t *ptr; bits256 srchash,desthash; uint32_t crc32,_msgbits,quoteid; int32_t i,size,offset,retval = -1; struct basilisk_swapmessage *mp = 0; - while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,0)) >= 0 ) - { - swap->lasttime = (uint32_t)time(NULL); - memset(srchash.bytes,0,sizeof(srchash)); - memset(desthash.bytes,0,sizeof(desthash)); - //printf("gotmsg.[%d] crc.%x\n",size,crc32); - offset = 0; - for (i=0; i<32; i++) - srchash.bytes[i] = ptr[offset++]; - for (i=0; i<32; i++) - desthash.bytes[i] = ptr[offset++]; - offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),"eid); - offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),&_msgbits); - if ( size > offset ) - { - crc32 = calc_crc32(0,&ptr[offset],size-offset); - if ( size > offset ) - { - //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); - basilisk_swapgotdata(swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); - } - } - else if ( bits256_nonz(srchash) == 0 && bits256_nonz(desthash) == 0 ) - { - if ( swap->aborted == 0 ) - { - swap->aborted = (uint32_t)time(NULL); - printf("got abort signal from other side\n"); - } - } else printf("basilisk_swapget: got strange packet\n"); - if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0; - } - //char str[65],str2[65]; - for (i=0; inummessages; i++) - { - //printf("%d: %s vs %s\n",i,bits256_str(str,swap->messages[i].srchash),bits256_str(str2,swap->messages[i].desthash)); - if ( bits256_cmp(swap->messages[i].desthash,swap->I.myhash) == 0 ) - { - if ( swap->messages[i].msgbits == msgbits ) - { - if ( swap->I.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) - { - printf("nothing received for a while from Bob, try new sockets\n"); - if ( swap->pushsock >= 0 ) // - nn_close(swap->pushsock), swap->pushsock = -1; - if ( swap->subsock >= 0 ) // - nn_close(swap->subsock), swap->subsock = -1; - swap->connected = 0; - basilisk_psockinit(swap,swap->I.iambob != 0); - } - mp = &swap->messages[i]; - if ( msgbits != 0x80000000 ) - break; - } - } - } - if ( mp != 0 ) - retval = (*basilisk_verify_func)(swap,mp->data,mp->datalen); - //printf("mine/other %s vs %s\n",bits256_str(str,swap->I.myhash),bits256_str(str2,swap->I.otherhash)); - return(retval); -} - -int32_t basilisk_messagekeyread(uint8_t *key,uint32_t *channelp,uint32_t *msgidp,bits256 *srchashp,bits256 *desthashp) -{ - int32_t keylen = 0; - keylen += iguana_rwnum(0,&key[keylen],sizeof(uint32_t),channelp); - keylen += iguana_rwnum(0,&key[keylen],sizeof(uint32_t),msgidp); - keylen += iguana_rwbignum(0,&key[keylen],sizeof(*srchashp),srchashp->bytes); - keylen += iguana_rwbignum(0,&key[keylen],sizeof(*desthashp),desthashp->bytes); - return(keylen); -} - -int32_t basilisk_messagekey(uint8_t *key,uint32_t channel,uint32_t msgid,bits256 srchash,bits256 desthash) -{ - int32_t keylen = 0; - keylen += iguana_rwnum(1,&key[keylen],sizeof(uint32_t),&channel); - keylen += iguana_rwnum(1,&key[keylen],sizeof(uint32_t),&msgid); - keylen += iguana_rwbignum(1,&key[keylen],sizeof(srchash),srchash.bytes); - keylen += iguana_rwbignum(1,&key[keylen],sizeof(desthash),desthash.bytes); - return(keylen); -} - -void LP_channelsend(bits256 srchash,bits256 desthash,uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen) -{ - int32_t keylen; uint8_t key[BASILISK_KEYSIZE]; //char *retstr; - keylen = basilisk_messagekey(key,channel,msgid,srchash,desthash); - //if ( (retstr= _dex_reqsend(myinfo,"DEX",key,keylen,data,datalen)) != 0 ) - // free(retstr); -} - diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c new file mode 100644 index 000000000..e7d83a93e --- /dev/null +++ b/iguana/exchanges/LP_peers.c @@ -0,0 +1,188 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_peers.c +// marketmaker +// + +struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port) +{ + struct LP_peerinfo *peer=0; uint64_t ip_port; + ip_port = ((uint64_t)port << 32) | ipbits; + portable_mutex_lock(&LP_peermutex); + HASH_FIND(hh,LP_peerinfos,&ip_port,sizeof(ip_port),peer); + portable_mutex_unlock(&LP_peermutex); + return(peer); +} + +cJSON *LP_peerjson(struct LP_peerinfo *peer) +{ + cJSON *item = cJSON_CreateObject(); + jaddstr(item,"ipaddr",peer->ipaddr); + jaddnum(item,"port",peer->port); + jaddnum(item,"profit",peer->profitmargin); + return(item); +} + +char *LP_peers() +{ + struct LP_peerinfo *peer,*tmp; cJSON *peersjson = cJSON_CreateArray(); + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + jaddi(peersjson,LP_peerjson(peer)); + } + return(jprint(peersjson,1)); +} + +struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) +{ + uint32_t ipbits; int32_t pushsock,subsock,timeout,enabled; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; + ipbits = (uint32_t)calc_ipbits(ipaddr); + expand_ipbits(checkip,ipbits); + if ( strcmp(checkip,ipaddr) == 0 ) + { + if ( (peer= LP_peerfind(ipbits,port)) != 0 ) + { + if ( peer->profitmargin == 0. ) + peer->profitmargin = profitmargin; + if ( numpeers > peer->numpeers ) + peer->numpeers = numpeers; + if ( numutxos > peer->numutxos ) + peer->numutxos = numutxos; + } + else + { + //printf("LPaddpeer %s\n",ipaddr); + peer = calloc(1,sizeof(*peer)); + peer->pushsock = peer->subsock = pushsock = subsock = -1; + strcpy(peer->ipaddr,ipaddr); + if ( amclient == 0 ) + enabled = 1; + else enabled = 1;//(rand() % (1 << Client_connections)) == 0; + if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + { + timeout = 1000; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); + if ( nn_connect(pushsock,pushaddr) >= 0 ) + { + printf("connected to push.(%s) %d\n",pushaddr,pushsock); + peer->connected = (uint32_t)time(NULL); + peer->pushsock = pushsock; + if ( enabled != 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + { + timeout = 1; + nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + nanomsg_tcpname(subaddr,peer->ipaddr,subport); + if ( nn_connect(subsock,subaddr) >= 0 ) + { + peer->subsock = subsock; + printf("connected to sub.(%s) %d\n",subaddr,peer->subsock); + Client_connections += amclient; + } else nn_close(subsock); + } + } + else + { + nn_close(pushsock); + printf("error connecting to push.(%s)\n",pushaddr); + } + } else printf("%s pushport.%u subport.%u pushsock.%d\n",ipaddr,pushport,subport,pushsock); + peer->profitmargin = profitmargin; + peer->ipbits = ipbits; + peer->port = port; + peer->ip_port = ((uint64_t)port << 32) | ipbits; + portable_mutex_lock(&LP_peermutex); + HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer); + if ( mypeer != 0 ) + { + mypeer->numpeers++; + printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d other.(%d %d)\n",ipaddr,mypeer->numpeers,mypubsock,numpeers,numutxos); + } else peer->numpeers = 1; // will become mypeer + portable_mutex_unlock(&LP_peermutex); + if ( mypubsock >= 0 ) + LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); + } + } else printf("LP_addpeer: checkip.(%s) vs (%s)\n",checkip,ipaddr); + return(peer); +} + +int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +{ + struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; ilasttime = now; + if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers != n ) + peer->numpeers = n; + } + } + } + } + free_json(array); + } + return(n); +} + +void LP_peersquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) +{ + char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; + peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); + if ( peer != 0 && peer->errors > 0 ) + return; + if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer!=0?mypeer->numpeers:0,mypeer!=0?mypeer->numutxos:0)) != 0 ) + { + //printf("got.(%s)\n",retstr); + now = (uint32_t)time(NULL); + LP_peersparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); + free(retstr); + if ( amclient == 0 ) + { + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( peer->lasttime != now ) + { + printf("{%s:%u %.6f}.%d ",peer->ipaddr,peer->port,peer->profitmargin,peer->lasttime - now); + flag++; + if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->profitmargin,peer->numpeers,0)) != 0 ) + free(retstr); + } + } + if ( flag != 0 ) + printf(" <- missing peers\n"); + } + } else if ( peer != 0 ) + peer->errors++; +} diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 4d1fff738..37cd3275c 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -20,8 +20,168 @@ double LP_kmdbtc; +struct LP_cacheinfo +{ + UT_hash_handle hh; + struct LP_quoteinfo Q; + uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(int32_t)]; + double price; + uint32_t timestamp; +} *LP_cacheinfos; + +int32_t LP_cachekey(uint8_t *key,char *base,char *rel,bits256 txid,int32_t vout) +{ + uint64_t basebits,relbits; int32_t offset = 0; + basebits = stringbits(base); + relbits = stringbits(rel); + memcpy(&key[offset],&basebits,sizeof(basebits)), offset += sizeof(basebits); + memcpy(&key[offset],&relbits,sizeof(relbits)), offset += sizeof(relbits); + memcpy(&key[offset],&txid,sizeof(txid)), offset += sizeof(txid); + memcpy(&key[offset],&vout,sizeof(vout)), offset += sizeof(vout); + return(offset); +} + +struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout) +{ + struct LP_cacheinfo *ptr=0; uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(vout)]; + if ( LP_cachekey(key,base,rel,txid,vout) == sizeof(key) ) + { + portable_mutex_lock(&LP_cachemutex); + HASH_FIND(hh,LP_cacheinfos,key,sizeof(key),ptr); + portable_mutex_unlock(&LP_cachemutex); + } else printf("LP_cachefind keysize mismatch?\n"); + if ( 0 && ptr != 0 && ptr->timestamp != 0 && ptr->timestamp < time(NULL)-LP_CACHEDURATION ) + { + printf("expire price %.8f\n",ptr->price); + ptr->price = 0.; + ptr->timestamp = 0; + memset(&ptr->Q,0,sizeof(ptr->Q)); + } + return(ptr); +} + +double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,int32_t vout) +{ + struct LP_cacheinfo *ptr; + if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) + { + if ( qp != 0 ) + (*qp) = ptr->Q; + if ( ptr->price == 0. && ptr->Q.satoshis != 0 ) + { + printf("null ptr->price? "); + ptr->price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; + } + //printf("found %s/%s %.8f\n",base,rel,ptr->price); + return(ptr->price); + } + //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); + return(0.); +} + +struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout,double price,struct LP_quoteinfo *qp) +{ + char str[65]; struct LP_cacheinfo *ptr=0; + if ( (ptr= LP_cachefind(base,rel,txid,vout)) == 0 ) + { + ptr = calloc(1,sizeof(*ptr)); + if ( LP_cachekey(ptr->key,base,rel,txid,vout) == sizeof(ptr->key) ) + { + portable_mutex_lock(&LP_cachemutex); + HASH_ADD(hh,LP_cacheinfos,key,sizeof(ptr->key),ptr); + portable_mutex_unlock(&LP_cachemutex); + } else printf("LP_cacheadd keysize mismatch?\n"); + } + if ( price != ptr->price ) + { + printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)qp->satoshis,price); + } + ptr->price = price; + ptr->Q = *qp; + ptr->timestamp = (uint32_t)time(NULL); + return(ptr); +} + +static int _cmp_orderbook(const void *a,const void *b) +{ +#define ptr_a ((struct LP_cacheinfo *)a)->price +#define ptr_b ((struct LP_cacheinfo *)b)->price + if ( ptr_b > ptr_a ) + return(1); + else if ( ptr_b < ptr_a ) + return(-1); + else + { +#undef ptr_a +#undef ptr_b +#define ptr_a ((struct LP_cacheinfo *)a)->Q.satoshis +#define ptr_b ((struct LP_cacheinfo *)b)->Q.satoshis + if ( ptr_b > ptr_a ) + return(1); + else if ( ptr_b < ptr_a ) + return(-1); + } + return(0); +#undef ptr_a +#undef ptr_b +} + +static int _cmp_orderbookrev(const void *a,const void *b) +{ + return(-_cmp_orderbook(a,b)); +} + +cJSON *LP_orderbookjson(struct LP_cacheinfo *ptr,int32_t polarity) +{ + double price,volume; cJSON *item = cJSON_CreateObject(); + if ( (price= ptr->price) != 0. && (volume= dstr(ptr->Q.satoshis)) != 0. ) + { + jaddnum(item,"price",polarity > 0 ? price : 1. / price); + jaddnum(item,"volume",polarity > 0 ? volume : volume / price); + jaddbits256(item,"txid",ptr->Q.txid); + jaddnum(item,"vout",ptr->Q.vout); + } + return(item); +} + +char *LP_orderbook(char *base,char *rel) +{ + uint32_t now,i; struct LP_cacheinfo *ptr,*tmp,**bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0; + now = (uint32_t)time(NULL); + HASH_ITER(hh,LP_cacheinfos,ptr,tmp) + { + if ( ptr->timestamp < now-60 || ptr->price == 0. ) + continue; + if ( strcmp(ptr->Q.srccoin,base) == 0 && strcmp(ptr->Q.destcoin,rel) == 0 ) + { + asks = realloc(asks,sizeof(*asks) * (numasks+1)); + asks[numasks++] = ptr; + } + else if ( strcmp(ptr->Q.srccoin,rel) == 0 && strcmp(ptr->Q.destcoin,base) == 0 ) + { + bids = realloc(bids,sizeof(*bids) * (numbids+1)); + bids[numbids++] = ptr; + } + } + retjson = cJSON_CreateObject(); + array = cJSON_CreateArray(); + if ( numbids > 1 ) + qsort(bids,numbids,sizeof(*bids),_cmp_orderbook); + for (i=0; i 1 ) + qsort(asks,numasks,sizeof(*asks),_cmp_orderbookrev); + for (i=0; iswapsfp= fopen(fname,"rb+")) != 0 ) - { - while ( fread(&requestid,1,sizeof(requestid),myinfo->swapsfp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),myinfo->swapsfp) == sizeof(quoteid) ) - { - sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); - printf("%s\n",fname); - if ( (fp= fopen(fname,"rb+")) != 0 ) // check to see if completed - { - memset(&M,0,sizeof(M)); - swapcompleted = 1; - for (iter=0; iter<2; iter++) - { - if ( fread(privkey.bytes,1,sizeof(privkey),fp) == sizeof(privkey) && - fread(&R,1,sizeof(R),fp) == sizeof(R) && - fread(&statebits,1,sizeof(statebits),fp) == sizeof(statebits) && - fread(&optionduration,1,sizeof(optionduration),fp) == sizeof(optionduration) ) - { - while ( 0 && fread(&M,1,sizeof(M),fp) == sizeof(M) ) - { - M.data = 0; - //printf("entry iter.%d crc32.%x datalen.%d\n",iter,M.crc32,M.datalen); - if ( M.datalen < 100000 ) - { - M.data = malloc(M.datalen); - if ( fread(M.data,1,M.datalen,fp) == M.datalen ) - { - if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) - { - if ( iter == 1 ) - { - if ( swap == 0 ) - { - swap = basilisk_thread_start(privkey,&R,statebits,optionduration,1); - swap->I.choosei = swap->I.otherchoosei = -1; - } - if ( swap != 0 ) - basilisk_swapgotdata(swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); - } - } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); - } else printf("error reading M.datalen %d\n",M.datalen); - free(M.data), M.data = 0; - } - } - } - if ( swapcompleted != 0 ) - break; - rewind(fp); - } - } - } - } else myinfo->swapsfp = fopen(fname,"wb+"); -}*/ - -FILE *basilisk_swap_save(struct basilisk_swap *swap,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) -{ - FILE *fp=0; /*char fname[512]; - sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,rp->requestid,rp->quoteid), OS_compatible_path(fname); - if ( (fp= fopen(fname,"rb+")) == 0 ) - { - if ( (fp= fopen(fname,"wb+")) != 0 ) - { - fwrite(privkey.bytes,1,sizeof(privkey),fp); - fwrite(rp,1,sizeof(*rp),fp); - fwrite(&statebits,1,sizeof(statebits),fp); - fwrite(&optionduration,1,sizeof(optionduration),fp); - fflush(fp); - } - } - else if ( reinit != 0 ) - { - }*/ - return(fp); -} - -int32_t basilisk_swap_load(uint32_t requestid,uint32_t quoteid,bits256 *privkeyp,struct basilisk_request *rp,uint32_t *statebitsp,int32_t *optiondurationp) -{ - FILE *fp=0; char fname[512]; int32_t retval = -1; - sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); - if ( (fp= fopen(fname,"rb+")) != 0 ) - { - if ( fread(privkeyp,1,sizeof(*privkeyp),fp) == sizeof(*privkeyp) && - fread(rp,1,sizeof(*rp),fp) == sizeof(*rp) && - fread(statebitsp,1,sizeof(*statebitsp),fp) == sizeof(*statebitsp) && - fread(optiondurationp,1,sizeof(*optiondurationp),fp) == sizeof(*optiondurationp) ) - retval = 0; - fclose(fp); - } - return(retval); -} - -void basilisk_swap_saveupdate(struct basilisk_swap *swap) -{ - FILE *fp; char fname[512]; - sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); - if ( (fp= fopen(fname,"wb")) != 0 ) - { - fwrite(&swap->I,1,sizeof(swap->I),fp); - /*fwrite(&swap->bobdeposit,1,sizeof(swap->bobdeposit),fp); - fwrite(&swap->bobpayment,1,sizeof(swap->bobpayment),fp); - fwrite(&swap->alicepayment,1,sizeof(swap->alicepayment),fp); - fwrite(&swap->myfee,1,sizeof(swap->myfee),fp); - fwrite(&swap->otherfee,1,sizeof(swap->otherfee),fp); - fwrite(&swap->aliceclaim,1,sizeof(swap->aliceclaim),fp); - fwrite(&swap->alicespend,1,sizeof(swap->alicespend),fp); - fwrite(&swap->bobreclaim,1,sizeof(swap->bobreclaim),fp); - fwrite(&swap->bobspend,1,sizeof(swap->bobspend),fp); - fwrite(&swap->bobrefund,1,sizeof(swap->bobrefund),fp); - fwrite(&swap->alicereclaim,1,sizeof(swap->alicereclaim),fp);*/ - fwrite(swap->privkeys,1,sizeof(swap->privkeys),fp); - fwrite(swap->otherdeck,1,sizeof(swap->otherdeck),fp); - fwrite(swap->deck,1,sizeof(swap->deck),fp); - fclose(fp); - } -} - -/*int32_t basilisk_swap_loadtx(struct basilisk_rawtx *rawtx,FILE *fp,char *bobcoinstr,char *alicecoinstr) -{ - if ( fread(rawtx,1,sizeof(*rawtx),fp) == sizeof(*rawtx) ) - { - rawtx->coin = 0; - rawtx->vins = 0; - if ( strcmp(rawtx->I.coinstr,bobcoinstr) == 0 || strcmp(rawtx->I.coinstr,alicecoinstr) == 0 ) - { - rawtx->coin = LP_coinfind(rawtx->I.coinstr); - if ( rawtx->vinstr[0] != 0 ) - rawtx->vins = cJSON_Parse(rawtx->vinstr); - printf("loaded.%s len.%d\n",rawtx->name,rawtx->I.datalen); - return(0); - } - } - return(-1); -}*/ - void basilisk_dontforget_userdata(char *userdataname,FILE *fp,uint8_t *script,int32_t scriptlen) { int32_t i; char scriptstr[513]; @@ -350,8 +213,6 @@ void basilisk_dontforget_update(struct basilisk_swap *swap,struct basilisk_rawtx basilisk_dontforget(swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid); } - - bits256 basilisk_swap_privbob_extract(char *symbol,bits256 spendtxid,int32_t vini,int32_t revflag) { bits256 privkey; int32_t i,scriptlen,siglen; uint8_t script[1024]; // from Bob refund of Bob deposit diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index d3742e5e0..ed3784b55 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -17,31 +17,45 @@ // LP_rpc.c // marketmaker // +char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) +{ + char url[512],*retstr; + sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); + //printf("send.(%s)\n",url); + retstr = issue_curl(url); + //printf("GETPEERS.(%s)\n",retstr); + return(retstr); +} -char *LP_getdatadir() +char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { - return("/root"); + char url[512]; + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); + return(issue_curl(url)); } -cJSON *basilisk_nullretjson(cJSON *retjson) +char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t lastn) { - /*char *outstr; - if ( retjson != 0 ) - { - outstr = jprint(retjson,0); - if ( strcmp(outstr,"{}") == 0 || strcmp(outstr,"[]") == 0 ) - { - free_json(retjson); - retjson = 0; - } - free(outstr); - }*/ - return(retjson); + char url[512]; + sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); + //printf("getutxos.(%s)\n",url); + return(issue_curl(url)); } -char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) +char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { - return(0); + char url[512]; + sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); + return(issue_curl(url)); +} + +char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) +{ + char url[4096],str[65],str2[65]; + sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&txid2=%s&vout2=%d&value2=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->txid2),utxo->vout2,dstr(utxo->satoshis2),utxo->spendscript,utxo->coinaddr); + if ( strlen(url) > 1024 ) + printf("WARNING long url.(%s)\n",url); + return(issue_curl(url)); } cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) @@ -59,7 +73,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) } //printf("dpow_gettxout.(%s)\n",retstr); } - return(basilisk_nullretjson(retjson)); + return(retjson); } void LP_unspents_mark(char *symbol,cJSON *vins) diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index 9b4604c25..dc0240c1b 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -17,6 +17,317 @@ // LP_statemachine.c // marketmaker // + +/*void basilisk_swaps_init(struct supernet_info *myinfo) + { + char fname[512]; uint32_t iter,swapcompleted,requestid,quoteid,optionduration,statebits; FILE *fp; bits256 privkey;struct basilisk_request R; struct basilisk_swapmessage M; struct basilisk_swap *swap = 0; + sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname); + if ( (myinfo->swapsfp= fopen(fname,"rb+")) != 0 ) + { + while ( fread(&requestid,1,sizeof(requestid),myinfo->swapsfp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),myinfo->swapsfp) == sizeof(quoteid) ) + { + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + printf("%s\n",fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) // check to see if completed + { + memset(&M,0,sizeof(M)); + swapcompleted = 1; + for (iter=0; iter<2; iter++) + { + if ( fread(privkey.bytes,1,sizeof(privkey),fp) == sizeof(privkey) && + fread(&R,1,sizeof(R),fp) == sizeof(R) && + fread(&statebits,1,sizeof(statebits),fp) == sizeof(statebits) && + fread(&optionduration,1,sizeof(optionduration),fp) == sizeof(optionduration) ) + { + while ( 0 && fread(&M,1,sizeof(M),fp) == sizeof(M) ) + { + M.data = 0; + //printf("entry iter.%d crc32.%x datalen.%d\n",iter,M.crc32,M.datalen); + if ( M.datalen < 100000 ) + { + M.data = malloc(M.datalen); + if ( fread(M.data,1,M.datalen,fp) == M.datalen ) + { + if ( calc_crc32(0,M.data,M.datalen) == M.crc32 ) + { + if ( iter == 1 ) + { + if ( swap == 0 ) + { + swap = basilisk_thread_start(privkey,&R,statebits,optionduration,1); + swap->I.choosei = swap->I.otherchoosei = -1; + } + if ( swap != 0 ) + basilisk_swapgotdata(swap,M.crc32,M.srchash,M.desthash,M.quoteid,M.msgbits,M.data,M.datalen,1); + } + } else printf("crc mismatch %x vs %x\n",calc_crc32(0,M.data,M.datalen),M.crc32); + } else printf("error reading M.datalen %d\n",M.datalen); + free(M.data), M.data = 0; + } + } + } + if ( swapcompleted != 0 ) + break; + rewind(fp); + } + } + } + } else myinfo->swapsfp = fopen(fname,"wb+"); + }*/ + +FILE *basilisk_swap_save(struct basilisk_swap *swap,bits256 privkey,struct basilisk_request *rp,uint32_t statebits,int32_t optionduration,int32_t reinit) +{ + FILE *fp=0; /*char fname[512]; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,rp->requestid,rp->quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) == 0 ) + { + if ( (fp= fopen(fname,"wb+")) != 0 ) + { + fwrite(privkey.bytes,1,sizeof(privkey),fp); + fwrite(rp,1,sizeof(*rp),fp); + fwrite(&statebits,1,sizeof(statebits),fp); + fwrite(&optionduration,1,sizeof(optionduration),fp); + fflush(fp); + } + } + else if ( reinit != 0 ) + { + }*/ + return(fp); +} + +int32_t basilisk_swap_load(uint32_t requestid,uint32_t quoteid,bits256 *privkeyp,struct basilisk_request *rp,uint32_t *statebitsp,int32_t *optiondurationp) +{ + FILE *fp=0; char fname[512]; int32_t retval = -1; + sprintf(fname,"%s/SWAPS/%u-%u",GLOBAL_DBDIR,requestid,quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"rb+")) != 0 ) + { + if ( fread(privkeyp,1,sizeof(*privkeyp),fp) == sizeof(*privkeyp) && + fread(rp,1,sizeof(*rp),fp) == sizeof(*rp) && + fread(statebitsp,1,sizeof(*statebitsp),fp) == sizeof(*statebitsp) && + fread(optiondurationp,1,sizeof(*optiondurationp),fp) == sizeof(*optiondurationp) ) + retval = 0; + fclose(fp); + } + return(retval); +} + +void basilisk_swap_saveupdate(struct basilisk_swap *swap) +{ + FILE *fp; char fname[512]; + sprintf(fname,"%s/SWAPS/%u-%u.swap",GLOBAL_DBDIR,swap->I.req.requestid,swap->I.req.quoteid), OS_compatible_path(fname); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fwrite(&swap->I,1,sizeof(swap->I),fp); + /*fwrite(&swap->bobdeposit,1,sizeof(swap->bobdeposit),fp); + fwrite(&swap->bobpayment,1,sizeof(swap->bobpayment),fp); + fwrite(&swap->alicepayment,1,sizeof(swap->alicepayment),fp); + fwrite(&swap->myfee,1,sizeof(swap->myfee),fp); + fwrite(&swap->otherfee,1,sizeof(swap->otherfee),fp); + fwrite(&swap->aliceclaim,1,sizeof(swap->aliceclaim),fp); + fwrite(&swap->alicespend,1,sizeof(swap->alicespend),fp); + fwrite(&swap->bobreclaim,1,sizeof(swap->bobreclaim),fp); + fwrite(&swap->bobspend,1,sizeof(swap->bobspend),fp); + fwrite(&swap->bobrefund,1,sizeof(swap->bobrefund),fp); + fwrite(&swap->alicereclaim,1,sizeof(swap->alicereclaim),fp);*/ + fwrite(swap->privkeys,1,sizeof(swap->privkeys),fp); + fwrite(swap->otherdeck,1,sizeof(swap->otherdeck),fp); + fwrite(swap->deck,1,sizeof(swap->deck),fp); + fclose(fp); + } +} + +/*int32_t basilisk_swap_loadtx(struct basilisk_rawtx *rawtx,FILE *fp,char *bobcoinstr,char *alicecoinstr) + { + if ( fread(rawtx,1,sizeof(*rawtx),fp) == sizeof(*rawtx) ) + { + rawtx->coin = 0; + rawtx->vins = 0; + if ( strcmp(rawtx->I.coinstr,bobcoinstr) == 0 || strcmp(rawtx->I.coinstr,alicecoinstr) == 0 ) + { + rawtx->coin = LP_coinfind(rawtx->I.coinstr); + if ( rawtx->vinstr[0] != 0 ) + rawtx->vins = cJSON_Parse(rawtx->vinstr); + printf("loaded.%s len.%d\n",rawtx->name,rawtx->I.datalen); + return(0); + } + } + return(-1); + }*/ + +void basilisk_swap_sendabort(struct basilisk_swap *swap) +{ + uint32_t msgbits = 0; uint8_t buf[sizeof(msgbits) + sizeof(swap->I.req.quoteid) + sizeof(bits256)*2]; int32_t sentbytes,offset=0; + memset(buf,0,sizeof(buf)); + offset += iguana_rwnum(1,&buf[offset],sizeof(swap->I.req.quoteid),&swap->I.req.quoteid); + offset += iguana_rwnum(1,&buf[offset],sizeof(msgbits),&msgbits); + if ( (sentbytes= nn_send(swap->pushsock,buf,offset,0)) != offset ) + { + if ( sentbytes < 0 ) + { + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; + } + } else printf("basilisk_swap_sendabort\n"); +} + +void basilisk_psockinit(struct basilisk_swap *swap,int32_t amlp); + +void basilisk_swapgotdata(struct basilisk_swap *swap,uint32_t crc32,bits256 srchash,bits256 desthash,uint32_t quoteid,uint32_t msgbits,uint8_t *data,int32_t datalen,int32_t reinit) +{ + int32_t i; struct basilisk_swapmessage *mp; + for (i=0; inummessages; i++) + if ( crc32 == swap->messages[i].crc32 && msgbits == swap->messages[i].msgbits && bits256_cmp(srchash,swap->messages[i].srchash) == 0 && bits256_cmp(desthash,swap->messages[i].desthash) == 0 ) + return; + //printf(" new message.[%d] datalen.%d Q.%x msg.%x [%llx]\n",swap->nummessages,datalen,quoteid,msgbits,*(long long *)data); + swap->messages = realloc(swap->messages,sizeof(*swap->messages) * (swap->nummessages + 1)); + mp = &swap->messages[swap->nummessages++]; + mp->crc32 = crc32; + mp->srchash = srchash; + mp->desthash = desthash; + mp->msgbits = msgbits; + mp->quoteid = quoteid; + mp->data = malloc(datalen); + mp->datalen = datalen; + memcpy(mp->data,data,datalen); + if ( reinit == 0 && swap->fp != 0 ) + { + fwrite(mp,1,sizeof(*mp),swap->fp); + fwrite(data,1,datalen,swap->fp); + fflush(swap->fp); + } +} + +int32_t basilisk_swapget(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(void *ptr,uint8_t *data,int32_t datalen)) +{ + uint8_t *ptr; bits256 srchash,desthash; uint32_t crc32,_msgbits,quoteid; int32_t i,size,offset,retval = -1; struct basilisk_swapmessage *mp = 0; + while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,0)) >= 0 ) + { + swap->lasttime = (uint32_t)time(NULL); + memset(srchash.bytes,0,sizeof(srchash)); + memset(desthash.bytes,0,sizeof(desthash)); + //printf("gotmsg.[%d] crc.%x\n",size,crc32); + offset = 0; + for (i=0; i<32; i++) + srchash.bytes[i] = ptr[offset++]; + for (i=0; i<32; i++) + desthash.bytes[i] = ptr[offset++]; + offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),"eid); + offset += iguana_rwnum(0,&ptr[offset],sizeof(uint32_t),&_msgbits); + if ( size > offset ) + { + crc32 = calc_crc32(0,&ptr[offset],size-offset); + if ( size > offset ) + { + //printf("size.%d offset.%d datalen.%d\n",size,offset,size-offset); + basilisk_swapgotdata(swap,crc32,srchash,desthash,quoteid,_msgbits,&ptr[offset],size-offset,0); + } + } + else if ( bits256_nonz(srchash) == 0 && bits256_nonz(desthash) == 0 ) + { + if ( swap->aborted == 0 ) + { + swap->aborted = (uint32_t)time(NULL); + printf("got abort signal from other side\n"); + } + } else printf("basilisk_swapget: got strange packet\n"); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } + //char str[65],str2[65]; + for (i=0; inummessages; i++) + { + //printf("%d: %s vs %s\n",i,bits256_str(str,swap->messages[i].srchash),bits256_str(str2,swap->messages[i].desthash)); + if ( bits256_cmp(swap->messages[i].desthash,swap->I.myhash) == 0 ) + { + if ( swap->messages[i].msgbits == msgbits ) + { + if ( swap->I.iambob == 0 && swap->lasttime != 0 && time(NULL) > swap->lasttime+360 ) + { + printf("nothing received for a while from Bob, try new sockets\n"); + if ( swap->pushsock >= 0 ) // + nn_close(swap->pushsock), swap->pushsock = -1; + if ( swap->subsock >= 0 ) // + nn_close(swap->subsock), swap->subsock = -1; + swap->connected = 0; + basilisk_psockinit(swap,swap->I.iambob != 0); + } + mp = &swap->messages[i]; + if ( msgbits != 0x80000000 ) + break; + } + } + } + if ( mp != 0 ) + retval = (*basilisk_verify_func)(swap,mp->data,mp->datalen); + //printf("mine/other %s vs %s\n",bits256_str(str,swap->I.myhash),bits256_str(str2,swap->I.otherhash)); + return(retval); +} + +int32_t basilisk_messagekeyread(uint8_t *key,uint32_t *channelp,uint32_t *msgidp,bits256 *srchashp,bits256 *desthashp) +{ + int32_t keylen = 0; + keylen += iguana_rwnum(0,&key[keylen],sizeof(uint32_t),channelp); + keylen += iguana_rwnum(0,&key[keylen],sizeof(uint32_t),msgidp); + keylen += iguana_rwbignum(0,&key[keylen],sizeof(*srchashp),srchashp->bytes); + keylen += iguana_rwbignum(0,&key[keylen],sizeof(*desthashp),desthashp->bytes); + return(keylen); +} + +int32_t basilisk_messagekey(uint8_t *key,uint32_t channel,uint32_t msgid,bits256 srchash,bits256 desthash) +{ + int32_t keylen = 0; + keylen += iguana_rwnum(1,&key[keylen],sizeof(uint32_t),&channel); + keylen += iguana_rwnum(1,&key[keylen],sizeof(uint32_t),&msgid); + keylen += iguana_rwbignum(1,&key[keylen],sizeof(srchash),srchash.bytes); + keylen += iguana_rwbignum(1,&key[keylen],sizeof(desthash),desthash.bytes); + return(keylen); +} + +void LP_channelsend(bits256 srchash,bits256 desthash,uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen) +{ + int32_t keylen; uint8_t key[BASILISK_KEYSIZE]; //char *retstr; + keylen = basilisk_messagekey(key,channel,msgid,srchash,desthash); + //if ( (retstr= _dex_reqsend(myinfo,"DEX",key,keylen,data,datalen)) != 0 ) + // free(retstr); +} + + +#ifdef adfafds +void iguana_ensure_privkey(struct iguana_info *coin,bits256 privkey) +{ + uint8_t pubkey33[33]; struct iguana_waccount *wacct; struct iguana_waddress *waddr,addr; char coinaddr[128]; + bitcoin_pubkey33(swap->ctx,pubkey33,privkey); + bitcoin_address(coinaddr,coin->pubtype,pubkey33,33); + //printf("privkey for (%s)\n",coinaddr); + if ( myinfo->expiration != 0 && ((waddr= iguana_waddresssearch(&wacct,coinaddr)) == 0 || bits256_nonz(waddr->privkey) == 0) ) + { + if ( waddr == 0 ) + { + memset(&addr,0,sizeof(addr)); + iguana_waddresscalc(coin->pubtype,coin->wiftype,&addr,privkey); + if ( (wacct= iguana_waccountfind("default")) != 0 ) + waddr = iguana_waddressadd(coin,wacct,&addr,0); + } + if ( waddr != 0 ) + { + waddr->privkey = privkey; + if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->wiftype) > 0 ) + { + if ( (0) && waddr->wiftype != coin->wiftype ) + printf("ensurepriv warning: mismatched wiftype %02x != %02x\n",waddr->wiftype,coin->wiftype); + if ( (0) && waddr->addrtype != coin->pubtype ) + printf("ensurepriv warning: mismatched addrtype %02x != %02x\n",waddr->addrtype,coin->pubtype); + } + } + } +} +#endif + + int32_t basilisk_rawtx_return(struct basilisk_rawtx *rawtx,cJSON *item,int32_t lockinputs,struct vin_info *V) { char *signedtx,*txbytes; cJSON *vins,*privkeyarray; int32_t i,n,retval = -1; diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 6ee6499f7..63ca5beee 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -202,37 +202,6 @@ int32_t iguana_msgtx_Vset(uint8_t *serialized,int32_t maxlen,struct iguana_msgtx return(len); } -#ifdef adfafds -void iguana_ensure_privkey(struct iguana_info *coin,bits256 privkey) -{ - uint8_t pubkey33[33]; struct iguana_waccount *wacct; struct iguana_waddress *waddr,addr; char coinaddr[128]; - bitcoin_pubkey33(swap->ctx,pubkey33,privkey); - bitcoin_address(coinaddr,coin->pubtype,pubkey33,33); - //printf("privkey for (%s)\n",coinaddr); - if ( myinfo->expiration != 0 && ((waddr= iguana_waddresssearch(&wacct,coinaddr)) == 0 || bits256_nonz(waddr->privkey) == 0) ) - { - if ( waddr == 0 ) - { - memset(&addr,0,sizeof(addr)); - iguana_waddresscalc(coin->pubtype,coin->wiftype,&addr,privkey); - if ( (wacct= iguana_waccountfind("default")) != 0 ) - waddr = iguana_waddressadd(coin,wacct,&addr,0); - } - if ( waddr != 0 ) - { - waddr->privkey = privkey; - if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->wiftype) > 0 ) - { - if ( (0) && waddr->wiftype != coin->wiftype ) - printf("ensurepriv warning: mismatched wiftype %02x != %02x\n",waddr->wiftype,coin->wiftype); - if ( (0) && waddr->addrtype != coin->pubtype ) - printf("ensurepriv warning: mismatched addrtype %02x != %02x\n",waddr->addrtype,coin->pubtype); - } - } - } -} -#endif - int32_t iguana_interpreter(struct iguana_info *coin,cJSON *logarray,int64_t nLockTime,struct vin_info *V,int32_t numvins) { uint8_t script[IGUANA_MAXSCRIPTSIZE],*activescript,savescript[IGUANA_MAXSCRIPTSIZE]; char str[IGUANA_MAXSCRIPTSIZE*2+1]; int32_t vini,scriptlen,activescriptlen,savelen,errs = 0; cJSON *spendscript,*item=0; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c new file mode 100644 index 000000000..b620c65c5 --- /dev/null +++ b/iguana/exchanges/LP_utxos.c @@ -0,0 +1,327 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_utxos.c +// marketmaker +// + +struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) +{ + struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; + memcpy(key,txid.bytes,sizeof(txid)); + memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); + portable_mutex_lock(&LP_utxomutex); + HASH_FIND(hh,LP_utxoinfos,key,sizeof(key),utxo); + portable_mutex_unlock(&LP_utxomutex); + return(utxo); +} + +cJSON *LP_utxojson(struct LP_utxoinfo *utxo) +{ + cJSON *item = cJSON_CreateObject(); + jaddstr(item,"ipaddr",utxo->ipaddr); + jaddnum(item,"port",utxo->port); + jaddnum(item,"profit",utxo->profitmargin); + jaddstr(item,"base",utxo->coin); + jaddstr(item,"coin",utxo->coin); + jaddstr(item,"address",utxo->coinaddr); + jaddstr(item,"script",utxo->spendscript); + jaddbits256(item,"txid",utxo->txid); + jaddnum(item,"vout",utxo->vout); + jaddnum(item,"value",dstr(utxo->satoshis)); + jaddbits256(item,"txid2",utxo->txid2); + jaddnum(item,"vout2",utxo->vout2); + jaddnum(item,"value2",dstr(utxo->satoshis2)); + return(item); +} + +char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) +{ + int32_t i,firsti; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); + i = 0; + if ( lastn >= mypeer->numutxos ) + firsti = -1; + else firsti = (mypeer->numutxos - lastn); + HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + { + if ( i++ < firsti ) + continue; + if ( coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0 ) + { + jaddi(utxosjson,LP_utxojson(utxo)); + } + } + return(jprint(utxosjson,1)); +} + +struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) +{ + struct LP_utxoinfo *utxo = 0; + if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) + { + printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); + return(0); + } + if ( amclient == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) + { + printf("LP node got localhost utxo\n"); + return(0); + } + if ( (utxo= LP_utxofind(txid,vout)) != 0 ) + { + if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->txid2) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->vout2 || depositsatoshis != utxo->satoshis2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) + { + utxo->errors++; + char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->txid2) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->vout2,depositsatoshis != utxo->satoshis2,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); + } + else if ( profitmargin != 0. ) + utxo->profitmargin = profitmargin; + } + else + { + utxo = calloc(1,sizeof(*utxo)); + utxo->pair = -1; + utxo->profitmargin = profitmargin; + strcpy(utxo->ipaddr,ipaddr); + utxo->port = port; + safecopy(utxo->coin,coin,sizeof(utxo->coin)); + safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); + safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); + utxo->txid = txid; + utxo->vout = vout; + utxo->satoshis = satoshis; + utxo->txid2 = deposittxid; + utxo->vout2 = depositvout; + utxo->satoshis2 = depositsatoshis; + memcpy(utxo->key,txid.bytes,sizeof(txid)); + memcpy(&utxo->key[sizeof(txid)],&vout,sizeof(vout)); + portable_mutex_lock(&LP_utxomutex); + HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); + if ( mypeer != 0 ) + mypeer->numutxos++; + portable_mutex_unlock(&LP_utxomutex); + if ( mypubsock >= 0 ) + LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); + //char str[65],str2[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); + } + return(utxo); +} + +int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +{ + struct LP_peerinfo *peer,*destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + if ( amclient != 0 ) + { + printf("LP_utxosparse not for clientside\n"); + return(-1); + } + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; ilasttime = now; + } + } + } + if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) + { + if ( destpeer->numutxos < n ) + { + //destpeer->numutxos = n; + //printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); + } + } + } + free_json(array); + } + return(n); +} + +void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) +{ + char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; + if ( amclient != 0 ) + { + printf("LP_utxosquery not for clientside\n"); + return; + } + peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); + if ( (peer != 0 && peer->errors > 0) || mypeer == 0 ) + return; + if ( coin == 0 ) + coin = ""; + if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) + { + now = (uint32_t)time(NULL); + LP_utxosparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); + free(retstr); + i = 0; + if ( lastn >= mypeer->numutxos ) + firsti = -1; + else firsti = (mypeer->numutxos - lastn); + HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + { + if ( i++ < firsti ) + continue; + if ( utxo->lasttime != now && strcmp(utxo->ipaddr,"127.0.0.1") != 0 ) + { + char str[65]; printf("{%s:%u %s} ",utxo->ipaddr,utxo->port,bits256_str(str,utxo->txid)); + flag++; + if ( (retstr= issue_LP_notifyutxo(destipaddr,destport,utxo)) != 0 ) + free(retstr); + } + } + if ( flag != 0 ) + printf(" <- missing utxos\n"); + } else if ( peer != 0 ) + peer->errors++; +} + +int32_t LP_maxvalue(uint64_t *values,int32_t n) +{ + int32_t i,maxi = -1; uint64_t maxval = 0; + for (i=0; i maxval ) + { + maxi = i; + maxval = values[i]; + } + return(maxi); +} + +int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) +{ + int32_t i,mini = -1; int64_t dist; uint64_t mindist = (1 << 31); + for (i=0; i= 0 && dist < mindist ) + { + mini = i; + mindist = dist; + } + } + return(mini); +} + +uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t amclient) +{ + char coinaddr[64],*script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + if ( coin == 0 ) + { + printf("cant add privkey for %s, coin not active\n",symbol); + return(0); + } + if ( passphrase != 0 ) + conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); + else privkey = iguana_wif2privkey(wifstr); + iguana_priv2pub(pubkey33,coinaddr,privkey,coin->pubtype); + { + char tmpstr[128]; + bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); + printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); + if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) + printf("importprivkey -> (%s)\n",jprint(retjson,1)); + } + bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); + LP_privkeyadd(privkey,rmd160); + if ( (array= LP_listunspent(symbol,coinaddr)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + values = calloc(n,sizeof(*values)); + for (i=0; i= 0 ) + { + item = jitem(array,i); + deposittxid = jbits256(item,"txid"); + depositvout = juint(item,"vout"); + script = jstr(item,"scriptPubKey"); + depositval = values[i]; + values[i] = 0, used++; + if ( amclient != 0 ) + targetval = (depositval / 776) + 50000; + else targetval = (depositval / 9) * 8; + //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); + if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) + { + item = jitem(array,i); + txid = jbits256(item,"txid"); + vout = juint(item,"vout"); + printf("j.%d %.8f target %.8f\n",i,dstr(values[i]),dstr(targetval)); + if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 ) + { + value = values[i]; + values[i] = 0, used++; + if ( amclient == 0 ) + { + if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) + utxo->mypub = curve25519(privkey,curve25519_basepoint9()); + } + else + { + if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coinaddr,"127.0.0.1",0,0)) != 0 ) + utxo->mypub = curve25519(privkey,curve25519_basepoint9()); + } + total += value; + } + } + } else break; + } + free(values); + } + free_json(array); + } + return(total); +} + +void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphrase,int32_t amclient) +{ + int32_t i; + for (i=0; i (b) ? (a) : (b)) char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port); #include "stats.c" -#include "LP_prices.c" +void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]); #if defined(__APPLE__) || defined(WIN32) || defined(USE_STATIC_NANOMSG) #include "../../crypto777/nanosrc/nn.h" From 6e580760fae7ef393245c5c46d2289b95240513f Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 2 Jun 2017 19:46:42 +0300 Subject: [PATCH 0939/2705] Test --- iguana/exchanges/LP_coins.c | 41 ++++++++----------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index d3f136c00..3ea9332d9 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -18,6 +18,7 @@ // marketmaker // +char *portstrs[][2] = { { "BTC", "8332" }, { "KMD", "7771" }, { "LTC", "9332" }, { "REVS", "10196" }, { "JUMBLR", "15106" }, }; char *parse_conf_line(char *line,char *field) { @@ -115,50 +116,26 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) return(-1); } -uint32_t LP_assetmagic(char *symbol,uint64_t supply) +uint16_t LP_rpcport(char *symbol) { - uint8_t buf[512]; int32_t len = 0; - if ( strcmp(symbol,"KMD") == 0 ) - return(0x8de4eef9); - len = iguana_rwnum(1,&buf[len],sizeof(supply),(void *)&supply); - strcpy((char *)&buf[len],symbol); - len += strlen(symbol); - return(calc_crc32(0,buf,len)); -} - -uint16_t LP_assetport(uint32_t magic) -{ - if ( magic == 0x8de4eef9 ) - return(7771); - else return(8000 + (magic % 7777)); -} - -uint16_t LP_rpcport(char *symbol,uint64_t supply,uint32_t *magicp) -{ - if ( symbol == 0 || symbol[0] == 0 || strcmp("KMD",symbol) == 0 ) - { - *magicp = 0x8de4eef9; - return(7771); - } - else if ( strcmp("BTC",symbol) == 0 ) - return(8332); - else if ( strcmp("LTC",symbol) == 0 ) - return(9332); - *magicp = LP_assetmagic(symbol,supply); - return(LP_assetport(*magicp)+1); + int32_t i; + for (i=0; i Date: Sat, 3 Jun 2017 04:48:12 +0300 Subject: [PATCH 0940/2705] Test --- iguana/coins/jumblr | 4 + iguana/coins/revs | 3 + iguana/exchanges/LP_commands.c | 178 ++++++++++++++++++++------------ iguana/exchanges/LP_include.h | 4 +- iguana/exchanges/LP_nativeDEX.c | 5 +- iguana/exchanges/LP_utxos.c | 48 +++++++-- iguana/exchanges/mm.c | 2 +- 7 files changed, 164 insertions(+), 80 deletions(-) create mode 100755 iguana/coins/jumblr create mode 100755 iguana/coins/revs diff --git a/iguana/coins/jumblr b/iguana/coins/jumblr new file mode 100755 index 000000000..5b52ce9a6 --- /dev/null +++ b/iguana/coins/jumblr @@ -0,0 +1,4 @@ +~/komodo/src/komodod -ac_name=JUMBLR -ac_supply=999999 -addnode=78.47.196.146 & + +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"JUMBLR.conf\",\"path\":\"${HOME#"/"}/.komodo/JUMBLR\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"JUMBLR\",\"name\":\"JUMBLR\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7223759e\",\"p2p\":15105,\"rpc\":15106,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" + diff --git a/iguana/coins/revs b/iguana/coins/revs new file mode 100755 index 000000000..f2cf9ef72 --- /dev/null +++ b/iguana/coins/revs @@ -0,0 +1,3 @@ +./komodod -ac_name=REVS -ac_supply=1300000 -addnode=78.47.196.146 & +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"REVS.conf\",\"path\":\"${HOME#"/"}/.komodo/REVS\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"REVS\",\"name\":\"REVS\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"905c3498\",\"p2p\":10195,\"rpc\":10196,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" + diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 00ca359b9..32ee01428 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -277,11 +277,13 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) return(retarray); } -cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) +cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) { static bits256 zero; int32_t i,n,besti,DEXselector=0; cJSON *array,*item,*bestitem=0; struct basilisk_request R; double bestmetric,metric,bestprice=0.,price,prices[100]; struct LP_quoteinfo Q[sizeof(prices)/sizeof(*prices)]; bestprice = 0.; + if ( maxprice == 0. ) + maxprice = LP_price(base,myutxo->coin) / 0.975; if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -329,33 +331,41 @@ cJSON *LP_bestprice(struct LP_utxoinfo *myutxo,char *base) if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) { item = jitem(array,besti); - bestitem = LP_quotejson(&Q[i]); i = besti; - Q[i].desttxid = myutxo->txid; - Q[i].destvout = myutxo->vout; - Q[i].feetxid = myutxo->txid2; - Q[i].feevout = myutxo->vout2; - strcpy(Q[i].destaddr,myutxo->coinaddr); - price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); - if ( jobj(bestitem,"price") != 0 ) - jdelete(bestitem,"price"); - jaddnum(bestitem,"price",prices[besti]); - if ( LP_price(base,myutxo->coin) > 0.975*price ) + bestitem = LP_quotejson(&Q[i]); + if ( bestprice <= maxprice ) { Q[i].desttxid = myutxo->txid; Q[i].destvout = myutxo->vout; Q[i].feetxid = myutxo->txid2; Q[i].feevout = myutxo->vout2; strcpy(Q[i].destaddr,myutxo->coinaddr); - price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); - LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); - printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); + price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); + if ( jobj(bestitem,"price") != 0 ) + jdelete(bestitem,"price"); + jaddnum(bestitem,"price",prices[besti]); + if ( price <= maxprice ) + { + Q[i].desttxid = myutxo->txid; + Q[i].destvout = myutxo->vout; + Q[i].feetxid = myutxo->txid2; + Q[i].feevout = myutxo->vout2; + strcpy(Q[i].destaddr,myutxo->coinaddr); + price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); + LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); + jaddstr(bestitem,"status","connected"); + jaddnum(bestitem,"requestid",R.requestid); + jaddnum(bestitem,"quoteid",R.quoteid); + printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); + } else jaddstr(bestitem,"status","too expensive"); } } } free_json(array); } } + if ( bestitem == 0 ) + return(cJSON_Parse("{\"error\":\"no match found\"}")); return(bestitem); } @@ -488,72 +498,104 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; + char *method,*ipaddr,*userpass,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); - else + if ( IAMCLIENT != 0 && USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) { - amclient = (LP_mypeer == 0); - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + if ( (userpass= jstr(argjson,"userpass")) == 0 || strcmp(userpass,USERPASS) != 0 ) + return(clonestr("{\"error\":\"authentication error\"}")); + if ( USERPASS_COUNTER == 0 ) { - if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) - { - if ( (pushport= juint(argjson,"push")) == 0 ) - pushport = argport + 1; - if ( (subport= juint(argjson,"sub")) == 0 ) - subport = argport + 2; - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) - { - if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) - peer->numpeers = otherpeers; - if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) - { - printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer != 0 ? LP_mypeer->numutxos:0); - peer->numutxos = othernumutxos; - } - //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); - } else LP_addpeer(amclient,LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); - } + USERPASS_COUNTER = 1; + retjson = cJSON_CreateObject(); + jaddstr(retjson,"userpass",USERPASS); + return(jprint(retjson,1)); } - printf("CMD.(%s)\n",jprint(argjson,0)); - if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) - retstr = LP_quotereceived(argjson); - else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) + if ( (coin= jstr(argjson,"coin")) != 0 ) { - int32_t pairsock = -1; char *pairstr; - if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) - printf("error creating pairsock\n"); - else if ( nn_connect(pairsock,pairstr) >= 0 ) + if ( strcmp(method,"inventory") == 0 ) + { + LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); + return(LP_inventory(coin)); + } + else if ( strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0 ) { - struct LP_quoteinfo *qp; int32_t DEXselector = 0; - qp = calloc(1,sizeof(*qp)); - LP_quoteparse(qp,argjson); - qp->pair = pairsock; - qp->privkey = LP_privkey(qp->destaddr); - LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis,qp->destcoin,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); - printf("alice pairstr.(%s)\n",pairstr); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)qp) == 0 ) + bits256 txid; int32_t vout; struct LP_utxoinfo *utxo; + txid = jbits256(argjson,"txid"); + if ( bits256_nonz(txid) == 0 ) + return(clonestr("{\"error\":\"invalid or missing txid\"}")); + if ( jobj(argjson,"vout") == 0 ) + return(clonestr("{\"error\":\"missing vout\"}")); + vout = jint(argjson,"vout"); + if ( (utxo= LP_utxofind(txid,vout)) == 0 ) + return(clonestr("{\"error\":\"txid/vout not found\"}")); + if ( strcmp(method,"candidates") == 0 ) + return(jprint(LP_tradecandidates(utxo,coin),1)); + else return(jprint(LP_autotrade(utxo,coin,jdouble(argjson,"maxprice")),1)); + } + } else return(clonestr("{\"error\":\"no coin specified\"}")); + } + amclient = (LP_mypeer == 0); + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + { + if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) + { + if ( (pushport= juint(argjson,"push")) == 0 ) + pushport = argport + 1; + if ( (subport= juint(argjson,"sub")) == 0 ) + subport = argport + 2; + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) + { + if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) + peer->numpeers = otherpeers; + if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) { + printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer != 0 ? LP_mypeer->numutxos:0); + peer->numutxos = othernumutxos; } - } + //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); + } else LP_addpeer(amclient,LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); } - else if ( IAMCLIENT == 0 && strcmp(method,"getprice") == 0 ) - retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); - else if ( strcmp(method,"orderbook") == 0 ) - retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); - else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) - retstr = LP_peers(); - else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) - retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) - retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( IAMCLIENT == 0 && strcmp(method,"notifyutxo") == 0 ) + } + printf("CMD.(%s)\n",jprint(argjson,0)); + if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) + retstr = LP_quotereceived(argjson); + else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) + { + int32_t pairsock = -1; char *pairstr; + if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) + printf("error creating pairsock\n"); + else if ( nn_connect(pairsock,pairstr) >= 0 ) { - printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),SATOSHIDEN * jdouble(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); - retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); + struct LP_quoteinfo *qp; int32_t DEXselector = 0; + qp = calloc(1,sizeof(*qp)); + LP_quoteparse(qp,argjson); + qp->pair = pairsock; + qp->privkey = LP_privkey(qp->destaddr); + LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis,qp->destcoin,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); + printf("alice pairstr.(%s)\n",pairstr); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)qp) == 0 ) + { + } } } + else if ( IAMCLIENT == 0 && strcmp(method,"getprice") == 0 ) + retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); + else if ( strcmp(method,"orderbook") == 0 ) + retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); + else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) + retstr = LP_peers(); + else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); + else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) + retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); + else if ( IAMCLIENT == 0 && strcmp(method,"notifyutxo") == 0 ) + { + printf("utxonotify.(%s)\n",jprint(argjson,0)); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),SATOSHIDEN * jdouble(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); + } if ( retstr != 0 ) return(retstr); retjson = cJSON_CreateObject(); diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 4cfacff3f..9dc21ab9b 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -42,8 +42,8 @@ #define DEX_SLEEP 3 #define BASILISK_KEYSIZE ((int32_t)(2*sizeof(bits256)+sizeof(uint32_t)*2)) -extern char GLOBAL_DBDIR[]; -extern int32_t IAMCLIENT; +extern char GLOBAL_DBDIR[],USERPASS[],USERPASS_WIFSTR[]; +extern int32_t IAMCLIENT,USERPASS_COUNTER; struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 68915cd7a..cfa6d1e09 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -28,13 +28,14 @@ struct LP_peerinfo *LP_peerinfos,*LP_mypeer; char *activecoins[] = { "BTC", "KMD", "REVS", "JUMBLR" };//"LTC", "USD", }; char GLOBAL_DBDIR[] = "DB"; +char USERPASS[65],USERPASS_WIFSTR[64]; char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; int32_t LP_mypubsock = -1; int32_t Client_connections; -int32_t IAMCLIENT = 0; +int32_t USERPASS_COUNTER,IAMCLIENT = 0; // stubs @@ -282,3 +283,5 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } LP_mainloop(mypeer,mypubport,pubsock,pullsock,myport,amclient,passphrase,profitmargin); } + + diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b620c65c5..6ba0a819b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -29,22 +29,36 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) return(utxo); } -cJSON *LP_utxojson(struct LP_utxoinfo *utxo) +cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { - cJSON *item = cJSON_CreateObject(); - jaddstr(item,"ipaddr",utxo->ipaddr); - jaddnum(item,"port",utxo->port); - jaddnum(item,"profit",utxo->profitmargin); - jaddstr(item,"base",utxo->coin); jaddstr(item,"coin",utxo->coin); jaddstr(item,"address",utxo->coinaddr); - jaddstr(item,"script",utxo->spendscript); jaddbits256(item,"txid",utxo->txid); jaddnum(item,"vout",utxo->vout); jaddnum(item,"value",dstr(utxo->satoshis)); jaddbits256(item,"txid2",utxo->txid2); jaddnum(item,"vout2",utxo->vout2); jaddnum(item,"value2",dstr(utxo->satoshis2)); + if ( utxo->swappending != 0 ) + jaddnum(item,"pending",utxo->swappending); + if ( bits256_nonz(utxo->otherpubkey) != 0 ) + jaddbits256(item,"desthash",utxo->otherpubkey); + if ( utxo->pair >= 0 ) + jaddnum(item,"socket",utxo->pair); + if ( utxo->swap != 0 ) + jaddstr(item,"swap","in progress"); + return(item); +} + +cJSON *LP_utxojson(struct LP_utxoinfo *utxo) +{ + cJSON *item = cJSON_CreateObject(); + item = LP_inventoryjson(item,utxo); + jaddstr(item,"ipaddr",utxo->ipaddr); + jaddnum(item,"port",utxo->port); + jaddnum(item,"profit",utxo->profitmargin); + jaddstr(item,"base",utxo->coin); + jaddstr(item,"script",utxo->spendscript); return(item); } @@ -207,6 +221,17 @@ void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock peer->errors++; } +char *LP_inventory(char *symbol) +{ + struct LP_utxoinfo *utxo,*tmp; cJSON *array = cJSON_CreateArray(); + HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + { + if ( strcmp(symbol,utxo->coin) == 0 ) + jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); + } + return(jprint(array,1)); +} + int32_t LP_maxvalue(uint64_t *values,int32_t n) { int32_t i,maxi = -1; uint64_t maxval = 0; @@ -238,7 +263,8 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t amclient) { - char coinaddr[64],*script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + static uint32_t counter; + char coinaddr[64],*script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 userpass,userpub,txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) { printf("cant add privkey for %s, coin not active\n",symbol); @@ -248,9 +274,15 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); iguana_priv2pub(pubkey33,coinaddr,privkey,coin->pubtype); + if ( counter == 0 ) { char tmpstr[128]; + counter++; + bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); + conv_NXTpassword(userpass.bytes,pubkey.bytes,(uint8_t *)tmpstr,(int32_t)strlen(tmpstr)); + userpub = curve25519(userpass,curve25519_basepoint9()); + printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 89ce9c3cd..6cfc332cf 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -846,7 +846,7 @@ int main(int argc, const char * argv[]) struct LP_utxoinfo *utxo,*utmp; HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { - if ( (matchjson= LP_bestprice(utxo,"KMD")) != 0 ) + if ( (matchjson= LP_autotrade(utxo,"KMD",0.)) != 0 ) printf("bestprice (%s)\n",jprint(matchjson,1)); } } From 78d5ee5025ae12e92338b7bacac022fc62f750a0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 05:09:42 +0300 Subject: [PATCH 0941/2705] Test --- iguana/exchanges/LP_utxos.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6ba0a819b..902942824 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -129,14 +129,14 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - //char str[65],str2[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); + char str[65],str2[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); } return(utxo); } int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { - struct LP_peerinfo *peer,*destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; if ( amclient != 0 ) { printf("LP_utxosparse not for clientside\n"); @@ -167,14 +167,14 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs } } } - if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) + /*if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) { if ( destpeer->numutxos < n ) { //destpeer->numutxos = n; //printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); } - } + }*/ } free_json(array); } From a2b4ddd02ce7fc0312c5f53a7d3e6e6b5b65b5fa Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 05:11:58 +0300 Subject: [PATCH 0942/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 902942824..a8e7f48be 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -89,7 +89,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); return(0); } - if ( amclient == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) + if ( IAMCLIENT == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) { printf("LP node got localhost utxo\n"); return(0); @@ -129,7 +129,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - char str[65],str2[65]; printf("%s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); + char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); } return(utxo); } From 76ce1d0944e109c0ccbc07affda7cfd353936564 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 06:02:04 +0300 Subject: [PATCH 0943/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/mm.c | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 32ee01428..dd5044682 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -393,7 +393,7 @@ int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double p int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey,txid; struct LP_utxoinfo *utxo; int32_t retval = -1,DEXselector = 0; uint64_t destvalue; struct basilisk_request R; struct LP_quoteinfo Q; - if ( (method= jstr(argjson,"method")) != 0 ) + if ( IAMCLIENT == 0 && (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(txid,jint(argjson,"vout"))) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 84a7cb512..ff2e35c11 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -29,7 +29,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) int32_t sentbytes,len,i; struct nn_pollfd pfd; if ( sock < 0 ) { - printf("LP_send to illegal socket\n"); + printf("LP_send.(%s) to illegal socket\n",msg); if ( freeflag != 0 ) free(msg); return(-1); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 6cfc332cf..bf3017da3 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -836,9 +836,9 @@ int main(int argc, const char * argv[]) free(retstr); } incr = 100.; - while ( 1 ) + while ( IAMCLIENT != 0 ) { - theoretical = marketmaker_updateprice("komodo","KMD","BTC",theoretical,&incr); + theoretical = marketmaker_updateprice("komodo","REVS","KMD",theoretical,&incr); sleep(3); LP_privkey_updates(0,-1,passphrase,1); if ( jint(retjson,"client") != 0 ) @@ -846,12 +846,13 @@ int main(int argc, const char * argv[]) struct LP_utxoinfo *utxo,*utmp; HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { - if ( (matchjson= LP_autotrade(utxo,"KMD",0.)) != 0 ) + if ( strcmp(utxo->coin,"REVS") == 0 && (matchjson= LP_autotrade(utxo,"KMD",0.)) != 0 ) printf("bestprice (%s)\n",jprint(matchjson,1)); } } sleep(1000); } +getchar(); profitmargin = jdouble(retjson,"profitmargin"); minask = jdouble(retjson,"minask"); maxbid = jdouble(retjson,"maxbid"); From e856ee55a499d3aab401e07aca8110f83a09b6be Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 07:43:58 +0300 Subject: [PATCH 0944/2705] Test --- crypto777/OS_portable.h | 1 + iguana/exchanges/LP_commands.c | 30 +++++- iguana/exchanges/LP_nativeDEX.c | 3 + iguana/exchanges/LP_prices.c | 178 ++++++++++++++++++++++++++++---- iguana/exchanges/LP_utxos.c | 1 - 5 files changed, 187 insertions(+), 26 deletions(-) diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index a90889279..23a051b01 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -359,6 +359,7 @@ void calc_base64_decodestr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); void calc_hexstr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); void calc_unhexstr(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len); int32_t safecopy(char *dest,char *src,long len); +double dxblend(double *destp,double val,double decay); uint64_t calc_ipbits(char *ip_port); void expand_ipbits(char *ipaddr,uint64_t ipbits); diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index dd5044682..4be342e24 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -498,10 +498,10 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*userpass,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; + char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); - if ( IAMCLIENT != 0 && USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) + if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) { if ( (userpass= jstr(argjson,"userpass")) == 0 || strcmp(userpass,USERPASS) != 0 ) return(clonestr("{\"error\":\"authentication error\"}")); @@ -512,7 +512,29 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port jaddstr(retjson,"userpass",USERPASS); return(jprint(retjson,1)); } - if ( (coin= jstr(argjson,"coin")) != 0 ) + if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) + { + if ( strcmp(method,"setprice") == 0 ) + { + if ( LP_mypriceset(base,rel,jdouble(argjson,"price")) < 0 ) + return(clonestr("{\"error\":\"couldnt set price\"}")); + else return(clonestr("{\"result\":\"success\"}")); + } + else if ( strcmp(method,"myprice") == 0 ) + { + double bid,ask; + if ( LP_myprice(&bid,&ask,base,rel) != 0. ) + { + retjson = cJSON_CreateObject(); + jaddstr(retjson,"base",base); + jaddstr(retjson,"rel",rel); + jaddnum(retjson,"bid",bid); + jaddnum(retjson,"ask",ask); + return(jprint(retjson,1)); + } else return(clonestr("{\"error\":\"no price set\"}")); + } + } + else if ( IAMCLIENT != 0 && (coin= jstr(argjson,"coin")) != 0 ) { if ( strcmp(method,"inventory") == 0 ) { @@ -534,7 +556,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port return(jprint(LP_tradecandidates(utxo,coin),1)); else return(jprint(LP_autotrade(utxo,coin,jdouble(argjson,"maxprice")),1)); } - } else return(clonestr("{\"error\":\"no coin specified\"}")); + } } amclient = (LP_mypeer == 0); if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index cfa6d1e09..450d9bad3 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -107,7 +107,10 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i exit(-1); } for (i=0; i 0 ) + { + coinbits = stringbits(symbol); + pp = LP_priceinfos; + for (i=0; icoinbits == coinbits ) + return(pp); + } + return(0); +} + +struct LP_priceinfo *LP_priceinfoptr(int32_t *indp,char *base,char *rel) +{ + struct LP_priceinfo *basepp,*relpp; + if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + { + *indp = relpp->ind; + return(basepp); + } + else + { + *indp = -1; + return(0); + } +} + +void LP_priceinfoupdate(char *base,char *rel,double price) +{ + struct LP_priceinfo *basepp,*relpp; + if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + { + dxblend(&basepp->relvals[relpp->ind],price,0.9); + dxblend(&relpp->relvals[basepp->ind],1. / price,0.9); + } +} + +double LP_myprice(double *bidp,double *askp,char *base,char *rel) +{ + struct LP_priceinfo *basepp,*relpp; + if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + { + *askp = basepp->myprices[relpp->ind]; + *bidp = relpp->myprices[basepp->ind]; + return((*askp + *bidp) * 0.5); + } else return(0.); +} + +int32_t LP_mypriceset(char *base,char *rel,double price) +{ + struct LP_priceinfo *basepp,*relpp; + if ( price != 0. && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + { + basepp->myprices[relpp->ind] = price; // ask + relpp->myprices[basepp->ind] = 1. / price; // bid + return(0); + } else return(-1); +} + +double LP_price(char *base,char *rel) +{ + struct LP_priceinfo *basepp; int32_t relind; double price = 0.; + if ( (basepp= LP_priceinfoptr(&relind,base,rel)) != 0 ) + { + if ( (price= basepp->myprices[relind]) == 0. ) + price = basepp->relvals[relind]; + } + return(price); +} + +cJSON *LP_priceinfomatrix(int32_t usemyprices) +{ + int32_t i,j,n,m; double total,sum,val; struct LP_priceinfo *pp; uint32_t now; struct LP_cacheinfo *ptr,*tmp; cJSON *vectorjson = cJSON_CreateObject(); + now = (uint32_t)time(NULL); + HASH_ITER(hh,LP_cacheinfos,ptr,tmp) + { + if ( ptr->timestamp < now-60 || ptr->price == 0. ) + continue; + LP_priceinfoupdate(ptr->Q.srccoin,ptr->Q.destcoin,ptr->price); + } + pp = LP_priceinfos; + total = m = 0; + for (i=0; idiagval = sum = n = 0; + for (j=0; jmyprices[j]) == 0. ) + val = pp->relvals[j]; + if ( val != 0. ) + { + sum += val; + n++; + } + } + if ( n > 0 ) + { + pp->diagval = sum / n; + total += pp->diagval, m++; + } + } + if ( m > 0 ) + { + pp = LP_priceinfos; + for (i=0; idiagval /= total; + jaddnum(vectorjson,pp->symbol,pp->diagval); + } + } + return(vectorjson); +} + +struct LP_priceinfo *LP_priceinfoadd(char *symbol) +{ + struct LP_priceinfo *pp; int32_t i,vecsize; cJSON *retjson; + LP_priceinfos = realloc(LP_priceinfos,sizeof(*LP_priceinfos) * (LP_numpriceinfos + 1)); + pp = &LP_priceinfos[LP_numpriceinfos]; + memset(pp,0,sizeof(*pp)); + safecopy(pp->symbol,symbol,sizeof(pp->symbol)); + pp->coinbits = stringbits(symbol); + pp->ind = LP_numpriceinfos; + pp->relvals = calloc(LP_numpriceinfos+1,sizeof(*pp->relvals)); + pp->myprices = calloc(LP_numpriceinfos+1,sizeof(*pp->myprices)); + vecsize = sizeof(*LP_priceinfos[i].relvals) * (LP_numpriceinfos + 1); + for (i=0; iQ = *qp; + ptr->timestamp = (uint32_t)time(NULL); if ( price != ptr->price ) { + ptr->price = price; + LP_priceinfoupdate(base,rel,price); printf("updated %s/v%d %s/%s %llu price %.8f\n",bits256_str(str,txid),vout,base,rel,(long long)qp->satoshis,price); - } - ptr->price = price; - ptr->Q = *qp; - ptr->timestamp = (uint32_t)time(NULL); + } else ptr->price = price; return(ptr); } @@ -182,24 +331,9 @@ char *LP_orderbook(char *base,char *rel) return(jprint(retjson,1)); } -// very, very simple for now - void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]) { - if ( avebid > SMALLVAL && aveask > SMALLVAL && strcmp(base,"KMD") == 0 && strcmp(rel,"BTC") == 0 ) - LP_kmdbtc = (avebid + aveask) * 0.5; -} - -double LP_price(char *base,char *rel) -{ - if ( LP_kmdbtc != 0. ) - { - if ( strcmp(base,"KMD") == 0 && strcmp(rel,"BTC") == 0 ) - return(LP_kmdbtc); - else if ( strcmp(rel,"KMD") == 0 && strcmp(base,"BTC") == 0 ) - return(1. / LP_kmdbtc); - } - return(0.); + LP_priceinfoupdate(base,rel,price); } char *LP_pricestr(char *base,char *rel) @@ -214,6 +348,8 @@ char *LP_pricestr(char *base,char *rel) jaddstr(retjson,"base",base); jaddstr(retjson,"rel",rel); jaddnum(retjson,"price",price); + jadd(retjson,"theoretical",LP_priceinfomatrix(0)); + jadd(retjson,"quotes",LP_priceinfomatrix(1)); return(jprint(retjson,1)); } else return(clonestr("{\"error\":\"cant find baserel pair\"}")); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a8e7f48be..2560f2297 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -322,7 +322,6 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb item = jitem(array,i); txid = jbits256(item,"txid"); vout = juint(item,"vout"); - printf("j.%d %.8f target %.8f\n",i,dstr(values[i]),dstr(targetval)); if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 ) { value = values[i]; From b6f09e2bead0ceff36263032f963e4b0909b811a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 07:46:23 +0300 Subject: [PATCH 0945/2705] Test --- iguana/exchanges/mm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index bf3017da3..24294466b 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -852,7 +852,8 @@ int main(int argc, const char * argv[]) } sleep(1000); } -getchar(); + while ( 1 ) + sleep(1); profitmargin = jdouble(retjson,"profitmargin"); minask = jdouble(retjson,"minask"); maxbid = jdouble(retjson,"maxbid"); From 5d26807a66f505e198d2eb55a10c1bb168fe7f5e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 07:53:41 +0300 Subject: [PATCH 0946/2705] Test --- iguana/exchanges/LP_prices.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 1a9864c5c..a6f86cc6d 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -26,7 +26,7 @@ struct LP_priceinfo double diagval; double *relvals; double *myprices; -} *LP_priceinfos; +} LP_priceinfos[256]; int32_t LP_numpriceinfos; struct LP_cacheinfo @@ -206,7 +206,11 @@ cJSON *LP_priceinfomatrix(int32_t usemyprices) struct LP_priceinfo *LP_priceinfoadd(char *symbol) { struct LP_priceinfo *pp; int32_t i,vecsize; cJSON *retjson; - LP_priceinfos = realloc(LP_priceinfos,sizeof(*LP_priceinfos) * (LP_numpriceinfos + 1)); + if ( LP_numpriceinfos >= sizeof(LP_priceinfos)/sizeof(*LP_priceinfos) ) + { + printf("cant add any more priceinfos\n"); + return(0); + } pp = &LP_priceinfos[LP_numpriceinfos]; memset(pp,0,sizeof(*pp)); safecopy(pp->symbol,symbol,sizeof(pp->symbol)); @@ -217,6 +221,7 @@ struct LP_priceinfo *LP_priceinfoadd(char *symbol) vecsize = sizeof(*LP_priceinfos[i].relvals) * (LP_numpriceinfos + 1); for (i=0; i Date: Sat, 3 Jun 2017 07:56:50 +0300 Subject: [PATCH 0947/2705] Test --- iguana/exchanges/LP_prices.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index a6f86cc6d..aa3df855b 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -18,15 +18,16 @@ // marketmaker // +#define LP_MAXPRICEINFOS 64 struct LP_priceinfo { char symbol[16]; uint64_t coinbits; int32_t ind,pad; double diagval; - double *relvals; - double *myprices; -} LP_priceinfos[256]; + double relvals[LP_MAXPRICEINFOS]; + double myprices[LP_MAXPRICEINFOS]; +} LP_priceinfos[LP_MAXPRICEINFOS]; int32_t LP_numpriceinfos; struct LP_cacheinfo @@ -205,7 +206,7 @@ cJSON *LP_priceinfomatrix(int32_t usemyprices) struct LP_priceinfo *LP_priceinfoadd(char *symbol) { - struct LP_priceinfo *pp; int32_t i,vecsize; cJSON *retjson; + struct LP_priceinfo *pp; cJSON *retjson; if ( LP_numpriceinfos >= sizeof(LP_priceinfos)/sizeof(*LP_priceinfos) ) { printf("cant add any more priceinfos\n"); @@ -215,9 +216,9 @@ struct LP_priceinfo *LP_priceinfoadd(char *symbol) memset(pp,0,sizeof(*pp)); safecopy(pp->symbol,symbol,sizeof(pp->symbol)); pp->coinbits = stringbits(symbol); - pp->ind = LP_numpriceinfos; - pp->relvals = calloc(LP_numpriceinfos+1,sizeof(*pp->relvals)); - pp->myprices = calloc(LP_numpriceinfos+1,sizeof(*pp->myprices)); + pp->ind = LP_numpriceinfos++; + /*pp->relvals = calloc(LP_numpriceinfos+1,sizeof(*pp->relvals)); + //pp->myprices = calloc(LP_numpriceinfos+1,sizeof(*pp->myprices)); vecsize = sizeof(*LP_priceinfos[i].relvals) * (LP_numpriceinfos + 1); for (i=0; i Date: Sat, 3 Jun 2017 08:09:07 +0300 Subject: [PATCH 0948/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 2560f2297..0816aa2ad 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -203,7 +203,7 @@ void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock if ( lastn >= mypeer->numutxos ) firsti = -1; else firsti = (mypeer->numutxos - lastn); - HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + /*HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { if ( i++ < firsti ) continue; @@ -216,7 +216,7 @@ void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock } } if ( flag != 0 ) - printf(" <- missing utxos\n"); + printf(" <- missing utxos\n");*/ } else if ( peer != 0 ) peer->errors++; } From c7a05f4d638fd83750c66a9b1a58780fe508da99 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 08:14:15 +0300 Subject: [PATCH 0949/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++++ iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 450d9bad3..17c25ee75 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -111,6 +111,11 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_coinfind(activecoins[i]); LP_priceinfoadd(activecoins[i]); } + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) + LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer->ipaddr,myport,profitmargin); + } if ( amclient != 0 ) { while ( 1 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0816aa2ad..5340de818 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -183,7 +183,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { - char *retstr; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now,flag = 0; + char *retstr; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now; if ( amclient != 0 ) { printf("LP_utxosquery not for clientside\n"); From 6cc19fd8c8c1ede91b0c0659ceaa17232fbeda84 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 08:18:14 +0300 Subject: [PATCH 0950/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 17c25ee75..3316a162b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -111,6 +111,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_coinfind(activecoins[i]); LP_priceinfoadd(activecoins[i]); } + LP_privkey_updates(mypeer,pubsock,passphrase,amclient); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) @@ -121,7 +122,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i while ( 1 ) { nonz = n = 0; - if ( (counter++ % 3600) == 0 ) + if ( (++counter % 3600) == 0 ) LP_privkey_updates(mypeer,pubsock,passphrase,amclient); if ( (counter % 500) == 0 ) { @@ -163,7 +164,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i while ( 1 ) { nonz = 0; - if ( (counter++ % 2000) == 0 ) + if ( (++counter % 2000) == 0 ) LP_privkey_updates(mypeer,pubsock,passphrase,amclient); HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -174,7 +175,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) LP_peersquery(amclient,mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); } - if ( peer->numutxos > mypeer->numutxos ) + if ( peer->numutxos != mypeer->numutxos ) { lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; if ( lastn < 0 ) From f2666d809d35b1891e480131d4646aef884a7120 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 08:20:11 +0300 Subject: [PATCH 0951/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3316a162b..4b871c7f8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -178,7 +178,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( peer->numutxos != mypeer->numutxos ) { lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; - if ( lastn < 0 ) + if ( lastn < LP_PROPAGATION_SLACK * 2 ) lastn = LP_PROPAGATION_SLACK * 2; printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) From 6c3487a8eb926f767d0e567663a593a186a5f6a5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 08:25:33 +0300 Subject: [PATCH 0952/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/LP_utxos.c | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 4be342e24..e1d600b8c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -569,9 +569,9 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port subport = argport + 2; if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) { - if ( (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) + if ( 0 && (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) peer->numpeers = otherpeers; - if ( (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) + if ( 0 && (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) { printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer != 0 ? LP_mypeer->numutxos:0); peer->numutxos = othernumutxos; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 5340de818..1096fd338 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -136,7 +136,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { - struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + struct LP_peerinfo *peer,*destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; if ( amclient != 0 ) { printf("LP_utxosparse not for clientside\n"); @@ -167,14 +167,15 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs } } } - /*if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) + if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) { + destpeer->numutxos = n; if ( destpeer->numutxos < n ) { //destpeer->numutxos = n; //printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); } - }*/ + } } free_json(array); } From 371bb08502f7eb710340f0cf541ed2dbde9ed1bb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 08:28:30 +0300 Subject: [PATCH 0953/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 1096fd338..7a44196b9 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -191,7 +191,7 @@ void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock return; } peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); - if ( (peer != 0 && peer->errors > 0) || mypeer == 0 ) + if ( mypeer == 0 ) //(peer != 0 && peer->errors > 0) || return; if ( coin == 0 ) coin = ""; From 52d4190cfd166c980e41aa391bbb44a07d041936 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 08:45:45 +0300 Subject: [PATCH 0954/2705] Test --- iguana/coins/mesh_7776 | 2 +- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/tests/dexgetbalance | 2 +- iguana/tests/dexlistunspent | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/coins/mesh_7776 b/iguana/coins/mesh_7776 index 01d8dd737..bcccf8d8d 100755 --- a/iguana/coins/mesh_7776 +++ b/iguana/coins/mesh_7776 @@ -1 +1 @@ -curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"4d6bbfb6\",\"p2p\":8399,\"rpc\":8400,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"MESH.conf\",\"path\":\"${HOME#"/"}/.komodo/MESH\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"MESH\",\"name\":\"MESH\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"4d6bbfb6\",\"p2p\":9454,\"rpc\":9455,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4b871c7f8..e02714b2e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -114,8 +114,8 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_privkey_updates(mypeer,pubsock,passphrase,amclient); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) - LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer->ipaddr,myport,profitmargin); + if ( strcmp(peer->ipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) + LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } if ( amclient != 0 ) { diff --git a/iguana/tests/dexgetbalance b/iguana/tests/dexgetbalance index 77d8982af..f096618ee 100755 --- a/iguana/tests/dexgetbalance +++ b/iguana/tests/dexgetbalance @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getbalance\",\"address\":\"RHrAStvASzi5pJB6xqgmsVGD5AxxpAFzZ6\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"getbalance\",\"address\":\"RYZx1e7kVNTuQ6RTrvTkYeZAz5uJobC3pg\",\"symbol\":\"KMD\"}" diff --git a/iguana/tests/dexlistunspent b/iguana/tests/dexlistunspent index 0f6eb190f..4c06d2429 100755 --- a/iguana/tests/dexlistunspent +++ b/iguana/tests/dexlistunspent @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RVy1qgs2HRmXKWWawoqFSo3WGBkjC19cmJ\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RYZx1e7kVNTuQ6RTrvTkYeZAz5uJobC3pg\",\"symbol\":\"KMD\"}" From 59f04f5404f114a469f3433250038ab5bd918bf2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 08:57:43 +0300 Subject: [PATCH 0955/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index e1d600b8c..6ee80db40 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -503,8 +503,6 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port return(clonestr("{\"error\":\"need method in request\"}")); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) { - if ( (userpass= jstr(argjson,"userpass")) == 0 || strcmp(userpass,USERPASS) != 0 ) - return(clonestr("{\"error\":\"authentication error\"}")); if ( USERPASS_COUNTER == 0 ) { USERPASS_COUNTER = 1; @@ -512,6 +510,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port jaddstr(retjson,"userpass",USERPASS); return(jprint(retjson,1)); } + if ( (userpass= jstr(argjson,"userpass")) == 0 || strcmp(userpass,USERPASS) != 0 ) + return(clonestr("{\"error\":\"authentication error\"}")); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) { if ( strcmp(method,"setprice") == 0 ) From 1bbffbb0a90831ed48a1384acc1ce5bfd3dbc086 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 08:58:33 +0300 Subject: [PATCH 0956/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e02714b2e..977892321 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -78,7 +78,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) { - static uint16_t tmpport; + //static uint16_t tmpport; char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson; if ( amclient == 0 ) { @@ -98,10 +98,10 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_peersquery(amclient,mypeer,pubsock,default_LPnodes[i],myport,"127.0.0.1",myport,profitmargin); } } - if ( amclient != 0 ) - tmpport = myport + 10; - else tmpport = myport; - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&tmpport) != 0 ) + //if ( amclient != 0 ) + // tmpport = myport + 10; + //else tmpport = myport; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); From 1892d3f4bb60e874249e931572b9a0585c9f8b6f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:12:33 +0300 Subject: [PATCH 0957/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6ee80db40..977c201b4 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -534,14 +534,14 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } else return(clonestr("{\"error\":\"no price set\"}")); } } - else if ( IAMCLIENT != 0 && (coin= jstr(argjson,"coin")) != 0 ) + else if ( (coin= jstr(argjson,"coin")) != 0 ) { if ( strcmp(method,"inventory") == 0 ) { LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); return(LP_inventory(coin)); } - else if ( strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0 ) + else if ( IAMCLIENT != 0 && (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) { bits256 txid; int32_t vout; struct LP_utxoinfo *utxo; txid = jbits256(argjson,"txid"); From 0d1ee1a7a24065099ded17fe0a9b9fe102b9f400 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:14:06 +0300 Subject: [PATCH 0958/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7a44196b9..5f897a525 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -227,7 +227,7 @@ char *LP_inventory(char *symbol) struct LP_utxoinfo *utxo,*tmp; cJSON *array = cJSON_CreateArray(); HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { - if ( strcmp(symbol,utxo->coin) == 0 ) + if ( strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || strcmp(utxo->ipaddr,"127.0.0.1") != 0) ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } return(jprint(array,1)); From d24769d56b03d134cb814b8fef9965fbf4f47f8c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:15:50 +0300 Subject: [PATCH 0959/2705] Test --- iguana/exchanges/LP_utxos.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 5f897a525..68b9f3987 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -224,10 +224,13 @@ void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock char *LP_inventory(char *symbol) { - struct LP_utxoinfo *utxo,*tmp; cJSON *array = cJSON_CreateArray(); + struct LP_utxoinfo *utxo,*tmp; char *myipaddr; cJSON *array = cJSON_CreateArray(); + if ( LP_mypeer != 0 ) + myipaddr = LP_mypeer->ipaddr; + else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { - if ( strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || strcmp(utxo->ipaddr,"127.0.0.1") != 0) ) + if ( strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || strcmp(utxo->ipaddr,myipaddr) != 0) ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } return(jprint(array,1)); From 9797734042776a2fc4e609071f024432d5c3fad9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:16:18 +0300 Subject: [PATCH 0960/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 68b9f3987..22ba7fc2f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -230,7 +230,7 @@ char *LP_inventory(char *symbol) else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { - if ( strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || strcmp(utxo->ipaddr,myipaddr) != 0) ) + if ( strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || strcmp(utxo->ipaddr,myipaddr) == 0) ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } return(jprint(array,1)); From a3a465d625b7b57d9dd3128a6e0b3686c983fe11 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:20:54 +0300 Subject: [PATCH 0961/2705] Test --- iguana/exchanges/inv | 2 ++ iguana/exchanges/randval | 1 + iguana/exchanges/run | 2 ++ iguana/exchanges/userpass | 1 + 4 files changed, 6 insertions(+) create mode 100755 iguana/exchanges/inv create mode 100644 iguana/exchanges/randval create mode 100755 iguana/exchanges/run create mode 100644 iguana/exchanges/userpass diff --git a/iguana/exchanges/inv b/iguana/exchanges/inv new file mode 100755 index 000000000..b0b5e52b1 --- /dev/null +++ b/iguana/exchanges/inv @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"inventory\",\"coin\":\"KMD\"}" diff --git a/iguana/exchanges/randval b/iguana/exchanges/randval new file mode 100644 index 000000000..ca5c33f4d --- /dev/null +++ b/iguana/exchanges/randval @@ -0,0 +1 @@ +export randval="" diff --git a/iguana/exchanges/run b/iguana/exchanges/run new file mode 100755 index 000000000..c65b97bc8 --- /dev/null +++ b/iguana/exchanges/run @@ -0,0 +1,2 @@ +source randval +pkill -15 marketmaker; git pull; ./m_mm; ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\"}" & diff --git a/iguana/exchanges/userpass b/iguana/exchanges/userpass new file mode 100644 index 000000000..1a8a9ad5a --- /dev/null +++ b/iguana/exchanges/userpass @@ -0,0 +1 @@ +export userpass="" From c2c5c53ee44f2f7262471ce83f0ff0e7d2bf2796 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:22:32 +0300 Subject: [PATCH 0962/2705] Test --- iguana/exchanges/client | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 iguana/exchanges/client diff --git a/iguana/exchanges/client b/iguana/exchanges/client new file mode 100755 index 000000000..3ea2eecb8 --- /dev/null +++ b/iguana/exchanges/client @@ -0,0 +1,2 @@ +source randval +pkill -15 marketmaker; git pull; ./m_mm; ./marketmaker "{\"client\":1,\"passphrase\":\"$randval\"}" & From 5e1dbe509dadc010012a3cc93098d9361757dffc Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:25:12 +0300 Subject: [PATCH 0963/2705] Test --- iguana/exchanges/myprice | 2 ++ iguana/exchanges/setprice | 2 ++ 2 files changed, 4 insertions(+) create mode 100755 iguana/exchanges/myprice create mode 100755 iguana/exchanges/setprice diff --git a/iguana/exchanges/myprice b/iguana/exchanges/myprice new file mode 100755 index 000000000..cdb93dabc --- /dev/null +++ b/iguana/exchanges/myprice @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"myprice\",\"base\":\"REVS\",\"rel\":\"KMD\"}" diff --git a/iguana/exchanges/setprice b/iguana/exchanges/setprice new file mode 100755 index 000000000..e5a9c3c9c --- /dev/null +++ b/iguana/exchanges/setprice @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"setprice\",\"base\":\"REVS\",\"rel\":\"KMD\",\"price\":1.234}" From 85b76c06f5d41f9057780ab86b91ce6c3b2dcf87 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:31:36 +0300 Subject: [PATCH 0964/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/getpeers | 1 + iguana/exchanges/getprice | 1 + iguana/exchanges/orderbook | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) create mode 100755 iguana/exchanges/getpeers create mode 100755 iguana/exchanges/getprice create mode 100755 iguana/exchanges/orderbook diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 977c201b4..df8233d8e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -602,11 +602,11 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } } } - else if ( IAMCLIENT == 0 && strcmp(method,"getprice") == 0 ) + else if ( strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"orderbook") == 0 ) retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); - else if ( IAMCLIENT == 0 && strcmp(method,"getpeers") == 0 ) + else if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); diff --git a/iguana/exchanges/getpeers b/iguana/exchanges/getpeers new file mode 100755 index 000000000..93e7b9f8d --- /dev/null +++ b/iguana/exchanges/getpeers @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7779" --data "{\"method\":\"getpeers\"}" diff --git a/iguana/exchanges/getprice b/iguana/exchanges/getprice new file mode 100755 index 000000000..88e8e6502 --- /dev/null +++ b/iguana/exchanges/getprice @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7779" --data "{\"method\":\"myprice\",\"base\":\"REVS\",\"rel\":\"KMD\"}" diff --git a/iguana/exchanges/orderbook b/iguana/exchanges/orderbook new file mode 100755 index 000000000..8ed8b537f --- /dev/null +++ b/iguana/exchanges/orderbook @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7779" --data "{\"method\":\"orderbook\",\"base\":\"REVS\",\"rel\":\"KMD\"}" From 75883011bcb720f89b3fed52d7a0779195d68182 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:36:31 +0300 Subject: [PATCH 0965/2705] Test --- iguana/exchanges/getpeers | 3 ++- iguana/exchanges/getpeersIP | 10 ++++++++++ iguana/exchanges/getprice | 3 ++- iguana/exchanges/orderbook | 3 ++- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100755 iguana/exchanges/getpeersIP diff --git a/iguana/exchanges/getpeers b/iguana/exchanges/getpeers index 93e7b9f8d..32852ba6a 100755 --- a/iguana/exchanges/getpeers +++ b/iguana/exchanges/getpeers @@ -1 +1,2 @@ -curl --url "http://127.0.0.1:7779" --data "{\"method\":\"getpeers\"}" +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"getpeers\"}" diff --git a/iguana/exchanges/getpeersIP b/iguana/exchanges/getpeersIP new file mode 100755 index 000000000..feef2e5d8 --- /dev/null +++ b/iguana/exchanges/getpeersIP @@ -0,0 +1,10 @@ +curl --url "http://5.9.253.195:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.196:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.197:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.198:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.199:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.200:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.201:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.202:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.203:7779" --data "{\"method\":\"getpeers\"}" +curl --url "http://5.9.253.204:7779" --data "{\"method\":\"getpeers\"}" diff --git a/iguana/exchanges/getprice b/iguana/exchanges/getprice index 88e8e6502..4b9614be7 100755 --- a/iguana/exchanges/getprice +++ b/iguana/exchanges/getprice @@ -1 +1,2 @@ -curl --url "http://127.0.0.1:7779" --data "{\"method\":\"myprice\",\"base\":\"REVS\",\"rel\":\"KMD\"}" +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"getprice\",\"base\":\"REVS\",\"rel\":\"KMD\"}" diff --git a/iguana/exchanges/orderbook b/iguana/exchanges/orderbook index 8ed8b537f..4d2367a42 100755 --- a/iguana/exchanges/orderbook +++ b/iguana/exchanges/orderbook @@ -1 +1,2 @@ -curl --url "http://127.0.0.1:7779" --data "{\"method\":\"orderbook\",\"base\":\"REVS\",\"rel\":\"KMD\"}" +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"orderbook\",\"base\":\"REVS\",\"rel\":\"KMD\"}" From 058d2677dc9ee1d01466f26d2ae3a939293cdd62 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:43:49 +0300 Subject: [PATCH 0966/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 977892321..24bf9d0c6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -124,15 +124,6 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i nonz = n = 0; if ( (++counter % 3600) == 0 ) LP_privkey_updates(mypeer,pubsock,passphrase,amclient); - if ( (counter % 500) == 0 ) - { - HASH_ITER(hh,LP_utxoinfos,utxo,utmp) - { - if ( strcmp(utxo->coin,"KMD") == 0 ) - LP_priceping(pubsock,utxo,"BTC",profitmargin); - else LP_priceping(pubsock,utxo,"KMD",profitmargin); - } - } HASH_ITER(hh,LP_peerinfos,peer,tmp) { n++; @@ -166,6 +157,15 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i nonz = 0; if ( (++counter % 2000) == 0 ) LP_privkey_updates(mypeer,pubsock,passphrase,amclient); + if ( (counter % 500) == 0 ) + { + HASH_ITER(hh,LP_utxoinfos,utxo,utmp) + { + if ( strcmp(utxo->coin,"KMD") == 0 ) + LP_priceping(pubsock,utxo,"BTC",profitmargin); + else LP_priceping(pubsock,utxo,"KMD",profitmargin); + } + } HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0 ) From 9599b64ccd503f2147c3a5e39dac2bd6d157a151 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:46:59 +0300 Subject: [PATCH 0967/2705] Test --- iguana/exchanges/client | 2 +- iguana/exchanges/run | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 3ea2eecb8..fe29cc7ce 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; ./m_mm; ./marketmaker "{\"client\":1,\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; ../m_mm; ../marketmaker "{\"client\":1,\"passphrase\":\"$randval\"}" & diff --git a/iguana/exchanges/run b/iguana/exchanges/run index c65b97bc8..9ee0a2690 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; ./m_mm; ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; ../m_mm; ../marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\"}" & From abcf1f1c125c9e9dc0d7a1dfe0a94f448d9d9433 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 09:48:06 +0300 Subject: [PATCH 0968/2705] Test --- iguana/exchanges/client | 2 +- iguana/exchanges/run | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index fe29cc7ce..261b1d36a 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; ../m_mm; ../marketmaker "{\"client\":1,\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"passphrase\":\"$randval\"}" & diff --git a/iguana/exchanges/run b/iguana/exchanges/run index 9ee0a2690..ccc62231a 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; ../m_mm; ../marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\"}" & From 505b7f7d8db58ab1fdf9ea0ed251bc78bdc8bc10 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 10:07:46 +0300 Subject: [PATCH 0969/2705] Test --- iguana/coins/jumblr_osx | 3 +++ iguana/coins/revs_osx | 3 +++ 2 files changed, 6 insertions(+) create mode 100755 iguana/coins/jumblr_osx create mode 100755 iguana/coins/revs_osx diff --git a/iguana/coins/jumblr_osx b/iguana/coins/jumblr_osx new file mode 100755 index 000000000..dd50b1842 --- /dev/null +++ b/iguana/coins/jumblr_osx @@ -0,0 +1,3 @@ +/Applications/komodoOSX.app/Contents/komodod -ac_name=JUMBLR -ac_supply=999999 -addnode=78.47.196.146 & +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"JUMBLR.conf\",\"path\":\"/${HOME#"/"}/Library/Application\ Support/Komodo/JUMBLR\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"JUMBLR\",\"name\":\"JUMBLR\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7223759e\",\"p2p\":15105,\"rpc\":15106,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" + diff --git a/iguana/coins/revs_osx b/iguana/coins/revs_osx new file mode 100755 index 000000000..c98b4fabb --- /dev/null +++ b/iguana/coins/revs_osx @@ -0,0 +1,3 @@ +/Applications/komodoOSX.app/Contents/komodod -ac_name=REVS -ac_supply=1300000 -addnode=78.47.196.146 & +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"REVS.conf\",\"path\":\"/${HOME#"/"}/Library/Application\ Support/Komodo/REVS\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"REVS\",\"name\":\"REVS\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"905c3498\",\"p2p\":10195,\"rpc\":10196,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" + From 55188bb4753cfe4bc9866bd470fbc22aedfb3e38 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 10:18:05 +0300 Subject: [PATCH 0970/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 10 ++++++---- iguana/exchanges/mm.c | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 24bf9d0c6..498308c9f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -27,8 +27,8 @@ struct LP_utxoinfo *LP_utxoinfos; struct LP_peerinfo *LP_peerinfos,*LP_mypeer; char *activecoins[] = { "BTC", "KMD", "REVS", "JUMBLR" };//"LTC", "USD", }; -char GLOBAL_DBDIR[] = "DB"; -char USERPASS[65],USERPASS_WIFSTR[64]; +char GLOBAL_DBDIR[] = { "DB" }; +char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", @@ -56,7 +56,7 @@ void tradebot_pendingadd(cJSON *tradejson,char *base,double basevolume,char *rel } char *LP_getdatadir() { - return("/root"); + return(USERHOME); } char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip) @@ -229,12 +229,14 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } } -void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient) +void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome) { char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128]; IAMCLIENT = amclient; OS_randombytes((void *)&n,sizeof(n)); srand((int32_t)n); + if ( userhome != 0 && userhome[0] != 0 ) + safecopy(USERHOME,userhome,sizeof(USERHOME)); portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); portable_mutex_init(&LP_commandmutex); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 24294466b..b2baba05e 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -811,7 +811,7 @@ void LP_main(void *ptr) if ( (passphrase= jstr(argjson,"passphrase")) != 0 ) { profitmargin = jdouble(argjson,"profitmargin"); - LPinit(7779,7780,7781,profitmargin,passphrase,jint(argjson,"client")); + LPinit(7779,7780,7781,profitmargin,passphrase,jint(argjson,"client"),jstr(argjson,"userhome")); } } From 7a1129a3a7e463556aef057ed1d064c709268b6e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 10:26:29 +0300 Subject: [PATCH 0971/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 498308c9f..e31d540f8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -135,7 +135,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypubport)) != 0 ) { - //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); From 725b938cdc148c1aab93daa3a55f4573095c2d7a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 10:30:41 +0300 Subject: [PATCH 0972/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e31d540f8..aad9241a2 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -133,7 +133,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { portable_mutex_lock(&LP_commandmutex); - if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypubport)) != 0 ) + if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); @@ -190,7 +190,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { portable_mutex_lock(&LP_commandmutex); - if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypubport)) != 0 ) + if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); @@ -211,7 +211,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i portable_mutex_lock(&LP_commandmutex); if ( LP_command(mypeer,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) == 0 ) { - if ( (retstr= stats_JSON(argjson,"127.0.0.1",mypubport)) != 0 ) + if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); From 2b14c3f9bc6d08bdd4489c053cfddd9c46acd0c2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 10:33:37 +0300 Subject: [PATCH 0973/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index aad9241a2..8db037e1e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -161,9 +161,12 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { - if ( strcmp(utxo->coin,"KMD") == 0 ) - LP_priceping(pubsock,utxo,"BTC",profitmargin); - else LP_priceping(pubsock,utxo,"KMD",profitmargin); + if ( strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port ) + { + if ( strcmp(utxo->coin,"KMD") == 0 ) + LP_priceping(pubsock,utxo,"BTC",profitmargin); + else LP_priceping(pubsock,utxo,"KMD",profitmargin); + } } } HASH_ITER(hh,LP_peerinfos,peer,tmp) From c44cbd28df6f4e6ab5163341041782ff9b065544 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 10:39:49 +0300 Subject: [PATCH 0974/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- iguana/exchanges/LP_prices.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 8db037e1e..95b94fdd2 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -135,7 +135,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); @@ -195,7 +195,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); @@ -216,7 +216,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } } diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index aa3df855b..b18794fe7 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -288,11 +288,11 @@ static int _cmp_orderbookrev(const void *a,const void *b) cJSON *LP_orderbookjson(struct LP_cacheinfo *ptr,int32_t polarity) { - double price,volume; cJSON *item = cJSON_CreateObject(); - if ( (price= ptr->price) != 0. && (volume= dstr(ptr->Q.satoshis)) != 0. ) + double price; cJSON *item = cJSON_CreateObject(); + if ( (price= ptr->price) != 0. ) { jaddnum(item,"price",polarity > 0 ? price : 1. / price); - jaddnum(item,"volume",polarity > 0 ? volume : volume / price); + jaddnum(item,"volume",polarity > 0 ? dstr(ptr->Q.satoshis) : dstr(ptr->Q.destsatoshis)); jaddbits256(item,"txid",ptr->Q.txid); jaddnum(item,"vout",ptr->Q.vout); } @@ -323,13 +323,13 @@ char *LP_orderbook(char *base,char *rel) if ( numbids > 1 ) qsort(bids,numbids,sizeof(*bids),_cmp_orderbook); for (i=0; i 1 ) qsort(asks,numasks,sizeof(*asks),_cmp_orderbookrev); for (i=0; i Date: Sat, 3 Jun 2017 10:47:50 +0300 Subject: [PATCH 0975/2705] Test --- iguana/exchanges/LP_coins.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 3ea9332d9..f397ee075 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -72,12 +72,28 @@ void LP_statefname(char *fname,char *symbol,char *assetname,char *str) strcat(fname,"/"); #endif if ( strcmp(symbol,"BTC") == 0 ) + { +#ifdef __APPLE__ + strcat(fname,"Bitcoin"); +#else strcat(fname,".bitcoin"); +#endif + } else if ( strcmp(symbol,"LTC") == 0 ) + { +#ifdef __APPLE__ + strcat(fname,"Litecoin"); +#else strcat(fname,".litecoin"); +#endif + } else { +#ifdef __APPLE__ + strcat(fname,"Komodo"); +#else strcat(fname,".komodo"); +#endif if ( strcmp(symbol,"KMD") != 0 ) { #ifdef WIN32 From 8ac57c2d15de2f5c1888fddf5476845c76af91bc Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 10:55:27 +0300 Subject: [PATCH 0976/2705] Test --- iguana/exchanges/LP_prices.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index b18794fe7..6f202c070 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -289,8 +289,9 @@ static int _cmp_orderbookrev(const void *a,const void *b) cJSON *LP_orderbookjson(struct LP_cacheinfo *ptr,int32_t polarity) { double price; cJSON *item = cJSON_CreateObject(); - if ( (price= ptr->price) != 0. ) + if ( ptr->Q.satoshis != 0 && ptr->Q.destsatoshis != 0 ) { + price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; jaddnum(item,"price",polarity > 0 ? price : 1. / price); jaddnum(item,"volume",polarity > 0 ? dstr(ptr->Q.satoshis) : dstr(ptr->Q.destsatoshis)); jaddbits256(item,"txid",ptr->Q.txid); From 64bae2be42b1e3c608afb78f7600995de013333f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 10:59:15 +0300 Subject: [PATCH 0977/2705] Test --- iguana/exchanges/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index b2baba05e..c69d170f0 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -836,7 +836,7 @@ int main(int argc, const char * argv[]) free(retstr); } incr = 100.; - while ( IAMCLIENT != 0 ) + while ( (0) && IAMCLIENT != 0 ) { theoretical = marketmaker_updateprice("komodo","REVS","KMD",theoretical,&incr); sleep(3); From 4ece3f0834db9bd2e4f043d74d2a149217d48c45 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 11:00:52 +0300 Subject: [PATCH 0978/2705] Test --- iguana/exchanges/LP_prices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 6f202c070..d7b29804b 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -322,13 +322,13 @@ char *LP_orderbook(char *base,char *rel) retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); if ( numbids > 1 ) - qsort(bids,numbids,sizeof(*bids),_cmp_orderbook); + qsort(bids,numbids,sizeof(*bids),_cmp_orderbookrev); for (i=0; i 1 ) - qsort(asks,numasks,sizeof(*asks),_cmp_orderbookrev); + qsort(asks,numasks,sizeof(*asks),_cmp_orderbook); for (i=0; i Date: Sat, 3 Jun 2017 11:05:41 +0300 Subject: [PATCH 0979/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- iguana/exchanges/LP_prices.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 95b94fdd2..79be79a61 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -36,7 +36,7 @@ portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; int32_t LP_mypubsock = -1; int32_t Client_connections; int32_t USERPASS_COUNTER,IAMCLIENT = 0; - +double LP_profitratio = 1.; // stubs int32_t basilisk_istrustedbob(struct basilisk_swap *swap) @@ -236,6 +236,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128]; IAMCLIENT = amclient; + LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); srand((int32_t)n); if ( userhome != 0 && userhome[0] != 0 ) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index d7b29804b..11fe76813 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -144,8 +144,8 @@ int32_t LP_mypriceset(char *base,char *rel,double price) struct LP_priceinfo *basepp,*relpp; if ( price != 0. && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { - basepp->myprices[relpp->ind] = price; // ask - relpp->myprices[basepp->ind] = 1. / price; // bid + basepp->myprices[relpp->ind] = price * LP_profitratio; // ask + relpp->myprices[basepp->ind] = (1. / price) * LP_profitratio; // bid return(0); } else return(-1); } From 038d1a019d74f596c3a707166c5a3d145762a433 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 11:25:31 +0300 Subject: [PATCH 0980/2705] Test --- iguana/exchanges/autotrade | 2 ++ iguana/exchanges/candidates | 2 ++ 2 files changed, 4 insertions(+) create mode 100755 iguana/exchanges/autotrade create mode 100755 iguana/exchanges/candidates diff --git a/iguana/exchanges/autotrade b/iguana/exchanges/autotrade new file mode 100755 index 000000000..8c68b61d0 --- /dev/null +++ b/iguana/exchanges/autotrade @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"candidates\",\"txid\":\"\",\"vout\":0,\"coin\":\"REVS\",\"maxprice\":1.5}" diff --git a/iguana/exchanges/candidates b/iguana/exchanges/candidates new file mode 100755 index 000000000..ae72e206a --- /dev/null +++ b/iguana/exchanges/candidates @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"candidates\",\"txid\":\"\",\"vout\":0,\"coin\":\"REVS\"}" From b9c86dfaeab0db5860f4c1d3cd7f816604692499 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 11:31:20 +0300 Subject: [PATCH 0981/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index df8233d8e..bb4ea07d7 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -233,9 +233,9 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) if ( (price= LP_price(base,myutxo->coin)) == .0 ) return(0); estimatedbase = myutxo->satoshis / price; + printf("%s -> %s price %.8f mysatoshis %llu estimated base %llu\n",base,myutxo->coin,price,(long long)myutxo->satoshis,(long long)estimatedbase); if ( estimatedbase <= 0 ) return(0); - //printf("%s -> %s price %.8f mysatoshis %llu estimated base %llu\n",base,myutxo->coin,price,(long long)myutxo->satoshis,(long long)estimatedbase); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) From 9d5f9f2693253f8fe454a98be2923eec6396b113 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 11:33:05 +0300 Subject: [PATCH 0982/2705] Test --- iguana/exchanges/LP_commands.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bb4ea07d7..bafe82548 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -231,7 +231,10 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase; if ( (price= LP_price(base,myutxo->coin)) == .0 ) + { + printf("no LP_price\n"); return(0); + } estimatedbase = myutxo->satoshis / price; printf("%s -> %s price %.8f mysatoshis %llu estimated base %llu\n",base,myutxo->coin,price,(long long)myutxo->satoshis,(long long)estimatedbase); if ( estimatedbase <= 0 ) From cde872a56fd2de4d594a91f3abe3403d05dbb8cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 11:37:58 +0300 Subject: [PATCH 0983/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bafe82548..36b7c81d2 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -232,7 +232,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase; if ( (price= LP_price(base,myutxo->coin)) == .0 ) { - printf("no LP_price\n"); + printf("no LP_price (%s -> %s)\n",base,myutxo->coin); return(0); } estimatedbase = myutxo->satoshis / price; @@ -583,7 +583,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } else LP_addpeer(amclient,LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); } } - printf("CMD.(%s)\n",jprint(argjson,0)); + //printf("CMD.(%s)\n",jprint(argjson,0)); if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quotereceived(argjson); else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) From 56033e0a90b66e8c8e56b99279ac993a277ecebd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 11:46:06 +0300 Subject: [PATCH 0984/2705] Test --- iguana/exchanges/LP_commands.c | 2 ++ iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 36b7c81d2..8474c5e0b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -511,6 +511,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port USERPASS_COUNTER = 1; retjson = cJSON_CreateObject(); jaddstr(retjson,"userpass",USERPASS); + jaddstr(retjson,"BTC",BTCADDR); + jaddstr(retjson,"KMD",KMDADDR); return(jprint(retjson,1)); } if ( (userpass= jstr(argjson,"userpass")) == 0 || strcmp(userpass,USERPASS) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 79be79a61..dbda8d683 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -28,7 +28,7 @@ struct LP_peerinfo *LP_peerinfos,*LP_mypeer; char *activecoins[] = { "BTC", "KMD", "REVS", "JUMBLR" };//"LTC", "USD", }; char GLOBAL_DBDIR[] = { "DB" }; -char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; +char USERPASS[65],USERPASS_WIFSTR[64],BTCADDR[64],KMDADDR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 22ba7fc2f..b10a7d93f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -278,6 +278,10 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); iguana_priv2pub(pubkey33,coinaddr,privkey,coin->pubtype); + if ( strcmp("BTC",symbol) == 0 ) + strcpy(BTCADDR,coinaddr); + else if ( strcmp("KMD",symbol) == 0 ) + strcpy(KMDADDR,coinaddr); if ( counter == 0 ) { char tmpstr[128]; From 93184292f8b0c09183620bb7ec87c080b56f8835 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 3 Jun 2017 13:22:58 +0300 Subject: [PATCH 0985/2705] Test --- iguana/exchanges/LP_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 8474c5e0b..824008714 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -252,6 +252,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) for (i=0; i Date: Sat, 3 Jun 2017 13:25:58 +0300 Subject: [PATCH 0986/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 824008714..5ea2e6d08 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -252,7 +252,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) for (i=0; i Date: Sun, 4 Jun 2017 11:32:41 +0300 Subject: [PATCH 0987/2705] Test --- iguana/exchanges/LP_commands.c | 5 ++--- iguana/exchanges/autotrade | 2 +- iguana/exchanges/candidates | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 5ea2e6d08..023272a96 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -300,7 +300,6 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) if ( (price= jdouble(item,"price")) == 0. ) { LP_quoteparse(&Q[i],item); - //char str[65]; printf("i.%d of %d: (%s) -> txid.%s\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid)); price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,zero); if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"satoshis")/Q[i].destsatoshis > price ) { @@ -310,7 +309,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; - //printf("i.%d price %.8f bestprice %.8f: (%s)\n",i,price,bestprice,jprint(item,0)); + char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice); } if ( bestprice != 0. ) { @@ -498,7 +497,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin return(retval); } -// add orderbook api +// addcoin api char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { diff --git a/iguana/exchanges/autotrade b/iguana/exchanges/autotrade index 8c68b61d0..d519ab735 100755 --- a/iguana/exchanges/autotrade +++ b/iguana/exchanges/autotrade @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"candidates\",\"txid\":\"\",\"vout\":0,\"coin\":\"REVS\",\"maxprice\":1.5}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"candidates\",\"txid\":\"$1\",\"vout\":$2,\"coin\":\"REVS\",\"maxprice\":$3}" diff --git a/iguana/exchanges/candidates b/iguana/exchanges/candidates index ae72e206a..ec3e2c1a1 100755 --- a/iguana/exchanges/candidates +++ b/iguana/exchanges/candidates @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"candidates\",\"txid\":\"\",\"vout\":0,\"coin\":\"REVS\"}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"candidates\",\"txid\":\"$1\",\"vout\":$2,\"coin\":\"REVS\"}" From f5b6f7c8e72cb91343ee4bab6946c32e242c7df3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 11:36:31 +0300 Subject: [PATCH 0988/2705] Test --- iguana/exchanges/LP_commands.c | 1 + iguana/exchanges/autotrade | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 023272a96..9e084f325 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -290,6 +290,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) maxprice = LP_price(base,myutxo->coin) / 0.975; if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { + printf("candidates.(%s)\n",jprint(array,0)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); diff --git a/iguana/exchanges/autotrade b/iguana/exchanges/autotrade index d519ab735..c24a0a89a 100755 --- a/iguana/exchanges/autotrade +++ b/iguana/exchanges/autotrade @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"candidates\",\"txid\":\"$1\",\"vout\":$2,\"coin\":\"REVS\",\"maxprice\":$3}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"autotrade\",\"txid\":\"$1\",\"vout\":$2,\"coin\":\"REVS\",\"maxprice\":$3}" From bc023bc8d6660b6a358452bdda64aa2279ebf925 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 13:06:13 +0300 Subject: [PATCH 0989/2705] Test --- iguana/exchanges/LP_commands.c | 49 +++++++++++++++++----------- iguana/exchanges/LP_transaction.c | 53 ++++++++++++++++--------------- 2 files changed, 58 insertions(+), 44 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9e084f325..fba1e4444 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -498,6 +498,34 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin return(retval); } +char *LP_connected(cJSON *argjson) +{ + cJSON *retjson; int32_t pairsock = -1; char *pairstr; struct LP_quoteinfo *qp; int32_t DEXselector = 0; + retjson = cJSON_CreateObject(); + if ( IAMCLIENT == 0 ) + jaddstr(retjson,"result","update stats"); + else + { + if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) + jaddstr(retjson,"error","couldnt create pairsock"); + else if ( nn_connect(pairsock,pairstr) >= 0 ) + { + qp = calloc(1,sizeof(*qp)); + LP_quoteparse(qp,argjson); + qp->pair = pairsock; + qp->privkey = LP_privkey(qp->destaddr); + LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis,qp->destcoin,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); + printf("alice pairstr.(%s)\n",pairstr); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)qp) == 0 ) + { + jaddstr(retjson,"result","success"); + jadd(retjson,"trade",LP_quotejson(qp)); + } else jaddstr(retjson,"error","couldnt aliceloop"); + } + } + return(jprint(retjson,1)); +} + // addcoin api char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port @@ -589,25 +617,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port //printf("CMD.(%s)\n",jprint(argjson,0)); if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quotereceived(argjson); - else if ( IAMCLIENT != 0 && strcmp(method,"connected") == 0 ) - { - int32_t pairsock = -1; char *pairstr; - if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) - printf("error creating pairsock\n"); - else if ( nn_connect(pairsock,pairstr) >= 0 ) - { - struct LP_quoteinfo *qp; int32_t DEXselector = 0; - qp = calloc(1,sizeof(*qp)); - LP_quoteparse(qp,argjson); - qp->pair = pairsock; - qp->privkey = LP_privkey(qp->destaddr); - LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis,qp->destcoin,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); - printf("alice pairstr.(%s)\n",pairstr); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)qp) == 0 ) - { - } - } - } + else if ( strcmp(method,"connected") == 0 ) + retstr = LP_connected(argjson); else if ( strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"orderbook") == 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 63ca5beee..2e710b7af 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1163,7 +1163,8 @@ int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) { - int32_t j; //char str[65]; + int32_t j; char coinaddr[64]; + bitcoin_address(coinaddr,swap->bobcoin.pubtype,swap->changermd160,20); if ( genflag != 0 && swap->I.iambob == 0 ) printf("basilisk_bobscripts_set WARNING: alice generating BOB tx\n"); if ( depositflag == 0 ) @@ -1176,7 +1177,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); if ( genflag != 0 && bits256_nonz(*(bits256 *)swap->I.secretBn256) != 0 && swap->bobpayment.I.datalen == 0 ) { - basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); + basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); if ( swap->bobpayment.I.spendlen == 0 || swap->bobpayment.I.datalen == 0 ) { printf("error bob generating %p payment.%d\n",swap->bobpayment.txbytes,swap->bobpayment.I.spendlen); @@ -1209,7 +1210,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) { - basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); + basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); if ( swap->bobdeposit.I.datalen == 0 || swap->bobdeposit.I.spendlen == 0 ) { printf("error bob generating %p deposit.%d\n",swap->bobdeposit.txbytes,swap->bobdeposit.I.spendlen); @@ -1291,38 +1292,40 @@ int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_r void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) { + int32_t i; char coinaddr[64]; alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); - basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0); + for (i=0; i<33; i++) + printf("%02x",swap->persistent_pubkey33[i]); + printf(" pubkey33, "); + for (i=0; i<20; i++) + printf("%02x",swap->changermd160[i]); + printf(" rmd160, "); + bitcoin_address(coinaddr,coin->pubtype,swap->changermd160,20); + printf("%s\n",coinaddr); + basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); } int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { - int32_t i,retval = -1; - printf("alicetxs\n"); - for (i=0; i<3; i++) + char coinaddr[64]; int32_t i,retval = -1; + if ( swap->alicepayment.I.datalen == 0 ) + basilisk_alicepayment(swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); + if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) + printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); + else { - if ( swap->alicepayment.I.datalen == 0 ) - basilisk_alicepayment(swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); - if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) - { - printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); - sleep(20); - } - else - { - retval = 0; - for (i=0; ialicepayment.I.datalen; i++) - printf("%02x",swap->alicepayment.txbytes[i]); - printf(" ALICE PAYMENT created\n"); - LP_unspents_mark(swap->alicecoin.symbol,swap->alicepayment.vins); - //basilisk_txlog(swap,&swap->alicepayment,-1); - break; - } + retval = 0; + for (i=0; ialicepayment.I.datalen; i++) + printf("%02x",swap->alicepayment.txbytes[i]); + printf(" ALICE PAYMENT created\n"); + LP_unspents_mark(swap->alicecoin.symbol,swap->alicepayment.vins); + //basilisk_txlog(swap,&swap->alicepayment,-1); } if ( swap->myfee.I.datalen == 0 ) { //printf("generate fee\n"); - if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,0) == 0 ) + bitcoin_address(coinaddr,swap->alicecoin.pubtype,swap->changermd160,20); + if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr) == 0 ) { swap->I.statebits |= LP_swapdata_rawtxsend(pairsock,swap,0x80,data,maxlen,&swap->myfee,0x40,0); LP_unspents_mark(swap->I.iambob!=0?swap->bobcoin.symbol:swap->alicecoin.symbol,swap->myfee.vins); From 9ab45e5117b4a3ab9b6206a0b16ca6070fe2fb14 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 13:12:19 +0300 Subject: [PATCH 0990/2705] Test --- iguana/exchanges/LP_commands.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index fba1e4444..8b7eac1a6 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -298,9 +298,9 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) for (i=0; icoin,zero); if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"satoshis")/Q[i].destsatoshis > price ) { @@ -321,9 +321,11 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) if ( (price= prices[i]) != 0. && Q[i].destsatoshis != 0 ) { metric = price / bestprice; + printf("%f ",metric); if ( metric > 0.9 ) { metric = Q[i].destsatoshis / metric * metric * metric; + printf("%f, ",metric); if ( metric > bestmetric ) { besti = i; @@ -332,12 +334,15 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) } } } + printf("metrics, best %f\n",bestmetric); if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) { - item = jitem(array,besti); i = besti; + bestprice = prices[i]; + item = jitem(array,i); bestitem = LP_quotejson(&Q[i]); - if ( bestprice <= maxprice ) + printf("bestprice %f vs maxprice %f\n",bestprice,maxprice); + if ( maxprice == 0. || bestprice <= maxprice ) { Q[i].desttxid = myutxo->txid; Q[i].destvout = myutxo->vout; @@ -347,7 +352,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); - jaddnum(bestitem,"price",prices[besti]); + jaddnum(bestitem,"price",prices[i]); if ( price <= maxprice ) { Q[i].desttxid = myutxo->txid; From d90cd5c9a98b325dd576cc5604276ca6625b373e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 13:27:46 +0300 Subject: [PATCH 0991/2705] Test --- iguana/exchanges/LP_remember.c | 8 ++++---- iguana/exchanges/LP_transaction.c | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 0871e1fdd..bf9d34b82 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -630,7 +630,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } for (j=0; j<32; j++) rev.bytes[j] = myprivs[0].bytes[31 - j]; - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr,1)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } @@ -655,7 +655,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0,bobdepositaddr)) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0,bobdepositaddr,1)) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } @@ -731,7 +731,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0,bobpaymentaddr)) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0,bobpaymentaddr,1)) != 0 ) { int32_t z; for (z=0; z<20; z++) @@ -761,7 +761,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0,bobdepositaddr)) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0,bobdepositaddr,1)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 2e710b7af..f891f25bd 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -557,9 +557,9 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t return(complete); } -char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr) +char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr,int32_t suppress_pubkeys) { - char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1,suppress_pubkeys=1; struct vin_info V[16]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; + char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1; struct vin_info V[16]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -658,12 +658,12 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); else if ( completed == 0 ) { - printf("incomplete signing %s (%s)\n",name,jprint(vins,0)); + printf("incomplete signing suppress.%d %s (%s)\n",suppress_pubkeys,name,jprint(vins,0)); if ( signedtx != 0 ) free(signedtx), signedtx = 0; } else printf("%s -> %s\n",name,bits256_str(str,*signedtxidp)); free(rawtxbytes); - } else printf("error making rawtx\n"); + } else printf("error making rawtx suppress.%d\n",suppress_pubkeys); free_json(privkeys); free_json(txobj); return(signedtx); @@ -683,7 +683,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -722,7 +722,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -778,7 +778,7 @@ char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2sht for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ txfee = LP_txfee(symbol); - signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr); + signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr,0); } return(signedtx); } @@ -1301,7 +1301,7 @@ void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,s printf("%02x",swap->changermd160[i]); printf(" rmd160, "); bitcoin_address(coinaddr,coin->pubtype,swap->changermd160,20); - printf("%s\n",coinaddr); + printf("%s suppress.%d fee.%d\n",coinaddr,alicepayment->I.suppress_pubkeys,swap->myfee.I.suppress_pubkeys); basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); } From 6cde3ced014d1cc8d5b0e78b1b698bb942b7f556 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 13:45:06 +0300 Subject: [PATCH 0992/2705] Test --- iguana/exchanges/LP_swap.c | 5 ++++- iguana/exchanges/LP_transaction.c | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 5d4a085d8..1fa5d4725 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -406,12 +406,13 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i { if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { - printf("received %d bytes\n",datalen); + printf("wait for got.%d\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); return(retval); } else printf("error nn_recv\n"); } + printf("waitfor timedout\n"); return(retval); } @@ -551,6 +552,7 @@ void LP_bobloop(void *_utxo) printf("error bobscripts payment\n"); else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) printf("error sending bobpayment\n"); + printf("looping on swaplist\n"); while ( 1 ) { if ( (retstr= basilisk_swaplist()) != 0 ) @@ -598,6 +600,7 @@ void LP_aliceloop(void *_qp) printf("error sending alicepayment\n"); else if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobpayment) < 0 ) printf("error waiting for bobpayment\n"); + printf("looping on swaplist\n"); while ( 1 ) { if ( (retstr= basilisk_swaplist()) != 0 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index f891f25bd..c25628476 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1443,17 +1443,17 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da memcpy(swap->I.userdata_aliceclaim,userdata,len); swap->I.userdata_aliceclaimlen = len; retval = 0; - //if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) { for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); printf(" <- bobdeposit\n"); - //for (i=0; ialiceclaim.I.datalen; i++) - // printf("%02x",swap->aliceclaim.txbytes[i]); - //printf(" <- aliceclaim\n"); + for (i=0; ialiceclaim.I.datalen; i++) + printf("%02x",swap->aliceclaim.txbytes[i]); + printf(" <- aliceclaim\n"); //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); return(retval); - } //else printf("error signing aliceclaim\n"); + } else printf("error signing aliceclaim\n"); } printf("error with bobdeposit\n"); return(retval); From 477f14c313acc9f4c7a5ce2f2f57c76902f1d1d8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 14:00:47 +0300 Subject: [PATCH 0993/2705] Test --- iguana/exchanges/LP_swap.c | 30 ++++++++++++++++++------------ iguana/exchanges/LP_transaction.c | 5 ++++- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 1fa5d4725..b6e91d625 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -552,15 +552,18 @@ void LP_bobloop(void *_utxo) printf("error bobscripts payment\n"); else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) printf("error sending bobpayment\n"); - printf("looping on swaplist\n"); - while ( 1 ) + else { - if ( (retstr= basilisk_swaplist()) != 0 ) + printf("looping on swaplist\n"); + while ( 1 ) { - printf("%s\n",retstr); - free(retstr); + if ( (retstr= basilisk_swaplist()) != 0 ) + { + printf("%s\n",retstr); + free(retstr); + } + sleep(100); } - sleep(100); } } basilisk_swap_finished(swap); @@ -600,15 +603,18 @@ void LP_aliceloop(void *_qp) printf("error sending alicepayment\n"); else if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobpayment) < 0 ) printf("error waiting for bobpayment\n"); - printf("looping on swaplist\n"); - while ( 1 ) + else { - if ( (retstr= basilisk_swaplist()) != 0 ) + printf("looping on swaplist\n"); + while ( 1 ) { - printf("%s\n",retstr); - free(retstr); + if ( (retstr= basilisk_swaplist()) != 0 ) + { + printf("%s\n",retstr); + free(retstr); + } + sleep(100); } - sleep(100); } } basilisk_swap_finished(swap); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index c25628476..193c20475 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -720,6 +720,9 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ bitcoin_address(changeaddr,pubtype,changermd160,20); printf("changeaddr.(%s)\n",changeaddr); } + for (iter=0; iter<33; iter++) + printf("%02x",rawtx->I.pubkey33[iter]); + printf(" pubkey33.%s, suppress.%d\n",rawtx->name,rawtx->I.suppress_pubkeys); for (iter=0; iter<2; iter++) { if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) @@ -1453,7 +1456,7 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da printf(" <- aliceclaim\n"); //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); return(retval); - } else printf("error signing aliceclaim\n"); + } else printf("error signing aliceclaim suppress.%d vin.(%s)\n",swap->aliceclaim.I.suppress_pubkeys,swap->bobdeposit.I.destaddr); } printf("error with bobdeposit\n"); return(retval); From 809c59831813259bbc421670449ee38259f32450 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 14:08:49 +0300 Subject: [PATCH 0994/2705] Test --- iguana/exchanges/LP_prices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 11fe76813..319c91ed8 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -144,8 +144,8 @@ int32_t LP_mypriceset(char *base,char *rel,double price) struct LP_priceinfo *basepp,*relpp; if ( price != 0. && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { - basepp->myprices[relpp->ind] = price * LP_profitratio; // ask - relpp->myprices[basepp->ind] = (1. / price) * LP_profitratio; // bid + basepp->myprices[relpp->ind] = price; // ask + relpp->myprices[basepp->ind] = (1. / price); // bid return(0); } else return(-1); } From c4ea4ef0537bc2bc454a23c4a9f4a07aff7a7b55 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 14:20:21 +0300 Subject: [PATCH 0995/2705] Test --- iguana/exchanges/LP_transaction.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 193c20475..fafabb418 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1443,6 +1443,11 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da swap->depositunconf = 1; basilisk_dontforget_update(swap,&swap->bobdeposit); len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); + for (i=0; ibobdeposit.I.redeemlen; i++) + printf("%02x",swap->bobdeposit.redeemscript[i]); + printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); memcpy(swap->I.userdata_aliceclaim,userdata,len); swap->I.userdata_aliceclaimlen = len; retval = 0; @@ -1489,6 +1494,11 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da for (i=0; i<32; i++) revAm.bytes[i] = swap->I.privAm.bytes[31-i]; len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); + for (i=0; ibobpayment.I.redeemlen; i++) + printf("%02x",swap->bobpayment.redeemscript[i]); + printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); memcpy(swap->I.userdata_alicespend,userdata,len); swap->I.userdata_alicespendlen = len; retval = 0; @@ -1504,7 +1514,7 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da swap->I.alicespent = 1; //basilisk_txlog(swap,&swap->alicespend,-1); return(retval); - } + } else printf("error signing aliceclaim suppress.%d vin.(%s)\n",swap->alicespend.I.suppress_pubkeys,swap->bobpayment.I.destaddr); } printf("error validating bobpayment\n"); return(-1); From 644b5a89b9df3ad46d134f9b7562881567813c81 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 14:27:06 +0300 Subject: [PATCH 0996/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index b6e91d625..d4066b050 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -257,6 +257,10 @@ int32_t LP_choosei_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datal vcalc_sha256(0,swap->I.secretAm256,swap->I.privAm.bytes,sizeof(swap->I.privAm)); swap->I.pubAm = bitcoin_pubkey33(swap->ctx,pubkey33,swap->I.privAm); printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); + swap->bobdeposit.I.pubkey33[0] = 2; + for (i=0; i<32; i++) + swap->bobdeposit.I.pubkey33[i+1] = swap->I.pubA0.bytes[i]; + printf("SET bobdeposit pubkey33.(02%s)\n",bits256_str(str,swap->I.pubA0)); //basilisk_bobscripts_set(swap,0); } return(0); From 0ce87644ee12a2cc95ced762ed98589668171bc1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 15:11:47 +0300 Subject: [PATCH 0997/2705] Test --- iguana/exchanges/LP_transaction.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index fafabb418..de2d4f0c4 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -725,7 +725,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ printf(" pubkey33.%s, suppress.%d\n",rawtx->name,rawtx->I.suppress_pubkeys); for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,0,0,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -1443,13 +1443,15 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da swap->depositunconf = 1; basilisk_dontforget_update(swap,&swap->bobdeposit); len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + memcpy(swap->I.userdata_aliceclaim,userdata,len); + swap->I.userdata_aliceclaimlen = len; bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); for (i=0; ibobdeposit.I.redeemlen; i++) printf("%02x",swap->bobdeposit.redeemscript[i]); printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); - memcpy(swap->I.userdata_aliceclaim,userdata,len); - swap->I.userdata_aliceclaimlen = len; + memcpy(swap->aliceclaim.redeemscript,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + swap->aliceclaim.I.redeemlen = swap->bobdeposit.I.redeemlen; retval = 0; if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) { From 24337934a7fabe43502cfe654acbd118d2f888e6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 15:18:31 +0300 Subject: [PATCH 0998/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index de2d4f0c4..55d1afb2b 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -536,7 +536,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t } } finalized = iguana_vininfo_create(pubtype,p2shtype,isPoS,serialized2,maxsize,msgtx,vins,numinputs,V); - printf("finalized.%d\n",finalized); + printf("finalized.%d ignore_cltverr.%d\n",finalized,V[0].ignore_cltverr); if ( (complete= bitcoin_verifyvins(ctx,symbol,pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) { int32_t tmp; //char str[65]; From b4b1c35819ef8472b354f14d8af3e422b0273ea0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 15:26:17 +0300 Subject: [PATCH 0999/2705] Test --- iguana/exchanges/LP_transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 55d1afb2b..951c7e52b 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -536,7 +536,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t } } finalized = iguana_vininfo_create(pubtype,p2shtype,isPoS,serialized2,maxsize,msgtx,vins,numinputs,V); - printf("finalized.%d ignore_cltverr.%d\n",finalized,V[0].ignore_cltverr); + printf("finalized.%d ignore_cltverr.%d suppress.%d\n",finalized,V[0].ignore_cltverr,V[0].suppress_pubkeys); if ( (complete= bitcoin_verifyvins(ctx,symbol,pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) { int32_t tmp; //char str[65]; @@ -1449,7 +1449,7 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); for (i=0; ibobdeposit.I.redeemlen; i++) printf("%02x",swap->bobdeposit.redeemscript[i]); - printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); + printf(" <- bobdeposit redeem %d %s suppress.%d\n",i,swap->bobdeposit.I.destaddr,swap->aliceclaim.I.suppress_pubkeys); memcpy(swap->aliceclaim.redeemscript,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); swap->aliceclaim.I.redeemlen = swap->bobdeposit.I.redeemlen; retval = 0; From 3c25903df089c68743ffad272afcce686ccc14b6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 15:32:32 +0300 Subject: [PATCH 1000/2705] Test --- iguana/exchanges/LP_transaction.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 951c7e52b..919a4d4ea 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -225,6 +225,7 @@ int32_t iguana_interpreter(struct iguana_info *coin,cJSON *logarray,int64_t nLoc if ( activescriptlen < 16 ) continue; //printf("interpreter.(%s)\n",jprint(spendscript,0)); + printf("bitcoin_assembler ignore_cltverr.%d suppress.%d\n",V[vini].ignore_cltverr,V[vini].suppress_pubkeys); if ( (scriptlen= bitcoin_assembler(coin,logarray,script,spendscript,1,nLockTime,&V[vini])) < 0 ) { //printf("bitcoin_assembler error scriptlen.%d\n",scriptlen); @@ -722,10 +723,10 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ } for (iter=0; iter<33; iter++) printf("%02x",rawtx->I.pubkey33[iter]); - printf(" pubkey33.%s, suppress.%d\n",rawtx->name,rawtx->I.suppress_pubkeys); + printf(" pubkey33.%s, suppress.%d\n",rawtx->name,dest->I.suppress_pubkeys); for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) From 799a31f25bf5a038a6f938a016262bcf27b7c001 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 15:47:29 +0300 Subject: [PATCH 1001/2705] Test --- iguana/exchanges/LP_swap.c | 3 ++- iguana/exchanges/LP_transaction.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index d4066b050..eb6026c1a 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -258,8 +258,9 @@ int32_t LP_choosei_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datal swap->I.pubAm = bitcoin_pubkey33(swap->ctx,pubkey33,swap->I.privAm); printf("set privAm.%s %s\n",bits256_str(str,swap->I.privAm),bits256_str(str2,*(bits256 *)swap->I.secretAm256)); swap->bobdeposit.I.pubkey33[0] = 2; + swap->bobpayment.I.pubkey33[0] = 2; for (i=0; i<32; i++) - swap->bobdeposit.I.pubkey33[i+1] = swap->I.pubA0.bytes[i]; + swap->bobpayment.I.pubkey33[i+1] = swap->bobdeposit.I.pubkey33[i+1] = swap->I.pubA0.bytes[i]; printf("SET bobdeposit pubkey33.(02%s)\n",bits256_str(str,swap->I.pubA0)); //basilisk_bobscripts_set(swap,0); } diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 919a4d4ea..6c1a8b5b0 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1448,6 +1448,9 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da swap->I.userdata_aliceclaimlen = len; bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); + for (i=0; ibobdeposit.I.datalen; i++) + printf("%02x",swap->bobdeposit.txbytes[i]); + printf(" <- bobdeposit.%d\n",swap->bobdeposit.I.datalen); for (i=0; ibobdeposit.I.redeemlen; i++) printf("%02x",swap->bobdeposit.redeemscript[i]); printf(" <- bobdeposit redeem %d %s suppress.%d\n",i,swap->bobdeposit.I.destaddr,swap->aliceclaim.I.suppress_pubkeys); @@ -1499,6 +1502,9 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); + for (i=0; ibobpayment.I.datalen; i++) + printf("%02x",swap->bobpayment.txbytes[i]); + printf(" <- bobpayment.%d\n",swap->bobpayment.I.datalen); for (i=0; ibobpayment.I.redeemlen; i++) printf("%02x",swap->bobpayment.redeemscript[i]); printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); From 88c8ff6355cec3202e46e724a31bb8dc9ca23cd3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 15:57:05 +0300 Subject: [PATCH 1002/2705] Test --- iguana/exchanges/LP_swap.c | 1 + iguana/exchanges/LP_transaction.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index eb6026c1a..a6b6a2d91 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -501,6 +501,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 sendbuf[sendlen++] = rawtx->I.datalen & 0xff; sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; sendbuf[sendlen++] = rawtx->I.redeemlen; + int32_t z; for (z=0; zI.datalen; z++) printf("%02x",rawtx->txbytes[z]); printf(" >>>>>>> send %s\n",rawtx->name); //printf("datalen.%d redeemlen.%d\n",rawtx->I.datalen,rawtx->I.redeemlen); memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 6c1a8b5b0..ae6d37329 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1382,15 +1382,14 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); if ( rawtx->I.datalen == 0 ) { - //rawtx->txbytes = calloc(1,datalen); + int32_t i; for (i=0; itxbytes,data,datalen); rawtx->I.datalen = datalen; } else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) { - int32_t i; for (i=0; iI.datalen; i++) printf("%02x",rawtx->txbytes[i]); printf(" <- rawtx\n"); From 71339b69b3466021f76993354b9609468da4fba4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 16:12:23 +0300 Subject: [PATCH 1003/2705] Test --- iguana/exchanges/LP_swap.c | 2 +- iguana/exchanges/LP_transaction.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index a6b6a2d91..b0afeedb6 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -501,7 +501,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 sendbuf[sendlen++] = rawtx->I.datalen & 0xff; sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; sendbuf[sendlen++] = rawtx->I.redeemlen; - int32_t z; for (z=0; zI.datalen; z++) printf("%02x",rawtx->txbytes[z]); printf(" >>>>>>> send %s\n",rawtx->name); + int32_t z; for (z=0; zI.datalen; z++) printf("%02x",rawtx->txbytes[z]); printf(" >>>>>>> send.%d %s\n",rawtx->I.datalen,rawtx->name); //printf("datalen.%d redeemlen.%d\n",rawtx->I.datalen,rawtx->I.redeemlen); memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index ae6d37329..a50430dd1 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -48,15 +48,14 @@ bits256 LP_broadcast_tx(char *name,char *symbol,uint8_t *data,int32_t datalen) if ( data != 0 && datalen != 0 ) { char str[65]; -#ifdef BASILISK_DISABLESENDTX - txid = bits256_doublesha256(0,data,datalen); - printf("%s <- dont sendrawtransaction (%s)\n",name,bits256_str(str,txid)); - return(txid); -#endif signedtx = malloc(datalen*2 + 1); init_hexbytes_noT(signedtx,data,datalen); +#ifdef BASILISK_DISABLESENDTX + txid = bits256_doublesha256(0,data,datalen); + printf("%s <- dont sendrawtransaction (%s) %s\n",name,bits256_str(str,txid),signedtx); +#else txid = LP_broadcast(name,symbol,signedtx); - // sent to nn_socket! +#endif free(signedtx); } return(txid); From 5c5ba00bc3dc1760d674c595bc0998fffe0d99b1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 16:23:28 +0300 Subject: [PATCH 1004/2705] Test --- iguana/exchanges/LP_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index b0afeedb6..4e38f9f32 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -547,6 +547,7 @@ void LP_bobloop(void *_utxo) printf("error bobscripts deposit\n"); else { + printf("depositlen.%d\n",swap->bobdeposit.I.datalen); LP_swapsfp_update(&swap->I.req); if ( LP_waitfor(utxo->pair,swap,10,LP_verify_otherfee) < 0 ) printf("error waiting for alicefee\n"); From 476a9c94f201402a50d128db4873c2e001abc49f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 16:31:23 +0300 Subject: [PATCH 1005/2705] Test --- iguana/exchanges/LP_swap.c | 2 +- iguana/exchanges/LP_transaction.c | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 4e38f9f32..6a1def41e 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -411,7 +411,7 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i { if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { - printf("wait for got.%d\n",datalen); + //printf("wait for got.%d\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); return(retval); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index a50430dd1..309232afe 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -536,15 +536,15 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t } } finalized = iguana_vininfo_create(pubtype,p2shtype,isPoS,serialized2,maxsize,msgtx,vins,numinputs,V); - printf("finalized.%d ignore_cltverr.%d suppress.%d\n",finalized,V[0].ignore_cltverr,V[0].suppress_pubkeys); + //printf("finalized.%d ignore_cltverr.%d suppress.%d\n",finalized,V[0].ignore_cltverr,V[0].suppress_pubkeys); if ( (complete= bitcoin_verifyvins(ctx,symbol,pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) { - int32_t tmp; //char str[65]; + /*int32_t tmp; //char str[65]; if ( (tmp= iguana_interpreter(ctx,cJSON_CreateArray(),iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) { printf("iguana_interpreter %d error.(%s)\n",tmp,signedtx); complete = 0; - } else printf("interpreter passed\n"); + } else printf("interpreter passed\n");*/ } else printf("complete.%d\n",complete); } else printf("rwmsgtx error\n"); } else fprintf(stderr,"no inputs in vins.(%s)\n",vins!=0?jprint(vins,0):"null"); @@ -707,7 +707,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160,char *vinaddr) { - char *signedtx,*changeaddr = 0,_changeaddr[64]; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,len,retval = -1; double estimatedrate; + char *signedtx,*changeaddr = 0,_changeaddr[64]; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,retval = -1; double estimatedrate; timestamp = swap->I.started; if ( dest == &swap->aliceclaim ) locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; @@ -720,24 +720,20 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ bitcoin_address(changeaddr,pubtype,changermd160,20); printf("changeaddr.(%s)\n",changeaddr); } - for (iter=0; iter<33; iter++) - printf("%02x",rawtx->I.pubkey33[iter]); - printf(" pubkey33.%s, suppress.%d\n",rawtx->name,dest->I.suppress_pubkeys); for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&dest->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) { - rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; - if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) + dest->I.datalen = (int32_t)strlen(signedtx) >> 1; + if ( dest->I.datalen <= sizeof(dest->txbytes) ) { - decode_hex(rawtx->txbytes,rawtx->I.datalen,signedtx); - rawtx->I.completed = 1; + decode_hex(dest->txbytes,dest->I.datalen,signedtx); + dest->I.completed = 1; retval = 0; } free(signedtx); if ( strcmp(symbol,"BTC") != 0 ) return(retval); - len = rawtx->I.datalen; estimatedrate = LP_getestimatedrate(symbol); newtxfee = estimatedrate * len; } else break; From 60b6bfdb9ebe40a80c590b31e6836aa5b96d2e88 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 16:32:05 +0300 Subject: [PATCH 1006/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 309232afe..f04387b18 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -735,7 +735,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ if ( strcmp(symbol,"BTC") != 0 ) return(retval); estimatedrate = LP_getestimatedrate(symbol); - newtxfee = estimatedrate * len; + newtxfee = estimatedrate * dest->I.datalen; } else break; } return(retval); From 294a2341aa9866c788b1a25cfa398beb38473c13 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 16:51:51 +0300 Subject: [PATCH 1007/2705] Test --- iguana/exchanges/LP_transaction.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index f04387b18..d5cded1ad 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1171,9 +1171,9 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); - int32_t i; for (i=0; ibobpayment.I.redeemlen; i++) - printf("%02x",swap->bobpayment.redeemscript[i]); - printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); + //int32_t i; for (i=0; ibobpayment.I.redeemlen; i++) + // printf("%02x",swap->bobpayment.redeemscript[i]); + //printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); if ( genflag != 0 && bits256_nonz(*(bits256 *)swap->I.secretBn256) != 0 && swap->bobpayment.I.datalen == 0 ) { basilisk_rawtx_gen(swap->ctx,"payment",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobpayment,swap->bobpayment.I.locktime,swap->bobpayment.spendscript,swap->bobpayment.I.spendlen,swap->bobpayment.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); @@ -1204,9 +1204,9 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); - int32_t i; for (i=0; ibobdeposit.I.redeemlen; i++) - printf("%02x",swap->bobdeposit.redeemscript[i]); - printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); + //int32_t i; for (i=0; ibobdeposit.I.redeemlen; i++) + // printf("%02x",swap->bobdeposit.redeemscript[i]); + //printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) { basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); @@ -1392,7 +1392,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba return(-1); } txid = bits256_doublesha256(0,data,datalen); - char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); + //char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) rawtx->I.actualtxid = txid; if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) @@ -1450,6 +1450,8 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da printf(" <- bobdeposit redeem %d %s suppress.%d\n",i,swap->bobdeposit.I.destaddr,swap->aliceclaim.I.suppress_pubkeys); memcpy(swap->aliceclaim.redeemscript,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); swap->aliceclaim.I.redeemlen = swap->bobdeposit.I.redeemlen; + memcpy(swap->aliceclaim.I.pubkey33,swap->persistent_pubkey33,33); + bitcoin_address(swap->aliceclaim.I.destaddr,swap->alicecoin.pubtype,swap->persistent_pubkey33,33); retval = 0; if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) { @@ -1505,6 +1507,8 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da memcpy(swap->I.userdata_alicespend,userdata,len); swap->I.userdata_alicespendlen = len; retval = 0; + memcpy(swap->alicespend.I.pubkey33,swap->persistent_pubkey33,33); + bitcoin_address(swap->alicespend.I.destaddr,swap->bobcoin.pubtype,swap->persistent_pubkey33,33); char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->alicepayment.I.destaddr)) == 0 ) { From 5c6a00cbcaf8d3286ee39c1aef56ac2157446336 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 17:07:23 +0300 Subject: [PATCH 1008/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 8b7eac1a6..4514803ca 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -310,7 +310,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; - char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice); + char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); } if ( bestprice != 0. ) { @@ -332,7 +332,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) bestmetric = metric; } } - } + } else printf("(%f %f) ",price,dstr(Q[i].destsatoshis)); } printf("metrics, best %f\n",bestmetric); if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) From a481781cc2eb4731cab2325e3ea6f7436e3455fb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 17:12:49 +0300 Subject: [PATCH 1009/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 4514803ca..70cfedd82 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -112,9 +112,9 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) qp->destvout = jint(argjson,"destvout"); qp->desthash = jbits256(argjson,"desthash"); if ( (qp->satoshis= j64bits(argjson,"satoshis")) == 0 ) - qp->satoshis = j64bits(argjson,"value"); + qp->satoshis = SATOSHIDEN * jdouble(argjson,"value"); if ( (qp->satoshis2= j64bits(argjson,"satoshis2")) == 0 ) - qp->satoshis2 = j64bits(argjson,"value2"); + qp->satoshis = SATOSHIDEN * jdouble(argjson,"value2"); qp->destsatoshis = j64bits(argjson,"destsatoshis"); qp->change = SATOSHIDEN * jdouble(argjson,"change"); qp->txfee = j64bits(argjson,"txfee"); From 2b2173daab4f6a4579ce2e600fa4fb2fc7d7b75c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 17:20:15 +0300 Subject: [PATCH 1010/2705] Test --- iguana/exchanges/LP_commands.c | 5 ++--- iguana/exchanges/LP_transaction.c | 8 +++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 70cfedd82..d9a343110 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -113,9 +113,8 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) qp->desthash = jbits256(argjson,"desthash"); if ( (qp->satoshis= j64bits(argjson,"satoshis")) == 0 ) qp->satoshis = SATOSHIDEN * jdouble(argjson,"value"); - if ( (qp->satoshis2= j64bits(argjson,"satoshis2")) == 0 ) - qp->satoshis = SATOSHIDEN * jdouble(argjson,"value2"); - qp->destsatoshis = j64bits(argjson,"destsatoshis"); + if ( (qp->destsatoshis= j64bits(argjson,"destsatoshis")) == 0 ) + qp->destsatoshis = SATOSHIDEN * jdouble(argjson,"value2"); qp->change = SATOSHIDEN * jdouble(argjson,"change"); qp->txfee = j64bits(argjson,"txfee"); qp->desttxfee = j64bits(argjson,"desttxfee"); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index d5cded1ad..42ffb64d2 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -639,6 +639,12 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch if ( addrtype == p2shtype ) spendlen = bitcoin_p2shspend(spendscript,0,rmd160); else spendlen = bitcoin_standardspend(spendscript,0,rmd160); + if ( change != 0 && strcmp(changeaddr,destaddr) == 0 ) + { + printf("combine change %.8f -> %s\n",dstr(change),changeaddr); + satoshis += change; + change = 0; + } txobj = bitcoin_txoutput(txobj,spendscript,spendlen,satoshis); if ( change != 0 ) { @@ -722,7 +728,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&dest->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->p2shaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&dest->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->I.destaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) { dest->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( dest->I.datalen <= sizeof(dest->txbytes) ) From 8914ff996c1583ab06bd189a8bf8d61d467b9bec Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 17:32:09 +0300 Subject: [PATCH 1011/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_transaction.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index d9a343110..f1815bcbf 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -323,7 +323,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) printf("%f ",metric); if ( metric > 0.9 ) { - metric = Q[i].destsatoshis / metric * metric * metric; + metric = Q[i].destsatoshis * metric * metric * metric; printf("%f, ",metric); if ( metric > bestmetric ) { diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index ed3784b55..96096072d 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -160,7 +160,7 @@ int32_t LP_importaddress(char *symbol,char *address) double LP_getestimatedrate(char *symbol) { - char buf[512],*retstr; double rate = 200; struct iguana_info *coin = LP_coinfind(symbol); + char buf[512],*retstr; double rate = 20; struct iguana_info *coin = LP_coinfind(symbol); if ( coin != 0 ) { sprintf(buf,"[%d]",3); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 42ffb64d2..71d254fd0 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -705,6 +705,8 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub if ( coin->estimatedrate == 0. ) coin->estimatedrate = LP_getestimatedrate(coin->symbol); newtxfee = coin->estimatedrate * len; + if ( newtxfee < 10000 ) + newtxfee = 10000; printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); } else break; } From 3d58453b5b4c421455827058fa98a8d9615eccf5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 17:35:04 +0300 Subject: [PATCH 1012/2705] Test --- iguana/exchanges/LP_commands.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index f1815bcbf..716ca306e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -320,10 +320,10 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) if ( (price= prices[i]) != 0. && Q[i].destsatoshis != 0 ) { metric = price / bestprice; - printf("%f ",metric); - if ( metric > 0.9 ) + printf("%f %f ",price,metric); + if ( metric < 1.1 ) { - metric = Q[i].destsatoshis * metric * metric * metric; + metric = dstr(Q[i].destsatoshis) / metric * metric * metric; printf("%f, ",metric); if ( metric > bestmetric ) { From bce4383086996f3aa52b4c00dcc712384e7c598a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 17:38:35 +0300 Subject: [PATCH 1013/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 716ca306e..11fe322aa 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -323,9 +323,9 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) printf("%f %f ",price,metric); if ( metric < 1.1 ) { - metric = dstr(Q[i].destsatoshis) / metric * metric * metric; + metric = dstr(Q[i].destsatoshis) * metric * metric * metric; printf("%f, ",metric); - if ( metric > bestmetric ) + if ( bestmetric == 0. || metric < bestmetric ) { besti = i; bestmetric = metric; From 8682106cfe0bb86b4cc1c886bfc67fed4800f59e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 17:43:03 +0300 Subject: [PATCH 1014/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 11fe322aa..c839c5182 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -320,11 +320,11 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) if ( (price= prices[i]) != 0. && Q[i].destsatoshis != 0 ) { metric = price / bestprice; - printf("%f %f ",price,metric); + printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); if ( metric < 1.1 ) { metric = dstr(Q[i].destsatoshis) * metric * metric * metric; - printf("%f, ",metric); + printf("%f\n",metric); if ( bestmetric == 0. || metric < bestmetric ) { besti = i; From 47db38a0a6ae57c6f5b0113b460987e53ed2b59e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 18:05:20 +0300 Subject: [PATCH 1015/2705] Test --- iguana/exchanges/LP_transaction.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 71d254fd0..9058d3a12 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1438,10 +1438,11 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { - uint8_t userdata[512]; int32_t i,retval=-1,len = 0; static bits256 zero; + uint8_t userdata[512]; char str[65]; int32_t i,retval=-1,len = 0; static bits256 zero; if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { - swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + swap->bobdeposit.utxovout = 0; + swap->bobdeposit.utxotxid = swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) swap->depositunconf = 1; basilisk_dontforget_update(swap,&swap->bobdeposit); @@ -1452,7 +1453,7 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); - printf(" <- bobdeposit.%d\n",swap->bobdeposit.I.datalen); + printf(" <- bobdeposit.%d %s\n",swap->bobdeposit.I.datalen,bits256_str(str,swap->bobdeposit.I.signedtxid)); for (i=0; ibobdeposit.I.redeemlen; i++) printf("%02x",swap->bobdeposit.redeemscript[i]); printf(" <- bobdeposit redeem %d %s suppress.%d\n",i,swap->bobdeposit.I.destaddr,swap->aliceclaim.I.suppress_pubkeys); @@ -1481,7 +1482,10 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t { if ( LP_rawtx_spendscript(swap,swap->alicecoin.longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) { - swap->alicepayment.I.signedtxid = LP_broadcast_tx(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + swap->alicepayment.utxovout = 0; + swap->alicepayment.utxotxid = swap->alicepayment.I.signedtxid = LP_broadcast_tx(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + bitcoin_address(swap->alicepayment.p2shaddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); + strcpy(swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr); if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) swap->aliceunconf = 1; basilisk_dontforget_update(swap,&swap->alicepayment); @@ -1493,11 +1497,12 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { - uint8_t userdata[512]; int32_t i,retval=-1,len = 0; bits256 revAm; + uint8_t userdata[512]; char str[65]; int32_t i,retval=-1,len = 0; bits256 revAm; memset(revAm.bytes,0,sizeof(revAm)); if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { - swap->bobpayment.I.signedtxid = LP_broadcast_tx(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + swap->bobpayment.utxovout = 0; + swap->bobpayment.utxotxid = swap->bobpayment.I.signedtxid = LP_broadcast_tx(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) swap->paymentunconf = 1; basilisk_dontforget_update(swap,&swap->bobpayment); @@ -1511,7 +1516,7 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da printf(" <- bobpayment.%d\n",swap->bobpayment.I.datalen); for (i=0; ibobpayment.I.redeemlen; i++) printf("%02x",swap->bobpayment.redeemscript[i]); - printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); + printf(" <- bobpayment redeem %d %s %s\n",i,swap->bobpayment.I.destaddr,bits256_str(str,swap->bobpayment.I.signedtxid)); memcpy(swap->I.userdata_alicespend,userdata,len); swap->I.userdata_alicespendlen = len; retval = 0; From 504dc20fc4af2fc56349b1fe02fc3e10d9410670 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 18:14:18 +0300 Subject: [PATCH 1016/2705] Test --- iguana/exchanges/LP_transaction.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 9058d3a12..3b464cc21 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -559,7 +559,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr,int32_t suppress_pubkeys) { - char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1; struct vin_info V[16]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; + char *rawtxbytes=0,*signedtx=0,tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1; struct vin_info V[16]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -567,11 +567,16 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 ) return(0); +#ifndef BASILISK_DISABLESENDTX if ( (value= LP_txvalue(symbol,utxotxid,vout)) == 0 ) { + char str[65]; printf("basilisk_swap_bobtxspend.%s %s utxo.(%s) already spent or doesnt exist\n",name,symbol,bits256_str(str,utxotxid)); return(0); } +#else + value = satoshis; +#endif if ( satoshis != 0 ) { if ( value > satoshis+txfee ) From 1d8efc6fa0f9cd320a12720001138e85ec04524d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 18:24:33 +0300 Subject: [PATCH 1017/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 3b464cc21..26c81dc64 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -735,7 +735,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&dest->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,rawtx->utxotxid,rawtx->utxovout,dest->I.destaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&dest->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,dest->utxotxid,dest->utxovout,dest->I.destaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) { dest->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( dest->I.datalen <= sizeof(dest->txbytes) ) From 2671da72308fe7be71f50a13fb6f46515b7b4ba8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 18:33:10 +0300 Subject: [PATCH 1018/2705] Test --- iguana/exchanges/LP_transaction.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 26c81dc64..11ed036e7 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1446,8 +1446,8 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da uint8_t userdata[512]; char str[65]; int32_t i,retval=-1,len = 0; static bits256 zero; if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { - swap->bobdeposit.utxovout = 0; - swap->bobdeposit.utxotxid = swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + swap->bobrefund.utxovout = 0; + swap->bobrefund.utxotxid = swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) swap->depositunconf = 1; basilisk_dontforget_update(swap,&swap->bobdeposit); @@ -1487,8 +1487,8 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t { if ( LP_rawtx_spendscript(swap,swap->alicecoin.longestchain,&swap->alicepayment,0,data,datalen,0) == 0 ) { - swap->alicepayment.utxovout = 0; - swap->alicepayment.utxotxid = swap->alicepayment.I.signedtxid = LP_broadcast_tx(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); + swap->bobspend.utxovout = 0; + swap->bobspend.utxotxid = swap->alicepayment.I.signedtxid = LP_broadcast_tx(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); bitcoin_address(swap->alicepayment.p2shaddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); strcpy(swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr); if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) @@ -1506,8 +1506,8 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da memset(revAm.bytes,0,sizeof(revAm)); if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { - swap->bobpayment.utxovout = 0; - swap->bobpayment.utxotxid = swap->bobpayment.I.signedtxid = LP_broadcast_tx(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + swap->alicespend.utxovout = 0; + swap->alicespend.utxotxid = swap->bobpayment.I.signedtxid = LP_broadcast_tx(swap->bobpayment.name,swap->bobpayment.coin->symbol,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); if ( bits256_nonz(swap->bobpayment.I.signedtxid) != 0 ) swap->paymentunconf = 1; basilisk_dontforget_update(swap,&swap->bobpayment); From d791ed57d3a34071f4c5c0fe94f4d668bf09080d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 20:40:24 +0300 Subject: [PATCH 1019/2705] Test --- iguana/exchanges/LP_commands.c | 3 ++- iguana/tests/dexlistunspent | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c839c5182..da9a8c07e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -252,6 +252,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { item = jitem(array,i); //printf("%s\n",jprint(item,0)); + printf("i.%d %.8f %.8f, %.8f %.8f\n",i,dstr(estimatedbase),dstr(j64bits(item,"satoshis")),dstr(myutxo->satoshis),dstr(Q.destsatoshis)); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 && LP_sizematch(estimatedbase,j64bits(item,"satoshis")) == 0 ) { @@ -289,7 +290,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) maxprice = LP_price(base,myutxo->coin) / 0.975; if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { - printf("candidates.(%s)\n",jprint(array,0)); + //printf("candidates.(%s)\n",jprint(array,0)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); diff --git a/iguana/tests/dexlistunspent b/iguana/tests/dexlistunspent index 4c06d2429..4e13419d8 100755 --- a/iguana/tests/dexlistunspent +++ b/iguana/tests/dexlistunspent @@ -1,2 +1,2 @@ #!/bin/bash -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RYZx1e7kVNTuQ6RTrvTkYeZAz5uJobC3pg\",\"symbol\":\"KMD\"}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"RNmvQtThVZAbc1tFEFmKAnJZrc9XqciNog\",\"symbol\":\"KMD\"}" From 45329552923cb8683f6b2bf761f2a449e474c759 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 20:45:00 +0300 Subject: [PATCH 1020/2705] Test --- iguana/exchanges/LP_commands.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index da9a8c07e..af38ac4e0 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -228,7 +228,7 @@ int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase; + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase,satoshis; if ( (price= LP_price(base,myutxo->coin)) == .0 ) { printf("no LP_price (%s -> %s)\n",base,myutxo->coin); @@ -251,10 +251,12 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) for (i=0; isatoshis),dstr(Q.destsatoshis)); + LP_quoteparse(&Q,item); + if ( (satoshis= j64bits(item,"satoshis")) == 0 ) + satoshis = SATOSHIDEN * jdouble(item,"value"); + printf("i.%d %.8f %.8f, %.8f %.8f\n",i,dstr(estimatedbase),dstr(satoshis),dstr(myutxo->satoshis),dstr(Q.destsatoshis)); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); - if ( strcmp(coinstr,base) == 0 && LP_sizematch(estimatedbase,j64bits(item,"satoshis")) == 0 ) + if ( strcmp(coinstr,base) == 0 && LP_sizematch(estimatedbase,satoshis) == 0 ) { icopy = 0; if ( (price= LP_pricecache(&Q,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) From c6c4e931a29e706bd374e5a808f4f7bb5aa65c37 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 20:49:53 +0300 Subject: [PATCH 1021/2705] Test --- iguana/exchanges/LP_commands.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index af38ac4e0..a81a51a82 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -228,16 +228,12 @@ int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t estimatedbase,satoshis; + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t satoshis; if ( (price= LP_price(base,myutxo->coin)) == .0 ) { printf("no LP_price (%s -> %s)\n",base,myutxo->coin); return(0); } - estimatedbase = myutxo->satoshis / price; - printf("%s -> %s price %.8f mysatoshis %llu estimated base %llu\n",base,myutxo->coin,price,(long long)myutxo->satoshis,(long long)estimatedbase); - if ( estimatedbase <= 0 ) - return(0); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) @@ -254,9 +250,9 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) LP_quoteparse(&Q,item); if ( (satoshis= j64bits(item,"satoshis")) == 0 ) satoshis = SATOSHIDEN * jdouble(item,"value"); - printf("i.%d %.8f %.8f, %.8f %.8f\n",i,dstr(estimatedbase),dstr(satoshis),dstr(myutxo->satoshis),dstr(Q.destsatoshis)); + printf("i.%d %.8f %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis)); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); - if ( strcmp(coinstr,base) == 0 && LP_sizematch(estimatedbase,satoshis) == 0 ) + if ( strcmp(coinstr,base) == 0 ) { icopy = 0; if ( (price= LP_pricecache(&Q,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) @@ -270,7 +266,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) jaddnum(icopy,"price",price); jaddi(retarray,icopy); } - } else printf("skip %s estimated %.8f vs %.8f\n",coinstr,dstr(estimatedbase),dstr(j64bits(item,"satoshis"))); + } else printf("skip %s estimated %.8f\n",coinstr,dstr(satoshis)); } } free_json(array); From 47194ad67baa21e4994531a4255707d2402caa3c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 20:52:04 +0300 Subject: [PATCH 1022/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a81a51a82..e146bcc0d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -250,7 +250,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) LP_quoteparse(&Q,item); if ( (satoshis= j64bits(item,"satoshis")) == 0 ) satoshis = SATOSHIDEN * jdouble(item,"value"); - printf("i.%d %.8f %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis)); + printf(">>>> i.%d %.8f %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis)); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) { From cad80ddcdd604dddbef8ca4bd32ffcd8a52af266 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 20:56:00 +0300 Subject: [PATCH 1023/2705] Test --- iguana/exchanges/LP_commands.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index e146bcc0d..591b1e9ff 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -114,7 +114,7 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) if ( (qp->satoshis= j64bits(argjson,"satoshis")) == 0 ) qp->satoshis = SATOSHIDEN * jdouble(argjson,"value"); if ( (qp->destsatoshis= j64bits(argjson,"destsatoshis")) == 0 ) - qp->destsatoshis = SATOSHIDEN * jdouble(argjson,"value2"); + qp->destsatoshis = qp->satoshis * jdouble(argjson,"price"); qp->change = SATOSHIDEN * jdouble(argjson,"change"); qp->txfee = j64bits(argjson,"txfee"); qp->desttxfee = j64bits(argjson,"desttxfee"); @@ -248,8 +248,6 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { item = jitem(array,i); LP_quoteparse(&Q,item); - if ( (satoshis= j64bits(item,"satoshis")) == 0 ) - satoshis = SATOSHIDEN * jdouble(item,"value"); printf(">>>> i.%d %.8f %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis)); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) From bf7d9c60d45c3a385365cb851ca97e8a3360ced0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 21:03:18 +0300 Subject: [PATCH 1024/2705] Test --- iguana/exchanges/LP_commands.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 591b1e9ff..38016a30a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -248,7 +248,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { item = jitem(array,i); LP_quoteparse(&Q,item); - printf(">>>> i.%d %.8f %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis)); + printf(">>>> i.%d %.8f %.8f Q: price %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis),jdouble(item,"price")); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) { @@ -264,7 +264,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) jaddnum(icopy,"price",price); jaddi(retarray,icopy); } - } else printf("skip %s estimated %.8f\n",coinstr,dstr(satoshis)); + } } } free_json(array); @@ -306,7 +306,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; - char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); + //char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); } if ( bestprice != 0. ) { From 6efaf41a9f4f472d2d2208c8a0285f4766f7f95d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 21:06:45 +0300 Subject: [PATCH 1025/2705] Test --- iguana/exchanges/LP_commands.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 38016a30a..6390f541d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -248,13 +248,14 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { item = jitem(array,i); LP_quoteparse(&Q,item); - printf(">>>> i.%d %.8f %.8f Q: price %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis),jdouble(item,"price")); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) { icopy = 0; if ( (price= LP_pricecache(&Q,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) { + if ( Q.destsatoshis == 0 ) + Q.destsatoshis = Q.satoshis * price; if ( LP_sizematch(myutxo->satoshis,Q.destsatoshis) == 0 ) icopy = jduplicate(item); } else icopy = jduplicate(item); @@ -264,6 +265,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) jaddnum(icopy,"price",price); jaddi(retarray,icopy); } + printf(">>>> i.%d %.8f %.8f Q: price %.8f -> %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis),price,price * dstr(Q.satoshis)); } } } From ff093b08e380059cde986e31ec3630206e45a24e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 21:26:08 +0300 Subject: [PATCH 1026/2705] Test --- iguana/exchanges/LP_commands.c | 28 ++++------------------------ iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_utxos.c | 6 +++++- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6390f541d..b75ae40f6 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -228,7 +228,7 @@ int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*icopy,*retarray=0,*item; int32_t i,n; double price; int64_t satoshis; + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n; double price; if ( (price= LP_price(base,myutxo->coin)) == .0 ) { printf("no LP_price (%s -> %s)\n",base,myutxo->coin); @@ -250,23 +250,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) LP_quoteparse(&Q,item); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) - { - icopy = 0; - if ( (price= LP_pricecache(&Q,base,myutxo->coin,jbits256(item,"txid"),jint(item,"vout"))) != 0. ) - { - if ( Q.destsatoshis == 0 ) - Q.destsatoshis = Q.satoshis * price; - if ( LP_sizematch(myutxo->satoshis,Q.destsatoshis) == 0 ) - icopy = jduplicate(item); - } else icopy = jduplicate(item); - if ( icopy != 0 ) - { - if ( price != 0. ) - jaddnum(icopy,"price",price); - jaddi(retarray,icopy); - } - printf(">>>> i.%d %.8f %.8f Q: price %.8f -> %.8f\n",i,dstr(myutxo->satoshis),dstr(Q.destsatoshis),price,price * dstr(Q.satoshis)); - } + jaddi(retarray,jduplicate(item)); } } free_json(array); @@ -300,11 +284,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) if ( (price= jdouble(item,"price")) == 0. ) { price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,zero); - if ( Q[i].destsatoshis != 0 && (double)j64bits(item,"satoshis")/Q[i].destsatoshis > price ) - { - printf("adjustprice %.8f -> %.8f\n",price,(double)j64bits(item,"satoshis")/Q[i].destsatoshis); - price = (double)j64bits(item,"satoshis")/Q[i].destsatoshis; - } + Q[i].destsatoshis = price * Q[i].satoshis; } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; @@ -316,7 +296,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) besti = -1; for (i=0; isatoshis > Q[i].destsatoshis ) { metric = price / bestprice; printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 9dc21ab9b..cef33e7b0 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -164,6 +164,7 @@ struct LP_utxoinfo UT_hash_handle hh; bits256 txid,txid2,feetxid,otherpubkey,mypub; void *swap; + double value; uint64_t satoshis,satoshis2; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; int32_t vout,vout2,pair; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b10a7d93f..2a3d74ec7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -116,7 +116,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); utxo->txid = txid; utxo->vout = vout; - utxo->satoshis = satoshis; + utxo->value = dstr(satoshis); + if ( IAMCLIENT == 0 ) + utxo->satoshis = satoshis; + else if ( depositsatoshis < 9 * (satoshis >> 3) ) + utxo->satoshis = (depositsatoshis / 9) << 3; utxo->txid2 = deposittxid; utxo->vout2 = depositvout; utxo->satoshis2 = depositsatoshis; From 71c6f5356ca0868e4188a14c778d2520ec9eab73 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 21:30:28 +0300 Subject: [PATCH 1027/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index b75ae40f6..53bacf653 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -310,7 +310,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) bestmetric = metric; } } - } else printf("(%f %f) ",price,dstr(Q[i].destsatoshis)); + } else printf("(%f %f) ",dstr(myutxo->satoshis),dstr(Q[i].destsatoshis)); } printf("metrics, best %f\n",bestmetric); if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) From 2f3e3b0446a8639527f0577af535db07b45dc885 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 21:42:30 +0300 Subject: [PATCH 1028/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index dbda8d683..6cb4673fb 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -171,7 +171,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0 ) + if ( peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) { if ( peer->numpeers != mypeer->numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 2a3d74ec7..d84e93386 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -35,7 +35,8 @@ cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) jaddstr(item,"address",utxo->coinaddr); jaddbits256(item,"txid",utxo->txid); jaddnum(item,"vout",utxo->vout); - jaddnum(item,"value",dstr(utxo->satoshis)); + jaddnum(item,"value",utxo->value); + jadd64bits(item,"satoshis",utxo->satoshis); jaddbits256(item,"txid2",utxo->txid2); jaddnum(item,"vout2",utxo->vout2); jaddnum(item,"value2",dstr(utxo->satoshis2)); From 3dafc58ac0e1d0a870b1fbe609a27820da17f6f4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 21:51:21 +0300 Subject: [PATCH 1029/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index d84e93386..c552a3a3f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -118,7 +118,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 utxo->txid = txid; utxo->vout = vout; utxo->value = dstr(satoshis); - if ( IAMCLIENT == 0 ) + if ( IAMCLIENT != 0 ) utxo->satoshis = satoshis; else if ( depositsatoshis < 9 * (satoshis >> 3) ) utxo->satoshis = (depositsatoshis / 9) << 3; From 09ad6e3a2b24b2e236cd86906e642fb55bfb582b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 21:57:02 +0300 Subject: [PATCH 1030/2705] Test --- iguana/exchanges/LP_include.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index cef33e7b0..f7b123941 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -32,7 +32,7 @@ #define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" #define BASILISK_DISABLEWAITTX -#define BASILISK_DISABLESENDTX +//#define BASILISK_DISABLESENDTX #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 From 834cf55ccc0492e0ed054f0a1393117881689ecf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 4 Jun 2017 22:05:48 +0300 Subject: [PATCH 1031/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_transaction.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 53bacf653..ab180768b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -363,7 +363,7 @@ int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double p utxo->swappending = 0; if ( now > utxo->published+60 && utxo->swappending == 0 && utxo->pair < 0 && utxo->swap == 0 && (price= LP_price(utxo->coin,rel)) != 0. ) { - price *= (1. + profitmargin); + //price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); Q.timestamp = (uint32_t)time(NULL); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 11ed036e7..11d029d72 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1446,8 +1446,8 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da uint8_t userdata[512]; char str[65]; int32_t i,retval=-1,len = 0; static bits256 zero; if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { - swap->bobrefund.utxovout = 0; - swap->bobrefund.utxotxid = swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + swap->aliceclaim.utxovout = 0; + swap->aliceclaim.utxotxid = swap->bobdeposit.I.signedtxid = LP_broadcast_tx(swap->bobdeposit.name,swap->bobcoin.symbol,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); if ( bits256_nonz(swap->bobdeposit.I.signedtxid) != 0 ) swap->depositunconf = 1; basilisk_dontforget_update(swap,&swap->bobdeposit); From 5ba40582c8a69dbdff4b091785add307f25ab173 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 10:53:17 +0300 Subject: [PATCH 1032/2705] Test --- iguana/exchanges/LP_coins.c | 24 +- iguana/exchanges/LP_commands.c | 323 +-------------------------- iguana/exchanges/LP_include.h | 3 +- iguana/exchanges/LP_nativeDEX.c | 3 +- iguana/exchanges/LP_prices.c | 27 +-- iguana/exchanges/LP_quotes.c | 344 +++++++++++++++++++++++++++++ iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_statemachine.c | 9 +- iguana/exchanges/LP_transaction.c | 3 +- iguana/exchanges/LP_utxos.c | 25 +-- 10 files changed, 393 insertions(+), 370 deletions(-) create mode 100644 iguana/exchanges/LP_quotes.c diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index f397ee075..6f32b9372 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -141,9 +141,29 @@ uint16_t LP_rpcport(char *symbol) return(0); } +cJSON *LP_coinjson(struct iguana_info *coin) +{ + cJSON *item = cJSON_CreateObject(); + jaddstr(item,"coin",coin->symbol); + jaddstr(item,"smartaddress",coin->smartaddr); + jaddstr(item,"rpc",coin->serverport); + jaddnum(item,"pubtype",coin->pubtype); + jaddnum(item,"p2shtype",coin->p2shtype); + jaddnum(item,"wiftype",coin->wiftype); + return(item); +} + +static struct iguana_info *LP_coins; static int32_t LP_numcoins; +cJSON *LP_coinsjson() +{ + int32_t i; cJSON *array = cJSON_CreateArray(); + for (i=0; isrchash = srchash; - rp->srcamount = srcsatoshis; - rp->timestamp = timestamp; - rp->DEXselector = DEXselector; - safecopy(rp->src,src,sizeof(rp->src)); - safecopy(rp->dest,dest,sizeof(rp->dest)); - R = *rp; - rp->requestid = basilisk_requestid(rp); - rp->quotetime = quotetime; - rp->desthash = desthash; - rp->destamount = destsatoshis; - rp->quoteid = basilisk_quoteid(rp); - return(rp); -} - -cJSON *LP_quotejson(struct LP_quoteinfo *qp) -{ - double price; cJSON *retjson = cJSON_CreateObject(); - jaddstr(retjson,"base",qp->srccoin); - jaddstr(retjson,"rel",qp->destcoin); - if ( qp->coinaddr[0] != 0 ) - jaddstr(retjson,"address",qp->coinaddr); - if ( qp->timestamp != 0 ) - jaddnum(retjson,"timestamp",qp->timestamp); - if ( bits256_nonz(qp->txid) != 0 ) - { - jaddbits256(retjson,"txid",qp->txid); - jaddnum(retjson,"vout",qp->vout); - } - if ( bits256_nonz(qp->srchash) != 0 ) - jaddbits256(retjson,"srchash",qp->srchash); - if ( qp->txfee != 0 ) - jadd64bits(retjson,"txfee",qp->txfee); - if ( qp->quotetime != 0 ) - jaddnum(retjson,"quotetime",qp->quotetime); - if ( qp->satoshis != 0 ) - { - jadd64bits(retjson,"satoshis",qp->satoshis); - price = (double)(qp->destsatoshis+qp->desttxfee) / qp->satoshis; - jaddnum(retjson,"price",price); - } - if ( bits256_nonz(qp->desthash) != 0 ) - jaddbits256(retjson,"desthash",qp->desthash); - if ( bits256_nonz(qp->txid2) != 0 ) - { - jaddbits256(retjson,"txid2",qp->txid2); - jaddnum(retjson,"vout2",qp->vout2); - if ( qp->satoshis2 != 0 ) - jadd64bits(retjson,"satoshis2",qp->satoshis2); - } - if ( bits256_nonz(qp->desttxid) != 0 ) - { - if ( qp->destaddr[0] != 0 ) - jaddstr(retjson,"destaddr",qp->destaddr); - jaddbits256(retjson,"desttxid",qp->desttxid); - jaddnum(retjson,"destvout",qp->destvout); - } - if ( bits256_nonz(qp->feetxid) != 0 ) - { - jaddbits256(retjson,"feetxid",qp->feetxid); - jaddnum(retjson,"feevout",qp->feevout); - } - if ( qp->destsatoshis != 0 ) - jadd64bits(retjson,"destsatoshis",qp->destsatoshis); - if ( qp->desttxfee != 0 ) - jadd64bits(retjson,"desttxfee",qp->desttxfee); - if ( qp->change != 0 ) - jaddnum(retjson,"change",dstr(qp->change)); - return(retjson); -} - -int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) -{ - safecopy(qp->srccoin,jstr(argjson,"base"),sizeof(qp->srccoin)); - safecopy(qp->coinaddr,jstr(argjson,"address"),sizeof(qp->coinaddr)); - safecopy(qp->destcoin,jstr(argjson,"rel"),sizeof(qp->destcoin)); - safecopy(qp->destaddr,jstr(argjson,"destaddr"),sizeof(qp->destaddr)); - qp->timestamp = juint(argjson,"timestamp"); - qp->quotetime = juint(argjson,"quotetime"); - qp->txid = jbits256(argjson,"txid"); - qp->txid2 = jbits256(argjson,"txid2"); - qp->vout = jint(argjson,"vout"); - qp->vout2 = jint(argjson,"vout2"); - qp->feevout = jint(argjson,"feevout"); - qp->srchash = jbits256(argjson,"srchash"); - qp->desttxid = jbits256(argjson,"desttxid"); - qp->feetxid = jbits256(argjson,"feetxid"); - qp->destvout = jint(argjson,"destvout"); - qp->desthash = jbits256(argjson,"desthash"); - if ( (qp->satoshis= j64bits(argjson,"satoshis")) == 0 ) - qp->satoshis = SATOSHIDEN * jdouble(argjson,"value"); - if ( (qp->destsatoshis= j64bits(argjson,"destsatoshis")) == 0 ) - qp->destsatoshis = qp->satoshis * jdouble(argjson,"price"); - qp->change = SATOSHIDEN * jdouble(argjson,"change"); - qp->txfee = j64bits(argjson,"txfee"); - qp->desttxfee = j64bits(argjson,"desttxfee"); - return(0); -} - -int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price) -{ - memset(qp,0,sizeof(*qp)); - qp->timestamp = (uint32_t)time(NULL); - safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); - if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) - qp->txfee = 10000; - if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->satoshis2 ) - return(-1); - qp->txid = utxo->txid; - qp->vout = utxo->vout; - qp->txid2 = utxo->txid2; - qp->vout2 = utxo->vout2; - qp->satoshis2 = utxo->satoshis2 - qp->txfee; - qp->satoshis = utxo->satoshis - qp->txfee; - qp->destsatoshis = qp->satoshis * price; - if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) - qp->desttxfee = 10000; - if ( qp->desttxfee >= qp->destsatoshis ) - return(-2); - qp->destsatoshis -= qp->desttxfee; - safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); - safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); - qp->srchash = LP_pubkey(LP_privkey(utxo->coinaddr)); - return(0); -} - -int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quotetime,uint64_t value,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 desttxid,int32_t destvout,bits256 desthash,char *destaddr) -{ - if ( txfee != qp->txfee ) - { - if ( txfee >= value ) - return(-1); - qp->txfee = txfee; - qp->satoshis = value - txfee; - } - qp->timestamp = timestamp; - qp->quotetime = quotetime; - qp->destsatoshis = destsatoshis; - qp->desttxfee = desttxfee; - qp->desttxid = desttxid; - qp->destvout = destvout; - qp->desthash = desthash; - safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr)); - return(0); -} - -char *LP_quotereceived(cJSON *argjson) -{ - struct LP_cacheinfo *ptr; double price; struct LP_quoteinfo Q; - LP_quoteparse(&Q,argjson); - price = (double)(Q.destsatoshis + Q.desttxfee) / (Q.satoshis + Q.txfee); - if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) - { - ptr->Q = Q; - return(clonestr("{\"result\":\"updated\"}")); - } else return(clonestr("{\"error\":\"nullptr\"}")); -} - double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub) { cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; @@ -219,164 +57,6 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port, return(price); } -int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) -{ - if ( mysatoshis >= othersatoshis ) - return(0); - else return(-1); -} - -cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) -{ - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n; double price; - if ( (price= LP_price(base,myutxo->coin)) == .0 ) - { - printf("no LP_price (%s -> %s)\n",base,myutxo->coin); - return(0); - } - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) - { - //printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); - if ( (array= cJSON_Parse(utxostr)) != 0 ) - { - if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) - { - retarray = cJSON_CreateArray(); - for (i=0; icoin) / 0.975; - if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) - { - //printf("candidates.(%s)\n",jprint(array,0)); - if ( (n= cJSON_GetArraySize(array)) > 0 ) - { - memset(prices,0,sizeof(prices)); - memset(Q,0,sizeof(Q)); - for (i=0; icoin,zero); - Q[i].destsatoshis = price * Q[i].satoshis; - } - if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) - bestprice = price; - //char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); - } - if ( bestprice != 0. ) - { - bestmetric = 0.; - besti = -1; - for (i=0; isatoshis > Q[i].destsatoshis ) - { - metric = price / bestprice; - printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); - if ( metric < 1.1 ) - { - metric = dstr(Q[i].destsatoshis) * metric * metric * metric; - printf("%f\n",metric); - if ( bestmetric == 0. || metric < bestmetric ) - { - besti = i; - bestmetric = metric; - } - } - } else printf("(%f %f) ",dstr(myutxo->satoshis),dstr(Q[i].destsatoshis)); - } - printf("metrics, best %f\n",bestmetric); - if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) - { - i = besti; - bestprice = prices[i]; - item = jitem(array,i); - bestitem = LP_quotejson(&Q[i]); - printf("bestprice %f vs maxprice %f\n",bestprice,maxprice); - if ( maxprice == 0. || bestprice <= maxprice ) - { - Q[i].desttxid = myutxo->txid; - Q[i].destvout = myutxo->vout; - Q[i].feetxid = myutxo->txid2; - Q[i].feevout = myutxo->vout2; - strcpy(Q[i].destaddr,myutxo->coinaddr); - price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); - if ( jobj(bestitem,"price") != 0 ) - jdelete(bestitem,"price"); - jaddnum(bestitem,"price",prices[i]); - if ( price <= maxprice ) - { - Q[i].desttxid = myutxo->txid; - Q[i].destvout = myutxo->vout; - Q[i].feetxid = myutxo->txid2; - Q[i].feevout = myutxo->vout2; - strcpy(Q[i].destaddr,myutxo->coinaddr); - price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); - LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); - jaddstr(bestitem,"status","connected"); - jaddnum(bestitem,"requestid",R.requestid); - jaddnum(bestitem,"quoteid",R.quoteid); - printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); - } else jaddstr(bestitem,"status","too expensive"); - } - } - } - free_json(array); - } - } - if ( bestitem == 0 ) - return(cJSON_Parse("{\"error\":\"no match found\"}")); - return(bestitem); -} - -int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin) -{ - double price; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; - if ( (now= (uint32_t)time(NULL)) > utxo->swappending ) - utxo->swappending = 0; - if ( now > utxo->published+60 && utxo->swappending == 0 && utxo->pair < 0 && utxo->swap == 0 && (price= LP_price(utxo->coin,rel)) != 0. ) - { - //price *= (1. + profitmargin); - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - Q.timestamp = (uint32_t)time(NULL); - retjson = LP_quotejson(&Q); - jaddstr(retjson,"method","quote"); - retstr = jprint(retjson,1); - LP_send(pubsock,retstr,1); - utxo->published = now; - return(0); - } - return(-1); -} - int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey,txid; struct LP_utxoinfo *utxo; int32_t retval = -1,DEXselector = 0; uint64_t destvalue; struct basilisk_request R; struct LP_quoteinfo Q; @@ -523,8 +203,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port USERPASS_COUNTER = 1; retjson = cJSON_CreateObject(); jaddstr(retjson,"userpass",USERPASS); - jaddstr(retjson,"BTC",BTCADDR); - jaddstr(retjson,"KMD",KMDADDR); + jadd(retjson,"coins",LP_coinsjson()); return(jprint(retjson,1)); } if ( (userpass= jstr(argjson,"userpass")) == 0 || strcmp(userpass,USERPASS) != 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index f7b123941..1ffa32cb7 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -139,7 +139,7 @@ struct iguana_info uint64_t txfee; double estimatedrate; int32_t longestchain; uint8_t pubtype,p2shtype,isPoS,wiftype; - char symbol[16],changeaddr[64],userpass[1024],serverport[128]; + char symbol[16],smartaddr[64],userpass[1024],serverport[128]; }; struct basilisk_swap @@ -200,5 +200,6 @@ uint32_t basilisk_quoteid(struct basilisk_request *rp); struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp,struct LP_quoteinfo *qp); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend); +double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub); #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6cb4673fb..ab7251b68 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -28,7 +28,7 @@ struct LP_peerinfo *LP_peerinfos,*LP_mypeer; char *activecoins[] = { "BTC", "KMD", "REVS", "JUMBLR" };//"LTC", "USD", }; char GLOBAL_DBDIR[] = { "DB" }; -char USERPASS[65],USERPASS_WIFSTR[64],BTCADDR[64],KMDADDR[64],USERHOME[512] = { "/root" }; +char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", @@ -74,6 +74,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_swap.c" #include "LP_peers.c" #include "LP_utxos.c" +#include "LP_quotes.c" #include "LP_commands.c" void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 319c91ed8..999ed3c2b 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -130,13 +130,20 @@ void LP_priceinfoupdate(char *base,char *rel,double price) double LP_myprice(double *bidp,double *askp,char *base,char *rel) { - struct LP_priceinfo *basepp,*relpp; + struct LP_priceinfo *basepp,*relpp; double val; + *bidp = *askp = 0.; if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { - *askp = basepp->myprices[relpp->ind]; - *bidp = relpp->myprices[basepp->ind]; - return((*askp + *bidp) * 0.5); - } else return(0.); + if ( (*askp= basepp->myprices[relpp->ind]) != 0. ) + { + if ( (val= relpp->myprices[basepp->ind]) != 0. ) + { + *bidp = 1. / val; + return((*askp + *bidp) * 0.5); + } + } + } + return(0.); } int32_t LP_mypriceset(char *base,char *rel,double price) @@ -217,16 +224,6 @@ struct LP_priceinfo *LP_priceinfoadd(char *symbol) safecopy(pp->symbol,symbol,sizeof(pp->symbol)); pp->coinbits = stringbits(symbol); pp->ind = LP_numpriceinfos++; - /*pp->relvals = calloc(LP_numpriceinfos+1,sizeof(*pp->relvals)); - //pp->myprices = calloc(LP_numpriceinfos+1,sizeof(*pp->myprices)); - vecsize = sizeof(*LP_priceinfos[i].relvals) * (LP_numpriceinfos + 1); - for (i=0; isrchash = srchash; + rp->srcamount = srcsatoshis; + rp->timestamp = timestamp; + rp->DEXselector = DEXselector; + safecopy(rp->src,src,sizeof(rp->src)); + safecopy(rp->dest,dest,sizeof(rp->dest)); + R = *rp; + rp->requestid = basilisk_requestid(rp); + rp->quotetime = quotetime; + rp->desthash = desthash; + rp->destamount = destsatoshis; + rp->quoteid = basilisk_quoteid(rp); + return(rp); +} + +cJSON *LP_quotejson(struct LP_quoteinfo *qp) +{ + double price; cJSON *retjson = cJSON_CreateObject(); + jaddstr(retjson,"base",qp->srccoin); + jaddstr(retjson,"rel",qp->destcoin); + if ( qp->coinaddr[0] != 0 ) + jaddstr(retjson,"address",qp->coinaddr); + if ( qp->timestamp != 0 ) + jaddnum(retjson,"timestamp",qp->timestamp); + if ( bits256_nonz(qp->txid) != 0 ) + { + jaddbits256(retjson,"txid",qp->txid); + jaddnum(retjson,"vout",qp->vout); + } + if ( bits256_nonz(qp->srchash) != 0 ) + jaddbits256(retjson,"srchash",qp->srchash); + if ( qp->txfee != 0 ) + jadd64bits(retjson,"txfee",qp->txfee); + if ( qp->quotetime != 0 ) + jaddnum(retjson,"quotetime",qp->quotetime); + if ( qp->satoshis != 0 ) + { + jadd64bits(retjson,"satoshis",qp->satoshis); + price = (double)(qp->destsatoshis+qp->desttxfee) / qp->satoshis; + jaddnum(retjson,"price",price); + } + if ( bits256_nonz(qp->desthash) != 0 ) + jaddbits256(retjson,"desthash",qp->desthash); + if ( bits256_nonz(qp->txid2) != 0 ) + { + jaddbits256(retjson,"txid2",qp->txid2); + jaddnum(retjson,"vout2",qp->vout2); + if ( qp->satoshis2 != 0 ) + jadd64bits(retjson,"satoshis2",qp->satoshis2); + } + if ( bits256_nonz(qp->desttxid) != 0 ) + { + if ( qp->destaddr[0] != 0 ) + jaddstr(retjson,"destaddr",qp->destaddr); + jaddbits256(retjson,"desttxid",qp->desttxid); + jaddnum(retjson,"destvout",qp->destvout); + } + if ( bits256_nonz(qp->feetxid) != 0 ) + { + jaddbits256(retjson,"feetxid",qp->feetxid); + jaddnum(retjson,"feevout",qp->feevout); + } + if ( qp->destsatoshis != 0 ) + jadd64bits(retjson,"destsatoshis",qp->destsatoshis); + if ( qp->desttxfee != 0 ) + jadd64bits(retjson,"desttxfee",qp->desttxfee); + if ( qp->change != 0 ) + jaddnum(retjson,"change",dstr(qp->change)); + return(retjson); +} + +int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) +{ + safecopy(qp->srccoin,jstr(argjson,"base"),sizeof(qp->srccoin)); + safecopy(qp->coinaddr,jstr(argjson,"address"),sizeof(qp->coinaddr)); + safecopy(qp->destcoin,jstr(argjson,"rel"),sizeof(qp->destcoin)); + safecopy(qp->destaddr,jstr(argjson,"destaddr"),sizeof(qp->destaddr)); + qp->timestamp = juint(argjson,"timestamp"); + qp->quotetime = juint(argjson,"quotetime"); + qp->txid = jbits256(argjson,"txid"); + qp->txid2 = jbits256(argjson,"txid2"); + qp->vout = jint(argjson,"vout"); + qp->vout2 = jint(argjson,"vout2"); + qp->feevout = jint(argjson,"feevout"); + qp->srchash = jbits256(argjson,"srchash"); + qp->desttxid = jbits256(argjson,"desttxid"); + qp->feetxid = jbits256(argjson,"feetxid"); + qp->destvout = jint(argjson,"destvout"); + qp->desthash = jbits256(argjson,"desthash"); + if ( (qp->satoshis= j64bits(argjson,"satoshis")) == 0 ) + qp->satoshis = SATOSHIDEN * jdouble(argjson,"value"); + if ( (qp->destsatoshis= j64bits(argjson,"destsatoshis")) == 0 ) + qp->destsatoshis = qp->satoshis * jdouble(argjson,"price"); + qp->change = SATOSHIDEN * jdouble(argjson,"change"); + qp->txfee = j64bits(argjson,"txfee"); + qp->desttxfee = j64bits(argjson,"desttxfee"); + return(0); +} + +int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price) +{ + memset(qp,0,sizeof(*qp)); + qp->timestamp = (uint32_t)time(NULL); + safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); + if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) + qp->txfee = 10000; + if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->satoshis2 ) + return(-1); + qp->txid = utxo->txid; + qp->vout = utxo->vout; + qp->txid2 = utxo->txid2; + qp->vout2 = utxo->vout2; + qp->satoshis2 = utxo->satoshis2 - qp->txfee; + qp->satoshis = utxo->satoshis - qp->txfee; + qp->destsatoshis = qp->satoshis * price; + if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) + qp->desttxfee = 10000; + if ( qp->desttxfee >= qp->destsatoshis ) + return(-2); + qp->destsatoshis -= qp->desttxfee; + safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); + safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); + qp->srchash = LP_pubkey(LP_privkey(utxo->coinaddr)); + return(0); +} + +int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quotetime,uint64_t value,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 desttxid,int32_t destvout,bits256 desthash,char *destaddr) +{ + if ( txfee != qp->txfee ) + { + if ( txfee >= value ) + return(-1); + qp->txfee = txfee; + qp->satoshis = value - txfee; + } + qp->timestamp = timestamp; + qp->quotetime = quotetime; + qp->destsatoshis = destsatoshis; + qp->desttxfee = desttxfee; + qp->desttxid = desttxid; + qp->destvout = destvout; + qp->desthash = desthash; + safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr)); + return(0); +} + +char *LP_quotereceived(cJSON *argjson) +{ + struct LP_cacheinfo *ptr; double price; struct LP_quoteinfo Q; + LP_quoteparse(&Q,argjson); + price = (double)(Q.destsatoshis + Q.desttxfee) / (Q.satoshis + Q.txfee); + if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) + { + ptr->Q = Q; + return(clonestr("{\"result\":\"updated\"}")); + } else return(clonestr("{\"error\":\"nullptr\"}")); +} + + +int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) +{ + if ( mysatoshis >= othersatoshis ) + return(0); + else return(-1); +} + +cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) +{ + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n; double price; + if ( (price= LP_price(base,myutxo->coin)) == .0 ) + { + printf("no LP_price (%s -> %s)\n",base,myutxo->coin); + return(0); + } + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) + { + //printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); + if ( (array= cJSON_Parse(utxostr)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + retarray = cJSON_CreateArray(); + for (i=0; icoin) / 0.975; + if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) + { + //printf("candidates.(%s)\n",jprint(array,0)); + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + memset(prices,0,sizeof(prices)); + memset(Q,0,sizeof(Q)); + for (i=0; icoin,zero); + Q[i].destsatoshis = price * Q[i].satoshis; + } + if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) + bestprice = price; + //char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); + } + if ( bestprice != 0. ) + { + bestmetric = 0.; + besti = -1; + for (i=0; isatoshis > Q[i].destsatoshis ) + { + metric = price / bestprice; + printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); + if ( metric < 1.1 ) + { + metric = dstr(Q[i].destsatoshis) * metric * metric * metric; + printf("%f\n",metric); + if ( bestmetric == 0. || metric < bestmetric ) + { + besti = i; + bestmetric = metric; + } + } + } else printf("(%f %f) ",dstr(myutxo->satoshis),dstr(Q[i].destsatoshis)); + } + printf("metrics, best %f\n",bestmetric); + if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) + { + i = besti; + bestprice = prices[i]; + item = jitem(array,i); + bestitem = LP_quotejson(&Q[i]); + printf("bestprice %f vs maxprice %f\n",bestprice,maxprice); + if ( maxprice == 0. || bestprice <= maxprice ) + { + Q[i].desttxid = myutxo->txid; + Q[i].destvout = myutxo->vout; + Q[i].feetxid = myutxo->txid2; + Q[i].feevout = myutxo->vout2; + strcpy(Q[i].destaddr,myutxo->coinaddr); + price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); + if ( jobj(bestitem,"price") != 0 ) + jdelete(bestitem,"price"); + jaddnum(bestitem,"price",prices[i]); + if ( price <= maxprice ) + { + Q[i].desttxid = myutxo->txid; + Q[i].destvout = myutxo->vout; + Q[i].feetxid = myutxo->txid2; + Q[i].feevout = myutxo->vout2; + strcpy(Q[i].destaddr,myutxo->coinaddr); + price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); + LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); + jaddstr(bestitem,"status","connected"); + jaddnum(bestitem,"requestid",R.requestid); + jaddnum(bestitem,"quoteid",R.quoteid); + printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); + } else jaddstr(bestitem,"status","too expensive"); + } + } + } + free_json(array); + } + } + if ( bestitem == 0 ) + return(cJSON_Parse("{\"error\":\"no match found\"}")); + return(bestitem); +} + +int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin) +{ + double price; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; + if ( (now= (uint32_t)time(NULL)) > utxo->swappending ) + utxo->swappending = 0; + if ( now > utxo->published+60 && utxo->swappending == 0 && utxo->pair < 0 && utxo->swap == 0 && (price= LP_price(utxo->coin,rel)) != 0. ) + { + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + Q.timestamp = (uint32_t)time(NULL); + retjson = LP_quotejson(&Q); + jaddstr(retjson,"method","quote"); + retstr = jprint(retjson,1); + LP_send(pubsock,retstr,1); + utxo->published = now; + return(0); + } + return(-1); +} + + + + diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 96096072d..df6cfd6f2 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -168,7 +168,7 @@ double LP_getestimatedrate(char *symbol) { if ( retstr[0] != '-' ) { - rate = atof(retstr) / 1024.; + coin->estimatedrate = rate = atof(retstr) / 1024.; printf("estimated rate.(%s) %s -> %.8f\n",symbol,retstr,rate); } free(retstr); diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index dc0240c1b..ed4fe4fc8 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -404,18 +404,12 @@ cJSON *LP_createvins(struct basilisk_rawtx *dest,struct vin_info *V,struct basil int32_t _basilisk_rawtx_gen(char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey) { char scriptstr[1024],wifstr[256],coinaddr[64],*signedtx,*rawtxbytes; uint32_t basilisktag; int32_t retval = -1; cJSON *vins,*privkeys,*addresses,*valsobj; struct vin_info *V; - //bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,myinfo->persistent_pubkey33,33); - if ( rawtx->coin->changeaddr[0] == 0 ) - { - bitcoin_address(rawtx->coin->changeaddr,rawtx->coin->pubtype,pubkey33,33); - printf("set change address.(%s)\n",rawtx->coin->changeaddr); - } init_hexbytes_noT(scriptstr,script,scriptlen); basilisktag = (uint32_t)rand(); valsobj = cJSON_CreateObject(); jaddstr(valsobj,"coin",rawtx->coin->symbol); jaddstr(valsobj,"spendscript",scriptstr); - jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); + jaddstr(valsobj,"changeaddr",rawtx->coin->smartaddr); jadd64bits(valsobj,"satoshis",rawtx->I.amount); if ( strcmp(rawtx->coin->symbol,"BTC") == 0 && txfee > 0 && txfee < 50000 ) txfee = 50000; @@ -990,7 +984,6 @@ cJSON *basilisk_privkeyarray(struct iguana_info *coin,cJSON *vins) { cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],typestr[64],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; double bidasks[2]; privkeyarray = cJSON_CreateArray(); - //printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr); if ( (n= cJSON_GetArraySize(vins)) > 0 ) { for (i=0; inumutxos = n; - if ( destpeer->numutxos < n ) - { - //destpeer->numutxos = n; - //printf("got.(%s) from %s numutxos.%d\n",retstr,destpeer->ipaddr,destpeer->numutxos); - } } } free_json(array); @@ -273,7 +268,7 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t amclient) { static uint32_t counter; - char coinaddr[64],*script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 userpass,userpub,txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + char *script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 userpass,userpub,txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) { printf("cant add privkey for %s, coin not active\n",symbol); @@ -282,11 +277,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb if ( passphrase != 0 ) conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); - iguana_priv2pub(pubkey33,coinaddr,privkey,coin->pubtype); - if ( strcmp("BTC",symbol) == 0 ) - strcpy(BTCADDR,coinaddr); - else if ( strcmp("KMD",symbol) == 0 ) - strcpy(KMDADDR,coinaddr); + iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); if ( counter == 0 ) { char tmpstr[128]; @@ -296,13 +287,13 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb conv_NXTpassword(userpass.bytes,pubkey.bytes,(uint8_t *)tmpstr,(int32_t)strlen(tmpstr)); userpub = curve25519(userpass,curve25519_basepoint9()); printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); - printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coinaddr,coin->pubtype,tmpstr,passphrase); - if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coinaddr,-1)) != 0 ) + printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); + if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } - bitcoin_addr2rmd160(&tmptype,rmd160,coinaddr); + bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); - if ( (array= LP_listunspent(symbol,coinaddr)) != 0 ) + if ( (array= LP_listunspent(symbol,coin->smartaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { @@ -341,12 +332,12 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb values[i] = 0, used++; if ( amclient == 0 ) { - if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coinaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) + if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) utxo->mypub = curve25519(privkey,curve25519_basepoint9()); } else { - if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coinaddr,"127.0.0.1",0,0)) != 0 ) + if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,"127.0.0.1",0,0)) != 0 ) utxo->mypub = curve25519(privkey,curve25519_basepoint9()); } total += value; From c45d388cf5aec8b0079449c45d1aa7e6704db5d2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 11:00:31 +0300 Subject: [PATCH 1033/2705] Test --- iguana/exchanges/LP_utxos.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index ffa440388..c7b8371bd 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -84,7 +84,7 @@ char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) { - struct LP_utxoinfo *utxo = 0; + uint64_t tmpsatoshis; struct LP_utxoinfo *utxo = 0; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); @@ -95,9 +95,12 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("LP node got localhost utxo\n"); return(0); } + if ( IAMCLIENT == 0 || depositsatoshis < 9 * (satoshis >> 3) ) + tmpsatoshis = (depositsatoshis / 9) << 3; + else tmpsatoshis = satoshis; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { - if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->txid2) != 0 || vout != utxo->vout || satoshis != utxo->satoshis || depositvout != utxo->vout2 || depositsatoshis != utxo->satoshis2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) + if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->txid2) != 0 || vout != utxo->vout || tmpsatoshis != utxo->satoshis || depositvout != utxo->vout2 || depositsatoshis != utxo->satoshis2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) { utxo->errors++; char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->txid2) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->vout2,depositsatoshis != utxo->satoshis2,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); @@ -118,10 +121,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 utxo->txid = txid; utxo->vout = vout; utxo->value = dstr(satoshis); - if ( IAMCLIENT != 0 ) - utxo->satoshis = satoshis; - else if ( depositsatoshis < 9 * (satoshis >> 3) ) - utxo->satoshis = (depositsatoshis / 9) << 3; + utxo->satoshis = tmpsatoshis; utxo->txid2 = deposittxid; utxo->vout2 = depositvout; utxo->satoshis2 = depositsatoshis; From e8611fd173bd32c40cf0633dffbc9571942661b5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 11:02:18 +0300 Subject: [PATCH 1034/2705] Test --- iguana/exchanges/LP_prices.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 999ed3c2b..f575ac0ec 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -123,8 +123,10 @@ void LP_priceinfoupdate(char *base,char *rel,double price) struct LP_priceinfo *basepp,*relpp; if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { - dxblend(&basepp->relvals[relpp->ind],price,0.9); - dxblend(&relpp->relvals[basepp->ind],1. / price,0.9); + //dxblend(&basepp->relvals[relpp->ind],price,0.9); + //dxblend(&relpp->relvals[basepp->ind],1. / price,0.9); + basepp->relvals[relpp->ind] = price; + relpp->relvals[basepp->ind] = 1. / price; } } @@ -139,6 +141,7 @@ double LP_myprice(double *bidp,double *askp,char *base,char *rel) if ( (val= relpp->myprices[basepp->ind]) != 0. ) { *bidp = 1. / val; + printf("myprice (%.8f %.8f)\n",*bidp,*askp); return((*askp + *bidp) * 0.5); } } From 8ee5ed4b8db6fdf108b9ccfab8a9f6ac6924b694 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 11:14:53 +0300 Subject: [PATCH 1035/2705] Test --- iguana/exchanges/LP_quotes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index ad8617d15..662017062 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -321,10 +321,10 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin) { - double price; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; + double price,bid,ask; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; if ( (now= (uint32_t)time(NULL)) > utxo->swappending ) utxo->swappending = 0; - if ( now > utxo->published+60 && utxo->swappending == 0 && utxo->pair < 0 && utxo->swap == 0 && (price= LP_price(utxo->coin,rel)) != 0. ) + if ( now > utxo->published+60 && utxo->swappending == 0 && utxo->pair < 0 && utxo->swap == 0 && (price= LP_myprice(&bid,&ask,utxo->coin,rel)) != 0. ) { if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); From fe5b65e269468d5f6ae7c66ac88387655ad3a2b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 12:23:19 +0300 Subject: [PATCH 1036/2705] Test --- iguana/exchanges/LP_commands.c | 3 +-- iguana/exchanges/LP_include.h | 5 ++--- iguana/exchanges/LP_quotes.c | 37 ++++++++++++++++++---------------- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_utxos.c | 32 ++++++++++++++--------------- 5 files changed, 40 insertions(+), 39 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 68dce8188..bae8bfd7d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -118,7 +118,6 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin utxo->mypub = LP_pubkey(privkey); if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { - Q.change = destvalue - (Q.destsatoshis+Q.desttxfee); nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) printf("error creating utxo->pair\n"); @@ -294,7 +293,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( IAMCLIENT == 0 && strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),SATOSHIDEN * jdouble(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } if ( retstr != 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 1ffa32cb7..bccb9e1bf 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -164,8 +164,7 @@ struct LP_utxoinfo UT_hash_handle hh; bits256 txid,txid2,feetxid,otherpubkey,mypub; void *swap; - double value; - uint64_t satoshis,satoshis2; + uint64_t value,satoshis,value2; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; int32_t vout,vout2,pair; uint32_t lasttime,errors,swappending,published; @@ -189,7 +188,7 @@ struct LP_quoteinfo { struct basilisk_request R; bits256 srchash,desthash,txid,txid2,desttxid,feetxid,privkey; - uint64_t satoshis,satoshis2,txfee,destsatoshis,desttxfee,change; + uint64_t value,satoshis,satoshis2,txfee,destsatoshis,desttxfee; uint32_t timestamp,quotetime; int32_t vout,vout2,destvout,feevout,pair; char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; }; diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 662017062..e406d44d7 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -59,11 +59,7 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) if ( qp->quotetime != 0 ) jaddnum(retjson,"quotetime",qp->quotetime); if ( qp->satoshis != 0 ) - { jadd64bits(retjson,"satoshis",qp->satoshis); - price = (double)(qp->destsatoshis+qp->desttxfee) / qp->satoshis; - jaddnum(retjson,"price",price); - } if ( bits256_nonz(qp->desthash) != 0 ) jaddbits256(retjson,"desthash",qp->desthash); if ( bits256_nonz(qp->txid2) != 0 ) @@ -84,13 +80,19 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) { jaddbits256(retjson,"feetxid",qp->feetxid); jaddnum(retjson,"feevout",qp->feevout); + //jadd64bits(retjson,"feesatoshis",qp->feesatoshis); } - if ( qp->destsatoshis != 0 ) - jadd64bits(retjson,"destsatoshis",qp->destsatoshis); if ( qp->desttxfee != 0 ) jadd64bits(retjson,"desttxfee",qp->desttxfee); - if ( qp->change != 0 ) - jaddnum(retjson,"change",dstr(qp->change)); + if ( qp->destsatoshis != 0 ) + { + jadd64bits(retjson,"destsatoshis",qp->destsatoshis); + if ( qp->satoshis != 0 ) + { + price = (double)(qp->destsatoshis + qp->desttxfee) / qp->satoshis; + jaddnum(retjson,"price",price); + } + } return(retjson); } @@ -112,11 +114,11 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) qp->feetxid = jbits256(argjson,"feetxid"); qp->destvout = jint(argjson,"destvout"); qp->desthash = jbits256(argjson,"desthash"); - if ( (qp->satoshis= j64bits(argjson,"satoshis")) == 0 ) - qp->satoshis = SATOSHIDEN * jdouble(argjson,"value"); - if ( (qp->destsatoshis= j64bits(argjson,"destsatoshis")) == 0 ) - qp->destsatoshis = qp->satoshis * jdouble(argjson,"price"); - qp->change = SATOSHIDEN * jdouble(argjson,"change"); + //qp->feesatoshis = j64bits(argjson,"feesatoshis"); + qp->satoshis = j64bits(argjson,"satoshis"); + qp->satoshis2 = j64bits(argjson,"satoshis2"); + qp->value = j64bits(argjson,"value"); + qp->destsatoshis = j64bits(argjson,"destsatoshis"); qp->txfee = j64bits(argjson,"txfee"); qp->desttxfee = j64bits(argjson,"desttxfee"); return(0); @@ -129,15 +131,16 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) qp->txfee = 10000; - if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->satoshis2 ) + if ( qp->txfee >= utxo->value || qp->txfee >= utxo->value2 || utxo->value2 < utxo->satoshis+(utxo->satoshis>>3) ) return(-1); qp->txid = utxo->txid; qp->vout = utxo->vout; qp->txid2 = utxo->txid2; qp->vout2 = utxo->vout2; - qp->satoshis2 = utxo->satoshis2 - qp->txfee; - qp->satoshis = utxo->satoshis - qp->txfee; + qp->satoshis = utxo->satoshis; + qp->satoshis2 = utxo->satoshis + (utxo->satoshis >> 3); qp->destsatoshis = qp->satoshis * price; + //qp->feesatoshis = qp->destsatoshis / INSTANTDEX_INSURANCEDIV; if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) qp->desttxfee = 10000; if ( qp->desttxfee >= qp->destsatoshis ) @@ -161,6 +164,7 @@ int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quot qp->timestamp = timestamp; qp->quotetime = quotetime; qp->destsatoshis = destsatoshis; + //qp->feesatoshis = qp->destsatoshis / INSTANTDEX_INSURANCEDIV; qp->desttxfee = desttxfee; qp->desttxid = desttxid; qp->destvout = destvout; @@ -181,7 +185,6 @@ char *LP_quotereceived(cJSON *argjson) } else return(clonestr("{\"error\":\"nullptr\"}")); } - int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) { if ( mysatoshis >= othersatoshis ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index df6cfd6f2..6010a78f6 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&txid2=%s&vout2=%d&value2=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->satoshis),bits256_str(str2,utxo->txid2),utxo->vout2,dstr(utxo->satoshis2),utxo->spendscript,utxo->coinaddr); + sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&txid2=%s&vout2=%d&value2=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value),bits256_str(str2,utxo->txid2),utxo->vout2,dstr(utxo->value2),utxo->spendscript,utxo->coinaddr); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index c7b8371bd..0070a639f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -35,11 +35,11 @@ cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) jaddstr(item,"address",utxo->coinaddr); jaddbits256(item,"txid",utxo->txid); jaddnum(item,"vout",utxo->vout); - jaddnum(item,"value",utxo->value); + jadd64bits(item,"value",utxo->value); jadd64bits(item,"satoshis",utxo->satoshis); jaddbits256(item,"txid2",utxo->txid2); jaddnum(item,"vout2",utxo->vout2); - jaddnum(item,"value2",dstr(utxo->satoshis2)); + jadd64bits(item,"value2",utxo->value2); if ( utxo->swappending != 0 ) jaddnum(item,"pending",utxo->swappending); if ( bits256_nonz(utxo->otherpubkey) != 0 ) @@ -82,12 +82,12 @@ char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) return(jprint(utxosjson,1)); } -struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t satoshis,bits256 deposittxid,int32_t depositvout,int64_t depositsatoshis,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) +struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) { uint64_t tmpsatoshis; struct LP_utxoinfo *utxo = 0; - if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(deposittxid) == 0 || vout < 0 || depositvout < 0 || satoshis <= 0 || depositsatoshis <= 0 ) + if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { - printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(deposittxid) == 0,vout < 0,depositvout < 0,satoshis <= 0,depositsatoshis <= 0); + printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } if ( IAMCLIENT == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) @@ -95,15 +95,15 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("LP node got localhost utxo\n"); return(0); } - if ( IAMCLIENT == 0 || depositsatoshis < 9 * (satoshis >> 3) ) - tmpsatoshis = (depositsatoshis / 9) << 3; - else tmpsatoshis = satoshis; + if ( IAMCLIENT == 0 || value2 < 9 * (value >> 3) ) + tmpsatoshis = (value2 / 9) << 3; + else tmpsatoshis = value; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { - if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(deposittxid,utxo->txid2) != 0 || vout != utxo->vout || tmpsatoshis != utxo->satoshis || depositvout != utxo->vout2 || depositsatoshis != utxo->satoshis2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) + if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(txid2,utxo->txid2) != 0 || vout != utxo->vout || value != utxo->value || tmpsatoshis != utxo->satoshis || vout2 != utxo->vout2 || value2 != utxo->value2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) { utxo->errors++; - char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(deposittxid,utxo->txid2) != 0,vout != utxo->vout,satoshis != utxo->satoshis,depositvout != utxo->vout2,depositsatoshis != utxo->satoshis2,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port); + char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(txid2,utxo->txid2) != 0,vout != utxo->vout,tmpsatoshis != utxo->satoshis,vout2 != utxo->vout2,value2 != utxo->value2,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port,value != utxo->value); } else if ( profitmargin != 0. ) utxo->profitmargin = profitmargin; @@ -120,11 +120,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); utxo->txid = txid; utxo->vout = vout; - utxo->value = dstr(satoshis); + utxo->value = value; utxo->satoshis = tmpsatoshis; - utxo->txid2 = deposittxid; - utxo->vout2 = depositvout; - utxo->satoshis2 = depositsatoshis; + utxo->txid2 = txid2; + utxo->vout2 = vout2; + utxo->value2 = value2; memcpy(utxo->key,txid.bytes,sizeof(txid)); memcpy(&utxo->key[sizeof(txid)],&vout,sizeof(vout)); portable_mutex_lock(&LP_utxomutex); @@ -134,7 +134,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(satoshis),dstr(depositsatoshis),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); + char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); } return(utxo); } @@ -166,7 +166,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),SATOSHIDEN*jdouble(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),SATOSHIDEN * jdouble(item,"value2"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),j64bits(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),j64bits(item,"value2"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; } From 559561d2b0ee398cb82127fe35a237e5ec31c025 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 12:28:35 +0300 Subject: [PATCH 1037/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0070a639f..319967505 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -100,6 +100,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 else tmpsatoshis = value; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { + printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(txid2,utxo->txid2) != 0 || vout != utxo->vout || value != utxo->value || tmpsatoshis != utxo->satoshis || vout2 != utxo->vout2 || value2 != utxo->value2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) { utxo->errors++; From a6006f3d50dd240636b84a524e0798a727291d07 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 12:41:57 +0300 Subject: [PATCH 1038/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 319967505..efa52b2d3 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -167,6 +167,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); + printf("parse.(%s)\n",jprint(item,0)); utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),j64bits(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),j64bits(item,"value2"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; From 62cbf1cfbe1f72c2163898231e9c7ee081b6b6c2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 13:01:33 +0300 Subject: [PATCH 1039/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bae8bfd7d..32bed2a93 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -293,7 +293,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( IAMCLIENT == 0 && strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),SATOSHIDEN * jdouble(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } if ( retstr != 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 6010a78f6..527ce50f0 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -38,7 +38,7 @@ char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); - //printf("getutxos.(%s)\n",url); + //printf("getutxo.(%s)\n",url); return(issue_curl(url)); } From a0a85cecbb86c55a107940c4fef8d7695ceaa852 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 13:28:07 +0300 Subject: [PATCH 1040/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 32bed2a93..bae8bfd7d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -293,7 +293,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( IAMCLIENT == 0 && strcmp(method,"notifyutxo") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),SATOSHIDEN * jdouble(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),SATOSHIDEN * jdouble(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } if ( retstr != 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 527ce50f0..cc4ee5e2c 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%.8f&txid2=%s&vout2=%d&value2=%.8f&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value),bits256_str(str2,utxo->txid2),utxo->vout2,dstr(utxo->value2),utxo->spendscript,utxo->coinaddr); + sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=llu&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); From 1dd8166ae1ce38d05c5f34b2ca7a2254d169b2fa Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 13:29:32 +0300 Subject: [PATCH 1041/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index cc4ee5e2c..47a1ad9e5 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=llu&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr); + sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); From 3bd91103e76fae9df7c098bc74b60b3e0944f8d8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 13:34:28 +0300 Subject: [PATCH 1042/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bae8bfd7d..fb8d470e7 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -290,7 +290,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( IAMCLIENT == 0 && strcmp(method,"notifyutxo") == 0 ) + else if ( IAMCLIENT == 0 && strcmp(method,"notified") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 47a1ad9e5..05e51f23c 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notifyutxo?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr); + sprintf(url,"http://%s:%u/api/stats/notified?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); From 1fdb995419d414fb9b264601da62e14d2e876f2c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 13:43:14 +0300 Subject: [PATCH 1043/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index fb8d470e7..303cfd20d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -293,7 +293,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( IAMCLIENT == 0 && strcmp(method,"notified") == 0 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"valuesats"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"valuesats2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } if ( retstr != 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 05e51f23c..7943cbc3c 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notified?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr); + sprintf(url,"http://%s:%u/api/stats/notified?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&valuesats=%llu&txid2=%s&vout2=%d&valuesats2=%llu&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); From bad3ebf12611121fbf70590b88073c3a0c09fd70 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 13:52:30 +0300 Subject: [PATCH 1044/2705] Test --- iguana/exchanges/LP_commands.c | 7 +++++-- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_utxos.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 303cfd20d..9f0f55c7c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -292,8 +292,11 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( IAMCLIENT == 0 && strcmp(method,"notified") == 0 ) { - printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"valuesats"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"valuesats2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + if ( juint(argjson,"timestamp") > time(NULL)-60 ) + { + printf("utxonotify.(%s)\n",jprint(argjson,0)); + LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"valuesats"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"valuesats2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + } retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } if ( retstr != 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 7943cbc3c..395f197b1 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notified?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&valuesats=%llu&txid2=%s&vout2=%d&valuesats2=%llu&script=%s&address=%s",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr); + sprintf(url,"http://%s:%u/api/stats/notified?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&valuesats=%llu&txid2=%s&vout2=%d&valuesats2=%llu&script=%s&address=%s×tamp=%u",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index efa52b2d3..055b37df3 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -32,6 +32,7 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { jaddstr(item,"coin",utxo->coin); + jaddnum(item,"now",time(NULL)); jaddstr(item,"address",utxo->coinaddr); jaddbits256(item,"txid",utxo->txid); jaddnum(item,"vout",utxo->vout); @@ -155,7 +156,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs for (i=0; i now-60 && (argipaddr= jstr(item,"ipaddr")) != 0 && (argport= juint(item,"port")) != 0 ) { if ( (pushport= juint(item,"push")) == 0 ) pushport = argport + 1; From cf9ebf00b602dba7342097fc70ebd325950ada58 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 13:59:50 +0300 Subject: [PATCH 1045/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 6 ++++-- iguana/exchanges/LP_utxos.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index bccb9e1bf..24cc54375 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -178,7 +178,7 @@ struct LP_peerinfo UT_hash_handle hh; uint64_t ip_port; double profitmargin; - uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected; + uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected,lastutxos; int32_t pushsock,subsock; uint16_t port; char ipaddr[64]; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ab7251b68..37edaeb03 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -80,7 +80,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) { //static uint16_t tmpport; - char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson; + char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson; if ( amclient == 0 ) { for (i=0; inumpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) @@ -179,8 +180,9 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) LP_peersquery(amclient,mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); } - if ( peer->numutxos != mypeer->numutxos ) + if ( peer->numutxos != mypeer->numutxos && now > peer->lastutxos+60 ) { + peer->lastutxos = now; lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; if ( lastn < LP_PROPAGATION_SLACK * 2 ) lastn = LP_PROPAGATION_SLACK * 2; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 055b37df3..2eb7b166c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -173,7 +173,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( utxo != 0 ) utxo->lasttime = now; } - } + } else printf("skip.(%s)\n",jprint(item,0)); } if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) { From ad7f0b18a23a0bd6a08416e0f7e3cad552040e49 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 14:09:22 +0300 Subject: [PATCH 1046/2705] Test --- iguana/exchanges/LP_commands.c | 3 +++ iguana/exchanges/LP_include.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9f0f55c7c..a92e866eb 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -287,7 +287,10 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + { retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); + printf("RETURN.(%s)\n",retstr); + } else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( IAMCLIENT == 0 && strcmp(method,"notified") == 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 24cc54375..63923eadb 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -32,7 +32,7 @@ #define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" #define BASILISK_DISABLEWAITTX -//#define BASILISK_DISABLESENDTX +#define BASILISK_DISABLESENDTX #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 From 0a8cc5aa066fe9655b180b1b2bfe12bff639a09e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 14:18:44 +0300 Subject: [PATCH 1047/2705] Test --- iguana/exchanges/LP_quotes.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index e406d44d7..42c5aa718 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -192,6 +192,18 @@ int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) else return(-1); } +int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) +{ + int32_t i,n = cJSON_GetArraySize(array); cJSON *item; + for (i=0; icoin) / 0.975; if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { - //printf("candidates.(%s)\n",jprint(array,0)); + printf("candidates.(%s)\n",jprint(array,0)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); From 7552abb8757f0efc73aac8417a7fe7912f5aa251 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 14:21:38 +0300 Subject: [PATCH 1048/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 42c5aa718..2b0a6e732 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -249,7 +249,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) maxprice = LP_price(base,myutxo->coin) / 0.975; if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { - printf("candidates.(%s)\n",jprint(array,0)); + printf("candidates.(%s)\nn.%d",jprint(array,0),cJSON_GetArraySize(array)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); From 6675873d74ad6384f15db4e071308d12bd5c6cf5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 14:25:16 +0300 Subject: [PATCH 1049/2705] Test --- iguana/exchanges/LP_quotes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 2b0a6e732..7a749a60c 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -181,6 +181,7 @@ char *LP_quotereceived(cJSON *argjson) if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) { ptr->Q = Q; + char str[65]; printf("received.(%s) quote %.8f\n",bits256_str(str,Q.txid),price); return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); } @@ -249,7 +250,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) maxprice = LP_price(base,myutxo->coin) / 0.975; if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { - printf("candidates.(%s)\nn.%d",jprint(array,0),cJSON_GetArraySize(array)); + printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); From 2677368d97cf2e031c433f42d4e2daa24eb84ea9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 14:26:03 +0300 Subject: [PATCH 1050/2705] Test --- iguana/exchanges/LP_prices.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index f575ac0ec..0807fc4c1 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -326,12 +326,14 @@ char *LP_orderbook(char *base,char *rel) for (i=0; i 1 ) qsort(asks,numasks,sizeof(*asks),_cmp_orderbook); for (i=0; i Date: Mon, 5 Jun 2017 14:35:19 +0300 Subject: [PATCH 1051/2705] Test --- iguana/exchanges/LP_commands.c | 15 +++++++++++++-- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 11 +++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a92e866eb..204afe6bf 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -192,7 +192,7 @@ char *LP_connected(cJSON *argjson) char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; + char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; cJSON *retjson; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) @@ -213,7 +213,18 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { if ( LP_mypriceset(base,rel,jdouble(argjson,"price")) < 0 ) return(clonestr("{\"error\":\"couldnt set price\"}")); - else return(clonestr("{\"result\":\"success\"}")); + else + { + if ( IAMCLIENT == 0 ) + { + HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + { + if ( LP_ismine(utxo) != 0 && strcmp(utxo->coin,base) == 0 ) + LP_priceping(LP_mypubsock,utxo,rel,LP_profitratio - 1.); + } + } + return(clonestr("{\"result\":\"success\"}")); + } } else if ( strcmp(method,"myprice") == 0 ) { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 37edaeb03..a5c5c9bfd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -162,7 +162,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { - if ( strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port ) + if ( LP_ismine(utxo) != 0 ) { if ( strcmp(utxo->coin,"KMD") == 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 2eb7b166c..2e4c7f6ed 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -18,6 +18,17 @@ // marketmaker // +int32_t LP_ismine(struct LP_utxoinfo *utxo) +{ + if ( strcmp(utxo->ipaddr,"127.0.0.1") == 0 ) + return(1); + else if ( LP_mypeer == 0 ) + return(0); + else if ( strcmp(utxo->ipaddr,LP_mypeer->ipaddr) == 0 && utxo->port == LP_mypeer->port )\ + return(1); + else return(0); +} + struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) { struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; From 594f75f54ac0fcc8df282bb09c3d75d4e0b430dc Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 14:40:17 +0300 Subject: [PATCH 1052/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_quotes.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 204afe6bf..7c802fff3 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -219,7 +219,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { - if ( LP_ismine(utxo) != 0 && strcmp(utxo->coin,base) == 0 ) + if ( LP_ismine(utxo) != 0 && (strcmp(utxo->coin,base) == 0 || strcmp(utxo->coin,rel) == 0) ) LP_priceping(LP_mypubsock,utxo,rel,LP_profitratio - 1.); } } diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 7a749a60c..5a0cf09f8 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -347,6 +347,7 @@ int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double p retjson = LP_quotejson(&Q); jaddstr(retjson,"method","quote"); retstr = jprint(retjson,1); + printf("PING.(%s)\n",retstr); LP_send(pubsock,retstr,1); utxo->published = now; return(0); From 66297a29182f1378358b8b03b6dbd980d8c70862 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 14:45:35 +0300 Subject: [PATCH 1053/2705] Test --- iguana/exchanges/inv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/inv b/iguana/exchanges/inv index b0b5e52b1..0009b7af4 100755 --- a/iguana/exchanges/inv +++ b/iguana/exchanges/inv @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"inventory\",\"coin\":\"KMD\"}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"inventory\",\"coin\":\"REVS\"}" From 0eae00f34567445b81255f222650607f0b473059 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 14:49:36 +0300 Subject: [PATCH 1054/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7c802fff3..a88e5de2d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -300,7 +300,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) { retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - printf("RETURN.(%s)\n",retstr); + //printf("RETURN.(%s)\n",retstr); } else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 2e4c7f6ed..4bb325b2f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -184,7 +184,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( utxo != 0 ) utxo->lasttime = now; } - } else printf("skip.(%s)\n",jprint(item,0)); + } // else printf("skip.(%s)\n",jprint(item,0)); } if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) { From 630986d42d3f825e5179cf4cc68de9ac4023a593 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 16:10:32 +0300 Subject: [PATCH 1055/2705] Test --- iguana/exchanges/LP_commands.c | 2 + iguana/exchanges/LP_include.h | 7 ++- iguana/exchanges/LP_nativeDEX.c | 12 +++++- iguana/exchanges/LP_quotes.c | 21 ++++----- iguana/exchanges/LP_swap.c | 14 +++--- iguana/exchanges/LP_utxos.c | 76 ++++++++++++++++++++++++++++++--- 6 files changed, 105 insertions(+), 27 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a88e5de2d..9e4c782ae 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -291,6 +291,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port retstr = LP_quotereceived(argjson); else if ( strcmp(method,"connected") == 0 ) retstr = LP_connected(argjson); + else if ( strcmp(method,"checktxid") == 0 ) + retstr = LP_spentcheck(argjson); else if ( strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"orderbook") == 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 63923eadb..314dbc92d 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -21,6 +21,9 @@ #ifndef LP_INCLUDE_H #define LP_INCLUDE_H +#define LP_DEXFEE(destsatoshis) ((destsatoshis) / INSTANTDEX_INSURANCEDIV) +#define LP_DEPOSITSATOSHIS(satoshis) ((satoshis) + (satoshis >> 3)) + #define INSTANTDEX_DECKSIZE 1000 #define INSTANTDEX_LOCKTIME (3600*2 + 300*2) #define INSTANTDEX_INSURANCEDIV 777 @@ -167,7 +170,7 @@ struct LP_utxoinfo uint64_t value,satoshis,value2; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; int32_t vout,vout2,pair; - uint32_t lasttime,errors,swappending,published; + uint32_t lasttime,errors,swappending,published,spentflag; double profitmargin; char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; uint16_t port; @@ -188,7 +191,7 @@ struct LP_quoteinfo { struct basilisk_request R; bits256 srchash,desthash,txid,txid2,desttxid,feetxid,privkey; - uint64_t value,satoshis,satoshis2,txfee,destsatoshis,desttxfee; + uint64_t satoshis,txfee,destsatoshis,desttxfee; uint32_t timestamp,quotetime; int32_t vout,vout2,destvout,feevout,pair; char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; }; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a5c5c9bfd..1d22abaa1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -162,7 +162,17 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { - if ( LP_ismine(utxo) != 0 ) + if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) + { + printf("txid %s %.8f has been spent\n",utxo->coin,dstr(utxo->value)); + LP_spentnotify(utxo,0); + } + else if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == 0 ) + { + printf("txid2 %s %.8f has been spent\n",utxo->coin,dstr(utxo->value2)); + LP_spentnotify(utxo,1); + } + else if ( LP_ismine(utxo) != 0 ) { if ( strcmp(utxo->coin,"KMD") == 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 5a0cf09f8..44722ea15 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -66,8 +66,6 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) { jaddbits256(retjson,"txid2",qp->txid2); jaddnum(retjson,"vout2",qp->vout2); - if ( qp->satoshis2 != 0 ) - jadd64bits(retjson,"satoshis2",qp->satoshis2); } if ( bits256_nonz(qp->desttxid) != 0 ) { @@ -114,10 +112,7 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) qp->feetxid = jbits256(argjson,"feetxid"); qp->destvout = jint(argjson,"destvout"); qp->desthash = jbits256(argjson,"desthash"); - //qp->feesatoshis = j64bits(argjson,"feesatoshis"); qp->satoshis = j64bits(argjson,"satoshis"); - qp->satoshis2 = j64bits(argjson,"satoshis2"); - qp->value = j64bits(argjson,"value"); qp->destsatoshis = j64bits(argjson,"destsatoshis"); qp->txfee = j64bits(argjson,"txfee"); qp->desttxfee = j64bits(argjson,"desttxfee"); @@ -131,16 +126,14 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) qp->txfee = 10000; - if ( qp->txfee >= utxo->value || qp->txfee >= utxo->value2 || utxo->value2 < utxo->satoshis+(utxo->satoshis>>3) ) + if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->value2 || utxo->value2 < LP_DEPOSITSATOSHIS(utxo->satoshis) ) return(-1); qp->txid = utxo->txid; qp->vout = utxo->vout; qp->txid2 = utxo->txid2; qp->vout2 = utxo->vout2; - qp->satoshis = utxo->satoshis; - qp->satoshis2 = utxo->satoshis + (utxo->satoshis >> 3); + qp->satoshis = utxo->satoshis - qp->txfee; qp->destsatoshis = qp->satoshis * price; - //qp->feesatoshis = qp->destsatoshis / INSTANTDEX_INSURANCEDIV; if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) qp->desttxfee = 10000; if ( qp->desttxfee >= qp->destsatoshis ) @@ -164,7 +157,6 @@ int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quot qp->timestamp = timestamp; qp->quotetime = quotetime; qp->destsatoshis = destsatoshis; - //qp->feesatoshis = qp->destsatoshis / INSTANTDEX_INSURANCEDIV; qp->desttxfee = desttxfee; qp->desttxid = desttxid; qp->destvout = destvout; @@ -229,8 +221,13 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) LP_quoteparse(&Q,item); safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) - if ( LP_arrayfind(retarray,Q.txid,Q.vout) < 0 ) - jaddi(retarray,jduplicate(item)); + { + if ( LP_iseligible(Q.txid,Q.vout) != 0 ) + { + if ( LP_arrayfind(retarray,Q.txid,Q.vout) < 0 ) + jaddi(retarray,jduplicate(item)); + } + } } } free_json(array); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 6a1def41e..f788c087b 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -818,20 +818,20 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); if ( swap->I.iambob != 0 ) { - basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,&swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); - basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,&swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,&swap->bobcoin,0,0,LP_DEXFEE(swap->I.bobsatoshis),0,0,jumblrflag); + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,&swap->alicecoin,0,0,LP_DEXFEE(swap->I.alicesatoshis),0,0,jumblrflag); bobpub33 = pubkey33; } else { - basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,&swap->bobcoin,0,0,swap->I.bobsatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); - basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,&swap->alicecoin,0,0,swap->I.alicesatoshis/INSTANTDEX_INSURANCEDIV,0,0,jumblrflag); + basilisk_rawtx_setparms("otherfee",swap->I.req.quoteid,&swap->otherfee,&swap->bobcoin,0,0,LP_DEXFEE(swap->I.bobsatoshis),0,0,jumblrflag); + basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,&swap->alicecoin,0,0,LP_DEXFEE(swap->I.alicesatoshis),0,0,jumblrflag); alicepub33 = pubkey33; } - basilisk_rawtx_setparms("bobdeposit",swap->I.req.quoteid,&swap->bobdeposit,&swap->bobcoin,swap->I.bobconfirms,0,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3) + swap->bobcoin.txfee,4,0,jumblrflag); - basilisk_rawtx_setparms("bobrefund",swap->I.req.quoteid,&swap->bobrefund,&swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,bobpub33,jumblrflag); + basilisk_rawtx_setparms("bobdeposit",swap->I.req.quoteid,&swap->bobdeposit,&swap->bobcoin,swap->I.bobconfirms,0,LP_DEPOSITSATOSHIS(swap->I.bobsatoshis) + swap->bobcoin.txfee,4,0,jumblrflag); + basilisk_rawtx_setparms("bobrefund",swap->I.req.quoteid,&swap->bobrefund,&swap->bobcoin,1,4,LP_DEPOSITSATOSHIS(swap->I.bobsatoshis),1,bobpub33,jumblrflag); swap->bobrefund.I.suppress_pubkeys = 1; - basilisk_rawtx_setparms("aliceclaim",swap->I.req.quoteid,&swap->aliceclaim,&swap->bobcoin,1,4,swap->I.bobsatoshis + (swap->I.bobsatoshis>>3),1,alicepub33,jumblrflag); + basilisk_rawtx_setparms("aliceclaim",swap->I.req.quoteid,&swap->aliceclaim,&swap->bobcoin,1,4,LP_DEPOSITSATOSHIS(swap->I.bobsatoshis),1,alicepub33,jumblrflag); swap->aliceclaim.I.suppress_pubkeys = 1; swap->aliceclaim.I.locktime = swap->I.started + swap->I.putduration+swap->I.callduration + 1; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 4bb325b2f..652acea7d 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -29,6 +29,13 @@ int32_t LP_ismine(struct LP_utxoinfo *utxo) else return(0); } +int32_t LP_isunspent(struct LP_utxoinfo *utxo) +{ + if ( utxo->spentflag == 0 && utxo->swappending == 0 ) + return(1); + else return(0); +} + struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) { struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; @@ -60,6 +67,8 @@ cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) jaddnum(item,"socket",utxo->pair); if ( utxo->swap != 0 ) jaddstr(item,"swap","in progress"); + if ( utxo->spentflag != 0 ) + jaddnum(item,"spent",utxo->spentflag); return(item); } @@ -94,6 +103,63 @@ char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) return(jprint(utxosjson,1)); } +void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) +{ + cJSON *argjson; + utxo->spentflag = (uint32_t)time(NULL); + if ( LP_mypubsock >= 0 ) + { + argjson = cJSON_CreateObject(); + jaddstr(argjson,"method","checktxid"); + jaddbits256(argjson,"txid",utxo->txid); + jaddnum(argjson,"vout",utxo->vout); + if ( selector != 0 ) + { + jaddbits256(argjson,"checktxid",utxo->txid2); + jaddnum(argjson,"checkvout",utxo->vout2); + } + LP_send(LP_mypubsock,jprint(argjson,1),1); + } +} + +char *LP_spentcheck(cJSON *argjson) +{ + bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; + txid = jbits256(argjson,"txid"); + vout = jint(argjson,"vout"); + if ( (utxo= LP_utxofind(txid,vout)) != 0 ) + { + if ( jobj(argjson,"check") == 0 ) + checktxid = txid, checkvout = vout; + else + { + checktxid = jbits256(argjson,"checktxid"); + checkvout = jint(argjson,"checkvout"); + } + if ( LP_txvalue(utxo->coin,checktxid,checkvout) == 0 ) + { + utxo->spentflag = (uint32_t)time(NULL); + printf("indeed txid was spent\n"); + return(clonestr("{\"result\":\"marked as spent\"}")); + } else return(clonestr("{\"error\":\"txid is still unspent?\"}")); + } else return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); +} + +int32_t LP_iseligible(bits256 txid,int32_t vout) +{ + struct LP_utxoinfo *utxo; + if ( (utxo= LP_utxofind(txid,vout)) != 0 ) + { + if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == utxo->value ) + { + if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == utxo->value2 ) + return(1); + else printf("mismatched txid value2\n"); + } else printf("mismatched txid value\n"); + } + return(0); +} + struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) { uint64_t tmpsatoshis; struct LP_utxoinfo *utxo = 0; @@ -107,8 +173,8 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("LP node got localhost utxo\n"); return(0); } - if ( IAMCLIENT == 0 || value2 < 9 * (value >> 3) ) - tmpsatoshis = (value2 / 9) << 3; + if ( IAMCLIENT == 0 || value2 < 9 * (value >> 3) + 100000 ) + tmpsatoshis = ((value2 / 9) << 3) - 100000; else tmpsatoshis = value; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { @@ -244,7 +310,7 @@ char *LP_inventory(char *symbol) else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { - if ( strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || strcmp(utxo->ipaddr,myipaddr) == 0) ) + if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || LP_ismine(utxo) != 0) ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } return(jprint(array,1)); @@ -332,8 +398,8 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb depositval = values[i]; values[i] = 0, used++; if ( amclient != 0 ) - targetval = (depositval / 776) + 50000; - else targetval = (depositval / 9) * 8; + targetval = (depositval / 776) + 100000; + else targetval = (depositval / 9) * 8 + 100000; //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) { From 6b22e3fac33e9cdfe357dafafd1c90706a4b169f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 16:16:59 +0300 Subject: [PATCH 1056/2705] Test --- iguana/exchanges/LP_prices.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 0807fc4c1..77731da74 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -306,7 +306,7 @@ char *LP_orderbook(char *base,char *rel) now = (uint32_t)time(NULL); HASH_ITER(hh,LP_cacheinfos,ptr,tmp) { - if ( ptr->timestamp < now-60 || ptr->price == 0. ) + if ( ptr->timestamp < now-60*2 || ptr->price == 0. ) continue; if ( strcmp(ptr->Q.srccoin,base) == 0 && strcmp(ptr->Q.destcoin,rel) == 0 ) { @@ -329,7 +329,15 @@ char *LP_orderbook(char *base,char *rel) jaddnum(retjson,"numbids",numbids); array = cJSON_CreateArray(); if ( numasks > 1 ) + { + for (i=0; iprice); + printf(" -> "); qsort(asks,numasks,sizeof(*asks),_cmp_orderbook); + for (i=0; iprice); + printf("sorted asks.%d\n",numasks); + } for (i=0; i Date: Mon, 5 Jun 2017 16:19:16 +0300 Subject: [PATCH 1057/2705] Test --- iguana/exchanges/LP_prices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 77731da74..43e56d472 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -265,7 +265,7 @@ static int _cmp_orderbook(const void *a,const void *b) return(1); else if ( ptr_b < ptr_a ) return(-1); - else +/* else { #undef ptr_a #undef ptr_b @@ -275,7 +275,7 @@ static int _cmp_orderbook(const void *a,const void *b) return(1); else if ( ptr_b < ptr_a ) return(-1); - } + }*/ return(0); #undef ptr_a #undef ptr_b From 8240b45820e52af3fcbd7216c1047b00a1d15579 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 16:21:28 +0300 Subject: [PATCH 1058/2705] Test --- iguana/exchanges/LP_prices.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 43e56d472..c6b965fe9 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -259,12 +259,13 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, static int _cmp_orderbook(const void *a,const void *b) { + int32_t retval = 0; #define ptr_a ((struct LP_cacheinfo *)a)->price #define ptr_b ((struct LP_cacheinfo *)b)->price if ( ptr_b > ptr_a ) - return(1); + retval = 1; else if ( ptr_b < ptr_a ) - return(-1); + retval = -1; /* else { #undef ptr_a @@ -276,7 +277,8 @@ static int _cmp_orderbook(const void *a,const void *b) else if ( ptr_b < ptr_a ) return(-1); }*/ - return(0); + printf("%.8f vs %.8f -> %d\n",ptr_a,ptr_b,retval); + return(retval); #undef ptr_a #undef ptr_b } From a509035d43f76eca3ac044d4be612f1f762779be Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 16:23:45 +0300 Subject: [PATCH 1059/2705] Test --- iguana/exchanges/LP_prices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index c6b965fe9..5655c309f 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -260,8 +260,8 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, static int _cmp_orderbook(const void *a,const void *b) { int32_t retval = 0; -#define ptr_a ((struct LP_cacheinfo *)a)->price -#define ptr_b ((struct LP_cacheinfo *)b)->price +#define ptr_a (*(struct LP_cacheinfo **)a)->price +#define ptr_b (*(struct LP_cacheinfo **)b)->price if ( ptr_b > ptr_a ) retval = 1; else if ( ptr_b < ptr_a ) From 0e98a91945d1add8c22a1e491db893de13c7f4b3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 16:32:04 +0300 Subject: [PATCH 1060/2705] Test --- iguana/exchanges/LP_prices.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 5655c309f..5b7ad7ed1 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -266,7 +266,7 @@ static int _cmp_orderbook(const void *a,const void *b) retval = 1; else if ( ptr_b < ptr_a ) retval = -1; -/* else + else { #undef ptr_a #undef ptr_b @@ -276,8 +276,8 @@ static int _cmp_orderbook(const void *a,const void *b) return(1); else if ( ptr_b < ptr_a ) return(-1); - }*/ - printf("%.8f vs %.8f -> %d\n",ptr_a,ptr_b,retval); + } + // printf("%.8f vs %.8f -> %d\n",ptr_a,ptr_b,retval); return(retval); #undef ptr_a #undef ptr_b @@ -324,7 +324,7 @@ char *LP_orderbook(char *base,char *rel) retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); if ( numbids > 1 ) - qsort(bids,numbids,sizeof(*bids),_cmp_orderbookrev); + qsort(bids,numbids,sizeof(*bids),_cmp_orderbook); for (i=0; iprice); printf(" -> "); - qsort(asks,numasks,sizeof(*asks),_cmp_orderbook); + qsort(asks,numasks,sizeof(*asks),_cmp_orderbookrev); for (i=0; iprice); printf("sorted asks.%d\n",numasks); From b3ce009c0d5b4ed5098cb76380935217840a91da Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 16:45:08 +0300 Subject: [PATCH 1061/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 44722ea15..a6116eb47 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -226,7 +226,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { if ( LP_arrayfind(retarray,Q.txid,Q.vout) < 0 ) jaddi(retarray,jduplicate(item)); - } + } else printf("ineligible.(%s)\n",jprint(item,0)); } } } From 7b070b73f7408128d5beb370f7bce765591d8136 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 16:52:52 +0300 Subject: [PATCH 1062/2705] Test --- iguana/exchanges/LP_utxos.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 652acea7d..de897ee4e 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -147,15 +147,15 @@ char *LP_spentcheck(cJSON *argjson) int32_t LP_iseligible(bits256 txid,int32_t vout) { - struct LP_utxoinfo *utxo; + struct LP_utxoinfo *utxo; uint64_t value; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { - if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == utxo->value ) + if ( (value= LP_txvalue(utxo->coin,utxo->txid,utxo->vout)) == utxo->value ) { if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == utxo->value2 ) return(1); - else printf("mismatched txid value2\n"); - } else printf("mismatched txid value\n"); + else printf("mismatched txid value2 %.8f vs %.8f\n",dstr(value),dstr(utxo->value2)); + } else printf("mismatched txid value %.8f vs %.8f\n",dstr(value),dstr(utxo->value)); } return(0); } From 71d6b7db72298094667be7497207343be84ea423 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 16:59:10 +0300 Subject: [PATCH 1063/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index de897ee4e..34e344fc3 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -147,7 +147,7 @@ char *LP_spentcheck(cJSON *argjson) int32_t LP_iseligible(bits256 txid,int32_t vout) { - struct LP_utxoinfo *utxo; uint64_t value; + struct LP_utxoinfo *utxo; uint64_t value; char str[65]; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { if ( (value= LP_txvalue(utxo->coin,utxo->txid,utxo->vout)) == utxo->value ) @@ -156,7 +156,7 @@ int32_t LP_iseligible(bits256 txid,int32_t vout) return(1); else printf("mismatched txid value2 %.8f vs %.8f\n",dstr(value),dstr(utxo->value2)); } else printf("mismatched txid value %.8f vs %.8f\n",dstr(value),dstr(utxo->value)); - } + } else printf("cant find (%s/v%d)\n",bits256_str(str,txid),vout); return(0); } From 5ba4b50d4c70ebd1340639dacb60a24512b960d9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:03:53 +0300 Subject: [PATCH 1064/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- iguana/exchanges/LP_utxos.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index a6116eb47..c409a5760 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -222,7 +222,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) { - if ( LP_iseligible(Q.txid,Q.vout) != 0 ) + if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.value,Q.txid2,Q.vout2,Q.va.ue2) != 0 ) { if ( LP_arrayfind(retarray,Q.txid,Q.vout) < 0 ) jaddi(retarray,jduplicate(item)); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 34e344fc3..6cf96495c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -145,17 +145,17 @@ char *LP_spentcheck(cJSON *argjson) } else return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); } -int32_t LP_iseligible(bits256 txid,int32_t vout) +int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t value,bits256 txid2,int32_t vout2,uint64_t value2) { - struct LP_utxoinfo *utxo; uint64_t value; char str[65]; + struct LP_utxoinfo *utxo; uint64_t val,val2; char str[65]; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { - if ( (value= LP_txvalue(utxo->coin,utxo->txid,utxo->vout)) == utxo->value ) + if ( (val= LP_txvalue(coin,txid,vout)) != value ) { - if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == utxo->value2 ) + if ( (val2= LP_txvalue(coin,txid2,vout2)) != value2 ) return(1); - else printf("mismatched txid value2 %.8f vs %.8f\n",dstr(value),dstr(utxo->value2)); - } else printf("mismatched txid value %.8f vs %.8f\n",dstr(value),dstr(utxo->value)); + else printf("mismatched txid value2 %.8f vs %.8f\n",dstr(val2),dstr(value2)); + } else printf("mismatched txid value %.8f vs %.8f\n",dstr(val),dstr(value)); } else printf("cant find (%s/v%d)\n",bits256_str(str,txid),vout); return(0); } From 7cb24bf90e222469c17aad27c3b0342e6444f67b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:06:29 +0300 Subject: [PATCH 1065/2705] Test --- iguana/exchanges/LP_utxos.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6cf96495c..b74f0a809 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -147,16 +147,13 @@ char *LP_spentcheck(cJSON *argjson) int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t value,bits256 txid2,int32_t vout2,uint64_t value2) { - struct LP_utxoinfo *utxo; uint64_t val,val2; char str[65]; - if ( (utxo= LP_utxofind(txid,vout)) != 0 ) + uint64_t val,val2; + if ( (val= LP_txvalue(coin,txid,vout)) != value ) { - if ( (val= LP_txvalue(coin,txid,vout)) != value ) - { - if ( (val2= LP_txvalue(coin,txid2,vout2)) != value2 ) - return(1); - else printf("mismatched txid value2 %.8f vs %.8f\n",dstr(val2),dstr(value2)); - } else printf("mismatched txid value %.8f vs %.8f\n",dstr(val),dstr(value)); - } else printf("cant find (%s/v%d)\n",bits256_str(str,txid),vout); + if ( (val2= LP_txvalue(coin,txid2,vout2)) != value2 ) + return(1); + else printf("mismatched %s txid value2 %.8f vs %.8f\n",coin,dstr(val2),dstr(value2)); + } else printf("mismatched %s txid value %.8f vs %.8f\n",coin,dstr(val),dstr(value)); return(0); } From 5f67a0752e34b2be57c94f9cc36d0e9d94589c1a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:09:24 +0300 Subject: [PATCH 1066/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- iguana/exchanges/LP_utxos.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index c409a5760..2d6263628 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -222,7 +222,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) { - if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.value,Q.txid2,Q.vout2,Q.va.ue2) != 0 ) + if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) != 0 ) { if ( LP_arrayfind(retarray,Q.txid,Q.vout) < 0 ) jaddi(retarray,jduplicate(item)); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b74f0a809..5c5a0b4a5 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -145,15 +145,15 @@ char *LP_spentcheck(cJSON *argjson) } else return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); } -int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t value,bits256 txid2,int32_t vout2,uint64_t value2) +int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) { - uint64_t val,val2; - if ( (val= LP_txvalue(coin,txid,vout)) != value ) + uint64_t val,val2; + if ( (val= LP_txvalue(coin,txid,vout)) < satoshis ) { - if ( (val2= LP_txvalue(coin,txid2,vout2)) != value2 ) + if ( (val2= LP_txvalue(coin,txid2,vout2)) < LP_DEPOSITSATOSHIS(satoshis) ) return(1); - else printf("mismatched %s txid value2 %.8f vs %.8f\n",coin,dstr(val2),dstr(value2)); - } else printf("mismatched %s txid value %.8f vs %.8f\n",coin,dstr(val),dstr(value)); + else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); + } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); return(0); } From 82540d4be448deeac40654de79590383c9eb21db Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:12:18 +0300 Subject: [PATCH 1067/2705] Test --- iguana/exchanges/LP_quotes.c | 1 - iguana/exchanges/LP_utxos.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 2d6263628..100fa1f6c 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -78,7 +78,6 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) { jaddbits256(retjson,"feetxid",qp->feetxid); jaddnum(retjson,"feevout",qp->feevout); - //jadd64bits(retjson,"feesatoshis",qp->feesatoshis); } if ( qp->desttxfee != 0 ) jadd64bits(retjson,"desttxfee",qp->desttxfee); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 5c5a0b4a5..6f18e709b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -148,9 +148,9 @@ char *LP_spentcheck(cJSON *argjson) int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) { uint64_t val,val2; - if ( (val= LP_txvalue(coin,txid,vout)) < satoshis ) + if ( (val= LP_txvalue(coin,txid,vout)) >= satoshis ) { - if ( (val2= LP_txvalue(coin,txid2,vout2)) < LP_DEPOSITSATOSHIS(satoshis) ) + if ( (val2= LP_txvalue(coin,txid2,vout2)) >= LP_DEPOSITSATOSHIS(satoshis) ) return(1); else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); From d45169018540f566ab6ad3ac99fb42190e533ec7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:18:20 +0300 Subject: [PATCH 1068/2705] Test --- iguana/exchanges/LP_commands.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9e4c782ae..e46448767 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -209,6 +209,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port return(clonestr("{\"error\":\"authentication error\"}")); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) { + char str[65]; if ( strcmp(method,"setprice") == 0 ) { if ( LP_mypriceset(base,rel,jdouble(argjson,"price")) < 0 ) @@ -221,6 +222,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { if ( LP_ismine(utxo) != 0 && (strcmp(utxo->coin,base) == 0 || strcmp(utxo->coin,rel) == 0) ) LP_priceping(LP_mypubsock,utxo,rel,LP_profitratio - 1.); + else printf("notmine.(%s %s)\n",utxo->coin,bits256_str(str,utxo->txid)); } } return(clonestr("{\"result\":\"success\"}")); From 497009ce0ed3a59e325b7d29375ea13a26efd943 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:29:13 +0300 Subject: [PATCH 1069/2705] Test --- iguana/exchanges/LP_utxos.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6f18e709b..caf0f5553 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -151,7 +151,10 @@ int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bit if ( (val= LP_txvalue(coin,txid,vout)) >= satoshis ) { if ( (val2= LP_txvalue(coin,txid2,vout2)) >= LP_DEPOSITSATOSHIS(satoshis) ) + { + printf("val %.8f and val2 %.8f\n",dstr(val),dstr(val2)); return(1); + } else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); return(0); From 43476d8cd1a9bb89f2fbb18d95918c57ff01890e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:31:02 +0300 Subject: [PATCH 1070/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index caf0f5553..4fbb87d82 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -95,7 +95,7 @@ char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) { if ( i++ < firsti ) continue; - if ( coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0 ) + if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) && LP_ismine(utxo) != 0 ) { jaddi(utxosjson,LP_utxojson(utxo)); } @@ -152,7 +152,7 @@ int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bit { if ( (val2= LP_txvalue(coin,txid2,vout2)) >= LP_DEPOSITSATOSHIS(satoshis) ) { - printf("val %.8f and val2 %.8f\n",dstr(val),dstr(val2)); + printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); return(1); } else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); From 8542917aea95f7a42e24f93ea2df55173ed37b43 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:36:20 +0300 Subject: [PATCH 1071/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 100fa1f6c..22786d75a 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -208,7 +208,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { - //printf("%s:%u %s\n",peer->ipaddr,peer->port,utxostr); + printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); if ( (array= cJSON_Parse(utxostr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) From dbf5e11760b24e94b22316d071d8954dd5b4fee2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 17:39:21 +0300 Subject: [PATCH 1072/2705] Test --- iguana/exchanges/LP_peers.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index e7d83a93e..091943d4f 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -50,6 +50,8 @@ char *LP_peers() struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) { uint32_t ipbits; int32_t pushsock,subsock,timeout,enabled; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; + if ( strcmp(ipaddr,"173.208.149.42") == 0 ) + return(0); ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) From 17bd73a6babaa4388edbb3be8ae1f1b6b4e5812a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 18:39:10 +0300 Subject: [PATCH 1073/2705] Test --- iguana/exchanges/LP_quotes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 22786d75a..419821ea0 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -208,7 +208,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { - printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); + //printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); if ( (array= cJSON_Parse(utxostr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) @@ -270,7 +270,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) besti = -1; for (i=0; isatoshis > Q[i].destsatoshis ) + if ( (price= prices[i]) != 0. && myutxo->satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) { metric = price / bestprice; printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); From 48183d01c7007f8c086291a550da65a6ae550014 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 18:42:26 +0300 Subject: [PATCH 1074/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- iguana/exchanges/LP_utxos.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 419821ea0..04da9278f 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -262,7 +262,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) bestprice = price; - //char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); + char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); } if ( bestprice != 0. ) { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 4fbb87d82..335b3494a 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -152,10 +152,9 @@ int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bit { if ( (val2= LP_txvalue(coin,txid2,vout2)) >= LP_DEPOSITSATOSHIS(satoshis) ) { - printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); return(1); - } - else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); + } else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); return(0); } From ab503df182b6a6efe57b32646728b10be0ae07b6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 18:52:08 +0300 Subject: [PATCH 1075/2705] Test --- iguana/exchanges/LP_quotes.c | 16 ++++++++++++++-- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 04da9278f..8a5ad2bab 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -198,14 +198,16 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) { - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n; double price; + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; double price; if ( (price= LP_price(base,myutxo->coin)) == .0 ) { printf("no LP_price (%s -> %s)\n",base,myutxo->coin); return(0); } + totaladded = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { + n = 0; if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { //printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); @@ -214,6 +216,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { retarray = cJSON_CreateArray(); + added = 0; for (i=0; icoin) == 0) && LP_ismine(utxo) != 0 ) + if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) )//&& LP_ismine(utxo) != 0 ) { jaddi(utxosjson,LP_utxojson(utxo)); } From 5a74e4db586b60402d1c9dc09334aa17a5373065 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 19:06:38 +0300 Subject: [PATCH 1076/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index e46448767..21ffd8ca2 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -304,7 +304,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) { retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - //printf("RETURN.(%s)\n",retstr); + printf("RETURN. %d utxos\n",cJSON_GetArraySize(cJSON_Parse(retstr))); } else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); From 969fd66ad076549a86b00e7f78535d2280c51fb6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 19:10:05 +0300 Subject: [PATCH 1077/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 045dca9f3..63afe847c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -232,7 +232,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs for (i=0; i now-60 && (argipaddr= jstr(item,"ipaddr")) != 0 && (argport= juint(item,"port")) != 0 ) + if ( (argipaddr= jstr(item,"ipaddr")) != 0 && (argport= juint(item,"port")) != 0 ) { if ( (pushport= juint(item,"push")) == 0 ) pushport = argport + 1; From 7a1cf0ffb3cfe16655a0605aa212d0f358558c89 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 19:10:49 +0300 Subject: [PATCH 1078/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 21ffd8ca2..6a8bdd215 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -222,7 +222,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { if ( LP_ismine(utxo) != 0 && (strcmp(utxo->coin,base) == 0 || strcmp(utxo->coin,rel) == 0) ) LP_priceping(LP_mypubsock,utxo,rel,LP_profitratio - 1.); - else printf("notmine.(%s %s)\n",utxo->coin,bits256_str(str,utxo->txid)); + //else printf("notmine.(%s %s)\n",utxo->coin,bits256_str(str,utxo->txid)); } } return(clonestr("{\"result\":\"success\"}")); From 7078125aea655e7ec18051a60dea3005f65829b3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 19:24:23 +0300 Subject: [PATCH 1079/2705] Test --- iguana/exchanges/LP_quotes.c | 18 ++++++++++++------ iguana/exchanges/LP_utxos.c | 4 ++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 8a5ad2bab..de9407ea8 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -172,7 +172,7 @@ char *LP_quotereceived(cJSON *argjson) if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) { ptr->Q = Q; - char str[65]; printf("received.(%s) quote %.8f\n",bits256_str(str,Q.txid),price); + //char str[65]; printf("received.(%s) quote %.8f\n",bits256_str(str,Q.txid),price); return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); } @@ -207,7 +207,7 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) totaladded = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { - n = 0; + n = added = 0; if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { //printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); @@ -216,7 +216,6 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { retarray = cJSON_CreateArray(); - added = 0; for (i=0; icoin) / 0.975; if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) { - printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); + //printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); @@ -330,7 +329,14 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) jaddnum(bestitem,"requestid",R.requestid); jaddnum(bestitem,"quoteid",R.quoteid); printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); - } else jaddstr(bestitem,"status","too expensive"); + } + else + { + jaddstr(bestitem,"status","too expensive"); + jaddnum(bestitem,"price",price); + jaddnum(bestitem,"maxprice",maxprice); + jaddnum(bestitem,"bestprice",bestprice); + } } } } @@ -355,7 +361,7 @@ int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double p retjson = LP_quotejson(&Q); jaddstr(retjson,"method","quote"); retstr = jprint(retjson,1); - printf("PING.(%s)\n",retstr); + //printf("PING.(%s)\n",retstr); LP_send(pubsock,retstr,1); utxo->published = now; return(0); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 63afe847c..89bc8e88c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -177,7 +177,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 else tmpsatoshis = value; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { - printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); + //printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(txid2,utxo->txid2) != 0 || vout != utxo->vout || value != utxo->value || tmpsatoshis != utxo->satoshis || vout2 != utxo->vout2 || value2 != utxo->value2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) { utxo->errors++; @@ -244,7 +244,7 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - printf("parse.(%s)\n",jprint(item,0)); + //printf("parse.(%s)\n",jprint(item,0)); utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),j64bits(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),j64bits(item,"value2"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) utxo->lasttime = now; From db242a860d0e841f42d543c6cd657bab8f451145 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 19:35:51 +0300 Subject: [PATCH 1080/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_transaction.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 314dbc92d..cead54feb 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -35,7 +35,7 @@ #define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" #define BASILISK_DISABLEWAITTX -#define BASILISK_DISABLESENDTX +//#define BASILISK_DISABLESENDTX #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 7acfe1f48..9a2bb6998 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1205,7 +1205,11 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i printf(" <- GENERATED BOB PAYMENT.%d destaddr.(%s)\n",swap->bobpayment.I.datalen,swap->bobpayment.I.destaddr); LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); if ( swap->I.iambob != 0 ) + { + swap->bobpayment.utxovout = 0; + swap->bobpayment.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); + } //printf("bobscripts set completed\n"); return(0); } @@ -1234,7 +1238,11 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); LP_unspents_mark(swap->bobcoin.symbol,swap->bobdeposit.vins); if ( swap->I.iambob != 0 ) + { + swap->bobrefund.utxovout = 0; + swap->bobrefund.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobdeposit_refund(swap,swap->I.putduration); + } printf("bobscripts set completed\n"); return(0); } From 45f1e761a2cf28c2ce35418f1ab7b937acd6b1af Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 19:49:34 +0300 Subject: [PATCH 1081/2705] Test --- iguana/exchanges/LP_swap.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index f788c087b..e4067a2d7 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -864,18 +864,18 @@ struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 swap->persistent_privkey = privkey; memcpy(swap->persistent_pubkey33,pubkey33,33); calc_rmd160_sha256(swap->changermd160,pubkey33,33); - if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,!iambob) == 0 ) - { - printf("error doing swapinit\n"); - free(swap); - swap = 0; - } swap->bobpayment.utxotxid = qp->txid, swap->bobpayment.utxovout = qp->vout; swap->bobdeposit.utxotxid = qp->txid2, swap->bobdeposit.utxovout = qp->vout2; swap->alicepayment.utxotxid = qp->desttxid, swap->alicepayment.utxovout = qp->destvout; if ( iambob != 0 ) swap->otherfee.utxotxid = qp->feetxid, swap->otherfee.utxovout = qp->feevout; else swap->myfee.utxotxid = qp->feetxid, swap->myfee.utxovout = qp->feevout; + if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,!iambob) == 0 ) + { + printf("error doing swapinit\n"); + free(swap); + swap = 0; + } return(swap); } From 055623e1f908f1594b827e7e043926ca54df37fa Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 19:58:56 +0300 Subject: [PATCH 1082/2705] Test --- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index ff2e35c11..f014e3095 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -43,7 +43,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) len = (int32_t)strlen(msg) + 1; if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); - else printf("SENT.(%s)\n",msg); + //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); return(sentbytes); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 89bc8e88c..13ca0b72d 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -212,7 +212,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid)); + char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid2)); } return(utxo); } From 27eb04d57581b02a03193aad133ecb81e9bad5cc Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 20:08:10 +0300 Subject: [PATCH 1083/2705] Test --- iguana/exchanges/LP_swap.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index e4067a2d7..f4d305b20 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -739,7 +739,7 @@ void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx * } else printf("%s vouttype.%d destaddr.(%s)\n",name,rawtx->I.vouttype,rawtx->I.destaddr); } -struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 pubkey25519,struct basilisk_swap *swap,int32_t optionduration,uint32_t statebits) +struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 pubkey25519,struct basilisk_swap *swap,int32_t optionduration,uint32_t statebits,struct LP_quoteinfo *qp) { //FILE *fp; char fname[512]; uint8_t *alicepub33=0,*bobpub33=0; int32_t jumblrflag=-2,x = -1; struct iguana_info *coin; @@ -846,7 +846,13 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 swap->bobspend.I.suppress_pubkeys = 1; basilisk_rawtx_setparms("alicereclaim",swap->I.req.quoteid,&swap->alicereclaim,&swap->alicecoin,swap->I.aliceconfirms,2,swap->I.alicesatoshis,1,alicepub33,jumblrflag); swap->alicereclaim.I.suppress_pubkeys = 1; - printf("IAMBOB.%d\n",swap->I.iambob); + swap->bobpayment.utxotxid = qp->txid, swap->bobpayment.utxovout = qp->vout; + swap->bobdeposit.utxotxid = qp->txid2, swap->bobdeposit.utxovout = qp->vout2; + swap->alicepayment.utxotxid = qp->desttxid, swap->alicepayment.utxovout = qp->destvout; + if ( swap->I.iambob != 0 ) + swap->otherfee.utxotxid = qp->feetxid, swap->otherfee.utxovout = qp->feevout; + else swap->myfee.utxotxid = qp->feetxid, swap->myfee.utxovout = qp->feevout; + char str[65],str2[65]; printf("IAMBOB.%d %s %s\n",swap->I.iambob,bits256_str(str,qp->txid),bits256_str(str2,qp->txid2)); return(swap); } @@ -864,13 +870,7 @@ struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 swap->persistent_privkey = privkey; memcpy(swap->persistent_pubkey33,pubkey33,33); calc_rmd160_sha256(swap->changermd160,pubkey33,33); - swap->bobpayment.utxotxid = qp->txid, swap->bobpayment.utxovout = qp->vout; - swap->bobdeposit.utxotxid = qp->txid2, swap->bobdeposit.utxovout = qp->vout2; - swap->alicepayment.utxotxid = qp->desttxid, swap->alicepayment.utxovout = qp->destvout; - if ( iambob != 0 ) - swap->otherfee.utxotxid = qp->feetxid, swap->otherfee.utxovout = qp->feevout; - else swap->myfee.utxotxid = qp->feetxid, swap->myfee.utxovout = qp->feevout; - if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,!iambob) == 0 ) + if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,!iambob,qp) == 0 ) { printf("error doing swapinit\n"); free(swap); From 4595a675b20906f02957d3d4b7edc1628943d989 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 20:18:09 +0300 Subject: [PATCH 1084/2705] Test --- iguana/exchanges/LP_swap.c | 2 +- iguana/exchanges/LP_transaction.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index f4d305b20..960a26384 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -852,7 +852,7 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 if ( swap->I.iambob != 0 ) swap->otherfee.utxotxid = qp->feetxid, swap->otherfee.utxovout = qp->feevout; else swap->myfee.utxotxid = qp->feetxid, swap->myfee.utxovout = qp->feevout; - char str[65],str2[65]; printf("IAMBOB.%d %s %s\n",swap->I.iambob,bits256_str(str,qp->txid),bits256_str(str2,qp->txid2)); + char str[65],str2[65],str3[65]; printf("IAMBOB.%d %s %s %s\n",swap->I.iambob,bits256_str(str,qp->txid),bits256_str(str2,qp->txid2),bits256_str(str3,qp->feetxid)); return(swap); } diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 9a2bb6998..9328cb267 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -682,6 +682,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160,char *vinaddr) { int32_t retval=-1,len,iter; char *signedtx,*changeaddr = 0,_changeaddr[64]; struct iguana_info *coin; int64_t newtxfee=0,destamount; + printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str,rawtx->utxotxid),rawtx->utxovout); if ( (coin= rawtx->coin) == 0 ) return(-1); //return(_basilisk_rawtx_gen(str,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay,privkey)); From 8d6ee3a754c6a1f423228e0a4c6551a0b81d05d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 20:49:54 +0300 Subject: [PATCH 1085/2705] Test --- iguana/exchanges/LP_commands.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6a8bdd215..0de787665 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -113,17 +113,18 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( LP_quoteparse(&Q,argjson) < 0 ) return(-2); //printf("connect with.(%s)\n",jprint(argjson,0)); + Q.destsatoshis = Q.satoshis * price; privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); - if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) != 0 && bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { + printf("txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) printf("error creating utxo->pair\n"); else if ( nn_bind(utxo->pair,pairstr) >= 0 ) { - //char str[65]; printf("destsatoshis %.8f %s t%u\n",dstr(Q.destsatoshis),bits256_str(str,Q.desthash),Q.quotetime); LP_requestinit(&R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) == 0 ) { From 273c5c6e71c19b7a15f08c3c1502b1415c82b2a9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 20:56:52 +0300 Subject: [PATCH 1086/2705] Test --- iguana/exchanges/LP_commands.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 0de787665..7e9243b00 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -80,6 +80,12 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); + printf("txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); + if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) + { + printf("not eligible\n"); + return(-1); + } if ( strcmp(method,"price") == 0 ) Q.timestamp = (uint32_t)time(NULL); retjson = LP_quotejson(&Q); @@ -117,9 +123,8 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); - if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) != 0 && bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { - printf("txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) printf("error creating utxo->pair\n"); From af9538d46b19e1f0d9f6b4e4c5e3df7f122f8246 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 21:03:27 +0300 Subject: [PATCH 1087/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7e9243b00..bb46aea7f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -80,7 +80,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); - printf("txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); + //printf("txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); From a75a9c876898265ec8785565211a7d032fe24763 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 21:03:45 +0300 Subject: [PATCH 1088/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bb46aea7f..2a043dc27 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -65,7 +65,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(txid,jint(argjson,"vout"))) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { - //printf("LP_command.(%s)\n",jprint(argjson,0)); + printf("LP_command.(%s)\n",jprint(argjson,0)); if ( time(NULL) > utxo->swappending ) utxo->swappending = 0; if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) From cc8cdcb9e2100a5c7f017adb0e7b00cba69a485f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 21:13:15 +0300 Subject: [PATCH 1089/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2a043dc27..3c9fcbff4 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -81,11 +81,11 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); //printf("txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); - if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) + /*if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); return(-1); - } + }*/ if ( strcmp(method,"price") == 0 ) Q.timestamp = (uint32_t)time(NULL); retjson = LP_quotejson(&Q); From 5b04db522aec5b8aceaf67c638da1390580f419b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 21:25:51 +0300 Subject: [PATCH 1090/2705] Test --- iguana/exchanges/LP_swap.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 960a26384..16552ddbe 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -409,9 +409,10 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i void *data; int32_t datalen,retval = -1; uint32_t expiration = (uint32_t)time(NULL) + timeout; while ( time(NULL) < expiration ) { + printf("start wait\n"); if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { - //printf("wait for got.%d\n",datalen); + printf("wait for got.%d\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); return(retval); @@ -424,14 +425,19 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; + printf("waitsend.%s\n",statename); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { + printf("waited for %s\n",statename); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) + { + printf("sent.%d after waitfor.%s\n",sendlen,statename); retval = 0; + } else printf("send %s error\n",statename); - } + } else printf("%s datagen no data\n",statename); } else printf("didnt get valid data\n"); return(retval); } @@ -439,15 +445,20 @@ int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basi int32_t LP_sendwait(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; + printf("sendwait.%s\n",statename); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { + printf("generated %d for %s\n",datalen,statename); if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { + printf("sendwait.%s sent %d\n",statename,sendlen); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) + { + printf("waited! sendwait.%s sent %d\n",statename,sendlen); retval = 0; - else printf("didnt get %s\n",statename); + } else printf("didnt get %s\n",statename); } else printf("send pubkeys error\n"); - } + } else printf("no datagen for %s\n",statename); return(retval); } From 9731661ef2c6acb373766127e849f7c5656131f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 21:33:08 +0300 Subject: [PATCH 1091/2705] Test --- iguana/exchanges/LP_commands.c | 8 ++++---- iguana/exchanges/LP_transaction.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 3c9fcbff4..23293800a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -81,11 +81,11 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); //printf("txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); - /*if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) + if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); return(-1); - }*/ + } if ( strcmp(method,"price") == 0 ) Q.timestamp = (uint32_t)time(NULL); retjson = LP_quotejson(&Q); @@ -215,7 +215,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port return(clonestr("{\"error\":\"authentication error\"}")); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) { - char str[65]; + //char str[65]; if ( strcmp(method,"setprice") == 0 ) { if ( LP_mypriceset(base,rel,jdouble(argjson,"price")) < 0 ) @@ -310,7 +310,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) { retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - printf("RETURN. %d utxos\n",cJSON_GetArraySize(cJSON_Parse(retstr))); + //printf("RETURN. %d utxos\n",cJSON_GetArraySize(cJSON_Parse(retstr))); } else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 9328cb267..d0458696e 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -682,7 +682,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160,char *vinaddr) { int32_t retval=-1,len,iter; char *signedtx,*changeaddr = 0,_changeaddr[64]; struct iguana_info *coin; int64_t newtxfee=0,destamount; - printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str,rawtx->utxotxid),rawtx->utxovout); + char str2[65]; printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str2,rawtx->utxotxid),rawtx->utxovout); if ( (coin= rawtx->coin) == 0 ) return(-1); //return(_basilisk_rawtx_gen(str,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay,privkey)); From 1cf000ca5d87fb4540f2a88594cf17f83a6264ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 21:43:44 +0300 Subject: [PATCH 1092/2705] Test --- iguana/exchanges/LP_swap.c | 25 ++++++++++++------------- iguana/exchanges/LP_transaction.c | 5 +++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 16552ddbe..68ed6450f 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -409,10 +409,10 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i void *data; int32_t datalen,retval = -1; uint32_t expiration = (uint32_t)time(NULL) + timeout; while ( time(NULL) < expiration ) { - printf("start wait\n"); + //printf("start wait\n"); if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { - printf("wait for got.%d\n",datalen); + //printf("wait for got.%d\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); return(retval); @@ -425,18 +425,17 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; - printf("waitsend.%s\n",statename); + //printf("waitsend.%s\n",statename); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { - printf("waited for %s\n",statename); + //printf("waited for %s\n",statename); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { - printf("sent.%d after waitfor.%s\n",sendlen,statename); + //printf("sent.%d after waitfor.%s\n",sendlen,statename); retval = 0; - } - else printf("send %s error\n",statename); + } else printf("send %s error\n",statename); } else printf("%s datagen no data\n",statename); } else printf("didnt get valid data\n"); return(retval); @@ -445,16 +444,16 @@ int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basi int32_t LP_sendwait(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; - printf("sendwait.%s\n",statename); + //printf("sendwait.%s\n",statename); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { - printf("generated %d for %s\n",datalen,statename); + //printf("generated %d for %s\n",datalen,statename); if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { - printf("sendwait.%s sent %d\n",statename,sendlen); + //printf("sendwait.%s sent %d\n",statename,sendlen); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { - printf("waited! sendwait.%s sent %d\n",statename,sendlen); + //printf("waited! sendwait.%s sent %d\n",statename,sendlen); retval = 0; } else printf("didnt get %s\n",statename); } else printf("send pubkeys error\n"); @@ -512,7 +511,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 sendbuf[sendlen++] = rawtx->I.datalen & 0xff; sendbuf[sendlen++] = (rawtx->I.datalen >> 8) & 0xff; sendbuf[sendlen++] = rawtx->I.redeemlen; - int32_t z; for (z=0; zI.datalen; z++) printf("%02x",rawtx->txbytes[z]); printf(" >>>>>>> send.%d %s\n",rawtx->I.datalen,rawtx->name); + //int32_t z; for (z=0; zI.datalen; z++) printf("%02x",rawtx->txbytes[z]); printf(" >>>>>>> send.%d %s\n",rawtx->I.datalen,rawtx->name); //printf("datalen.%d redeemlen.%d\n",rawtx->I.datalen,rawtx->I.redeemlen); memcpy(&sendbuf[sendlen],rawtx->txbytes,rawtx->I.datalen), sendlen += rawtx->I.datalen; if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) @@ -558,7 +557,7 @@ void LP_bobloop(void *_utxo) printf("error bobscripts deposit\n"); else { - printf("depositlen.%d\n",swap->bobdeposit.I.datalen); + //printf("depositlen.%d\n",swap->bobdeposit.I.datalen); LP_swapsfp_update(&swap->I.req); if ( LP_waitfor(utxo->pair,swap,10,LP_verify_otherfee) < 0 ) printf("error waiting for alicefee\n"); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index d0458696e..8a4428def 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -721,6 +721,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160,char *vinaddr) { char *signedtx,*changeaddr = 0,_changeaddr[64]; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,retval = -1; double estimatedrate; + char str2[65]; printf("%s rawtxsign.(%s/v%d)\n",dest->name,bits256_str(str2,dest->utxotxid),dest->utxovout); timestamp = swap->I.started; if ( dest == &swap->aliceclaim ) locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; @@ -1207,8 +1208,8 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); if ( swap->I.iambob != 0 ) { - swap->bobpayment.utxovout = 0; - swap->bobpayment.utxotxid = swap->bobpayment.I.signedtxid; + swap->bobreclaim.utxovout = 0; + swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); } //printf("bobscripts set completed\n"); From 29288d23ed80e980d99446022ce44d5db2bd212d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 21:48:50 +0300 Subject: [PATCH 1093/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 13ca0b72d..26f694580 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -172,8 +172,8 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("LP node got localhost utxo\n"); return(0); } - if ( IAMCLIENT == 0 || value2 < 9 * (value >> 3) + 100000 ) - tmpsatoshis = ((value2 / 9) << 3) - 100000; + if ( IAMCLIENT == 0 && value2 < 9 * (value >> 3) + 100000 ) + tmpsatoshis = (((value2-100000) / 9) << 3); else tmpsatoshis = value; if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { From 967a28647ebd12d7fe03584d568846c76b8040f3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 21:53:38 +0300 Subject: [PATCH 1094/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 8a4428def..633c654ad 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1242,7 +1242,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i if ( swap->I.iambob != 0 ) { swap->bobrefund.utxovout = 0; - swap->bobrefund.utxotxid = swap->bobpayment.I.signedtxid; + swap->bobrefund.utxotxid = swap->bobdeposit.I.signedtxid; basilisk_bobdeposit_refund(swap,swap->I.putduration); } printf("bobscripts set completed\n"); From b26c28e293a3ec5a7d6d37f75ccf6b578ceb3af4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 22:03:55 +0300 Subject: [PATCH 1095/2705] Test --- iguana/exchanges/LP_commands.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 23293800a..12b1d8fe4 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -80,7 +80,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); - //printf("txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); + printf("GETTXOUT: txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); @@ -123,6 +123,12 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); + printf("GETTXOUT: txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); + if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) + { + printf("not eligible\n"); + return(-1); + } if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); From 88859d6f093d38bbed84e4e56aa8e35f7f732265 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 22:11:12 +0300 Subject: [PATCH 1096/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 26f694580..3c90d467b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -152,7 +152,7 @@ int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bit { if ( (val2= LP_txvalue(coin,txid2,vout2)) >= LP_DEPOSITSATOSHIS(satoshis) ) { - //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); return(1); } else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); From dd961938fb31b2012bd609ec749e3f3045ca3070 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 22:26:23 +0300 Subject: [PATCH 1097/2705] Test --- iguana/exchanges/LP_transaction.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 633c654ad..8a823c5a5 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -60,7 +60,7 @@ bits256 LP_broadcast_tx(char *name,char *symbol,uint8_t *data,int32_t datalen) return(txid); } -uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) +uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) { uint64_t value = 0; double interest; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; if ( (txobj= LP_gettx(symbol,txid)) != 0 ) @@ -91,6 +91,29 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) return(value); } +uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) +{ + uint64_t value = 0; double interest; cJSON *txobj; + if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) + { + //char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); + if ( (value= jdouble(txobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(txobj,"value")*SATOSHIDEN) == 0 ) + { + char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d\n",symbol,bits256_str(str,txid),jprint(txobj,0),vout); + } + else if ( strcmp(symbol,"KMD") == 0 ) + { + if ( (interest= jdouble(txobj,"interest")) != 0. ) + { + printf("add interest of %.8f to %.8f\n",interest,dstr(value)); + value += SATOSHIDEN * interest; + } + } + free_json(txobj); + } + return(value); +} + int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) { int32_t numconfirms = 100; From b7576a75f7efe7a3023ff5418310a45fdd6b746e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 22:35:07 +0300 Subject: [PATCH 1098/2705] Test --- iguana/exchanges/LP_utxos.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 3c90d467b..2483ff12b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -139,7 +139,7 @@ char *LP_spentcheck(cJSON *argjson) if ( LP_txvalue(utxo->coin,checktxid,checkvout) == 0 ) { utxo->spentflag = (uint32_t)time(NULL); - printf("indeed txid was spent\n"); + //printf("indeed txid was spent\n"); return(clonestr("{\"result\":\"marked as spent\"}")); } else return(clonestr("{\"error\":\"txid is still unspent?\"}")); } else return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); @@ -152,7 +152,7 @@ int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bit { if ( (val2= LP_txvalue(coin,txid2,vout2)) >= LP_DEPOSITSATOSHIS(satoshis) ) { - printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); return(1); } else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); @@ -167,6 +167,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } + if ( LP_iseligible(coin,txid,vout,value,txid2,vout2) <= 0 ) + { + printf("LP_addutxo got spent txid\n"); + return(0); + } if ( IAMCLIENT == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) { printf("LP node got localhost utxo\n"); From cebfc827c5f8ba8f61ec43e953bfa32f3f36cc81 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 22:45:46 +0300 Subject: [PATCH 1099/2705] Test --- iguana/exchanges/LP_utxos.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 2483ff12b..45f61cb36 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -152,7 +152,7 @@ int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bit { if ( (val2= LP_txvalue(coin,txid2,vout2)) >= LP_DEPOSITSATOSHIS(satoshis) ) { - //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); return(1); } else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); @@ -167,7 +167,10 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } - if ( LP_iseligible(coin,txid,vout,value,txid2,vout2) <= 0 ) + if ( IAMCLIENT == 0 && value2 < 9 * (value >> 3) + 100000 ) + tmpsatoshis = (((value2-100000) / 9) << 3); + else tmpsatoshis = value; + if ( LP_iseligible(coin,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("LP_addutxo got spent txid\n"); return(0); @@ -177,10 +180,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("LP node got localhost utxo\n"); return(0); } - if ( IAMCLIENT == 0 && value2 < 9 * (value >> 3) + 100000 ) - tmpsatoshis = (((value2-100000) / 9) << 3); - else tmpsatoshis = value; - if ( (utxo= LP_utxofind(txid,vout)) != 0 ) + if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { //printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(txid2,utxo->txid2) != 0 || vout != utxo->vout || value != utxo->value || tmpsatoshis != utxo->satoshis || vout2 != utxo->vout2 || value2 != utxo->value2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) From 1ee4dbc6b2c209689d7286dd15b58bbdb9bd48b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 22:47:03 +0300 Subject: [PATCH 1100/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index cead54feb..0ca6db3b0 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -181,7 +181,7 @@ struct LP_peerinfo UT_hash_handle hh; uint64_t ip_port; double profitmargin; - uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected,lastutxos; + uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected,lastutxos,lastpeers; int32_t pushsock,subsock; uint16_t port; char ipaddr[64]; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1d22abaa1..93959eab3 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -183,8 +183,9 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i now = (uint32_t)time(NULL); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) + if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) { + peer->lastpeers = now; if ( peer->numpeers != mypeer->numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) From f92c901391a6998ae9f8ef6d54cf0381eb1eae97 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 22:56:03 +0300 Subject: [PATCH 1101/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 45f61cb36..42b072337 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -172,7 +172,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 else tmpsatoshis = value; if ( LP_iseligible(coin,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { - printf("LP_addutxo got spent txid\n"); + printf("LP_addutxo got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); } if ( IAMCLIENT == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) From 6a90ce477a58fe243f500cb792ab92c54dc3a44e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 23:01:23 +0300 Subject: [PATCH 1102/2705] Test --- iguana/exchanges/LP_utxos.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 42b072337..cdc802946 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -147,10 +147,11 @@ char *LP_spentcheck(cJSON *argjson) int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) { - uint64_t val,val2; + uint64_t val,val2,threshold; if ( (val= LP_txvalue(coin,txid,vout)) >= satoshis ) { - if ( (val2= LP_txvalue(coin,txid2,vout2)) >= LP_DEPOSITSATOSHIS(satoshis) ) + threshold = (IAMCLIENT == 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); + if ( (val2= LP_txvalue(coin,txid2,vout2)) >= threshold ) { printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); return(1); From a458a814dda4da4463b540585480a26ed1502b93 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 5 Jun 2017 23:09:19 +0300 Subject: [PATCH 1103/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 8a823c5a5..924aebc27 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -96,7 +96,6 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) uint64_t value = 0; double interest; cJSON *txobj; if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) { - //char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); if ( (value= jdouble(txobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(txobj,"value")*SATOSHIDEN) == 0 ) { char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d\n",symbol,bits256_str(str,txid),jprint(txobj,0),vout); @@ -109,6 +108,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) value += SATOSHIDEN * interest; } } + char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); free_json(txobj); } return(value); From 84dee477bf040988294d3a060ad77a4e373713e7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 08:42:11 +0300 Subject: [PATCH 1104/2705] Test --- iguana/exchanges/LP_swap.c | 74 +++++++++++++++++++++++++++++++ iguana/exchanges/LP_transaction.c | 69 +--------------------------- 2 files changed, 75 insertions(+), 68 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 68ed6450f..2c51bd4f4 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -492,6 +492,80 @@ struct basilisk_rawtx *LP_swapdata_rawtx(struct basilisk_swap *swap,uint8_t *dat return(0); } +int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) +{ + bits256 otherhash,myhash,txid; int32_t i,offset=0,datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; uint32_t quoteid,msgbits; + for (i=0; i<32; i++) + otherhash.bytes[i] = recvbuf[offset++]; + for (i=0; i<32; i++) + myhash.bytes[i] = recvbuf[offset++]; + offset += iguana_rwnum(0,&recvbuf[offset],sizeof(quoteid),"eid); + offset += iguana_rwnum(0,&recvbuf[offset],sizeof(msgbits),&msgbits); + datalen = recvbuf[offset++]; + datalen += (int32_t)recvbuf[offset++] << 8; + if ( datalen > 1024 ) + { + printf("LP_rawtx_spendscript %s datalen.%d too big\n",rawtx->name,datalen); + return(-1); + } + rawtx->I.redeemlen = recvbuf[offset++]; + data = &recvbuf[offset]; + if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) + { + memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); + for (i=0; iI.redeemlen; i++) + printf("%02x",rawtx->redeemscript[i]); + printf(" received redeemscript\n"); + } + //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); + if ( rawtx->I.datalen == 0 ) + { + for (i=0; itxbytes,data,datalen); + rawtx->I.datalen = datalen; + } + else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) + { + for (i=0; iI.datalen; i++) + printf("%02x",rawtx->txbytes[i]); + printf(" <- rawtx\n"); + printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); + return(-1); + } + if ( recvlen != datalen+rawtx->I.redeemlen ) + printf("RECVLEN %d != %d + %d\n",recvlen,datalen,rawtx->I.redeemlen); + txid = bits256_doublesha256(0,data,datalen); + //char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); + if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) + rawtx->I.actualtxid = txid; + if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + rawtx->I.actualtxid = rawtx->I.signedtxid; + char str[65]; printf("got %s txid.%s (%s)\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),jprint(txobj,0)); + rawtx->I.locktime = rawtx->msgtx.lock_time; + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) + { + vout = jitem(vouts,v); + if ( j64bits(vout,"satoshis") == rawtx->I.amount && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) + { + if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) + { + decode_hex(rawtx->spendscript,hexlen,hexstr); + rawtx->I.spendlen = hexlen; + bitcoin_address(rawtx->p2shaddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); + //if ( swap != 0 ) + // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment + retval = 0; + } + } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); + } + free_json(txobj); + } + return(retval); +} + uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) { uint8_t sendbuf[32768]; int32_t sendlen; diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 924aebc27..a6e5cb5e2 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -108,7 +108,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) value += SATOSHIDEN * interest; } } - char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); + // char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); free_json(txobj); } return(value); @@ -1399,73 +1399,6 @@ int32_t LP_verify_otherfee(struct basilisk_swap *swap,uint8_t *data,int32_t data return(0); } -int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) -{ - bits256 otherhash,myhash,txid; int32_t i,offset=0,datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; uint32_t quoteid,msgbits; - for (i=0; i<32; i++) - otherhash.bytes[i] = recvbuf[offset++]; - for (i=0; i<32; i++) - myhash.bytes[i] = recvbuf[offset++]; - offset += iguana_rwnum(0,&recvbuf[offset],sizeof(quoteid),"eid); - offset += iguana_rwnum(0,&recvbuf[offset],sizeof(msgbits),&msgbits); - datalen = recvbuf[offset++]; - datalen += (int32_t)recvbuf[offset++] << 8; - if ( datalen > 1024 ) - { - printf("LP_rawtx_spendscript %s datalen.%d too big\n",rawtx->name,datalen); - return(-1); - } - rawtx->I.redeemlen = recvbuf[offset++]; - data = &recvbuf[offset++]; - if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) - memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); - //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); - if ( rawtx->I.datalen == 0 ) - { - int32_t i; for (i=0; itxbytes,data,datalen); - rawtx->I.datalen = datalen; - } - else if ( datalen != rawtx->I.datalen || memcmp(rawtx->txbytes,data,datalen) != 0 ) - { - for (i=0; iI.datalen; i++) - printf("%02x",rawtx->txbytes[i]); - printf(" <- rawtx\n"); - printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); - return(-1); - } - txid = bits256_doublesha256(0,data,datalen); - //char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); - if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) - rawtx->I.actualtxid = txid; - if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) - { - rawtx->I.actualtxid = rawtx->I.signedtxid; - char str[65]; printf("got %s txid.%s (%s)\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),jprint(txobj,0)); - rawtx->I.locktime = rawtx->msgtx.lock_time; - if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) - { - vout = jitem(vouts,v); - if ( j64bits(vout,"satoshis") == rawtx->I.amount && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) - { - if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) - { - decode_hex(rawtx->spendscript,hexlen,hexstr); - rawtx->I.spendlen = hexlen; - bitcoin_address(rawtx->p2shaddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); - //if ( swap != 0 ) - // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment - retval = 0; - } - } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); - } - free_json(txobj); - } - return(retval); -} - /* Bob deposit: OP_IF OP_CLTV OP_DROP OP_CHECKSIG From bcca880949de6b1e17186e054e926908b28e8ee1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 08:43:13 +0300 Subject: [PATCH 1105/2705] Test --- iguana/exchanges/LP_include.h | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 0ca6db3b0..ae1b1a4a0 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -203,5 +203,6 @@ struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend); double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub); +int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); #endif From e787ebcbd2892e189f1d12ddd860d397dd88fac0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 08:45:14 +0300 Subject: [PATCH 1106/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index cdc802946..8e74a944e 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -153,7 +153,7 @@ int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bit threshold = (IAMCLIENT == 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); if ( (val2= LP_txvalue(coin,txid2,vout2)) >= threshold ) { - printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); return(1); } else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); From 4f7570854f6bdafce5ea0d78818704d6cfa569e0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 08:51:08 +0300 Subject: [PATCH 1107/2705] Test --- iguana/exchanges/LP_swap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 2c51bd4f4..80a96f9a7 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -494,7 +494,7 @@ struct basilisk_rawtx *LP_swapdata_rawtx(struct basilisk_swap *swap,uint8_t *dat int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) { - bits256 otherhash,myhash,txid; int32_t i,offset=0,datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr; uint32_t quoteid,msgbits; + bits256 otherhash,myhash,txid; int32_t i,offset=0,datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr,redeemaddr[64]; uint32_t quoteid,msgbits; for (i=0; i<32; i++) otherhash.bytes[i] = recvbuf[offset++]; for (i=0; i<32; i++) @@ -515,7 +515,8 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); for (i=0; iI.redeemlen; i++) printf("%02x",rawtx->redeemscript[i]); - printf(" received redeemscript\n"); + bitcoin_address(redeemaddr,rawtx->coin->p2shtype,rawtx->redeemscript,rawtx->I.redeemlen); + printf(" received redeemscript.(%s)\n",redeemaddr); } //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); if ( rawtx->I.datalen == 0 ) @@ -557,7 +558,9 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba bitcoin_address(rawtx->p2shaddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); //if ( swap != 0 ) // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment - retval = 0; + if ( strcmp(redeemaddr,rawtx->p2shaddr) == 0 ) + retval = 0; + else printf("mismatched redeemscript %s != %s\n",redeemaddr,rawtx->p2shaddr); } } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); } From f45e155cf84848aac1ed36816642a032ee3c5bc0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 09:04:19 +0300 Subject: [PATCH 1108/2705] Test --- iguana/exchanges/LP_swap.c | 18 ++++++++++++++---- iguana/exchanges/LP_transaction.c | 12 ------------ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 80a96f9a7..701570267 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -494,7 +494,7 @@ struct basilisk_rawtx *LP_swapdata_rawtx(struct basilisk_swap *swap,uint8_t *dat int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) { - bits256 otherhash,myhash,txid; int32_t i,offset=0,datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr,redeemaddr[64]; uint32_t quoteid,msgbits; + bits256 otherhash,myhash,txid; int32_t i,offset=0,datalen=0,retval=-1,hexlen,n; uint8_t *data; cJSON *txobj,*skey,*vouts,*vout; char *hexstr,redeemaddr[64],checkaddr[64]; uint32_t quoteid,msgbits; for (i=0; i<32; i++) otherhash.bytes[i] = recvbuf[offset++]; for (i=0; i<32; i++) @@ -517,6 +517,12 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba printf("%02x",rawtx->redeemscript[i]); bitcoin_address(redeemaddr,rawtx->coin->p2shtype,rawtx->redeemscript,rawtx->I.redeemlen); printf(" received redeemscript.(%s)\n",redeemaddr); + LP_swap_coinaddr(swap,rawtx->coin,checkaddr,data,datalen); + if ( strcmp(redeemaddr,checkaddr) != 0 ) + { + printf("REDEEMADDR MISMATCH??? %s != %s\n",redeemaddr,checkaddr); + return(-1); + } } //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); if ( rawtx->I.datalen == 0 ) @@ -558,9 +564,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba bitcoin_address(rawtx->p2shaddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); //if ( swap != 0 ) // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment - if ( strcmp(redeemaddr,rawtx->p2shaddr) == 0 ) - retval = 0; - else printf("mismatched redeemscript %s != %s\n",redeemaddr,rawtx->p2shaddr); + retval = 0; } } else printf("%s ERROR.(%s)\n",rawtx->name,jprint(txobj,0)); } @@ -634,6 +638,9 @@ void LP_bobloop(void *_utxo) printf("error bobscripts deposit\n"); else { + swap->bobrefund.utxovout = 0; + swap->bobrefund.utxotxid = swap->bobdeposit.I.signedtxid; + basilisk_bobdeposit_refund(swap,swap->I.putduration); //printf("depositlen.%d\n",swap->bobdeposit.I.datalen); LP_swapsfp_update(&swap->I.req); if ( LP_waitfor(utxo->pair,swap,10,LP_verify_otherfee) < 0 ) @@ -648,6 +655,9 @@ void LP_bobloop(void *_utxo) printf("error sending bobpayment\n"); else { + swap->bobreclaim.utxovout = 0; + swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; + basilisk_bobpayment_reclaim(swap,swap->I.callduration); printf("looping on swaplist\n"); while ( 1 ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index a6e5cb5e2..f8eb8d5f5 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1229,12 +1229,6 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i printf(" <- redeem.%d\n",swap->bobpayment.I.redeemlen); printf(" <- GENERATED BOB PAYMENT.%d destaddr.(%s)\n",swap->bobpayment.I.datalen,swap->bobpayment.I.destaddr); LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); - if ( swap->I.iambob != 0 ) - { - swap->bobreclaim.utxovout = 0; - swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; - basilisk_bobpayment_reclaim(swap,swap->I.callduration); - } //printf("bobscripts set completed\n"); return(0); } @@ -1262,12 +1256,6 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i printf("%02x",swap->bobdeposit.txbytes[j]); printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); LP_unspents_mark(swap->bobcoin.symbol,swap->bobdeposit.vins); - if ( swap->I.iambob != 0 ) - { - swap->bobrefund.utxovout = 0; - swap->bobrefund.utxotxid = swap->bobdeposit.I.signedtxid; - basilisk_bobdeposit_refund(swap,swap->I.putduration); - } printf("bobscripts set completed\n"); return(0); } From f2501442921ca1d3f2423536f14ef155b3929f3b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 09:05:31 +0300 Subject: [PATCH 1109/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 93959eab3..07368ec05 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -160,16 +160,17 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_privkey_updates(mypeer,pubsock,passphrase,amclient); if ( (counter % 500) == 0 ) { + char str[65]; HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) { - printf("txid %s %.8f has been spent\n",utxo->coin,dstr(utxo->value)); + printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value)); LP_spentnotify(utxo,0); } else if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == 0 ) { - printf("txid2 %s %.8f has been spent\n",utxo->coin,dstr(utxo->value2)); + printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid2),utxo->vout2,dstr(utxo->value2)); LP_spentnotify(utxo,1); } else if ( LP_ismine(utxo) != 0 ) From 0ffdb6037447ad19d0dd5004861ef388e7015763 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 09:06:47 +0300 Subject: [PATCH 1110/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 8e74a944e..7d675cc4d 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -95,7 +95,7 @@ char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) { if ( i++ < firsti ) continue; - if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) )//&& LP_ismine(utxo) != 0 ) + if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) && utxo->spentflag == 0 )//&& LP_ismine(utxo) != 0 ) { jaddi(utxosjson,LP_utxojson(utxo)); } From 7a12ab716cf42df2761413e56847f1369ffbb524 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 09:51:37 +0300 Subject: [PATCH 1111/2705] Test --- iguana/exchanges/LP_swap.c | 2 +- iguana/exchanges/LP_transaction.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 701570267..195a1301d 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -541,7 +541,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba printf("%s rawtx data compare error, len %d vs %d <<<<<<<<<< warning\n",rawtx->name,rawtx->I.datalen,datalen); return(-1); } - if ( recvlen != datalen+rawtx->I.redeemlen ) + if ( recvlen != datalen+rawtx->I.redeemlen+75 ) printf("RECVLEN %d != %d + %d\n",recvlen,datalen,rawtx->I.redeemlen); txid = bits256_doublesha256(0,data,datalen); //char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index f8eb8d5f5..6f8919576 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1208,6 +1208,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); + LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); //int32_t i; for (i=0; ibobpayment.I.redeemlen; i++) // printf("%02x",swap->bobpayment.redeemscript[i]); //printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); @@ -1239,6 +1240,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); + LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); //int32_t i; for (i=0; ibobdeposit.I.redeemlen; i++) // printf("%02x",swap->bobdeposit.redeemscript[i]); //printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); @@ -1346,11 +1348,16 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); else { + bitcoin_address(swap->alicepayment.I.destaddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); + LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.I.destaddr); + if ( strcmp(swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr) != 0 ) + printf("alice addr mismatch %s vs %s\n",swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr); retval = 0; for (i=0; ialicepayment.I.datalen; i++) printf("%02x",swap->alicepayment.txbytes[i]); - printf(" ALICE PAYMENT created\n"); + printf(" ALICE PAYMENT created.(%s)\n",swap->alicepayment.I.destaddr); LP_unspents_mark(swap->alicecoin.symbol,swap->alicepayment.vins); + LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.I.destaddr); //basilisk_txlog(swap,&swap->alicepayment,-1); } if ( swap->myfee.I.datalen == 0 ) @@ -1409,6 +1416,7 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da swap->I.userdata_aliceclaimlen = len; bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); + LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); printf(" <- bobdeposit.%d %s\n",swap->bobdeposit.I.datalen,bits256_str(str,swap->bobdeposit.I.signedtxid)); @@ -1447,6 +1455,8 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) swap->aliceunconf = 1; basilisk_dontforget_update(swap,&swap->alicepayment); + printf("import alicepayment address.(%s)\n",swap->alicepayment.p2shaddr); + LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.p2shaddr); return(0); } printf("error validating alicepayment\n"); @@ -1469,6 +1479,7 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); + LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); for (i=0; ibobpayment.I.datalen; i++) printf("%02x",swap->bobpayment.txbytes[i]); printf(" <- bobpayment.%d\n",swap->bobpayment.I.datalen); From 6e645b952766fd84294c75de3336b6739201d9a3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 09:52:29 +0300 Subject: [PATCH 1112/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 07368ec05..5ba9b7c54 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -165,13 +165,19 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) { - printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value)); - LP_spentnotify(utxo,0); + if ( utxo->spentflag == 0 ) + { + printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value)); + LP_spentnotify(utxo,0); + } } else if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == 0 ) { - printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid2),utxo->vout2,dstr(utxo->value2)); - LP_spentnotify(utxo,1); + if ( utxo->spentflag == 0 ) + { + printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid2),utxo->vout2,dstr(utxo->value2)); + LP_spentnotify(utxo,1); + } } else if ( LP_ismine(utxo) != 0 ) { From 1307a0972a0a39e1c8ccc9c3069651ca9c26f8dd Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 11:13:22 +0300 Subject: [PATCH 1113/2705] Test --- iguana/exchanges/LP_remember.c | 4 +- iguana/exchanges/LP_rpc.c | 55 +++++++++++++++++++++ iguana/exchanges/LP_transaction.c | 82 ++++++++++++++++++++++++++++--- 3 files changed, 131 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index bf9d34b82..c58cc2ea5 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -50,7 +50,7 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx LP_swap_coinaddr(swap,&swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); if ( coinaddr[0] != 0 ) { - LP_importaddress(swap->bobcoin.symbol,coinaddr); + //LP_importaddress(swap->bobcoin.symbol,coinaddr); if ( rawtx == &swap->bobdeposit ) safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); @@ -72,7 +72,7 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) { basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin.p2shtype,swap->I.pubAm,swap->I.pubBn); - LP_importaddress(swap->alicecoin.symbol,coinaddr); + //LP_importaddress(swap->alicecoin.symbol,coinaddr); fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); } if ( rawtx->I.redeemlen > 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 395f197b1..12ff20df1 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -101,6 +101,20 @@ cJSON *LP_gettx(char *symbol,bits256 txid) return(bitcoin_json(coin,"getrawtransaction",buf)); } +cJSON *LP_getblock(char *symbol,bits256 txid) +{ + char buf[128],str[65]; struct iguana_info *coin = LP_coinfind(symbol); + sprintf(buf,"[\"%s\"]",bits256_str(str,txid)); + return(bitcoin_json(coin,"getblock",buf)); +} + +cJSON *LP_getblockhashstr(char *symbol,char *blockhashstr) +{ + char buf[128]; struct iguana_info *coin = LP_coinfind(symbol); + sprintf(buf,"[\"%s\"]",blockhashstr); + return(bitcoin_json(coin,"getblock",buf)); +} + cJSON *LP_listunspent(char *symbol,char *coinaddr) { char buf[128]; struct iguana_info *coin = LP_coinfind(symbol); @@ -185,6 +199,19 @@ uint64_t LP_txfee(char *symbol) return(txfee); } +char *LP_blockhashstr(char *symbol,int32_t height) +{ + cJSON *array; char *paramstr,*retstr; struct iguana_info *coin = LP_coinfind(symbol); + if ( coin == 0 ) + return(0); + array = cJSON_CreateArray(); + jaddinum(array,height); + paramstr = jprint(array,1); + retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"getblockhash",paramstr); + free(paramstr); + return(retstr); +} + char *LP_sendrawtransaction(char *symbol,char *signedtx) { cJSON *array; char *paramstr,*retstr; struct iguana_info *coin = LP_coinfind(symbol); @@ -238,3 +265,31 @@ char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON * free(paramstr); return(signedtx); } + +cJSON *LP_blockjson(int32_t *heightp,char *symbol,char *blockhashstr,int32_t height) +{ + cJSON *json = 0; int32_t flag = 0; + if ( blockhashstr == 0 ) + blockhashstr = LP_blockhashstr(symbol,height), flag = 1; + if ( blockhashstr != 0 ) + { + if ( (json= LP_getblockhashstr(symbol,blockhashstr)) != 0 ) + { + if ( *heightp != 0 ) + { + *heightp = juint(json,"height"); + if ( height >= 0 && *heightp != height ) + { + printf("unexpected height %d vs %d\n",*heightp,height); + *heightp = -1; + free_json(json); + json = 0; + } + } + } + if ( flag != 0 && blockhashstr != 0 ) + free(blockhashstr); + } + return(json); +} + diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 6f8919576..c1dc15549 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -114,6 +114,69 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) return(value); } +int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 searchtxid,int32_t searchvout) +{ + cJSON *blockjson,*txids,*txobj,*vins,*vin; bits256 hash,txid,spenttxid; int32_t h,i,j,numtxids,numvins,spentvout,loadheight,errs = 0; + *indp = -1; + memset(spendtxidp,0,sizeof(*spendtxidp)); + if ( LP_txvalue(symbol,searchtxid,searchvout) > 0 ) + return(0); + if ( (txobj= LP_gettx(symbol,searchtxid)) == 0 ) + return(0); + hash = jbits256(txobj,"blockhash"); + free_json(txobj); + if ( bits256_nonz(hash) == 0 ) + return(0); + if ( (blockjson= LP_getblock(symbol,hash)) == 0 ) + return(0); + loadheight = jint(blockjson,"height"); + free_json(blockjson); + if ( loadheight <= 0 ) + return(0); + while ( errs == 0 && *indp < 0 ) + { + printf("search %s ht.%d\n",symbol,loadheight); + if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 ) + { + if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) + { + for (i=0; i= 0 ) + return(loadheight); + else return(0); +} + int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) { int32_t numconfirms = 100; @@ -944,11 +1007,14 @@ bits256 _LP_swap_spendtxid(char *symbol,char *destaddr,char *coinaddr,bits256 ut bits256 LP_swap_spendtxid(char *symbol,char *destaddr,bits256 utxotxid,int32_t vout) { - bits256 spendtxid,txid; char *catstr,*addr; cJSON *array,*item,*item2,*txobj,*vins; int32_t i,n,m; char coinaddr[64],str[65]; + bits256 spendtxid,txid; char *catstr,*addr; cJSON *array,*item,*item2,*txobj,*vins; int32_t i,n,m,spendvin; char coinaddr[64],str[65]; // listtransactions or listspents destaddr[0] = 0; coinaddr[0] = 0; memset(&spendtxid,0,sizeof(spendtxid)); + if ( LP_spendsearch(&spendtxid,&spendvin,symbol,utxotxid,vout) > 0 ) + printf("spend of %s/v%d detected\n",bits256_str(str,utxotxid),vout); + return(spendtxid); //char str[65]; printf("swap %s spendtxid.(%s)\n",symbol,bits256_str(str,utxotxid)); if ( 0 && strcmp("BTC",symbol) == 0 ) { @@ -1208,7 +1274,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); - LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); + //LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); //int32_t i; for (i=0; ibobpayment.I.redeemlen; i++) // printf("%02x",swap->bobpayment.redeemscript[i]); //printf(" <- bobpayment redeem %d %s\n",i,swap->bobpayment.I.destaddr); @@ -1240,7 +1306,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); - LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); + //LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); //int32_t i; for (i=0; ibobdeposit.I.redeemlen; i++) // printf("%02x",swap->bobdeposit.redeemscript[i]); //printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); @@ -1349,7 +1415,7 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d else { bitcoin_address(swap->alicepayment.I.destaddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); - LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.I.destaddr); + //LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.I.destaddr); if ( strcmp(swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr) != 0 ) printf("alice addr mismatch %s vs %s\n",swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr); retval = 0; @@ -1357,7 +1423,7 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d printf("%02x",swap->alicepayment.txbytes[i]); printf(" ALICE PAYMENT created.(%s)\n",swap->alicepayment.I.destaddr); LP_unspents_mark(swap->alicecoin.symbol,swap->alicepayment.vins); - LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.I.destaddr); + //LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.I.destaddr); //basilisk_txlog(swap,&swap->alicepayment,-1); } if ( swap->myfee.I.datalen == 0 ) @@ -1416,7 +1482,7 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da swap->I.userdata_aliceclaimlen = len; bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); - LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); + //LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); printf(" <- bobdeposit.%d %s\n",swap->bobdeposit.I.datalen,bits256_str(str,swap->bobdeposit.I.signedtxid)); @@ -1456,7 +1522,7 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t swap->aliceunconf = 1; basilisk_dontforget_update(swap,&swap->alicepayment); printf("import alicepayment address.(%s)\n",swap->alicepayment.p2shaddr); - LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.p2shaddr); + //LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.p2shaddr); return(0); } printf("error validating alicepayment\n"); @@ -1479,7 +1545,7 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); - LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); + //LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); for (i=0; ibobpayment.I.datalen; i++) printf("%02x",swap->bobpayment.txbytes[i]); printf(" <- bobpayment.%d\n",swap->bobpayment.I.datalen); From 9da16dd7d44592d5b3b1cca26ffed411705eea14 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 11:14:28 +0300 Subject: [PATCH 1114/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 ++++++ iguana/exchanges/mm.c | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5ba9b7c54..e8efb2c5f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -118,6 +118,12 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( strcmp(peer->ipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } + if ( (retstr= basilisk_swaplist()) != 0 ) + { + printf("%s\ngetchar to continue\n",retstr); + getchar(); + free(retstr); + } if ( amclient != 0 ) { while ( 1 ) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index c69d170f0..080fb7325 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -829,12 +829,6 @@ int main(int argc, const char * argv[]) printf("error launching LP_main (%s)\n",jprint(retjson,0)); exit(-1); } else printf("(%s) launched.(%s)\n",argv[1],passphrase); - if ( (0) && (retstr= basilisk_swaplist()) != 0 ) - { - printf("%s\ngetchar to continue\n",retstr); - getchar(); - free(retstr); - } incr = 100.; while ( (0) && IAMCLIENT != 0 ) { From b1ad213cc3f59ab614822c634faaff0735172c0c Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 11:26:02 +0300 Subject: [PATCH 1115/2705] Test --- iguana/exchanges/LP_transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index c1dc15549..823925587 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -23,7 +23,7 @@ bits256 LP_broadcast(char *txname,char *symbol,char *txbytes) { char *retstr; bits256 txid; int32_t i,sentflag = 0; memset(&txid,0,sizeof(txid)); - for (i=0; i<3; i++) + for (i=0; i<1; i++) { if ( (retstr= LP_sendrawtransaction(symbol,txbytes)) != 0 ) { @@ -877,7 +877,7 @@ char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2sht for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ txfee = LP_txfee(symbol); - signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr,0); + signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr,1); } return(signedtx); } From 360039ba06e73b6795aec6a76857f5172d194efd Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 11:38:43 +0300 Subject: [PATCH 1116/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ---- iguana/exchanges/LP_remember.c | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e8efb2c5f..6dcdb2bb7 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -119,11 +119,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } if ( (retstr= basilisk_swaplist()) != 0 ) - { - printf("%s\ngetchar to continue\n",retstr); - getchar(); free(retstr); - } if ( amclient != 0 ) { while ( 1 ) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index c58cc2ea5..bf9d34b82 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -50,7 +50,7 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx LP_swap_coinaddr(swap,&swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen); if ( coinaddr[0] != 0 ) { - //LP_importaddress(swap->bobcoin.symbol,coinaddr); + LP_importaddress(swap->bobcoin.symbol,coinaddr); if ( rawtx == &swap->bobdeposit ) safecopy(swap->Bdeposit,coinaddr,sizeof(swap->Bdeposit)); else safecopy(swap->Bpayment,coinaddr,sizeof(swap->Bpayment)); @@ -72,7 +72,7 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) { basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin.p2shtype,swap->I.pubAm,swap->I.pubBn); - //LP_importaddress(swap->alicecoin.symbol,coinaddr); + LP_importaddress(swap->alicecoin.symbol,coinaddr); fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); } if ( rawtx->I.redeemlen > 0 ) From 4d210dc76e19a51a7e57c06f4427fd467bf432ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 12:09:59 +0300 Subject: [PATCH 1117/2705] Test --- iguana/exchanges/LP_commands.c | 12 +++++++++++- iguana/exchanges/LP_remember.c | 29 +++++++++++++++++++++++++++++ iguana/exchanges/LP_swap.c | 24 +++++++++--------------- iguana/exchanges/LP_transaction.c | 2 +- iguana/exchanges/status | 2 ++ 5 files changed, 52 insertions(+), 17 deletions(-) create mode 100755 iguana/exchanges/status diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 12b1d8fe4..947a34131 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -276,7 +276,17 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port return(jprint(LP_tradecandidates(utxo,coin),1)); else return(jprint(LP_autotrade(utxo,coin,jdouble(argjson,"maxprice")),1)); } - } + } + else if ( strcmp(method,"swapstatus") == 0 ) + { + uint32_t requestid,quoteid; + if ( (requestid= juint(argjson,"requestid")) != 0 && (quoteid= juint(argjson,"quoteid")) != 0 ) + { + if ( (retstr= basilisk_swapfinished(requestid,quoteid)) == 0 ) + return(clonestr("{\"result\":\"swap pending\"}")); + else return(retstr); + } else return(basilisk_swaplist()); + } } amclient = (LP_mypeer == 0); if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index bf9d34b82..bb82d6dcf 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -952,3 +952,32 @@ char *basilisk_swaplist() return(jprint(retjson,1)); } +char *basilisk_swapfinished(uint32_t requestid,uint32_t quoteid) +{ + char *liststr,*retstr = 0; cJSON *array,*item; int32_t i,n; + if ( (liststr= basilisk_swaplist()) != 0 ) + { + if ( (array= cJSON_Parse(liststr)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; ibobreclaim.utxovout = 0; swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); - printf("looping on swaplist\n"); - while ( 1 ) + printf("wait for SWAP to complete\n"); + while ( (retstr= basilisk_swapfinished(swap->I.req.requestid,swap->I.req.quoteid)) == 0 ) { - if ( (retstr= basilisk_swaplist()) != 0 ) - { - printf("%s\n",retstr); - free(retstr); - } sleep(100); } + printf("SWAP completed! %u-%u %s\n",swap->I.req.requestid,swap->I.req.quoteid,retstr); + free(retstr); } } basilisk_swap_finished(swap); @@ -709,16 +706,13 @@ void LP_aliceloop(void *_qp) printf("error waiting for bobpayment\n"); else { - printf("looping on swaplist\n"); - while ( 1 ) + printf("wait for SWAP to complete\n"); + while ( (retstr= basilisk_swapfinished(swap->I.req.requestid,swap->I.req.quoteid)) == 0 ) { - if ( (retstr= basilisk_swaplist()) != 0 ) - { - printf("%s\n",retstr); - free(retstr); - } sleep(100); } + printf("SWAP completed! %u-%u %s\n",swap->I.req.requestid,swap->I.req.quoteid,retstr); + free(retstr); } } basilisk_swap_finished(swap); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 823925587..6c5e68e95 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -135,7 +135,7 @@ int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 se return(0); while ( errs == 0 && *indp < 0 ) { - printf("search %s ht.%d\n",symbol,loadheight); + //printf("search %s ht.%d\n",symbol,loadheight); if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 ) { if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) diff --git a/iguana/exchanges/status b/iguana/exchanges/status new file mode 100755 index 000000000..7e7b4bb0e --- /dev/null +++ b/iguana/exchanges/status @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"swapstatus\"}" From 4db426791faf242970b750049c6ab9fc7e918c82 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 12:13:55 +0300 Subject: [PATCH 1118/2705] Test --- iguana/exchanges/LP_remember.c | 1 + iguana/exchanges/swapstatus | 2 ++ 2 files changed, 3 insertions(+) create mode 100755 iguana/exchanges/swapstatus diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index bb82d6dcf..0ac108199 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -964,6 +964,7 @@ char *basilisk_swapfinished(uint32_t requestid,uint32_t quoteid) for (i=0; i Date: Tue, 6 Jun 2017 12:16:39 +0300 Subject: [PATCH 1119/2705] Test --- iguana/exchanges/LP_remember.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 0ac108199..d393f599f 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -954,12 +954,12 @@ char *basilisk_swaplist() char *basilisk_swapfinished(uint32_t requestid,uint32_t quoteid) { - char *liststr,*retstr = 0; cJSON *array,*item; int32_t i,n; + char *liststr,*retstr = 0; cJSON *retjson,*array,*item; int32_t i,n; if ( (liststr= basilisk_swaplist()) != 0 ) { - if ( (array= cJSON_Parse(liststr)) != 0 ) + if ( (retjson= cJSON_Parse(liststr)) != 0 ) { - if ( (n= cJSON_GetArraySize(array)) > 0 ) + if ( (array= jarray(&n,retjson,"swaps")) != 0 ) { for (i=0; i Date: Tue, 6 Jun 2017 12:17:54 +0300 Subject: [PATCH 1120/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index d393f599f..b41c60722 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -964,7 +964,7 @@ char *basilisk_swapfinished(uint32_t requestid,uint32_t quoteid) for (i=0; i Date: Tue, 6 Jun 2017 12:18:44 +0300 Subject: [PATCH 1121/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index b41c60722..2059fdad5 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -964,7 +964,7 @@ char *basilisk_swapfinished(uint32_t requestid,uint32_t quoteid) for (i=0; i Date: Tue, 6 Jun 2017 12:19:49 +0300 Subject: [PATCH 1122/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 2059fdad5..a830bfe2e 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -914,7 +914,7 @@ char *basilisk_swaplist() if ( (item= basilisk_remember(KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) { jaddi(array,item); - if ( 1 && (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + if ( (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) break; } } From 5206483da98c2afd70ec8e56b81b3402480d2dbc Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 12:33:35 +0300 Subject: [PATCH 1123/2705] Test --- iguana/exchanges/LP_commands.c | 7 ++--- iguana/exchanges/LP_remember.c | 11 ++++---- iguana/exchanges/LP_swap.c | 48 ++++++++++++++++++++++------------ 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 947a34131..aa074832b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -281,11 +281,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { uint32_t requestid,quoteid; if ( (requestid= juint(argjson,"requestid")) != 0 && (quoteid= juint(argjson,"quoteid")) != 0 ) - { - if ( (retstr= basilisk_swapfinished(requestid,quoteid)) == 0 ) - return(clonestr("{\"result\":\"swap pending\"}")); - else return(retstr); - } else return(basilisk_swaplist()); + return(basilisk_swapentry(requestid,quoteid)); + else return(basilisk_swaplist()); } } amclient = (LP_mypeer == 0); diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index a830bfe2e..1756b86a7 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -888,7 +888,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti char *basilisk_swaplist() { - char fname[512],*status; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16],Btotal,Ktotal; int32_t i; + char fname[512]; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16],Btotal,Ktotal; int32_t i; memset(KMDtotals,0,sizeof(KMDtotals)); memset(BTCtotals,0,sizeof(BTCtotals)); //,statebits; int32_t optionduration; struct basilisk_request R; bits256 privkey; @@ -914,8 +914,8 @@ char *basilisk_swaplist() if ( (item= basilisk_remember(KMDtotals,BTCtotals,requestid,quoteid)) != 0 ) { jaddi(array,item); - if ( (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) - break; + //if ( (status= jstr(item,"status")) != 0 && strcmp(status,"pending") == 0 ) + // break; } } } @@ -952,7 +952,7 @@ char *basilisk_swaplist() return(jprint(retjson,1)); } -char *basilisk_swapfinished(uint32_t requestid,uint32_t quoteid) +char *basilisk_swapentry(uint32_t requestid,uint32_t quoteid) { char *liststr,*retstr = 0; cJSON *retjson,*array,*item; int32_t i,n; if ( (liststr= basilisk_swaplist()) != 0 ) @@ -967,8 +967,7 @@ char *basilisk_swapfinished(uint32_t requestid,uint32_t quoteid) //printf("(%s) check r%u/q%u\n",jprint(item,0),juint(item,"requestid"),juint(item,"quoteid")); if ( juint(item,"requestid") == requestid && juint(item,"quoteid") == quoteid ) { - if ( jstr(item,"status") != 0 && strcmp(jstr(item,"status"),"finished") == 0 ) - retstr = jprint(item,0); + retstr = jprint(item,0); break; } } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 21ad1fa48..f512b294e 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -617,9 +617,37 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 return(0); } +int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t sleeptime) +{ + char *retstr; cJSON *retjson=0; uint32_t expiration = (uint32_t)(time(NULL) + duration); + printf("wait %d:%d for SWAP.(r%u/q%u) to complete\n",duration,sleeptime,requestid,quoteid); + while ( time(NULL) < expiration ) + { + sleep(3); + if ( (retstr= basilisk_swapentry(requestid,quoteid)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( jstr(retjson,"status") != 0 && strcmp(jstr(retjson,"status"),"finished") == 0 ) + break; + free_json(retjson); + retjson = 0; + } + free(retstr); + } + sleep(sleeptime); + } + if ( retjson != 0 ) + { + printf("SWAP completed! %u-%u %s\n",requestid,quoteid,jprint(retjson,0)); + free_json(retjson); + return(0); + } else return(-1); +} + void LP_bobloop(void *_utxo) { - uint8_t *data; int32_t maxlen; char *retstr; uint32_t expiration; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; + uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; fprintf(stderr,"start swap iambob\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); @@ -658,13 +686,7 @@ void LP_bobloop(void *_utxo) swap->bobreclaim.utxovout = 0; swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); - printf("wait for SWAP to complete\n"); - while ( (retstr= basilisk_swapfinished(swap->I.req.requestid,swap->I.req.quoteid)) == 0 ) - { - sleep(100); - } - printf("SWAP completed! %u-%u %s\n",swap->I.req.requestid,swap->I.req.quoteid,retstr); - free(retstr); + LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); } } basilisk_swap_finished(swap); @@ -677,7 +699,7 @@ void LP_bobloop(void *_utxo) void LP_aliceloop(void *_qp) { - uint8_t *data; char *retstr; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = 0; struct LP_quoteinfo *qp = _qp; + uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = 0; struct LP_quoteinfo *qp = _qp; fprintf(stderr,"start swap iamalice pair.%d\n",qp->pair); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); @@ -706,13 +728,7 @@ void LP_aliceloop(void *_qp) printf("error waiting for bobpayment\n"); else { - printf("wait for SWAP to complete\n"); - while ( (retstr= basilisk_swapfinished(swap->I.req.requestid,swap->I.req.quoteid)) == 0 ) - { - sleep(100); - } - printf("SWAP completed! %u-%u %s\n",swap->I.req.requestid,swap->I.req.quoteid,retstr); - free(retstr); + LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); } } basilisk_swap_finished(swap); From 907351af5c17ff122a6023e109336cd9f80dc11a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 13:10:00 +0300 Subject: [PATCH 1124/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- iguana/exchanges/LP_remember.c | 2 ++ iguana/exchanges/LP_swap.c | 25 ++++++++++++++++++------- iguana/exchanges/LP_transaction.c | 4 ++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6dcdb2bb7..d807a391a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -32,7 +32,7 @@ char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", -portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex; +portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex; int32_t LP_mypubsock = -1; int32_t Client_connections; int32_t USERPASS_COUNTER,IAMCLIENT = 0; @@ -267,6 +267,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); portable_mutex_init(&LP_commandmutex); + portable_mutex_init(&LP_swaplistmutex); portable_mutex_init(&LP_cachemutex); if ( amclient == 0 ) { diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 1756b86a7..485a71086 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -889,6 +889,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti char *basilisk_swaplist() { char fname[512]; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16],Btotal,Ktotal; int32_t i; + portable_mutex_lock(&LP_swaplistmutex); memset(KMDtotals,0,sizeof(KMDtotals)); memset(BTCtotals,0,sizeof(BTCtotals)); //,statebits; int32_t optionduration; struct basilisk_request R; bits256 privkey; @@ -949,6 +950,7 @@ char *basilisk_swaplist() jaddi(array,linfo_json(&myinfo->linfos[i])); } jadd(retjson,"quotes",array);*/ + portable_mutex_unlock(&LP_swaplistmutex); return(jprint(retjson,1)); } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index f512b294e..f6195d74b 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -677,15 +677,17 @@ void LP_bobloop(void *_utxo) printf("error sending bobdeposit\n"); else if ( LP_waitfor(utxo->pair,swap,10,LP_verify_alicepayment) < 0 ) printf("error waiting for alicepayment\n"); - else if ( basilisk_bobscripts_set(swap,0,1) < 0 ) - printf("error bobscripts payment\n"); - else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) - printf("error sending bobpayment\n"); else { swap->bobreclaim.utxovout = 0; swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); + while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + sleep(3); + if ( basilisk_bobscripts_set(swap,0,1) < 0 ) + printf("error bobscripts payment\n"); + else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) + printf("error sending bobpayment\n"); LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); } } @@ -724,11 +726,20 @@ void LP_aliceloop(void *_qp) printf("error waiting for bobdeposit\n"); else if ( LP_swapdata_rawtxsend(qp->pair,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0) == 0 ) printf("error sending alicepayment\n"); - else if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobpayment) < 0 ) - printf("error waiting for bobpayment\n"); else { - LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); + while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + sleep(3); + if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobpayment) < 0 ) + printf("error waiting for bobpayment\n"); + else + { + while ( LP_numconfirms(swap,&swap->bobpayment) < 1 ) + sleep(3); + if ( LP_swapdata_rawtxsend(qp->pair,swap,0x20000,data,maxlen,&swap->alicespend,0x0,0) == 0 ) + printf("error sending alicepayment\n"); + LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); + } } } basilisk_swap_finished(swap); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 6c5e68e95..cf541426b 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -79,7 +79,7 @@ uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) { if ( (interest= jdouble(utxoobj,"interest")) != 0. ) { - printf("add interest of %.8f to %.8f\n",interest,dstr(value)); + //printf("add interest of %.8f to %.8f\n",interest,dstr(value)); value += SATOSHIDEN * interest; } free_json(utxoobj); @@ -104,7 +104,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) { if ( (interest= jdouble(txobj,"interest")) != 0. ) { - printf("add interest of %.8f to %.8f\n",interest,dstr(value)); + //printf("add interest of %.8f to %.8f\n",interest,dstr(value)); value += SATOSHIDEN * interest; } } From 5788f9da498d7478e978064709d95006ffe91940 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 13:14:27 +0300 Subject: [PATCH 1125/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_swap.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index ae1b1a4a0..08b7c602b 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -35,7 +35,7 @@ #define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" #define BASILISK_DISABLEWAITTX -//#define BASILISK_DISABLESENDTX +#define BASILISK_DISABLESENDTX #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index f6195d74b..9972d0b11 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -736,8 +736,8 @@ void LP_aliceloop(void *_qp) { while ( LP_numconfirms(swap,&swap->bobpayment) < 1 ) sleep(3); - if ( LP_swapdata_rawtxsend(qp->pair,swap,0x20000,data,maxlen,&swap->alicespend,0x0,0) == 0 ) - printf("error sending alicepayment\n"); + if ( LP_swapdata_rawtxsend(qp->pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) + printf("error sending alicespend\n"); LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); } } From 20b296840e3f51604262514a16d26db5af44961a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 13:24:07 +0300 Subject: [PATCH 1126/2705] Test --- iguana/exchanges/LP_include.h | 4 ++-- iguana/exchanges/LP_transaction.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 08b7c602b..5ef70aa5f 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -34,8 +34,8 @@ #define INSTANTDEX_BTC "1KRhTPvoxyJmVALwHFXZdeeWFbcJSbkFPu" #define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" -#define BASILISK_DISABLEWAITTX -#define BASILISK_DISABLESENDTX +//#define BASILISK_DISABLEWAITTX +//#define BASILISK_DISABLESENDTX #define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index cf541426b..f9e180106 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -182,7 +182,7 @@ int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) int32_t numconfirms = 100; #ifndef BASILISK_DISABLEWAITTX cJSON *txobj; - if ( (txobj= LP_gettx(symbol,txid)) != 0 ) + if ( (txobj= LP_gettx(rawtx->coin->symbol,rawtx->I.signedtxid)) != 0 ) { numconfirms = jint(txobj,"confirmations"); free_json(txobj); From 2daa5c2c8370ccc2738f5717721f8380d37e7f22 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 13:47:20 +0300 Subject: [PATCH 1127/2705] Test --- iguana/exchanges/LP_transaction.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index f9e180106..6cee86cae 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -19,9 +19,9 @@ // -bits256 LP_broadcast(char *txname,char *symbol,char *txbytes) +bits256 LP_broadcast(char *txname,char *symbol,char *txbytes,bits256 expectedtxid) { - char *retstr; bits256 txid; int32_t i,sentflag = 0; + char *retstr; bits256 txid; cJSON *retjson,*errorobj; int32_t i,sentflag = 0; memset(&txid,0,sizeof(txid)); for (i=0; i<1; i++) { @@ -32,6 +32,15 @@ bits256 LP_broadcast(char *txname,char *symbol,char *txbytes) decode_hex(txid.bytes,32,retstr); sentflag = 1; } + else if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (errorobj= jobj(retjson,"error")) != 0 ) + { + if ( jint(errorobj,"code") == -27 ) // "transaction already in block chain" + txid = expectedtxid; + } + free_json(retjson); + } char str[65]; printf("[%s] %s RETSTR.(%s) %s.%s\n",txname,txbytes,retstr,symbol,bits256_str(str,txid)); free(retstr); } @@ -49,11 +58,11 @@ bits256 LP_broadcast_tx(char *name,char *symbol,uint8_t *data,int32_t datalen) { signedtx = malloc(datalen*2 + 1); init_hexbytes_noT(signedtx,data,datalen); -#ifdef BASILISK_DISABLESENDTX txid = bits256_doublesha256(0,data,datalen); +#ifdef BASILISK_DISABLESENDTX char str[65]; printf("%s <- dont sendrawtransaction (%s) %s\n",name,bits256_str(str,txid),signedtx); #else - txid = LP_broadcast(name,symbol,signedtx); + txid = LP_broadcast(name,symbol,signedtx,txid); #endif free(signedtx); } From 0b6b75ea53bdb88746d038b2c0ef02bc0948804d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 13:48:41 +0300 Subject: [PATCH 1128/2705] test --- iguana/exchanges/LP_swap.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 9972d0b11..73496a944 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -683,7 +683,10 @@ void LP_bobloop(void *_utxo) swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + { + printf("waiting for alicepayment to confirm\n"); sleep(3); + } if ( basilisk_bobscripts_set(swap,0,1) < 0 ) printf("error bobscripts payment\n"); else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) @@ -729,13 +732,19 @@ void LP_aliceloop(void *_qp) else { while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + { + printf("waiting for alicepayment to confirm\n"); sleep(3); + } if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobpayment) < 0 ) printf("error waiting for bobpayment\n"); else { while ( LP_numconfirms(swap,&swap->bobpayment) < 1 ) + { + printf("waiting for bobpayment to confirm\n"); sleep(3); + } if ( LP_swapdata_rawtxsend(qp->pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) printf("error sending alicespend\n"); LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); From 1070732f650921db9bcc9cd90f3985db175b9cb2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 13:50:12 +0300 Subject: [PATCH 1129/2705] Test --- iguana/exchanges/LP_remember.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 485a71086..dc02a419b 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -636,7 +636,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_ALICESPEND] != 0 ) { - txids[BASILISK_ALICESPEND] = LP_broadcast("alicespend",bobcoin,txbytes[BASILISK_ALICESPEND]); + txids[BASILISK_ALICESPEND] = LP_broadcast("alicespend",bobcoin,txbytes[BASILISK_ALICESPEND],zero); if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) // tested { sentflags[BASILISK_ALICESPEND] = 1; @@ -661,7 +661,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_ALICECLAIM] != 0 ) { - txids[BASILISK_ALICECLAIM] = LP_broadcast("aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM]); + txids[BASILISK_ALICECLAIM] = LP_broadcast("aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM],zero); if ( bits256_nonz(txids[BASILISK_ALICECLAIM]) != 0 ) // tested { sentflags[BASILISK_ALICECLAIM] = 1; @@ -683,7 +683,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_ALICERECLAIM] != 0 ) { - txids[BASILISK_ALICERECLAIM] = LP_broadcast("alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM]); + txids[BASILISK_ALICERECLAIM] = LP_broadcast("alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM],zero); if ( bits256_nonz(txids[BASILISK_ALICERECLAIM]) != 0 ) // tested { sentflags[BASILISK_ALICERECLAIM] = 1; @@ -713,7 +713,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_BOBSPEND] != 0 ) { - txids[BASILISK_BOBSPEND] = LP_broadcast("bobspend",alicecoin,txbytes[BASILISK_BOBSPEND]); + txids[BASILISK_BOBSPEND] = LP_broadcast("bobspend",alicecoin,txbytes[BASILISK_BOBSPEND],zero); if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) // tested { sentflags[BASILISK_BOBSPEND] = 1; @@ -742,7 +742,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_BOBRECLAIM] != 0 ) { - txids[BASILISK_BOBRECLAIM] = LP_broadcast("bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM]); + txids[BASILISK_BOBRECLAIM] = LP_broadcast("bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM],zero); if ( bits256_nonz(txids[BASILISK_BOBRECLAIM]) != 0 ) // tested { sentflags[BASILISK_BOBRECLAIM] = 1; @@ -766,7 +766,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( txbytes[BASILISK_BOBREFUND] != 0 ) { - txids[BASILISK_BOBREFUND] = LP_broadcast("bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND]); + txids[BASILISK_BOBREFUND] = LP_broadcast("bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND],zero); if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) // tested { sentflags[BASILISK_BOBREFUND] = 1; From 8149c542dcbcbeb9745853c6de2d68fb77fb81e0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 13:59:19 +0300 Subject: [PATCH 1130/2705] Test --- iguana/exchanges/LP_transaction.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 6cee86cae..b99b94919 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -37,7 +37,10 @@ bits256 LP_broadcast(char *txname,char *symbol,char *txbytes,bits256 expectedtxi if ( (errorobj= jobj(retjson,"error")) != 0 ) { if ( jint(errorobj,"code") == -27 ) // "transaction already in block chain" + { txid = expectedtxid; + sentflag = 1; + } } free_json(retjson); } @@ -145,7 +148,7 @@ int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 se while ( errs == 0 && *indp < 0 ) { //printf("search %s ht.%d\n",symbol,loadheight); - if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 ) + if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 && h == loadheight ) { if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) { @@ -177,7 +180,7 @@ int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 se } } free_json(blockjson); - } + } else errs++; loadheight++; } char str[65]; printf("reached %s ht.%d %s/v%d\n",symbol,loadheight,bits256_str(str,*spendtxidp),*indp); From 922009a4c94536747f25df0fdae8fd278487c37f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 14:16:03 +0300 Subject: [PATCH 1131/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_swap.c | 2 +- iguana/exchanges/LP_transaction.c | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 12ff20df1..7d1694162 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -221,7 +221,7 @@ char *LP_sendrawtransaction(char *symbol,char *signedtx) jaddistr(array,signedtx); paramstr = jprint(array,1); retstr = bitcoind_passthru(symbol,coin->serverport,coin->userpass,"sendrawtransaction",paramstr); - printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> (%s)\n",coin->symbol,paramstr,retstr); + //printf(">>>>>>>>>>> %s dpow_sendrawtransaction.(%s) -> (%s)\n",coin->symbol,paramstr,retstr); free(paramstr); return(retstr); } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 73496a944..fb2089468 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -471,7 +471,7 @@ void LP_swapsfp_update(struct basilisk_request *rp) if ( (swapsfp= fopen(fname,"rb+")) == 0 ) swapsfp = fopen(fname,"wb+"); else fseek(swapsfp,0,SEEK_END); - printf("LIST fp.%p\n",swapsfp); + //printf("LIST fp.%p\n",swapsfp); } if ( swapsfp != 0 ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index b99b94919..06fd6bcad 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -494,14 +494,14 @@ int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shty { flag++; numsigs++; - int32_t z; char tmpaddr[64]; + /*int32_t z; char tmpaddr[64]; for (z=0; zsigners[j].pubkey[z]); bitcoin_address(tmpaddr,60,vp->signers[j].pubkey,33); - printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d %s\n",vini,j,numsigs,vp->M,tmpaddr); + printf(" <- pub, SIG.%d.%d VERIFIED numsigs.%d vs M.%d %s\n",vini,j,numsigs,vp->M,tmpaddr);*/ } } if ( numsigs >= vp->M ) @@ -723,7 +723,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch if ( vinaddr != 0 ) bitcoin_addr2rmd160(&addrtype,rmd160,vinaddr); spendlen = bitcoin_p2shspend(spendscript,0,rmd160); - printf("P2SH path.%s\n",vinaddr!=0?vinaddr:0); + //printf("P2SH path.%s\n",vinaddr!=0?vinaddr:0); } else spendlen = bitcoin_standardspend(spendscript,0,rmd160); init_hexbytes_noT(hexstr,spendscript,spendlen); jaddstr(item,"scriptPubKey",hexstr); @@ -788,7 +788,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub { changeaddr = _changeaddr; bitcoin_address(changeaddr,coin->pubtype,changermd160,20); - printf("changeaddr.(%s) vs destaddr.(%s)\n",changeaddr,rawtx->I.destaddr); + //printf("changeaddr.(%s) vs destaddr.(%s)\n",changeaddr,rawtx->I.destaddr); } for (iter=0; iter<2; iter++) { @@ -819,7 +819,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160,char *vinaddr) { char *signedtx,*changeaddr = 0,_changeaddr[64]; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,retval = -1; double estimatedrate; - char str2[65]; printf("%s rawtxsign.(%s/v%d)\n",dest->name,bits256_str(str2,dest->utxotxid),dest->utxovout); + //char str2[65]; printf("%s rawtxsign.(%s/v%d)\n",dest->name,bits256_str(str2,dest->utxotxid),dest->utxovout); timestamp = swap->I.started; if ( dest == &swap->aliceclaim ) locktime = swap->bobdeposit.I.locktime + 1, sequenceid = 0; From 667a86d5976c27abc4c392ff1f65925cf610e3ea Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 14:21:29 +0300 Subject: [PATCH 1132/2705] Test --- iguana/exchanges/LP_swap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index fb2089468..35ce8f62f 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -747,6 +747,11 @@ void LP_aliceloop(void *_qp) } if ( LP_swapdata_rawtxsend(qp->pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) printf("error sending alicespend\n"); + while ( LP_numconfirms(swap,&swap->alicespend) < 1 ) + { + printf("waiting for alicespend to confirm\n"); + sleep(3); + } LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); } } From b3e5f9b993b76b212f9af987f69ca883180c0e3f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 14:32:39 +0300 Subject: [PATCH 1133/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/client | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index aa074832b..5d3fd931a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -80,7 +80,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); - printf("GETTXOUT: txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); + //printf("GETTXOUT: txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); @@ -123,7 +123,7 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); - printf("GETTXOUT: txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); + //printf("GETTXOUT: txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 261b1d36a..f84982ff2 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From e61ddd4d17de6b55fa9fdcdad23e6064378bbf59 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 17:14:09 +0300 Subject: [PATCH 1134/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 9 ++++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 5ef70aa5f..15cf24c31 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -169,6 +169,7 @@ struct LP_utxoinfo void *swap; uint64_t value,satoshis,value2; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; + uint8_t key2[sizeof(bits256) + sizeof(int32_t)]; int32_t vout,vout2,pair; uint32_t lasttime,errors,swappending,published,spentflag; double profitmargin; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d807a391a..0b747bb36 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -23,7 +23,7 @@ #include "LP_include.h" #include "LP_network.c" -struct LP_utxoinfo *LP_utxoinfos; +struct LP_utxoinfo *LP_utxoinfos,*LP_utxoinfos2; struct LP_peerinfo *LP_peerinfos,*LP_mypeer; char *activecoins[] = { "BTC", "KMD", "REVS", "JUMBLR" };//"LTC", "USD", }; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7d675cc4d..e7dc260c0 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -43,6 +43,8 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); portable_mutex_lock(&LP_utxomutex); HASH_FIND(hh,LP_utxoinfos,key,sizeof(key),utxo); + if ( utxo == 0 ) + HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); portable_mutex_unlock(&LP_utxomutex); return(utxo); } @@ -107,6 +109,8 @@ void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) { cJSON *argjson; utxo->spentflag = (uint32_t)time(NULL); + if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) + LP_mypeer->numutxos--; if ( LP_mypubsock >= 0 ) { argjson = cJSON_CreateObject(); @@ -181,7 +185,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("LP node got localhost utxo\n"); return(0); } - if ( (utxo= LP_utxofind(txid,vout)) != 0 ) + if ( (utxo= LP_utxofind(txid,vout)) != 0 ) { //printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(txid2,utxo->txid2) != 0 || vout != utxo->vout || value != utxo->value || tmpsatoshis != utxo->satoshis || vout2 != utxo->vout2 || value2 != utxo->value2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) @@ -211,8 +215,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 utxo->value2 = value2; memcpy(utxo->key,txid.bytes,sizeof(txid)); memcpy(&utxo->key[sizeof(txid)],&vout,sizeof(vout)); + memcpy(utxo->key2,txid2.bytes,sizeof(txid2)); + memcpy(&utxo->key2[sizeof(txid2)],&vout2,sizeof(vout2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); + HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); From 9768b5184c6546b3bdd4ead4e11663e9f927c2dc Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 17:41:40 +0300 Subject: [PATCH 1135/2705] Test --- iguana/coins/jumblr | 2 +- iguana/coins/revs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/coins/jumblr b/iguana/coins/jumblr index 5b52ce9a6..643fd9dab 100755 --- a/iguana/coins/jumblr +++ b/iguana/coins/jumblr @@ -1,4 +1,4 @@ -~/komodo/src/komodod -ac_name=JUMBLR -ac_supply=999999 -addnode=78.47.196.146 & +~/komodo/src/komodo/src/komodod -ac_name=JUMBLR -ac_supply=999999 -addnode=78.47.196.146 & curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"JUMBLR.conf\",\"path\":\"${HOME#"/"}/.komodo/JUMBLR\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"JUMBLR\",\"name\":\"JUMBLR\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7223759e\",\"p2p\":15105,\"rpc\":15106,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/revs b/iguana/coins/revs index f2cf9ef72..23f4948b2 100755 --- a/iguana/coins/revs +++ b/iguana/coins/revs @@ -1,3 +1,3 @@ -./komodod -ac_name=REVS -ac_supply=1300000 -addnode=78.47.196.146 & +~/komodo/src/komodod -ac_name=REVS -ac_supply=1300000 -addnode=78.47.196.146 & curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"REVS.conf\",\"path\":\"${HOME#"/"}/.komodo/REVS\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"REVS\",\"name\":\"REVS\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"905c3498\",\"p2p\":10195,\"rpc\":10196,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" From 3a3a733f117e14c1d32a8bd602618275a88dab2f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 17:42:31 +0300 Subject: [PATCH 1136/2705] Test --- iguana/coins/jumblr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/coins/jumblr b/iguana/coins/jumblr index 643fd9dab..5b52ce9a6 100755 --- a/iguana/coins/jumblr +++ b/iguana/coins/jumblr @@ -1,4 +1,4 @@ -~/komodo/src/komodo/src/komodod -ac_name=JUMBLR -ac_supply=999999 -addnode=78.47.196.146 & +~/komodo/src/komodod -ac_name=JUMBLR -ac_supply=999999 -addnode=78.47.196.146 & curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"JUMBLR.conf\",\"path\":\"${HOME#"/"}/.komodo/JUMBLR\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"JUMBLR\",\"name\":\"JUMBLR\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"7223759e\",\"p2p\":15105,\"rpc\":15106,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" From 7ecf3ec6395705f54fa8c561ee22a4200bfab6f0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 17:52:32 +0300 Subject: [PATCH 1137/2705] Test --- iguana/exchanges/LP_rpc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 7d1694162..d07a9c0a8 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -71,6 +71,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) retjson = cJSON_Parse(retstr); free(retstr); } + usleep(1000); //printf("dpow_gettxout.(%s)\n",retstr); } return(retjson); From 1f4238afb2508031701aa6e080f607dfcd464fc3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:01:29 +0300 Subject: [PATCH 1138/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0b747bb36..df8455a39 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -118,8 +118,8 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( strcmp(peer->ipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } - if ( (retstr= basilisk_swaplist()) != 0 ) - free(retstr); + //if ( (retstr= basilisk_swaplist()) != 0 ) + // free(retstr); if ( amclient != 0 ) { while ( 1 ) From 97cfbabb110f91606ac6da1533eb2fc77b08ea51 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:16:49 +0300 Subject: [PATCH 1139/2705] Test --- iguana/exchanges/LP_commands.c | 2 -- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_transaction.c | 2 +- iguana/exchanges/LP_utxos.c | 4 +++- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 5d3fd931a..621c7544b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -80,7 +80,6 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); - //printf("GETTXOUT: txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); @@ -123,7 +122,6 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->mypub) == 0 ) utxo->mypub = LP_pubkey(privkey); - //printf("GETTXOUT: txid.(%s)\ntxid2.(%s)\n",jprint(LP_gettxout(Q.srccoin,Q.txid,Q.vout),1),jprint(LP_gettxout(Q.srccoin,Q.txid2,Q.vout2),1)); if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index d07a9c0a8..8353f2d23 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -71,7 +71,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) retjson = cJSON_Parse(retstr); free(retstr); } - usleep(1000); + //usleep(1000); //printf("dpow_gettxout.(%s)\n",retstr); } return(retjson); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 06fd6bcad..d8703c7b5 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -120,7 +120,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) value += SATOSHIDEN * interest; } } - // char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); + char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); free_json(txobj); } return(value); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e7dc260c0..d73707f29 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -131,7 +131,7 @@ char *LP_spentcheck(cJSON *argjson) bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; txid = jbits256(argjson,"txid"); vout = jint(argjson,"vout"); - if ( (utxo= LP_utxofind(txid,vout)) != 0 ) + if ( (utxo= LP_utxofind(txid,vout)) != 0 && utxo->spentflag == 0 ) { if ( jobj(argjson,"check") == 0 ) checktxid = txid, checkvout = vout; @@ -142,6 +142,8 @@ char *LP_spentcheck(cJSON *argjson) } if ( LP_txvalue(utxo->coin,checktxid,checkvout) == 0 ) { + if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) + LP_mypeer->numutxos--; utxo->spentflag = (uint32_t)time(NULL); //printf("indeed txid was spent\n"); return(clonestr("{\"result\":\"marked as spent\"}")); From 88586ccd433cdb7c866146f6dd56a13b6b49baaf Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:21:13 +0300 Subject: [PATCH 1140/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index df8455a39..da601e7e0 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -165,27 +165,25 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i char str[65]; HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { - if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) + if ( utxo->spentflag == 0 ) { - if ( utxo->spentflag == 0 ) + printf("mainloop check spent\n"); + if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) { printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value)); LP_spentnotify(utxo,0); } - } - else if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == 0 ) - { - if ( utxo->spentflag == 0 ) + else if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == 0 ) { printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid2),utxo->vout2,dstr(utxo->value2)); LP_spentnotify(utxo,1); } - } - else if ( LP_ismine(utxo) != 0 ) - { - if ( strcmp(utxo->coin,"KMD") == 0 ) - LP_priceping(pubsock,utxo,"BTC",profitmargin); - else LP_priceping(pubsock,utxo,"KMD",profitmargin); + else if ( LP_ismine(utxo) != 0 ) + { + if ( strcmp(utxo->coin,"KMD") == 0 ) + LP_priceping(pubsock,utxo,"BTC",profitmargin); + else LP_priceping(pubsock,utxo,"KMD",profitmargin); + } } } } From 00666b9ec0e5dd5b09d75adc27d0640aeb74b7a1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:24:49 +0300 Subject: [PATCH 1141/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 15cf24c31..73c57e2fc 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -171,7 +171,7 @@ struct LP_utxoinfo uint8_t key[sizeof(bits256) + sizeof(int32_t)]; uint8_t key2[sizeof(bits256) + sizeof(int32_t)]; int32_t vout,vout2,pair; - uint32_t lasttime,errors,swappending,published,spentflag; + uint32_t lasttime,errors,swappending,published,spentflag,lastspentcheck; double profitmargin; char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; uint16_t port; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index da601e7e0..58c952f0b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -165,9 +165,10 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i char str[65]; HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { - if ( utxo->spentflag == 0 ) + now = (uint32_t)time(NULL); + if ( utxo->spentflag == 0 && now > utxo->lastspentcheck+60 ) { - printf("mainloop check spent\n"); + utxo->lastspentcheck = now; if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) { printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value)); From 877a2537f746b64ce42bc842984ed7904fb055ac Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:33:49 +0300 Subject: [PATCH 1142/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 58c952f0b..c63d58810 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -159,10 +159,15 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { nonz = 0; if ( (++counter % 2000) == 0 ) + { + printf("start privkey updates\n"); LP_privkey_updates(mypeer,pubsock,passphrase,amclient); + printf("done privkey updates\n"); + } if ( (counter % 500) == 0 ) { char str[65]; + printf("start utxos updates\n"); HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { now = (uint32_t)time(NULL); @@ -187,8 +192,10 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } } } + printf("done utxos updates\n"); } now = (uint32_t)time(NULL); + printf("start peers updates\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) @@ -227,6 +234,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i nn_freemsg(ptr), ptr = 0; } } + printf("done peers updates\n"); while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; @@ -250,6 +258,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } if ( nonz == 0 ) usleep(50000); + printf("nonz.%d in mainloop\n",nonz); } } } From 198ec880f119f6c870d13d69e1560ed94432d6da Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:38:33 +0300 Subject: [PATCH 1143/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c63d58810..2bafb4aa8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -174,7 +174,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( utxo->spentflag == 0 && now > utxo->lastspentcheck+60 ) { utxo->lastspentcheck = now; - if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) + /*if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) { printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value)); LP_spentnotify(utxo,0); @@ -184,7 +184,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid2),utxo->vout2,dstr(utxo->value2)); LP_spentnotify(utxo,1); } - else if ( LP_ismine(utxo) != 0 ) + else*/ if ( LP_ismine(utxo) != 0 ) { if ( strcmp(utxo->coin,"KMD") == 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); From ad44a6dc188bddb1f8ae9cc1dea79195e3676492 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:39:10 +0300 Subject: [PATCH 1144/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 2bafb4aa8..5def5812d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -166,7 +166,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } if ( (counter % 500) == 0 ) { - char str[65]; + //char str[65]; printf("start utxos updates\n"); HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { From bbd8347be68e8ba309ff3acf1e58118d466d89ad Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:43:03 +0300 Subject: [PATCH 1145/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5def5812d..b405770ef 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -166,15 +166,16 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } if ( (counter % 500) == 0 ) { - //char str[65]; + char str[65]; printf("start utxos updates\n"); HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { now = (uint32_t)time(NULL); + printf("%s lag.%d\n",bits256_str(str,utxo->txid),now-utxo->lastspentcheck); if ( utxo->spentflag == 0 && now > utxo->lastspentcheck+60 ) { utxo->lastspentcheck = now; - /*if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) + if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) { printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value)); LP_spentnotify(utxo,0); @@ -184,7 +185,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid2),utxo->vout2,dstr(utxo->value2)); LP_spentnotify(utxo,1); } - else*/ if ( LP_ismine(utxo) != 0 ) + else if ( LP_ismine(utxo) != 0 ) { if ( strcmp(utxo->coin,"KMD") == 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); @@ -198,6 +199,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i printf("start peers updates\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { + printf("updatepeer.%s lag.%d\n",now-peer->lastpeers); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) { peer->lastpeers = now; @@ -224,7 +226,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); @@ -246,7 +248,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + printf("%s PULL.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } } From 6ac3c87206c590cf27254c2871072e6747734b74 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:43:58 +0300 Subject: [PATCH 1146/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b405770ef..bb0b2bf2f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -199,7 +199,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i printf("start peers updates\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("updatepeer.%s lag.%d\n",now-peer->lastpeers); + printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) { peer->lastpeers = now; From 1cf217d6ded04417aa14d94a8f6a2365675c7285 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:50:33 +0300 Subject: [PATCH 1147/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index bb0b2bf2f..058207246 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -164,7 +164,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_privkey_updates(mypeer,pubsock,passphrase,amclient); printf("done privkey updates\n"); } - if ( (counter % 500) == 0 ) + if ( 0 && (counter % 500) == 0 ) { char str[65]; printf("start utxos updates\n"); @@ -199,6 +199,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i printf("start peers updates\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { + break; printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) { @@ -237,7 +238,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } } printf("done peers updates\n"); - while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + while ( 0 && pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) From 8d14c3dcb2ebb45bfcc459a2eac268889928a7ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 18:53:40 +0300 Subject: [PATCH 1148/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 - 1 file changed, 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 058207246..3f9406c65 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -199,7 +199,6 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i printf("start peers updates\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - break; printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) { From 1ddcaa9c9d9584f2b6c1455bb0fdc7d9d5ed1e44 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:13:27 +0300 Subject: [PATCH 1149/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3f9406c65..0a4e72094 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -164,14 +164,14 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_privkey_updates(mypeer,pubsock,passphrase,amclient); printf("done privkey updates\n"); } - if ( 0 && (counter % 500) == 0 ) + if ( (counter % 500) == 0 ) { char str[65]; - printf("start utxos updates\n"); + //printf("start utxos updates\n"); HASH_ITER(hh,LP_utxoinfos,utxo,utmp) { now = (uint32_t)time(NULL); - printf("%s lag.%d\n",bits256_str(str,utxo->txid),now-utxo->lastspentcheck); + //printf("%s lag.%d\n",bits256_str(str,utxo->txid),now-utxo->lastspentcheck); if ( utxo->spentflag == 0 && now > utxo->lastspentcheck+60 ) { utxo->lastspentcheck = now; @@ -193,13 +193,13 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } } } - printf("done utxos updates\n"); + //printf("done utxos updates\n"); } now = (uint32_t)time(NULL); - printf("start peers updates\n"); + //printf("start peers updates\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); + //printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) { peer->lastpeers = now; @@ -236,8 +236,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i nn_freemsg(ptr), ptr = 0; } } - printf("done peers updates\n"); - while ( 0 && pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) @@ -260,7 +259,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } if ( nonz == 0 ) usleep(50000); - printf("nonz.%d in mainloop\n",nonz); + //printf("nonz.%d in mainloop\n",nonz); } } } From e7c625cf43346cb40dccf58986064281717fa558 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:16:37 +0300 Subject: [PATCH 1150/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- iguana/exchanges/LP_utxos.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index d8703c7b5..b976dbb71 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -120,7 +120,7 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) value += SATOSHIDEN * interest; } } - char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); + //char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); free_json(txobj); } return(value); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index d73707f29..90034077d 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -403,6 +403,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb used = 0; while ( used < n ) { + printf("used.%d of n.%d\n",used,n); if ( (i= LP_maxvalue(values,n)) >= 0 ) { item = jitem(array,i); From b13d57eaac871d6e3b230bd8a087c1fb103e0303 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:20:07 +0300 Subject: [PATCH 1151/2705] Test --- iguana/exchanges/LP_utxos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 90034077d..54d517829 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -401,7 +401,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } //printf("array.%d\n",n); used = 0; - while ( used < n ) + while ( used < n-1 ) { printf("used.%d of n.%d\n",used,n); if ( (i= LP_maxvalue(values,n)) >= 0 ) @@ -444,6 +444,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } free_json(array); } + printf("privkey.%s %.8f\n",symbol,dstr(total)); return(total); } From 5ce716cbf3a0b3ea08bd98cdfe97e1149128cdd6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:22:48 +0300 Subject: [PATCH 1152/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 -- iguana/exchanges/LP_utxos.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0a4e72094..6e6398d2b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -160,9 +160,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i nonz = 0; if ( (++counter % 2000) == 0 ) { - printf("start privkey updates\n"); LP_privkey_updates(mypeer,pubsock,passphrase,amclient); - printf("done privkey updates\n"); } if ( (counter % 500) == 0 ) { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 54d517829..1a0a9e196 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -368,6 +368,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb printf("cant add privkey for %s, coin not active\n",symbol); return(0); } + printf("privkey.%s init\n",symbol); if ( passphrase != 0 ) conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); From c82413cf688313bfa6c8934d212988fc95d5d226 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:27:45 +0300 Subject: [PATCH 1153/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/mm.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 621c7544b..ddfbdc85c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -256,7 +256,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { if ( strcmp(method,"inventory") == 0 ) { - LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); + //LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); return(LP_inventory(coin)); } else if ( IAMCLIENT != 0 && (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 080fb7325..638acc5e8 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -818,8 +818,8 @@ void LP_main(void *ptr) int main(int argc, const char * argv[]) { char *base,*rel,*name,*exchange,*apikey,*apisecret,*blocktrail,*retstr,*baseaddr,*reladdr,*passphrase; - double profitmargin,maxexposure,incrratio,start_rel,start_base,minask,maxbid,incr,theoretical = 0.; - cJSON *retjson,*loginjson,*matchjson; int32_t i; + double profitmargin,maxexposure,incrratio,start_rel,start_base,minask,maxbid,incr; + cJSON *retjson,*loginjson; int32_t i; if ( argc > 1 && (retjson= cJSON_Parse(argv[1])) != 0 ) { if ( (passphrase= jstr(retjson,"passphrase")) == 0 ) @@ -830,7 +830,7 @@ int main(int argc, const char * argv[]) exit(-1); } else printf("(%s) launched.(%s)\n",argv[1],passphrase); incr = 100.; - while ( (0) && IAMCLIENT != 0 ) + /*while ( (0) && IAMCLIENT != 0 ) { theoretical = marketmaker_updateprice("komodo","REVS","KMD",theoretical,&incr); sleep(3); @@ -845,7 +845,7 @@ int main(int argc, const char * argv[]) } } sleep(1000); - } + }*/ while ( 1 ) sleep(1); profitmargin = jdouble(retjson,"profitmargin"); From cee16d48c0185e16f52d936eb3b9e3b178ebb851 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:39:45 +0300 Subject: [PATCH 1154/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 1a0a9e196..a0bd6bb8f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -324,6 +324,7 @@ char *LP_inventory(char *symbol) else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { + char str[65]; printf("iterate %s\n",bits256_str(str,utxo->txid)); if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || LP_ismine(utxo) != 0) ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } From 1c41483cc8b6855bfc1112b7ce0e542f25f21ad8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:45:26 +0300 Subject: [PATCH 1155/2705] Test --- iguana/exchanges/LP_utxos.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a0bd6bb8f..7b5f63556 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -43,8 +43,17 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); portable_mutex_lock(&LP_utxomutex); HASH_FIND(hh,LP_utxoinfos,key,sizeof(key),utxo); - if ( utxo == 0 ) - HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); + portable_mutex_unlock(&LP_utxomutex); + return(utxo); +} + +struct LP_utxoinfo *LP_utxo2find(bits256 txid,int32_t vout) +{ + struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; + memcpy(key,txid.bytes,sizeof(txid)); + memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); + portable_mutex_lock(&LP_utxomutex); + HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); portable_mutex_unlock(&LP_utxomutex); return(utxo); } @@ -221,7 +230,8 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 memcpy(&utxo->key2[sizeof(txid2)],&vout2,sizeof(vout2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); - HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); + if ( LP_utxo2find(txid2,vout2) == 0 ) + HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); From 7b2d3d9c5bb25f0300e0ae3a9876ab44414e2578 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:48:02 +0300 Subject: [PATCH 1156/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7b5f63556..6fd04fe4c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -196,7 +196,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("LP node got localhost utxo\n"); return(0); } - if ( (utxo= LP_utxofind(txid,vout)) != 0 ) + if ( (utxo= LP_utxofind(txid,vout)) != 0 || (utxo= LP_utxo2find(txid,vout)) != 0 ) { //printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(txid2,utxo->txid2) != 0 || vout != utxo->vout || value != utxo->value || tmpsatoshis != utxo->satoshis || vout2 != utxo->vout2 || value2 != utxo->value2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) From 32ac1fe98012c81462e064df86095735a7827a6b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:52:46 +0300 Subject: [PATCH 1157/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_utxos.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 73c57e2fc..0e9e37d89 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -140,7 +140,7 @@ struct basilisk_swapinfo struct iguana_info { uint64_t txfee; double estimatedrate; - int32_t longestchain; + int32_t longestchain; uint32_t counter; uint8_t pubtype,p2shtype,isPoS,wiftype; char symbol[16],smartaddr[64],userpass[1024],serverport[128]; }; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6fd04fe4c..d921c84c7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -372,22 +372,20 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t amclient) { - static uint32_t counter; char *script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 userpass,userpub,txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) { printf("cant add privkey for %s, coin not active\n",symbol); return(0); } - printf("privkey.%s init\n",symbol); if ( passphrase != 0 ) conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); - if ( counter == 0 ) + if ( coin->counter == 0 ) { char tmpstr[128]; - counter++; + coin->counter++; bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); conv_NXTpassword(userpass.bytes,pubkey.bytes,(uint8_t *)tmpstr,(int32_t)strlen(tmpstr)); From 22a19f347115cf881466592b8d2a9f9f1ec5fb49 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:53:19 +0300 Subject: [PATCH 1158/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index ddfbdc85c..621c7544b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -256,7 +256,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { if ( strcmp(method,"inventory") == 0 ) { - //LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); + LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); return(LP_inventory(coin)); } else if ( IAMCLIENT != 0 && (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) From 3901aa05eec68a5d44065f144b539e45e50ae327 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:58:32 +0300 Subject: [PATCH 1159/2705] Test --- iguana/exchanges/LP_utxos.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index d921c84c7..ea862d209 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -378,6 +378,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb printf("cant add privkey for %s, coin not active\n",symbol); return(0); } + printf("privkey init.(%s) %s\n",symbol,coin->symbol); if ( passphrase != 0 ) conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); @@ -413,7 +414,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb used = 0; while ( used < n-1 ) { - printf("used.%d of n.%d\n",used,n); + //printf("used.%d of n.%d\n",used,n); if ( (i= LP_maxvalue(values,n)) >= 0 ) { item = jitem(array,i); @@ -454,7 +455,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } free_json(array); } - printf("privkey.%s %.8f\n",symbol,dstr(total)); + //printf("privkey.%s %.8f\n",symbol,dstr(total)); return(total); } From c443a67150ae7baa4cc7c55f7a1d9806ca468ed4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 19:59:46 +0300 Subject: [PATCH 1160/2705] Test --- iguana/exchanges/LP_utxos.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index ea862d209..59a678965 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -463,7 +463,10 @@ void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphr { int32_t i; for (i=0; i Date: Tue, 6 Jun 2017 20:00:45 +0300 Subject: [PATCH 1161/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 59a678965..32cc98a73 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -455,7 +455,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } free_json(array); } - //printf("privkey.%s %.8f\n",symbol,dstr(total)); + printf("privkey.%s %.8f\n",symbol,dstr(total)); return(total); } From bdd4c3665cec68f5021e32e1bf5670c5f54df79d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:01:55 +0300 Subject: [PATCH 1162/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 32cc98a73..b62cd6708 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -228,6 +228,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 memcpy(&utxo->key[sizeof(txid)],&vout,sizeof(vout)); memcpy(utxo->key2,txid2.bytes,sizeof(txid2)); memcpy(&utxo->key2[sizeof(txid2)],&vout2,sizeof(vout2)); + char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); if ( LP_utxo2find(txid2,vout2) == 0 ) @@ -237,7 +238,6 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid2)); } return(utxo); } From 6ecba8169c30ccaf8389bdb6d09e907b4420a985 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:03:02 +0300 Subject: [PATCH 1163/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b62cd6708..0a4e26b6d 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -236,6 +236,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); + printf("added\n"); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); } From d5151f8ecd992e0a110faacbe6d44373fbb9abc6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:06:03 +0300 Subject: [PATCH 1164/2705] Test --- iguana/exchanges/LP_utxos.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0a4e26b6d..94401c6f7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -47,13 +47,22 @@ struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) return(utxo); } +struct LP_utxoinfo *_LP_utxo2find(bits256 txid,int32_t vout) +{ + struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; + memcpy(key,txid.bytes,sizeof(txid)); + memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); + HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); + return(utxo); +} + struct LP_utxoinfo *LP_utxo2find(bits256 txid,int32_t vout) { struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); portable_mutex_lock(&LP_utxomutex); - HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); + utxo = _LP_utxo2find(txid,vout); portable_mutex_unlock(&LP_utxomutex); return(utxo); } @@ -231,12 +240,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); - if ( LP_utxo2find(txid2,vout2) == 0 ) + if ( _LP_utxo2find(txid2,vout2) == 0 ) HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); - printf("added\n"); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); } From dc07592cff8cf36dbfe4403ca2216b8548f614be Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:11:05 +0300 Subject: [PATCH 1165/2705] Test --- iguana/exchanges/LP_utxos.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 94401c6f7..32ded78ba 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -394,13 +394,17 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); if ( coin->counter == 0 ) { + static uint32_t counter; char tmpstr[128]; coin->counter++; - bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); + if ( counter++ == 0 ) + { + bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); + conv_NXTpassword(userpass.bytes,pubkey.bytes,(uint8_t *)tmpstr,(int32_t)strlen(tmpstr)); + userpub = curve25519(userpass,curve25519_basepoint9()); + printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); + } bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - conv_NXTpassword(userpass.bytes,pubkey.bytes,(uint8_t *)tmpstr,(int32_t)strlen(tmpstr)); - userpub = curve25519(userpass,curve25519_basepoint9()); - printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); From 374d54e9d2c82c670e29f0441695e37212a2c0d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:13:36 +0300 Subject: [PATCH 1166/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 32ded78ba..92aba5909 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -381,6 +381,7 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t amclient) { + static uint32_t counter; char *script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 userpass,userpub,txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) { @@ -394,7 +395,6 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); if ( coin->counter == 0 ) { - static uint32_t counter; char tmpstr[128]; coin->counter++; if ( counter++ == 0 ) From 9ce523c71f90e2d0c0c0010e06e3fe527d047db3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:14:46 +0300 Subject: [PATCH 1167/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 92aba5909..417bfff20 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -397,6 +397,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { char tmpstr[128]; coin->counter++; + bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); if ( counter++ == 0 ) { bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); @@ -404,7 +405,6 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb userpub = curve25519(userpass,curve25519_basepoint9()); printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); } - bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); From e117b2ad4ec5cc10c394bcc8cedf9458b915d398 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:18:21 +0300 Subject: [PATCH 1168/2705] Test --- iguana/exchanges/LP_utxos.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 417bfff20..476182e4c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -52,7 +52,7 @@ struct LP_utxoinfo *_LP_utxo2find(bits256 txid,int32_t vout) struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); + //HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); return(utxo); } @@ -61,9 +61,9 @@ struct LP_utxoinfo *LP_utxo2find(bits256 txid,int32_t vout) struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - portable_mutex_lock(&LP_utxomutex); + //portable_mutex_lock(&LP_utxomutex); utxo = _LP_utxo2find(txid,vout); - portable_mutex_unlock(&LP_utxomutex); + //portable_mutex_unlock(&LP_utxomutex); return(utxo); } @@ -240,8 +240,8 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); - if ( _LP_utxo2find(txid2,vout2) == 0 ) - HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); + //if ( _LP_utxo2find(txid2,vout2) == 0 ) + // HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); From 53ebe213be5c196b4a8e58da5263f9544814c699 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:29:36 +0300 Subject: [PATCH 1169/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6e6398d2b..17dac45c4 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -325,7 +325,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); exit(-1); } - printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); + //printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); } LP_mainloop(mypeer,mypubport,pubsock,pullsock,myport,amclient,passphrase,profitmargin); } From 754f01bc419842155b5cba1bed9d6e7338102792 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 20:52:25 +0300 Subject: [PATCH 1170/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 17dac45c4..fee4b72b9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -81,6 +81,12 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { //static uint16_t tmpport; char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",myport); + exit(-1); + } + printf("query peers queried\n"); if ( amclient == 0 ) { for (i=0; i Date: Tue, 6 Jun 2017 21:03:05 +0300 Subject: [PATCH 1171/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 ++---- iguana/exchanges/LP_utxos.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fee4b72b9..d10b00c62 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -86,7 +86,6 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } - printf("query peers queried\n"); if ( amclient == 0 ) { for (i=0; iipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } - //if ( (retstr= basilisk_swaplist()) != 0 ) - // free(retstr); + if ( (retstr= basilisk_swaplist()) != 0 ) + free(retstr); if ( amclient != 0 ) { while ( 1 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 476182e4c..e2b342dc9 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -52,7 +52,7 @@ struct LP_utxoinfo *_LP_utxo2find(bits256 txid,int32_t vout) struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - //HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); + HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); return(utxo); } @@ -61,9 +61,9 @@ struct LP_utxoinfo *LP_utxo2find(bits256 txid,int32_t vout) struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - //portable_mutex_lock(&LP_utxomutex); + portable_mutex_lock(&LP_utxomutex); utxo = _LP_utxo2find(txid,vout); - //portable_mutex_unlock(&LP_utxomutex); + portable_mutex_unlock(&LP_utxomutex); return(utxo); } @@ -240,8 +240,8 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); - //if ( _LP_utxo2find(txid2,vout2) == 0 ) - // HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); + if ( _LP_utxo2find(txid2,vout2) == 0 ) + HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); @@ -343,7 +343,7 @@ char *LP_inventory(char *symbol) else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { - char str[65]; printf("iterate %s\n",bits256_str(str,utxo->txid)); + //char str[65]; printf("iterate %s\n",bits256_str(str,utxo->txid)); if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || LP_ismine(utxo) != 0) ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } @@ -388,7 +388,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb printf("cant add privkey for %s, coin not active\n",symbol); return(0); } - printf("privkey init.(%s) %s\n",symbol,coin->symbol); + //printf("privkey init.(%s) %s\n",symbol,coin->symbol); if ( passphrase != 0 ) conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else privkey = iguana_wif2privkey(wifstr); @@ -468,7 +468,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } free_json(array); } - printf("privkey.%s %.8f\n",symbol,dstr(total)); + //printf("privkey.%s %.8f\n",symbol,dstr(total)); return(total); } @@ -477,7 +477,7 @@ void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphr int32_t i; for (i=0; i Date: Tue, 6 Jun 2017 21:06:12 +0300 Subject: [PATCH 1172/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e2b342dc9..c2fc857d8 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -61,9 +61,9 @@ struct LP_utxoinfo *LP_utxo2find(bits256 txid,int32_t vout) struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - portable_mutex_lock(&LP_utxomutex); + //portable_mutex_lock(&LP_utxomutex); utxo = _LP_utxo2find(txid,vout); - portable_mutex_unlock(&LP_utxomutex); + //portable_mutex_unlock(&LP_utxomutex); return(utxo); } From 9f196f885373b2cbfcef6fcaca90135255375237 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 21:08:18 +0300 Subject: [PATCH 1173/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index c2fc857d8..3d4e5590e 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -52,7 +52,7 @@ struct LP_utxoinfo *_LP_utxo2find(bits256 txid,int32_t vout) struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); + //HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); return(utxo); } From 5bee10438dc4b605de95330f32d78bc5c5e4ace4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 21:09:22 +0300 Subject: [PATCH 1174/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_utxos.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 0e9e37d89..d1eba8e7c 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -164,7 +164,7 @@ struct basilisk_swap struct LP_utxoinfo { - UT_hash_handle hh; + UT_hash_handle hh,hh2; bits256 txid,txid2,feetxid,otherpubkey,mypub; void *swap; uint64_t value,satoshis,value2; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 3d4e5590e..875b29ca3 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -52,7 +52,7 @@ struct LP_utxoinfo *_LP_utxo2find(bits256 txid,int32_t vout) struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - //HASH_FIND(hh,LP_utxoinfos2,key,sizeof(key),utxo); + HASH_FIND(hh2,LP_utxoinfos2,key,sizeof(key),utxo); return(utxo); } @@ -61,9 +61,9 @@ struct LP_utxoinfo *LP_utxo2find(bits256 txid,int32_t vout) struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - //portable_mutex_lock(&LP_utxomutex); + portable_mutex_lock(&LP_utxomutex); utxo = _LP_utxo2find(txid,vout); - //portable_mutex_unlock(&LP_utxomutex); + portable_mutex_unlock(&LP_utxomutex); return(utxo); } @@ -241,7 +241,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); if ( _LP_utxo2find(txid2,vout2) == 0 ) - HASH_ADD_KEYPTR(hh,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); + HASH_ADD_KEYPTR(hh2,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); if ( mypeer != 0 ) mypeer->numutxos++; portable_mutex_unlock(&LP_utxomutex); From dc1be55b95621131b58e951ab29dc46604a8e8e4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 21:11:19 +0300 Subject: [PATCH 1175/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d10b00c62..14697ab34 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -162,7 +162,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { LP_privkey_updates(mypeer,pubsock,passphrase,amclient); } - if ( (counter % 500) == 0 ) + if ( (counter % 2500) == 0 ) { char str[65]; //printf("start utxos updates\n"); @@ -256,7 +256,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i nn_freemsg(ptr), ptr = 0; } if ( nonz == 0 ) - usleep(50000); + usleep(100000); //printf("nonz.%d in mainloop\n",nonz); } } From ef56f6946c4fa50b2fb3c5c1a44849361442e532 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 21:12:19 +0300 Subject: [PATCH 1176/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 14697ab34..2861155d7 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -150,7 +150,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } } if ( nonz == 0 ) - usleep(100000); + usleep(200000); } } else @@ -224,7 +224,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); From 458e5673cb9e4d92d850a4a6943d5920733e7522 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 21:12:54 +0300 Subject: [PATCH 1177/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 875b29ca3..5b9664c1c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -202,7 +202,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 } if ( IAMCLIENT == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) { - printf("LP node got localhost utxo\n"); + //printf("LP node got localhost utxo\n"); return(0); } if ( (utxo= LP_utxofind(txid,vout)) != 0 || (utxo= LP_utxo2find(txid,vout)) != 0 ) From 2bdbe27d4ca76b46fe0cba230af494f6e328ce40 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 21:31:35 +0300 Subject: [PATCH 1178/2705] Test --- iguana/exchanges/LP_prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 5b7ad7ed1..d9c0be254 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -324,7 +324,7 @@ char *LP_orderbook(char *base,char *rel) retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); if ( numbids > 1 ) - qsort(bids,numbids,sizeof(*bids),_cmp_orderbook); + qsort(bids,numbids,sizeof(*bids),_cmp_orderbookrev); for (i=0; i Date: Tue, 6 Jun 2017 21:35:20 +0300 Subject: [PATCH 1179/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 2861155d7..c58d99a51 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -162,7 +162,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { LP_privkey_updates(mypeer,pubsock,passphrase,amclient); } - if ( (counter % 2500) == 0 ) + if ( (counter % 500) == 0 ) { char str[65]; //printf("start utxos updates\n"); From 13cd60e0326a9b42604fd4e333f72eab0f0a1997 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 6 Jun 2017 21:42:50 +0300 Subject: [PATCH 1180/2705] Test --- iguana/exchanges/LP_prices.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index d9c0be254..edd9f760b 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -141,8 +141,15 @@ double LP_myprice(double *bidp,double *askp,char *base,char *rel) if ( (val= relpp->myprices[basepp->ind]) != 0. ) { *bidp = 1. / val; - printf("myprice (%.8f %.8f)\n",*bidp,*askp); - return((*askp + *bidp) * 0.5); + } else *bidp = *askp * 0.99; + return((*askp + *bidp) * 0.5); + } + else + { + if ( (val= relpp->myprices[basepp->ind]) != 0. ) + { + *bidp = 1. / val; + *askp = *bidp / 0.99; } } } @@ -177,7 +184,7 @@ cJSON *LP_priceinfomatrix(int32_t usemyprices) now = (uint32_t)time(NULL); HASH_ITER(hh,LP_cacheinfos,ptr,tmp) { - if ( ptr->timestamp < now-60 || ptr->price == 0. ) + if ( ptr->timestamp < now-3600*2 || ptr->price == 0. ) continue; LP_priceinfoupdate(ptr->Q.srccoin,ptr->Q.destcoin,ptr->price); } @@ -308,7 +315,7 @@ char *LP_orderbook(char *base,char *rel) now = (uint32_t)time(NULL); HASH_ITER(hh,LP_cacheinfos,ptr,tmp) { - if ( ptr->timestamp < now-60*2 || ptr->price == 0. ) + if ( ptr->timestamp < now-3600*2 || ptr->price == 0. ) continue; if ( strcmp(ptr->Q.srccoin,base) == 0 && strcmp(ptr->Q.destcoin,rel) == 0 ) { From c1686c9208fb60ae6dfce1a15c1f2c9819020f00 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 07:44:23 +0300 Subject: [PATCH 1181/2705] Test --- iguana/exchanges/LP_coins.c | 125 +++++++++++++++++++++----------- iguana/exchanges/LP_commands.c | 2 + iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 14 +++- iguana/exchanges/mm.c | 2 +- 5 files changed, 97 insertions(+), 48 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 6f32b9372..76cf7f0e3 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -18,7 +18,16 @@ // marketmaker // -char *portstrs[][2] = { { "BTC", "8332" }, { "KMD", "7771" }, { "LTC", "9332" }, { "REVS", "10196" }, { "JUMBLR", "15106" }, }; +char *portstrs[][2] = { { "BTC", "8332" }, { "KMD", "7771" }, { "REVS", "10196" }, { "JUMBLR", "15106" }, }; + +uint16_t LP_rpcport(char *symbol) +{ + int32_t i; + for (i=0; isymbol,symbol,sizeof(coin->symbol)); + sprintf(coin->serverport,"127.0.0.1:%u",port); + coin->longestchain = longestchain; + coin->txfee = txfee; + coin->estimatedrate = estimatedrate; + coin->pubtype = pubtype; + coin->p2shtype = p2shtype; + coin->wiftype = wiftype; + LP_userpass(coin->userpass,symbol,"",name); +} + +struct iguana_info *LP_coinadd(struct iguana_info *cdata) { - struct iguana_info *coin,cdata; int32_t i; uint16_t port; + struct iguana_info *coin; + //printf("%s: (%s) (%s)\n",symbol,cdata.serverport,cdata.userpass); + LP_coins = realloc(LP_coins,sizeof(*LP_coins) * (LP_numcoins+1)); + coin = &LP_coins[LP_numcoins]; + *coin = *cdata; + LP_numcoins++; + return(coin); +} + +struct iguana_info *LP_coinsearch(char *symbol) +{ + int32_t i; for (i=0; i", "rpcport":pppp}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }] + +struct iguana_info *LP_coincreate(cJSON *item) +{ + struct iguana_info cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*symbol; + if ( (symbol= jstr(item,"coin")) != 0 && symbol[0] != 0 && strlen(symbol) < 16 && LP_coinfind(symbol) == 0 && (port= juint(item,"rpcport")) != 0 ) { - cdata.pubtype = 60; - cdata.p2shtype = 85; - cdata.wiftype = 188; - LP_userpass(cdata.userpass,symbol,symbol,strcmp(symbol,"KMD") == 0 ? "komodo" : symbol); + if ( (txfee= j64bits(item,"txfee")) == 0 ) + txfee = 10000; + if ( (estimatedrate= jdouble(item,"estimatedrate")) == 0. ) + estimatedrate = 20; + if ( (pubtype= juint(item,"pubtype")) == 0 ) + pubtype = 60; + if ( (p2shtype= juint(item,"p2shtype")) == 0 ) + p2shtype = 85; + if ( (wiftype= juint(item,"wiftype")) == 0 ) + wiftype = 188; + if ( (name= jstr(item,"name")) == 0 ) + name = symbol; + LP_coininit(&cdata,symbol,name,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); + return(LP_coinadd(&cdata)); } - //printf("%s: (%s) (%s)\n",symbol,cdata.serverport,cdata.userpass); - LP_coins = realloc(LP_coins,sizeof(*LP_coins) * (LP_numcoins+1)); - coin = &LP_coins[LP_numcoins++]; - *coin = cdata; - return(coin); + return(0); } diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 621c7544b..366ab2556 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -38,6 +38,8 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port, if ( bits256_nonz(qp->desthash) != 0 ) flag = 1; jaddstr(reqjson,"method",method); + if ( strcmp(method,"price") != 0 ) + printf("QUERY.(%s)\n",jprint(reqjson,0)); LP_send(pushsock,jprint(reqjson,1),1); for (i=0; i<30; i++) { diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index d1eba8e7c..9b194a908 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -37,7 +37,7 @@ //#define BASILISK_DISABLEWAITTX //#define BASILISK_DISABLESENDTX -#define LP_PROPAGATION_SLACK 10 // txid ordering is not enforced, so getting extra recent txid +#define LP_PROPAGATION_SLACK 100 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 #define LP_AVETXSIZE 200 #define LP_CACHEDURATION 60 diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c58d99a51..f31e3c1ef 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -54,6 +54,7 @@ void tradebot_pendingadd(cJSON *tradejson,char *base,double basevolume,char *rel { // add to trades } + char *LP_getdatadir() { return(USERHOME); @@ -77,10 +78,10 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_quotes.c" #include "LP_commands.c" -void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin) +void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin,cJSON *coins) { //static uint16_t tmpport; - char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson; + char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson,*item; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); @@ -112,6 +113,11 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i LP_coinfind(activecoins[i]); LP_priceinfoadd(activecoins[i]); } + if ( (n= cJSON_GetArraySize(coins)) > 0 ) + { + for (i=0; i Date: Wed, 7 Jun 2017 07:47:55 +0300 Subject: [PATCH 1182/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/client | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 76cf7f0e3..18a38390a 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -18,7 +18,7 @@ // marketmaker // -char *portstrs[][2] = { { "BTC", "8332" }, { "KMD", "7771" }, { "REVS", "10196" }, { "JUMBLR", "15106" }, }; +char *portstrs[][2] = { { "BTC", "8332" }, { "KMD", "7771" } }; uint16_t LP_rpcport(char *symbol) { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f31e3c1ef..1e0aea7db 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -26,7 +26,7 @@ struct LP_utxoinfo *LP_utxoinfos,*LP_utxoinfos2; struct LP_peerinfo *LP_peerinfos,*LP_mypeer; -char *activecoins[] = { "BTC", "KMD", "REVS", "JUMBLR" };//"LTC", "USD", }; +char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; @@ -81,7 +81,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin,cJSON *coins) { //static uint16_t tmpport; - char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson,*item; + char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); diff --git a/iguana/exchanges/client b/iguana/exchanges/client index f84982ff2..2452d2855 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"rpcport\":15106}], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From 8195e3394d260b93c31904f6c846956c795f1f2b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 07:52:04 +0300 Subject: [PATCH 1183/2705] Test --- iguana/exchanges/LP_coins.c | 10 ++++++++-- iguana/exchanges/client | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 18a38390a..6b1a0f6f6 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -198,7 +198,7 @@ struct iguana_info *LP_coinsearch(char *symbol) struct iguana_info *LP_coinfind(char *symbol) { - struct iguana_info *coin,cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name; + struct iguana_info *coin,cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,namebuf[512]; if ( (coin= LP_coinsearch(symbol)) != 0 ) return(coin); if ( (port= LP_rpcport(symbol)) == 0 ) @@ -216,7 +216,13 @@ struct iguana_info *LP_coinfind(char *symbol) wiftype = 128; name = "bitcoin"; } - else name = (strcmp(symbol,"KMD") == 0) ? "komodo" : symbol; + else if ( strcmp(symbol,"KMD") == 0 ) + name = "komodo"; + else + { + sprintf(namebuf,"komodo/%s",symbol); + name = namebuf; + } LP_coininit(&cdata,symbol,name,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); return(LP_coinadd(&cdata)); } diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 2452d2855..bbc9b9575 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"rpcport\":15106}], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"name\":\"komodo/REVS", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"name\":\"komodo/JUMBLR\", \"rpcport\":15106}], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From 4d1ed4488a6374f05bae097c1ec793335b42cb7c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 07:58:20 +0300 Subject: [PATCH 1184/2705] Test --- iguana/exchanges/LP_coins.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 6b1a0f6f6..4d247cfb8 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -162,7 +162,7 @@ cJSON *LP_coinsjson() return(array); } -void LP_coininit(struct iguana_info *coin,char *symbol,char *name,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain) +void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain) { memset(coin,0,sizeof(*coin)); safecopy(coin->symbol,symbol,sizeof(coin->symbol)); @@ -173,7 +173,7 @@ void LP_coininit(struct iguana_info *coin,char *symbol,char *name,uint16_t port, coin->pubtype = pubtype; coin->p2shtype = p2shtype; coin->wiftype = wiftype; - LP_userpass(coin->userpass,symbol,"",name); + LP_userpass(coin->userpass,symbol,assetname,name); } struct iguana_info *LP_coinadd(struct iguana_info *cdata) @@ -198,7 +198,7 @@ struct iguana_info *LP_coinsearch(char *symbol) struct iguana_info *LP_coinfind(char *symbol) { - struct iguana_info *coin,cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,namebuf[512]; + struct iguana_info *coin,cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*assetname; if ( (coin= LP_coinsearch(symbol)) != 0 ) return(coin); if ( (port= LP_rpcport(symbol)) == 0 ) @@ -208,6 +208,7 @@ struct iguana_info *LP_coinfind(char *symbol) pubtype = 60; p2shtype = 85; wiftype = 188; + assetname = ""; if ( strcmp(symbol,"BTC") == 0 ) { txfee = 50000; @@ -220,10 +221,10 @@ struct iguana_info *LP_coinfind(char *symbol) name = "komodo"; else { - sprintf(namebuf,"komodo/%s",symbol); - name = namebuf; + name = symbol; + assetname = symbol; } - LP_coininit(&cdata,symbol,name,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); + LP_coininit(&cdata,symbol,name,assetname,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); return(LP_coinadd(&cdata)); } @@ -231,7 +232,7 @@ struct iguana_info *LP_coinfind(char *symbol) struct iguana_info *LP_coincreate(cJSON *item) { - struct iguana_info cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*symbol; + struct iguana_info cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*symbol,*assetname; if ( (symbol= jstr(item,"coin")) != 0 && symbol[0] != 0 && strlen(symbol) < 16 && LP_coinfind(symbol) == 0 && (port= juint(item,"rpcport")) != 0 ) { if ( (txfee= j64bits(item,"txfee")) == 0 ) @@ -244,9 +245,11 @@ struct iguana_info *LP_coincreate(cJSON *item) p2shtype = 85; if ( (wiftype= juint(item,"wiftype")) == 0 ) wiftype = 188; - if ( (name= jstr(item,"name")) == 0 ) + if ( (assetname= jstr(item,"asset")) != 0 ) + name = assetname; + else if ( (name= jstr(item,"name")) == 0 ) name = symbol; - LP_coininit(&cdata,symbol,name,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); + LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); return(LP_coinadd(&cdata)); } return(0); From c17d9cdd84015858813dfc4082275407bdec16d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:00:46 +0300 Subject: [PATCH 1185/2705] Test --- iguana/exchanges/LP_coins.c | 1 + iguana/exchanges/client | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 4d247cfb8..5de4359b2 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -213,6 +213,7 @@ struct iguana_info *LP_coinfind(char *symbol) { txfee = 50000; estimatedrate = 300; + pubtype = 0; p2shtype = 5; wiftype = 128; name = "bitcoin"; diff --git a/iguana/exchanges/client b/iguana/exchanges/client index bbc9b9575..6eac12ef1 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"name\":\"komodo/REVS", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"name\":\"komodo/JUMBLR\", \"rpcport\":15106}], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From db895dff124d2ce11d2cabfb74a8122dc1c7c00f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:02:09 +0300 Subject: [PATCH 1186/2705] Test --- iguana/exchanges/client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 6eac12ef1..80b5905f7 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From 0d48cb8b5e8ecf2abfbb04a68a87bc36e2807719 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:04:16 +0300 Subject: [PATCH 1187/2705] Test --- iguana/exchanges/client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 80b5905f7..a71a174c7 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,2 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From 4d52639ca597f92e7fe42e95dbb6ba5c779e144b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:06:23 +0300 Subject: [PATCH 1188/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 5b9664c1c..c31a3fb64 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -475,10 +475,10 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphrase,int32_t amclient) { int32_t i; - for (i=0; i Date: Wed, 7 Jun 2017 08:07:58 +0300 Subject: [PATCH 1189/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- iguana/exchanges/mm.c | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index c31a3fb64..4f7dc7eb9 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -477,7 +477,7 @@ void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphr int32_t i; for (i=0; icoin,"REVS") == 0 && (matchjson= LP_autotrade(utxo,"KMD",0.)) != 0 ) - printf("bestprice (%s)\n",jprint(matchjson,1)); - } - } - sleep(1000); - }*/ while ( 1 ) sleep(1); profitmargin = jdouble(retjson,"profitmargin"); From 53e4263e03ae9fb635b463c12fcca7f492892418 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:10:05 +0300 Subject: [PATCH 1190/2705] Test --- iguana/exchanges/client | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index a71a174c7..9b10b48a7 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,2 +1,7 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; +git pull; + cd ..; +./m_mm; +#./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & + ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From 8ba76912c5d6dfd271e6e9802db85bbf17687f16 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:27:52 +0300 Subject: [PATCH 1191/2705] Test --- iguana/exchanges/LP_coins.c | 22 ++++++++++++++++------ iguana/exchanges/LP_commands.c | 2 ++ iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_utxos.c | 2 +- iguana/exchanges/client | 3 +-- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 5de4359b2..2a8d4207a 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -145,11 +145,17 @@ cJSON *LP_coinjson(struct iguana_info *coin) { cJSON *item = cJSON_CreateObject(); jaddstr(item,"coin",coin->symbol); + if ( coin->inactive != 0 ) + jaddstr(item,"status","inactive"); + if ( coin->isPoS != 0 ) + jaddstr(item,"type","PoS"); jaddstr(item,"smartaddress",coin->smartaddr); jaddstr(item,"rpc",coin->serverport); jaddnum(item,"pubtype",coin->pubtype); jaddnum(item,"p2shtype",coin->p2shtype); jaddnum(item,"wiftype",coin->wiftype); + jaddnum(item,"estimatedrate",coin->estimatedrate); + jaddnum(item,"txfee",coin->txfee); return(item); } @@ -162,11 +168,12 @@ cJSON *LP_coinsjson() return(array); } -void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain) +void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain) { memset(coin,0,sizeof(*coin)); safecopy(coin->symbol,symbol,sizeof(coin->symbol)); sprintf(coin->serverport,"127.0.0.1:%u",port); + coin->isPoS = isPoS; coin->longestchain = longestchain; coin->txfee = txfee; coin->estimatedrate = estimatedrate; @@ -198,11 +205,12 @@ struct iguana_info *LP_coinsearch(char *symbol) struct iguana_info *LP_coinfind(char *symbol) { - struct iguana_info *coin,cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*assetname; + struct iguana_info *coin,cdata; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*assetname; if ( (coin= LP_coinsearch(symbol)) != 0 ) return(coin); if ( (port= LP_rpcport(symbol)) == 0 ) return(0); + isPoS = 0; txfee = 10000; estimatedrate = 20; pubtype = 60; @@ -225,7 +233,7 @@ struct iguana_info *LP_coinfind(char *symbol) name = symbol; assetname = symbol; } - LP_coininit(&cdata,symbol,name,assetname,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); + LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); return(LP_coinadd(&cdata)); } @@ -233,9 +241,10 @@ struct iguana_info *LP_coinfind(char *symbol) struct iguana_info *LP_coincreate(cJSON *item) { - struct iguana_info cdata; int32_t longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*symbol,*assetname; + struct iguana_info cdata,*coin; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*symbol,*assetname; if ( (symbol= jstr(item,"coin")) != 0 && symbol[0] != 0 && strlen(symbol) < 16 && LP_coinfind(symbol) == 0 && (port= juint(item,"rpcport")) != 0 ) { + isPoS = jint(item,"isPoS"); if ( (txfee= j64bits(item,"txfee")) == 0 ) txfee = 10000; if ( (estimatedrate= jdouble(item,"estimatedrate")) == 0. ) @@ -250,8 +259,9 @@ struct iguana_info *LP_coincreate(cJSON *item) name = assetname; else if ( (name= jstr(item,"name")) == 0 ) name = symbol; - LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); - return(LP_coinadd(&cdata)); + LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); + if ( (coin= LP_coinadd(&cdata)) != 0 ) + coin->inactive = jint(item,"inactive"); } return(0); } diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 366ab2556..7d873c0c4 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -314,6 +314,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port retstr = LP_connected(argjson); else if ( strcmp(method,"checktxid") == 0 ) retstr = LP_spentcheck(argjson); + else if ( strcmp(method,"getcoins") == 0 ) + retstr = jprint(LP_coinsjson(),1); else if ( strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"orderbook") == 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 9b194a908..e418c6899 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -140,7 +140,7 @@ struct basilisk_swapinfo struct iguana_info { uint64_t txfee; double estimatedrate; - int32_t longestchain; uint32_t counter; + int32_t longestchain; uint32_t counter,inactive; uint8_t pubtype,p2shtype,isPoS,wiftype; char symbol[16],smartaddr[64],userpass[1024],serverport[128]; }; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 4f7dc7eb9..e0847f382 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -411,7 +411,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); - if ( (array= LP_listunspent(symbol,coin->smartaddr)) != 0 ) + if ( coin->inactive == 0 && (array= LP_listunspent(symbol,coin->smartaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 9b10b48a7..52a5fe77f 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -3,5 +3,4 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; -#./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & - ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {\"coin\":\"LTC\", \"inactive\":1, \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From 52dbeeb431ed7103445d68f1f1932d1e205c0995 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:32:03 +0300 Subject: [PATCH 1192/2705] Test --- iguana/exchanges/LP_commands.c | 14 +++++++++++++- iguana/exchanges/LP_utxos.c | 2 +- iguana/exchanges/disable | 2 ++ iguana/exchanges/enable | 2 ++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100755 iguana/exchanges/disable create mode 100755 iguana/exchanges/enable diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7d873c0c4..c5cb13164 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -204,7 +204,7 @@ char *LP_connected(cJSON *argjson) char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; cJSON *retjson; + char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) @@ -261,6 +261,18 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); return(LP_inventory(coin)); } + else if ( strcmp(method,"enable") == 0 ) + { + if ( (ptr= LP_coinsearch(coin)) != 0 ) + ptr->inactive = 0; + return(jprint(LP_coins(),1)); + } + else if ( strcmp(method,"disable") == 0 ) + { + if ( (ptr= LP_coinsearch(coin)) != 0 ) + ptr->inactive = (uint32_t)time(NULL); + return(jprint(LP_coins(),1)); + } else if ( IAMCLIENT != 0 && (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) { bits256 txid; int32_t vout; struct LP_utxoinfo *utxo; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e0847f382..9a8be6592 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -477,7 +477,7 @@ void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphr int32_t i; for (i=0; i Date: Wed, 7 Jun 2017 08:36:49 +0300 Subject: [PATCH 1193/2705] Test --- iguana/exchanges/client | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 52a5fe77f..1d2617c02 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -3,4 +3,7 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; -./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\", \"asset\":\"REVS\", \"rpcport\":10196}, {\"coin\":\"JUMBLR\", \"asset\":\"JUMBLR\", \"rpcport\":15106}, {\"coin\":\"LTC\", \"inactive\":1, \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"asset\":\"JUMBLR\",\"rpcport\":15106},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400}, {\"coin\":\"LTC\", \"inactive\":1, \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & + +"{\"client\":1,\"coins\":[{\"coin\":\"BTC\",\"asset\":\"BTC\",\"rpcport\":8333},{\"coin\":\"BTCD\",\"asset\":\"BTCD\",\"rpcport\":14632},{\"coin\":\"LTC\",\"asset\":\"LTC\",\"rpcport\":9332},{\"coin\":\"DOGE\",\"asset\":\"DOGE\",\"rpcport\":22555},{\"coin\":\"DGB\",\"asset\":\"DGB\",\"rpcport\":14022},{\"coin\":\"MZC\",\"asset\":\"MZC\",\"rpcport\":12832},{\"coin\":\"SYS\",\"asset\":\"SYS\",\"rpcport\":8370},{\"coin\":\"UNO\",\"asset\":\"UNO\",\"rpcport\":65535},{\"coin\":\"ZET\",\"asset\":\"ZET\",\"rpcport\":17335},{\"coin\":\"KMD\",\"asset\":\"KMD\",\"rpcport\":7771},{\"coin\":\"ZEC\",\"asset\":\"ZEC\",\"rpcport\":8232},{\"coin\":\"BTM\",\"asset\":\"BTM\",\"rpcport\":9266},{\"coin\":\"CARB\",\"asset\":\"CARB\",\"rpcport\":9351},{\"coin\":\"ANC\",\"asset\":\"ANC\",\"rpcport\":28332},{\"coin\":\"FRK\",\"asset\":\"FRK\",\"rpcport\":7913},{\"coin\":\"GAME\",\"asset\":\"GAME\",\"rpcport\":40001},{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"asset\":\"JUMBLR\",\"rpcport\":10789},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400},{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" +Add Comment From 929a6677dcf0010a42c241d1f6bd28c62556faf9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:37:37 +0300 Subject: [PATCH 1194/2705] Test --- iguana/exchanges/client | 2 -- 1 file changed, 2 deletions(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 1d2617c02..7acd649d1 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -5,5 +5,3 @@ git pull; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"asset\":\"JUMBLR\",\"rpcport\":15106},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400}, {\"coin\":\"LTC\", \"inactive\":1, \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & -"{\"client\":1,\"coins\":[{\"coin\":\"BTC\",\"asset\":\"BTC\",\"rpcport\":8333},{\"coin\":\"BTCD\",\"asset\":\"BTCD\",\"rpcport\":14632},{\"coin\":\"LTC\",\"asset\":\"LTC\",\"rpcport\":9332},{\"coin\":\"DOGE\",\"asset\":\"DOGE\",\"rpcport\":22555},{\"coin\":\"DGB\",\"asset\":\"DGB\",\"rpcport\":14022},{\"coin\":\"MZC\",\"asset\":\"MZC\",\"rpcport\":12832},{\"coin\":\"SYS\",\"asset\":\"SYS\",\"rpcport\":8370},{\"coin\":\"UNO\",\"asset\":\"UNO\",\"rpcport\":65535},{\"coin\":\"ZET\",\"asset\":\"ZET\",\"rpcport\":17335},{\"coin\":\"KMD\",\"asset\":\"KMD\",\"rpcport\":7771},{\"coin\":\"ZEC\",\"asset\":\"ZEC\",\"rpcport\":8232},{\"coin\":\"BTM\",\"asset\":\"BTM\",\"rpcport\":9266},{\"coin\":\"CARB\",\"asset\":\"CARB\",\"rpcport\":9351},{\"coin\":\"ANC\",\"asset\":\"ANC\",\"rpcport\":28332},{\"coin\":\"FRK\",\"asset\":\"FRK\",\"rpcport\":7913},{\"coin\":\"GAME\",\"asset\":\"GAME\",\"rpcport\":40001},{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"asset\":\"JUMBLR\",\"rpcport\":10789},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400},{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" -Add Comment From 9493e3c850dc15239a1d3706d42dfb6c0bd612bf Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:38:37 +0300 Subject: [PATCH 1195/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c5cb13164..df00b26a9 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -265,13 +265,13 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { if ( (ptr= LP_coinsearch(coin)) != 0 ) ptr->inactive = 0; - return(jprint(LP_coins(),1)); + return(jprint(LP_coinsjson(),1)); } else if ( strcmp(method,"disable") == 0 ) { if ( (ptr= LP_coinsearch(coin)) != 0 ) ptr->inactive = (uint32_t)time(NULL); - return(jprint(LP_coins(),1)); + return(jprint(LP_coinsjson(),1)); } else if ( IAMCLIENT != 0 && (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) { From f50d0218e238bcf98d832791120eef11fc5ed8b0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:44:04 +0300 Subject: [PATCH 1196/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- iguana/exchanges/client | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 2a8d4207a..381d4f278 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -261,7 +261,7 @@ struct iguana_info *LP_coincreate(cJSON *item) name = symbol; LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); if ( (coin= LP_coinadd(&cdata)) != 0 ) - coin->inactive = jint(item,"inactive"); + coin->inactive = !jint(item,"active"); } return(0); } diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 7acd649d1..97f8f0952 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -3,5 +3,5 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; -./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"asset\":\"JUMBLR\",\"rpcport\":15106},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400}, {\"coin\":\"LTC\", \"inactive\":1, \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From f383b24d2558dd5f395e06c64dc78c2dda030305 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:45:31 +0300 Subject: [PATCH 1197/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 9a8be6592..738392bd1 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -406,7 +406,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); } printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); - if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) + if ( coin->inactive == 0 && (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); From c1c95667ec11af4077db0d54c982a00f118f8eec Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:46:25 +0300 Subject: [PATCH 1198/2705] Test --- iguana/exchanges/LP_utxos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 738392bd1..0e1832b08 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -406,7 +406,8 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); } printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); - if ( coin->inactive == 0 && (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) + if ( //coin->inactive == 0 && + (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); From 5a2a61681d397f1e2201997cc5412b3b42bf4d49 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:49:05 +0300 Subject: [PATCH 1199/2705] Test --- iguana/exchanges/getcoins | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 iguana/exchanges/getcoins diff --git a/iguana/exchanges/getcoins b/iguana/exchanges/getcoins new file mode 100755 index 000000000..132e9a9c0 --- /dev/null +++ b/iguana/exchanges/getcoins @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"getcoins\"}" From fafbecda0e6e413bedfed5359f696a7bed8a9081 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:50:34 +0300 Subject: [PATCH 1200/2705] Test --- iguana/exchanges/LP_coins.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 381d4f278..45f77b583 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -147,6 +147,7 @@ cJSON *LP_coinjson(struct iguana_info *coin) jaddstr(item,"coin",coin->symbol); if ( coin->inactive != 0 ) jaddstr(item,"status","inactive"); + else jaddstr(item,"status","active"); if ( coin->isPoS != 0 ) jaddstr(item,"type","PoS"); jaddstr(item,"smartaddress",coin->smartaddr); From 7804eda547f09ba050f430af5131d92f5b6eeae3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:56:02 +0300 Subject: [PATCH 1201/2705] Test --- iguana/exchanges/client | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 97f8f0952..a6b3ae853 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -3,5 +3,18 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; -./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400}, +{\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, +{\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, +{\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, +{\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, +{\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, +{\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, +{\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, +{\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, +{\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, +{\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, +{\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, +{\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, +{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From 46d8b7c62bad2fdd8fa64e2d5e003de20fc16391 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 08:59:23 +0300 Subject: [PATCH 1202/2705] Test --- iguana/exchanges/LP_coins.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 45f77b583..71cb13546 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -128,7 +128,11 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) userpass[0] = 0; sprintf(confname,"%s.conf",confroot); #ifdef __APPLE__ + int32_t len; confname[0] = toupper(confname[0]); + len = (int32_t)strlen(confname); + if ( strcmp(&confname[len-4],"coin") == 0 ) + confname[len - 4] = 'C'; #endif LP_statefname(fname,symbol,assetname,confname); if ( (fp= fopen(fname,"rb")) != 0 ) From 69e2e09480335945f086cf249b19f1eb3af96b7d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 09:02:43 +0300 Subject: [PATCH 1203/2705] Test --- iguana/exchanges/client | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index a6b3ae853..2eb925910 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -3,7 +3,7 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; -./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":11667},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":10074},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":9503},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":11222},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":10420},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":8010},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":14104},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":10151},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":15524},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":11676},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":13097},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":8400}, +./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, @@ -16,5 +16,7 @@ git pull; {\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, -{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":15432},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":8299},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From 96c745cc57ba4de41df9da3868c1e47a00529a1d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 09:06:22 +0300 Subject: [PATCH 1204/2705] Test --- iguana/exchanges/client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 2eb925910..ec3daecce 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -17,6 +17,6 @@ git pull; {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":15432},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":8299},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":8299},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} ], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From da94c86759a9159580af8f6bc439261f2bcf09bb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 09:18:06 +0300 Subject: [PATCH 1205/2705] Test --- iguana/exchanges/LP_coins.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 71cb13546..18af9fb47 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -45,7 +45,7 @@ char *parse_conf_line(char *line,char *field) return(clonestr(line)); } -void LP_userpassfp(char *username,char *password,FILE *fp) +void LP_userpassfp(char *symbol,char *username,char *password,FILE *fp) { char *rpcuser,*rpcpassword,*str,line[8192]; rpcuser = rpcpassword = 0; @@ -65,7 +65,7 @@ void LP_userpassfp(char *username,char *password,FILE *fp) strcpy(username,rpcuser); strcpy(password,rpcpassword); } - //printf("rpcuser.(%s) rpcpassword.(%s) KMDUSERPASS.(%s) %u\n",rpcuser,rpcpassword,KMDUSERPASS,port); + printf("%s rpcuser.(%s) rpcpassword.(%s) %u\n",symbol,rpcuser,rpcpassword,port); if ( rpcuser != 0 ) free(rpcuser); if ( rpcpassword != 0 ) @@ -137,7 +137,7 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) LP_statefname(fname,symbol,assetname,confname); if ( (fp= fopen(fname,"rb")) != 0 ) { - LP_userpassfp(username,password,fp); + LP_userpassfp(symbol,username,password,fp); sprintf(userpass,"%s:%s",username,password); fclose(fp); return((int32_t)strlen(userpass)); From 5db23bdd1647e287798b1849892a157288490f4c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 09:20:37 +0300 Subject: [PATCH 1206/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 18af9fb47..f423d20bd 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -141,7 +141,7 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) sprintf(userpass,"%s:%s",username,password); fclose(fp); return((int32_t)strlen(userpass)); - } + } else printf("cant open.(%s)\n",fname); return(-1); } From c75a7e343068b0354cb4e62b508d87ddb5183bc3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 09:25:07 +0300 Subject: [PATCH 1207/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index f423d20bd..ee53239b8 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -65,7 +65,7 @@ void LP_userpassfp(char *symbol,char *username,char *password,FILE *fp) strcpy(username,rpcuser); strcpy(password,rpcpassword); } - printf("%s rpcuser.(%s) rpcpassword.(%s) %u\n",symbol,rpcuser,rpcpassword,port); + printf("%s rpcuser.(%s) rpcpassword.(%s)\n",symbol,rpcuser,rpcpassword); if ( rpcuser != 0 ) free(rpcuser); if ( rpcpassword != 0 ) From 75e4e4d5017c18e6801466568c12efe114ae5c79 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 09:35:11 +0300 Subject: [PATCH 1208/2705] Test --- iguana/exchanges/LP_utxos.c | 3 +-- iguana/exchanges/client | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0e1832b08..738392bd1 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -406,8 +406,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); } printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); - if ( //coin->inactive == 0 && - (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) + if ( coin->inactive == 0 && (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) printf("importprivkey -> (%s)\n",jprint(retjson,1)); } bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); diff --git a/iguana/exchanges/client b/iguana/exchanges/client index ec3daecce..0f89a0f95 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -17,6 +17,6 @@ git pull; {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":8299},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} ], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & From c29f998292dfe3705f602bc410ad4cfbc61b7cdd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 09:49:03 +0300 Subject: [PATCH 1209/2705] Test --- basilisk/jumblr.c | 1 + iguana/exchanges/LP_coins.c | 10 ++++++++++ iguana/exchanges/LP_commands.c | 20 ++++++++++++++------ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index e7144fb57..618ce346c 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -648,6 +648,7 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 fee = JUMBLR_INCR * JUMBLR_FEE; OS_randombytes(&r,sizeof(r)); //r = 0; + // randomize size chosen and order of chunks if ( strcmp(coin->symbol,"KMD") == 0 && coin->FULLNODE < 0 ) { //printf("JUMBLR selector.%d modval.%d r.%d\n",selector,modval,r&7); diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index ee53239b8..e2951dad5 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -208,6 +208,16 @@ struct iguana_info *LP_coinsearch(char *symbol) return(0); } +int32_t LP_isdisabled(char *base,char *rel) +{ + struct iguana_info *coin; + if ( base != 0 && (coin= LP_coinsearch(base)) != 0 && coin->inactive != 0 ) + return(1); + else if ( rel != 0 && (coin= LP_coinsearch(rel)) != 0 && coin->inactive != 0 ) + return(1); + else return(0); +} + struct iguana_info *LP_coinfind(char *symbol) { struct iguana_info *coin,cdata; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*assetname; diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index df00b26a9..89905abc4 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -222,6 +222,8 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) { //char str[65]; + if ( LP_isdisabled(base,rel) != 0 ) + return(clonestr("{\"error\":\"at least one of coins disabled\"}")); if ( strcmp(method,"setprice") == 0 ) { if ( LP_mypriceset(base,rel,jdouble(argjson,"price")) < 0 ) @@ -256,12 +258,7 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port } else if ( (coin= jstr(argjson,"coin")) != 0 ) { - if ( strcmp(method,"inventory") == 0 ) - { - LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); - return(LP_inventory(coin)); - } - else if ( strcmp(method,"enable") == 0 ) + if ( strcmp(method,"enable") == 0 ) { if ( (ptr= LP_coinsearch(coin)) != 0 ) ptr->inactive = 0; @@ -273,6 +270,13 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port ptr->inactive = (uint32_t)time(NULL); return(jprint(LP_coinsjson(),1)); } + if ( LP_isdisabled(coin,0) != 0 ) + return(clonestr("{\"error\":\"coin is disabled\"}")); + if ( strcmp(method,"inventory") == 0 ) + { + LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); + return(LP_inventory(coin)); + } else if ( IAMCLIENT != 0 && (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) { bits256 txid; int32_t vout; struct LP_utxoinfo *utxo; @@ -297,6 +301,10 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port else return(basilisk_swaplist()); } } + if ( LP_isdisabled(jstr(argjson,"base"),jstr(argjson,"base")) != 0 ) + return(clonestr("{\"error\":\"at least one of coins disabled\"}")); + if ( LP_isdisabled(jstr(argjson,"coin"),0) != 0 ) + return(clonestr("{\"error\":\"coin is disabled\"}")); amclient = (LP_mypeer == 0); if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { From 8b2a1cfaeec8c332fe16137a35a14d497a33337f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 10:08:02 +0300 Subject: [PATCH 1210/2705] Test --- basilisk/jumblr.c | 13 ++++++++----- iguana/exchanges/LP_prices.c | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 618ce346c..2749560ee 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -642,7 +642,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_inf void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval) { //static uint32_t lasttime; - char BTCaddr[64],KMDaddr[64],*zaddr,*retstr; bits256 privkey; uint64_t amount=0,total=0; double fee; struct jumblr_item *ptr,*tmp; uint8_t r; + char BTCaddr[64],KMDaddr[64],*zaddr,*retstr; bits256 privkey; uint64_t amount=0,total=0; double fee; struct jumblr_item *ptr,*tmp; uint8_t r,s; if ( myinfo->IAMNOTARY != 0 ) return; fee = JUMBLR_INCR * JUMBLR_FEE; @@ -651,8 +651,9 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 // randomize size chosen and order of chunks if ( strcmp(coin->symbol,"KMD") == 0 && coin->FULLNODE < 0 ) { + s = (selector + (r>>1)) % 3; //printf("JUMBLR selector.%d modval.%d r.%d\n",selector,modval,r&7); - switch ( selector ) + switch ( s ) { case 0: // public -> z, need to importprivkey jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); @@ -662,12 +663,14 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 { if ( (zaddr= jumblr_zgetnewaddress(myinfo,coin)) != 0 ) { + amount = 0; if ( total >= SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE) ) amount = SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*100 + 3*JUMBLR_TXFEE); - else if ( total >= SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE) ) + if ( (r & 2) != 0 && total >= SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE) ) amount = SATOSHIDEN * ((JUMBLR_INCR + 3*fee)*10 + 3*JUMBLR_TXFEE); - else amount = SATOSHIDEN * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); - if ( (retstr= jumblr_sendt_to_z(myinfo,coin,KMDaddr,zaddr,dstr(amount))) != 0 ) + if ( (r & 4) != 0 ) + amount = SATOSHIDEN * ((JUMBLR_INCR + 3*fee) + 3*JUMBLR_TXFEE); + if ( amount > 0 && (retstr= jumblr_sendt_to_z(myinfo,coin,KMDaddr,zaddr,dstr(amount))) != 0 ) { printf("sendt_to_z.(%s)\n",retstr); free(retstr); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index edd9f760b..8266bc6e2 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -380,7 +380,7 @@ char *LP_pricestr(char *base,char *rel) } else return(clonestr("{\"error\":\"cant find baserel pair\"}")); } - +// bids disappear? From 54e625655b315691eb8dd608ea77feb559bf15e4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 10:49:26 +0300 Subject: [PATCH 1211/2705] Test --- iguana/exchanges/LP_commands.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 89905abc4..12ec548f2 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -207,6 +207,26 @@ char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); + else if ( strcmp(method,"help") == 0 ) + return(clonestr("{\"result\":\" \ +available localhost RPC commands:\n \ +setprice(base, rel, price)\n\ +myprice(base, rel)\n\ +enable(coin)\n\ +disable(coin)\n\ +inventory(coin)\n\ +candidates(txid, vout)\n\ +autotrade(txid, vout, maxprice)\n\ +swapstatus()\n\ +swapstatus(requestid, quoteid)\n\ +public API:\n \ +getcoins()\n\ +getpeers()\n\ +getutxos()\n\ +getutxos(coin, lastn)\n\ +orderbook(base, rel)\n\ +getprice(base, rel)\n\ +\"}")); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) { if ( USERPASS_COUNTER == 0 ) From 9aca9cedc4b6b520fe928173628ea7c39991adfe Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 21:41:31 +0300 Subject: [PATCH 1212/2705] Test --- iguana/exchanges/LP_rpc.c | 6 ++++++ iguana/exchanges/LP_transaction.c | 17 ++++++++++++++++- iguana/exchanges/loop | 7 +++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 iguana/exchanges/loop diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 8353f2d23..31e1e0255 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -88,6 +88,12 @@ cJSON *LP_getinfo(char *symbol) return(bitcoin_json(coin,"getinfo","[]")); } +cJSON *LP_getmempool(char *symbol) +{ + struct iguana_info *coin = LP_coinfind(symbol); + return(bitcoin_json(coin,"getrawmempool","[]")); +} + cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout) { char buf[128],str[65]; struct iguana_info *coin = LP_coinfind(symbol); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index b976dbb71..5c0c05dfd 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -193,12 +193,27 @@ int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) { int32_t numconfirms = 100; #ifndef BASILISK_DISABLEWAITTX - cJSON *txobj; + cJSON *txobj,*array; int32_t i,n; + numconfirms = -1; if ( (txobj= LP_gettx(rawtx->coin->symbol,rawtx->I.signedtxid)) != 0 ) { numconfirms = jint(txobj,"confirmations"); free_json(txobj); } + else if ( (array= LP_getmempool(rawtx->coin->symbol)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; iI.signedtxid,jbits256i(array,i)) == 0 ) + { + numconfirms = 0; + printf("found tx in mempool slot.%d\n",i); + break; + } + } + free_json(array); + } #endif return(numconfirms); } diff --git a/iguana/exchanges/loop b/iguana/exchanges/loop new file mode 100644 index 000000000..8703827ba --- /dev/null +++ b/iguana/exchanges/loop @@ -0,0 +1,7 @@ +while true +do +source userpass +#curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"setprice\",\"base\":\"REVS\",\"rel\":\"KMD\",\"price\":1.234}" +./s +sleep 3600 +done From aea6e29a02093767979ef60a658ea07addceaa11 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 21:44:19 +0300 Subject: [PATCH 1213/2705] Test --- iguana/exchanges/loop | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 iguana/exchanges/loop diff --git a/iguana/exchanges/loop b/iguana/exchanges/loop old mode 100644 new mode 100755 From e83b177e192b167c489350831bc9f39f8b3eb3a6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 21:47:44 +0300 Subject: [PATCH 1214/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 ++++++-- iguana/exchanges/LP_prices.c | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1e0aea7db..67fb646c0 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -81,7 +81,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin,cJSON *coins) { //static uint16_t tmpport; - char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson; + char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson,*item; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); @@ -116,7 +116,11 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( (n= cJSON_GetArraySize(coins)) > 0 ) { for (i=0; i= sizeof(LP_priceinfos)/sizeof(*LP_priceinfos) ) { printf("cant add any more priceinfos\n"); From 157c1a1ec02733a8a51a81b5c6157e8957dfbe10 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 21:50:02 +0300 Subject: [PATCH 1215/2705] Test --- iguana/exchanges/run | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/run b/iguana/exchanges/run index ccc62231a..deb5f6b77 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -1,2 +1,17 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\"}" & +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, +{\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, +{\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, +{\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, +{\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, +{\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, +{\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, +{\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, +{\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, +{\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, +{\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, +{\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, +{\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, +{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +]}" & From 6ade8b6618c6d93e9884337a281278c200a9a4e3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 22:04:31 +0300 Subject: [PATCH 1216/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 67fb646c0..059d07cf5 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -123,13 +123,16 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i } } LP_privkey_updates(mypeer,pubsock,passphrase,amclient); + if ( (retstr= basilisk_swaplist()) != 0 ) + free(retstr); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( strcmp(peer->ipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) + { + printf("query utxo from %s\n",peer->ipaddr); LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); + } } - if ( (retstr= basilisk_swaplist()) != 0 ) - free(retstr); if ( amclient != 0 ) { while ( 1 ) From e6336ef2ef315ba55ed82595811819e80bb45824 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 22:08:41 +0300 Subject: [PATCH 1217/2705] Test --- iguana/exchanges/LP_utxos.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 738392bd1..8d5c813da 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -281,7 +281,12 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs //printf("parse.(%s)\n",jprint(item,0)); utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),j64bits(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),j64bits(item,"value2"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); if ( utxo != 0 ) + { + struct LP_quoteinfo Q; + memset(&Q,0,sizeof(Q)); utxo->lasttime = now; + LP_query("price",&Q,utxo->ipaddr,utxo->port,utxo->coin,"KMD",utxo->mypub); + } } } // else printf("skip.(%s)\n",jprint(item,0)); } From d42ef22396fbc465bb64268c54d98585d72bd412 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 22:20:51 +0300 Subject: [PATCH 1218/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_prices.c | 2 ++ iguana/exchanges/LP_quotes.c | 30 +++++++++++++++++++++++++++--- iguana/exchanges/LP_utxos.c | 3 --- 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 12ec548f2..6e2410209 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -309,7 +309,7 @@ getprice(base, rel)\n\ if ( (utxo= LP_utxofind(txid,vout)) == 0 ) return(clonestr("{\"error\":\"txid/vout not found\"}")); if ( strcmp(method,"candidates") == 0 ) - return(jprint(LP_tradecandidates(utxo,coin),1)); + return(jprint(LP_tradecandidates(coin),1)); else return(jprint(LP_autotrade(utxo,coin,jdouble(argjson,"maxprice")),1)); } } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index e418c6899..b75202a12 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -205,5 +205,6 @@ char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *meth uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend); double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub); int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); +void LP_quotesinit(char *base,char *rel); #endif diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 31a558aab..92134e254 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -356,6 +356,8 @@ char *LP_orderbook(char *base,char *rel) jaddstr(retjson,"base",base); jaddstr(retjson,"rel",rel); jaddnum(retjson,"timestamp",now); + if ( numbids == 0 && numasks == 0 ) + LP_quotesinit(base,rel); return(jprint(retjson,1)); } diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index de9407ea8..86a8a7966 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -196,14 +196,14 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) return(-1); } -cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) +cJSON *LP_tradecandidates(char *base) { struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; double price; - if ( (price= LP_price(base,myutxo->coin)) == .0 ) + /*if ( (price= LP_price(base,myutxo->coin)) == .0 ) { printf("no LP_price (%s -> %s)\n",base,myutxo->coin); return(0); - } + }*/ totaladded = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -248,6 +248,30 @@ cJSON *LP_tradecandidates(struct LP_utxoinfo *myutxo,char *base) return(retarray); } +void LP_quotesinit(char *base,char *rel) +{ + cJSON *array,*item; struct LP_quoteinfo Q; bits256 zero; int32_t i,n,iter; + memset(&zero,0,sizeof(zero)); + for (iter=0; iter<2; iter++) + if ( (array= LP_tradecandidates(iter == 0 ? base : rel)) != 0 ) + { + //printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + memset(&Q,0,sizeof(Q)); + for (i=0; ilasttime = now; - LP_query("price",&Q,utxo->ipaddr,utxo->port,utxo->coin,"KMD",utxo->mypub); } } } // else printf("skip.(%s)\n",jprint(item,0)); From 5edf12dad25c0d24e9a6812fcd40ec7f44f7d463 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 22:21:35 +0300 Subject: [PATCH 1219/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 86a8a7966..131d2b5ea 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -279,7 +279,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) bestprice = 0.; if ( maxprice == 0. ) maxprice = LP_price(base,myutxo->coin) / 0.975; - if ( (array= LP_tradecandidates(myutxo,base)) != 0 ) + if ( (array= LP_tradecandidates(base)) != 0 ) { //printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); if ( (n= cJSON_GetArraySize(array)) > 0 ) From eae10cc2a05a8c2166b0e982c9ddbae8b5036b7f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 22:22:42 +0300 Subject: [PATCH 1220/2705] Test --- iguana/exchanges/LP_prices.c | 4 ++-- iguana/exchanges/LP_quotes.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 92134e254..d9426bcc1 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -356,8 +356,8 @@ char *LP_orderbook(char *base,char *rel) jaddstr(retjson,"base",base); jaddstr(retjson,"rel",rel); jaddnum(retjson,"timestamp",now); - if ( numbids == 0 && numasks == 0 ) - LP_quotesinit(base,rel); + //if ( numbids == 0 && numasks == 0 ) + // LP_quotesinit(base,rel); return(jprint(retjson,1)); } diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 131d2b5ea..9f60580bb 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -198,7 +198,7 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) cJSON *LP_tradecandidates(char *base) { - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; double price; + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; /*if ( (price= LP_price(base,myutxo->coin)) == .0 ) { printf("no LP_price (%s -> %s)\n",base,myutxo->coin); From cd24a9f73467d6473bae11ae59d592d5799240ae Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 22:28:31 +0300 Subject: [PATCH 1221/2705] Test --- iguana/exchanges/LP_quotes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 9f60580bb..4194b6966 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -198,7 +198,7 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) cJSON *LP_tradecandidates(char *base) { - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; /*if ( (price= LP_price(base,myutxo->coin)) == .0 ) { printf("no LP_price (%s -> %s)\n",base,myutxo->coin); @@ -210,7 +210,7 @@ cJSON *LP_tradecandidates(char *base) n = added = 0; if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { - //printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); + printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); if ( (array= cJSON_Parse(utxostr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) @@ -281,7 +281,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) maxprice = LP_price(base,myutxo->coin) / 0.975; if ( (array= LP_tradecandidates(base)) != 0 ) { - //printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); + printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { memset(prices,0,sizeof(prices)); From da9190acb729de01ba729ac910bdb66db3444f70 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 22:32:56 +0300 Subject: [PATCH 1222/2705] Test --- iguana/exchanges/LP_quotes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 4194b6966..943b103e2 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -207,6 +207,7 @@ cJSON *LP_tradecandidates(char *base) totaladded = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { + printf("%s:%u %s\n",peer->ipaddr,peer->port,base); n = added = 0; if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) { From a435a695da5b725ab59264d1849426d0b868a210 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 7 Jun 2017 22:36:00 +0300 Subject: [PATCH 1223/2705] Test --- iguana/exchanges/LP_peers.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 091943d4f..40e41fc37 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -52,6 +52,8 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 uint32_t ipbits; int32_t pushsock,subsock,timeout,enabled; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; if ( strcmp(ipaddr,"173.208.149.42") == 0 ) return(0); + if ( strncmp(ipaddr,"5.9.253",strlen("5.9.253")) != 0 ) + return(0); ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) From a3537ffb5bfb2133d7a39886da11dbd00868ff23 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 8 Jun 2017 07:30:29 +0300 Subject: [PATCH 1224/2705] Randomize jumblr processing --- basilisk/jumblr.c | 80 ++++++++++++++++++++++++--------- iguana/exchanges/LP_nativeDEX.c | 4 ++ iguana/exchanges/LP_prices.c | 4 -- 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c index 2749560ee..9618a9421 100755 --- a/basilisk/jumblr.c +++ b/basilisk/jumblr.c @@ -642,7 +642,7 @@ void jumblr_utxoupdate(struct supernet_info *myinfo,char *dest,struct iguana_inf void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int32_t selector,int32_t modval) { //static uint32_t lasttime; - char BTCaddr[64],KMDaddr[64],*zaddr,*retstr; bits256 privkey; uint64_t amount=0,total=0; double fee; struct jumblr_item *ptr,*tmp; uint8_t r,s; + char BTCaddr[64],KMDaddr[64],*zaddr,*retstr; int32_t iter,counter,chosen_one,n; bits256 privkey; uint64_t amount=0,total=0; double fee; struct jumblr_item *ptr,*tmp; uint8_t r,s; if ( myinfo->IAMNOTARY != 0 ) return; fee = JUMBLR_INCR * JUMBLR_FEE; @@ -682,24 +682,44 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 break; case 1: // z -> z jumblr_opidsupdate(myinfo,coin); - HASH_ITER(hh,myinfo->jumblrs,ptr,tmp) + chosen_one = -1; + for (iter=counter=0; iter<2; iter++) { - if ( jumblr_addresstype(myinfo,coin,ptr->src) == 't' && jumblr_addresstype(myinfo,coin,ptr->dest) == 'z' ) + counter = n = 0; + HASH_ITER(hh,myinfo->jumblrs,ptr,tmp) { - if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN ) + if ( jumblr_addresstype(myinfo,coin,ptr->src) == 't' && jumblr_addresstype(myinfo,coin,ptr->dest) == 'z' ) { - if ( (zaddr= jumblr_zgetnewaddress(myinfo,coin)) != 0 ) + if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN ) { - if ( (retstr= jumblr_sendz_to_z(myinfo,coin,ptr->dest,zaddr,dstr(total))) != 0 ) + if ( iter == 1 && counter == chosen_one ) { - printf("sendz_to_z.(%s)\n",retstr); - free(retstr); + if ( (zaddr= jumblr_zgetnewaddress(myinfo,coin)) != 0 ) + { + if ( (retstr= jumblr_sendz_to_z(myinfo,coin,ptr->dest,zaddr,dstr(total))) != 0 ) + { + printf("n.%d counter.%d chosen_one.%d sendz_to_z.(%s)\n",n,counter,chosen_one,retstr); + free(retstr); + } + ptr->spent = (uint32_t)time(NULL); + free(zaddr); + break; + } } - ptr->spent = (uint32_t)time(NULL); - free(zaddr); - break; + counter++; } } + n++; + } + if ( counter == 0 ) + break; + if ( iter == 0 ) + { + OS_randombytes((uint8_t *)&chosen_one,sizeof(chosen_one)); + if ( chosen_one < 0 ) + chosen_one = -chosen_one; + chosen_one %= counter; + printf("jumblr z->z chosen_one.%d of %d, from %d\n",chosen_one,counter,n); } } break; @@ -707,21 +727,41 @@ void jumblr_iteration(struct supernet_info *myinfo,struct iguana_info *coin,int3 if ( myinfo->runsilent == 0 ) { jumblr_opidsupdate(myinfo,coin); - HASH_ITER(hh,myinfo->jumblrs,ptr,tmp) + chosen_one = -1; + for (iter=0; iter<2; iter++) { - if ( jumblr_addresstype(myinfo,coin,ptr->src) == 'z' && jumblr_addresstype(myinfo,coin,ptr->dest) == 'z' ) + counter = n = 0; + HASH_ITER(hh,myinfo->jumblrs,ptr,tmp) { - if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN ) + if ( jumblr_addresstype(myinfo,coin,ptr->src) == 'z' && jumblr_addresstype(myinfo,coin,ptr->dest) == 'z' ) { - privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); - if ( (retstr= jumblr_sendz_to_t(myinfo,coin,ptr->dest,KMDaddr,dstr(total))) != 0 ) + if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN ) { - printf("sendz_to_t.(%s)\n",retstr); - free(retstr); + if ( iter == 1 && n == chosen_one ) + { + privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); + if ( (retstr= jumblr_sendz_to_t(myinfo,coin,ptr->dest,KMDaddr,dstr(total))) != 0 ) + { + printf("sendz_to_t.(%s)\n",retstr); + free(retstr); + } + ptr->spent = (uint32_t)time(NULL); + break; + } + counter++; } - ptr->spent = (uint32_t)time(NULL); - break; } + n++; + } + if ( counter == 0 ) + break; + if ( iter == 0 ) + { + OS_randombytes((uint8_t *)&chosen_one,sizeof(chosen_one)); + if ( chosen_one < 0 ) + chosen_one = -chosen_one; + chosen_one %= counter; + printf("jumblr z->t chosen_one.%d of %d, from %d\n",chosen_one,counter,n); } } } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 059d07cf5..31cf337e8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -344,3 +344,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } +// splitfunds cant trade? +// timeout on bad peers + + diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index d9426bcc1..3122cd252 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -384,9 +384,5 @@ char *LP_pricestr(char *base,char *rel) } else return(clonestr("{\"error\":\"cant find baserel pair\"}")); } -// bids disappear? - - - From 8f36671b03276ed8800a0b1e0badf93bfbb51d77 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 8 Jun 2017 10:33:11 +0300 Subject: [PATCH 1225/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 ++ iguana/exchanges/client_osx | 22 ++++++++++++++++++++++ iguana/exchanges/run_osx | 17 +++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100755 iguana/exchanges/client_osx create mode 100755 iguana/exchanges/run_osx diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 31cf337e8..97458867e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -82,6 +82,8 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { //static uint16_t tmpport; char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson,*item; + if ( amclient != 0 ) + myport += amclient * 10; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); diff --git a/iguana/exchanges/client_osx b/iguana/exchanges/client_osx new file mode 100755 index 000000000..a46cbff64 --- /dev/null +++ b/iguana/exchanges/client_osx @@ -0,0 +1,22 @@ +source randval +pkill -15 marketmaker; +git pull; + cd ..; +./m_mm; +./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, +{\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, +{\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, +{\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, +{\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, +{\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, +{\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, +{\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, +{\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, +{\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, +{\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, +{\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, +{\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, +{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +], \"userhome\":\"/${HOME#"/"}/Library/Application\ Support\", \"passphrase\":\"$randval\"}" & + diff --git a/iguana/exchanges/run_osx b/iguana/exchanges/run_osx new file mode 100755 index 000000000..e39934a75 --- /dev/null +++ b/iguana/exchanges/run_osx @@ -0,0 +1,17 @@ +source randval +pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"profitmargin\":0.01,\"userhome\":\"/${HOME#"/"}/Library/Application\ Support\",\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, +{\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, +{\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, +{\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, +{\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, +{\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, +{\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, +{\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, +{\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, +{\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, +{\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, +{\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, +{\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, +{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +]}" & From dbd2fda204dd97e503a37c7e3529c4e096cc2f2e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 8 Jun 2017 10:36:24 +0300 Subject: [PATCH 1226/2705] Test --- iguana/exchanges/LP_peers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 40e41fc37..1cd4c9056 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -50,10 +50,10 @@ char *LP_peers() struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) { uint32_t ipbits; int32_t pushsock,subsock,timeout,enabled; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; - if ( strcmp(ipaddr,"173.208.149.42") == 0 ) + /*if ( strcmp(ipaddr,"173.208.149.42") == 0 ) return(0); if ( strncmp(ipaddr,"5.9.253",strlen("5.9.253")) != 0 ) - return(0); + return(0);*/ ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) From 756144f92ff76a3a638425940689f7877fe9d1ac Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 8 Jun 2017 10:37:52 +0300 Subject: [PATCH 1227/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 97458867e..754ca56bc 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -82,8 +82,8 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i { //static uint16_t tmpport; char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson,*item; - if ( amclient != 0 ) - myport += amclient * 10; + //if ( amclient != 0 ) + // myport += amclient * 10; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); From 9130b5e367d011f1761e5ca5627c8d23fe21fe30 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 11:00:01 +0300 Subject: [PATCH 1228/2705] New utxoinfo --- iguana/coins/genltc | 2 +- iguana/exchanges/LP_coins.c | 8 +- iguana/exchanges/LP_commands.c | 336 +++++++++++++------------ iguana/exchanges/LP_forwarding.c | 165 +++++++++++++ iguana/exchanges/LP_include.h | 66 +++-- iguana/exchanges/LP_nativeDEX.c | 344 ++++++++++++++------------ iguana/exchanges/LP_peers.c | 24 +- iguana/exchanges/LP_quotes.c | 54 ++-- iguana/exchanges/LP_rpc.c | 18 +- iguana/exchanges/LP_swap.c | 84 +++---- iguana/exchanges/LP_transaction.c | 53 ++-- iguana/exchanges/LP_utxos.c | 394 +++++++++++++++++++++--------- 12 files changed, 976 insertions(+), 572 deletions(-) create mode 100644 iguana/exchanges/LP_forwarding.c diff --git a/iguana/coins/genltc b/iguana/coins/genltc index 9994529e0..ea034ed80 100755 --- a/iguana/coins/genltc +++ b/iguana/coins/genltc @@ -1,4 +1,4 @@ #!/bin/bash -curl --url "http://127.0.0.1:7776" --data "{\"RELAY\":1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7778" --data "{\"RELAY\":1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":68,\"endpend\":68,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index e2951dad5..c06acd1a1 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -185,6 +185,7 @@ void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetnam coin->pubtype = pubtype; coin->p2shtype = p2shtype; coin->wiftype = wiftype; + coin->inactive = (uint32_t)time(NULL); LP_userpass(coin->userpass,symbol,assetname,name); } @@ -256,7 +257,7 @@ struct iguana_info *LP_coinfind(char *symbol) struct iguana_info *LP_coincreate(cJSON *item) { - struct iguana_info cdata,*coin; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*symbol,*assetname; + struct iguana_info cdata,*coin=0; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*symbol,*assetname; if ( (symbol= jstr(item,"coin")) != 0 && symbol[0] != 0 && strlen(symbol) < 16 && LP_coinfind(symbol) == 0 && (port= juint(item,"rpcport")) != 0 ) { isPoS = jint(item,"isPoS"); @@ -275,9 +276,10 @@ struct iguana_info *LP_coincreate(cJSON *item) else if ( (name= jstr(item,"name")) == 0 ) name = symbol; LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); - if ( (coin= LP_coinadd(&cdata)) != 0 ) - coin->inactive = !jint(item,"active"); + coin = LP_coinadd(&cdata); } + if ( coin != 0 && item != 0 ) + coin->inactive = (strcmp("KMD",coin->symbol) == 0) ? 0 : !jint(item,"active"); return(0); } diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6e2410209..5972a432a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -18,71 +18,159 @@ // marketmaker // -double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub) +double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub) { - cJSON *reqjson; struct LP_peerinfo *peer; int32_t i,flag = 0,pushsock = -1; double price = 0.; - if ( ipaddr != 0 && port >= 1000 ) + cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; + qp->desthash = mypub; + strcpy(qp->srccoin,base); + strcpy(qp->destcoin,rel); + if ( strcmp(method,"request") == 0 ) { - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),port)) == 0 ) - peer = LP_addpeer(1,0,-1,ipaddr,port,port+1,port+2,0,0,0); - if ( peer != 0 ) + qp->quotetime = (uint32_t)time(NULL); + if ( (utxo= LP_utxofind(0,qp->desttxid,qp->destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) + LP_unavailableset(utxo,qp->srchash); + else { - if ( (pushsock= peer->pushsock) >= 0 ) + printf("couldnt find my txid to make request\n"); + return(0.); + } + } + reqjson = LP_quotejson(qp); + if ( bits256_nonz(qp->desthash) != 0 ) + flag = 1; + jaddstr(reqjson,"method",method); + if ( strcmp(method,"price") != 0 ) + printf("QUERY.(%s)\n",jprint(reqjson,0)); + LP_pubkey_send(qp->srchash,jprint(reqjson,1),1); + for (i=0; i<30; i++) + { + if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) != 0. ) + { + if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) { - qp->desthash = mypub; - strcpy(qp->srccoin,base); - strcpy(qp->destcoin,rel); - if ( strcmp(method,"request") == 0 ) - qp->quotetime = (uint32_t)time(NULL); - reqjson = LP_quotejson(qp); - if ( bits256_nonz(qp->desthash) != 0 ) - flag = 1; - jaddstr(reqjson,"method",method); - if ( strcmp(method,"price") != 0 ) - printf("QUERY.(%s)\n",jprint(reqjson,0)); - LP_send(pushsock,jprint(reqjson,1),1); - for (i=0; i<30; i++) - { - if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) != 0. ) - { - if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) - { - //printf("break out of loop.%d price %.8f\n",i,price); - break; - } - } - usleep(100000); - } - } else printf("no pushsock for peer.%s:%u\n",ipaddr,port); - } else printf("cant find/create peer.%s:%u\n",ipaddr,port); + //printf("break out of loop.%d price %.8f\n",i,price); + break; + } + } + usleep(100000); } return(price); } -int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) +int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) +{ + char *retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; + if ( (price= LP_price(base,rel)) != 0. ) + { + price *= (1. + profitmargin); + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + if ( LP_quoteparse(&Q,argjson) < 0 ) + return(-2); + //printf("connect with.(%s)\n",jprint(argjson,0)); + Q.destsatoshis = Q.satoshis * price; + privkey = LP_privkey(utxo->coinaddr); + if ( bits256_nonz(utxo->S.mypub) == 0 ) + utxo->S.mypub = LP_pubkey(privkey); + if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) + { + printf("not eligible\n"); + return(-1); + } + if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + { + nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 10000)); + if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) + printf("error creating utxo->pair\n"); + else if ( nn_bind(pair,pairstr) >= 0 ) + { + LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); + swap = LP_swapinit(1,0,privkey,&Q.R,&Q); + swap->N.pair = pair; + utxo->S.swap = swap; + swap->utxo = utxo; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)swap) == 0 ) + { + retjson = LP_quotejson(&Q); + jaddstr(retjson,"method","connected"); + jaddstr(retjson,"pair",pairstr); + jaddnum(retjson,"requestid",Q.R.requestid); + jaddnum(retjson,"quoteid",Q.R.quoteid); + retstr = jprint(retjson,1); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + else LP_pubkey_send(utxo->S.otherpubkey,retstr,1); + retval = 0; + } else printf("error launching swaploop\n"); + } else printf("printf error nn_connect to %s\n",pairstr); + } + else + { + printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); + } + } else printf("no price for %s/%s\n",base,rel); + if ( retval < 0 ) + { + if ( pair >= 0 ) + nn_close(pair); + LP_availableset(utxo); + } + return(retval); +} + +char *LP_connected(cJSON *argjson) // alice +{ + cJSON *retjson; int32_t pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; + retjson = cJSON_CreateObject(); + LP_quoteparse(&Q,argjson); + if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) + { + if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) + jaddstr(retjson,"error","couldnt create pairsock"); + else if ( nn_connect(pairsock,pairstr) >= 0 ) + { + LP_unavailableset(utxo,Q.srchash); + Q.privkey = LP_privkey(Q.destaddr); + LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); + swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q); + swap->N.pair = pairsock; + utxo->S.swap = swap; + swap->utxo = utxo; + printf("alice pairstr.(%s)\n",pairstr); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 ) + { + jaddstr(retjson,"result","success"); + jadd(retjson,"trade",LP_quotejson(&Q)); + jaddnum(retjson,"requestid",Q.R.requestid); + jaddnum(retjson,"quoteid",Q.R.quoteid); + } else jaddstr(retjson,"error","couldnt aliceloop"); + } + } else jaddstr(retjson,"result","update stats"); + return(jprint(retjson,1)); +} + +int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel,*retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey,txid; struct LP_utxoinfo *utxo; int32_t retval = -1,DEXselector = 0; uint64_t destvalue; struct basilisk_request R; struct LP_quoteinfo Q; - if ( IAMCLIENT == 0 && (method= jstr(argjson,"method")) != 0 ) + char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid; struct LP_utxoinfo *utxo; int32_t retval = -1; struct LP_quoteinfo Q; + if ( (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); - if ( (utxo= LP_utxofind(txid,jint(argjson,"vout"))) != 0 && strcmp(utxo->ipaddr,mypeer->ipaddr) == 0 && utxo->port == mypeer->port && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) + if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) != 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { printf("LP_command.(%s)\n",jprint(argjson,0)); - if ( time(NULL) > utxo->swappending ) - utxo->swappending = 0; - if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) + if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) + utxo->T.swappending = 0; + if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) // bob { retval = 1; - if ( utxo->swappending == 0 ) + if ( LP_isavailable(utxo) > 0 ) { - if ( strcmp(method,"request") == 0 && utxo->pair >= 0 ) - nn_close(utxo->pair), utxo->pair = -1; if ( (price= LP_price(base,rel)) != 0. ) { price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); - if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) + if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); return(-1); @@ -90,121 +178,40 @@ int32_t LP_command(struct LP_peerinfo *mypeer,int32_t pubsock,cJSON *argjson,uin if ( strcmp(method,"price") == 0 ) Q.timestamp = (uint32_t)time(NULL); retjson = LP_quotejson(&Q); + utxo->S.otherpubkey = jbits256(argjson,"desthash"); if ( strcmp(method,"request") == 0 ) { retval |= 2; - utxo->swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); - utxo->otherpubkey = jbits256(argjson,"desthash"); + LP_unavailableset(utxo,jbits256(argjson,"desthash")); jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); - jaddnum(retjson,"pending",utxo->swappending); - jaddbits256(retjson,"desthash",utxo->otherpubkey); + jaddnum(retjson,"pending",utxo->T.swappending); + jaddbits256(retjson,"desthash",utxo->S.otherpubkey); jaddstr(retjson,"method","reserved"); } else jaddstr(retjson,"method","quote"); retstr = jprint(retjson,1); - LP_send(pubsock,retstr,1); - utxo->published = (uint32_t)time(NULL); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + else LP_pubkey_send(utxo->S.otherpubkey,retstr,1); + utxo->T.published = (uint32_t)time(NULL); } else printf("null price\n"); - } else printf("swappending.%u pair.%d\n",utxo->swappending,utxo->pair); + } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); } - else if ( strcmp(method,"connect") == 0 ) + else if ( strcmp(method,"connect") == 0 ) // bob { retval = 4; - if ( utxo->pair < 0 ) - { - if ( (price= LP_price(base,rel)) != 0. ) - { - price *= (1. + profitmargin); - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - if ( LP_quoteparse(&Q,argjson) < 0 ) - return(-2); - //printf("connect with.(%s)\n",jprint(argjson,0)); - Q.destsatoshis = Q.satoshis * price; - privkey = LP_privkey(utxo->coinaddr); - if ( bits256_nonz(utxo->mypub) == 0 ) - utxo->mypub = LP_pubkey(privkey); - if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) - { - printf("not eligible\n"); - return(-1); - } - if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->swappending && bits256_cmp(utxo->mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) - { - nanomsg_tcpname(pairstr,mypeer->ipaddr,10000+(rand() % 10000)); - if ( (utxo->pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) - printf("error creating utxo->pair\n"); - else if ( nn_bind(utxo->pair,pairstr) >= 0 ) - { - LP_requestinit(&R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)utxo) == 0 ) - { - retjson = LP_quotejson(&Q); - jaddstr(retjson,"method","connected"); - jaddstr(retjson,"pair",pairstr); - jaddnum(retjson,"requestid",R.requestid); - jaddnum(retjson,"quoteid",R.quoteid); - retstr = jprint(retjson,1); - LP_send(pubsock,retstr,1); - utxo->swap = LP_swapinit(1,0,privkey,&R,&Q); - } - else - { - printf("error launching swaploop\n"); - free(utxo->swap); - utxo->swap = 0; - nn_close(utxo->pair); - utxo->pair = -1; - } - } - else - { - printf("printf error nn_connect to %s\n",pairstr); - nn_close(utxo->pair); - utxo->pair = -1; - } - } else printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->swappending ,bits256_cmp(utxo->mypub,Q.srchash) == 0 , LP_txvalue(rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); - } else printf("no price for %s/%s\n",base,rel); - } else printf("utxo->pair.%d when connect came in (%s)\n",utxo->pair,jprint(argjson,0)); + if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) + LP_connectstart(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); + else printf("swap %p when connect came in (%s)\n",utxo->S.swap,jprint(argjson,0)); } } } return(retval); } -char *LP_connected(cJSON *argjson) -{ - cJSON *retjson; int32_t pairsock = -1; char *pairstr; struct LP_quoteinfo *qp; int32_t DEXselector = 0; - retjson = cJSON_CreateObject(); - if ( IAMCLIENT == 0 ) - jaddstr(retjson,"result","update stats"); - else - { - if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) - jaddstr(retjson,"error","couldnt create pairsock"); - else if ( nn_connect(pairsock,pairstr) >= 0 ) - { - qp = calloc(1,sizeof(*qp)); - LP_quoteparse(qp,argjson); - qp->pair = pairsock; - qp->privkey = LP_privkey(qp->destaddr); - LP_requestinit(&qp->R,qp->srchash,qp->desthash,qp->srccoin,qp->satoshis,qp->destcoin,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); - printf("alice pairstr.(%s)\n",pairstr); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)qp) == 0 ) - { - jaddstr(retjson,"result","success"); - jadd(retjson,"trade",LP_quotejson(qp)); - } else jaddstr(retjson,"error","couldnt aliceloop"); - } - } - return(jprint(retjson,1)); -} - -// addcoin api - char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t amclient,otherpeers,othernumutxos; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; + char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); else if ( strcmp(method,"help") == 0 ) @@ -226,6 +233,9 @@ getutxos()\n\ getutxos(coin, lastn)\n\ orderbook(base, rel)\n\ getprice(base, rel)\n\ +register(pubkey,pushaddr)\n\ +lookup(pubkey)\n\ +forward(pubkey,hexstr)\n\ \"}")); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) { @@ -250,9 +260,9 @@ getprice(base, rel)\n\ return(clonestr("{\"error\":\"couldnt set price\"}")); else { - if ( IAMCLIENT == 0 ) + if ( IAMLP != 0 ) { - HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { if ( LP_ismine(utxo) != 0 && (strcmp(utxo->coin,base) == 0 || strcmp(utxo->coin,rel) == 0) ) LP_priceping(LP_mypubsock,utxo,rel,LP_profitratio - 1.); @@ -294,10 +304,10 @@ getprice(base, rel)\n\ return(clonestr("{\"error\":\"coin is disabled\"}")); if ( strcmp(method,"inventory") == 0 ) { - LP_privkey_init(0,-1,coin,0,USERPASS_WIFSTR,1); - return(LP_inventory(coin)); + LP_privkey_init(-1,coin,0,USERPASS_WIFSTR,0); + return(LP_inventory(coin,jobj(argjson,"client") != 0 ? jint(argjson,"client") : 0)); } - else if ( IAMCLIENT != 0 && (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) + else if ( (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) { bits256 txid; int32_t vout; struct LP_utxoinfo *utxo; txid = jbits256(argjson,"txid"); @@ -306,7 +316,7 @@ getprice(base, rel)\n\ if ( jobj(argjson,"vout") == 0 ) return(clonestr("{\"error\":\"missing vout\"}")); vout = jint(argjson,"vout"); - if ( (utxo= LP_utxofind(txid,vout)) == 0 ) + if ( (utxo= LP_utxofind(1,txid,vout)) == 0 ) return(clonestr("{\"error\":\"txid/vout not found\"}")); if ( strcmp(method,"candidates") == 0 ) return(jprint(LP_tradecandidates(coin),1)); @@ -325,7 +335,6 @@ getprice(base, rel)\n\ return(clonestr("{\"error\":\"at least one of coins disabled\"}")); if ( LP_isdisabled(jstr(argjson,"coin"),0) != 0 ) return(clonestr("{\"error\":\"coin is disabled\"}")); - amclient = (LP_mypeer == 0); if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) @@ -344,7 +353,7 @@ getprice(base, rel)\n\ peer->numutxos = othernumutxos; } //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); - } else LP_addpeer(amclient,LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); + } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); } } //printf("CMD.(%s)\n",jprint(argjson,0)); @@ -362,21 +371,30 @@ getprice(base, rel)\n\ retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); - else if ( IAMCLIENT == 0 && strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) - { - retstr = LP_utxos(LP_mypeer,coin,jint(argjson,"lastn")); - //printf("RETURN. %d utxos\n",cJSON_GetArraySize(cJSON_Parse(retstr))); - } - else if ( IAMCLIENT == 0 && strcmp(method,"notify") == 0 ) - retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( IAMCLIENT == 0 && strcmp(method,"notified") == 0 ) + else if ( IAMLP != 0 ) { - if ( juint(argjson,"timestamp") > time(NULL)-60 ) + if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) { - printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(amclient,LP_mypeer,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"valuesats"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"valuesats2"),jstr(argjson,"script"),jstr(argjson,"address"),jstr(argjson,"ipaddr"),juint(argjson,"port"),jdouble(argjson,"profit")); + retstr = LP_utxos(1,LP_mypeer,coin,jint(argjson,"lastn")); + //printf("RETURN. %d utxos\n",cJSON_GetArraySize(cJSON_Parse(retstr))); + } + else if ( strcmp(method,"register") == 0 ) + retstr = LP_register(jbits256(argjson,"pubkey"),jstr(argjson,"pushaddr")); + else if ( strcmp(method,"lookup") == 0 ) + retstr = LP_lookup(jbits256(argjson,"pubkey")); + else if ( strcmp(method,"forward") == 0 ) + retstr = LP_forward(jbits256(argjson,"pubkey"),jstr(argjson,"hexstr")); + else if ( strcmp(method,"notify") == 0 ) + retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); + else if ( strcmp(method,"notified") == 0 ) + { + if ( juint(argjson,"timestamp") > time(NULL)-60 ) + { + printf("utxonotify.(%s)\n",jprint(argjson,0)); + LP_addutxo(1,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"valuesats"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"valuesats2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit")); + } + retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } - retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } if ( retstr != 0 ) return(retstr); diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c new file mode 100644 index 000000000..2dd260294 --- /dev/null +++ b/iguana/exchanges/LP_forwarding.c @@ -0,0 +1,165 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_forwarding.c +// marketmaker +// + +struct LP_forwardinfo +{ + UT_hash_handle hh; + bits256 pubkey; + char pushaddr[64]; + int32_t pushsock; + uint32_t lasttime; +} *LP_forwardinfos; +#define LP_KEEPALIVE 300 + +struct LP_forwardinfo *LP_forwardfind(bits256 pubkey) +{ + struct LP_forwardinfo *ptr=0; + portable_mutex_lock(&LP_forwardmutex); + HASH_FIND(hh,LP_forwardinfos,&pubkey,sizeof(pubkey),ptr); + portable_mutex_unlock(&LP_forwardmutex); + if ( ptr != 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) + return(ptr); + else return(0); +} + +char *LP_lookup(bits256 pubkey) +{ + if ( LP_forwardfind(pubkey) != 0 ) + return(clonestr("{\"result\":\"success\",\"forwarding\":1}")); + else return(clonestr("{\"error\":\"notfound\"}")); +} + +char *LP_register(bits256 pubkey,char *pushaddr) +{ + struct LP_forwardinfo *ptr=0; int32_t pushsock; + if ( is_ipaddr(pushaddr) == 0 ) + return(clonestr("{\"error\":\"illegal ipaddr\"}")); + if ( (ptr= LP_forwardfind(pubkey)) != 0 ) + { + ptr->lasttime = (uint32_t)time(NULL); + return(clonestr("{\"error\":\"already registered\"}")); + } + else if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) + return(clonestr("{\"error\":\"out of sockets\"}")); + else if ( nn_connect(pushsock,pushaddr) < 0 ) + { + nn_close(pushsock); + return(clonestr("{\"error\":\"cant connect\"}")); + } + else + { + ptr = calloc(1,sizeof(*ptr)); + ptr->pubkey = pubkey; + strcpy(ptr->pushaddr,pushaddr); + ptr->pushsock = pushsock; + ptr->lasttime = (uint32_t)time(NULL); + portable_mutex_lock(&LP_forwardmutex); + HASH_ADD_KEYPTR(hh,LP_forwardinfos,&ptr->pubkey,sizeof(ptr->pubkey),ptr); + portable_mutex_unlock(&LP_forwardmutex); + return(LP_lookup(pubkey)); + } +} + +char *LP_forward(bits256 pubkey,char *hexstr) +{ + struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; cJSON *retjson; + if ( hexstr == 0 || hexstr[0] == 0 ) + return(clonestr("{\"error\":\"nohex\"}")); + if ( (ptr= LP_forwardfind(pubkey)) != 0 ) + { + if ( ptr->pushsock >= 0 ) + { + datalen = (int32_t)strlen(hexstr) >> 1; + data = malloc(datalen); + decode_hex(data,datalen,hexstr); + sentbytes = LP_send(ptr->pushsock,(char *)data,1); + } + retjson = cJSON_CreateObject(); + if ( sentbytes == datalen ) + { + jaddstr(retjson,"result","success"); + jaddnum(retjson,"forwarded",sentbytes); + return(jprint(retjson,1)); + } + else + { + jaddstr(retjson,"error","send error"); + jaddnum(retjson,"sentbytes",sentbytes); + jaddnum(retjson,"datalen",datalen); + return(jprint(retjson,1)); + } + } else return(clonestr("{\"error\":\"notfound\"}")); +} + +void LP_forwarding_register(bits256 pubkey,char *pushaddr) +{ + char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t retval = -1; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( jint(retjson,"registered") != 0 ) + retval = 0; + free_json(retjson); + } + free(retstr); + } + if ( retval == 0 ) + break; + } +} + +int32_t LP_pubkey_send(bits256 pubkey,char *jsonstr,int32_t freeflag) +{ + struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson; + if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) + { + return(LP_send(ptr->pushsock,jsonstr,1)); + } + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( (retstr= issue_LP_lookup(peer->ipaddr,peer->port,pubkey)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( jint(retjson,"forwarding") != 0 ) + retval = 0; + free_json(retjson); + } + free(retstr); + } + if ( retval == 0 ) + { + len = (int32_t)strlen(jsonstr) + 1; + hexstr = malloc(len*2 + 1); + init_hexbytes_noT(hexstr,(uint8_t *)jsonstr,len); + if ( freeflag != 0 ) + free(jsonstr); + if ( peer->pushsock >= 0 ) + return(LP_send(peer->pushsock,hexstr,1)); + } + } + return(-1); +} + + + diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index b75202a12..dd2422cdf 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -46,7 +46,7 @@ #define BASILISK_KEYSIZE ((int32_t)(2*sizeof(bits256)+sizeof(uint32_t)*2)) extern char GLOBAL_DBDIR[],USERPASS[],USERPASS_WIFSTR[]; -extern int32_t IAMCLIENT,USERPASS_COUNTER; +extern int32_t IAMLP,USERPASS_COUNTER; struct iguana_msgvin { bits256 prev_hash; uint8_t *vinscript,*userdata,*spendscript,*redeemscript; uint32_t prev_vout,sequence; uint16_t scriptlen,p2shlen,userdatalen,spendlen; }; @@ -139,42 +139,34 @@ struct basilisk_swapinfo struct iguana_info { - uint64_t txfee; double estimatedrate; + uint64_t txfee; double estimatedrate,profitmargin; int32_t longestchain; uint32_t counter,inactive; uint8_t pubtype,p2shtype,isPoS,wiftype; char symbol[16],smartaddr[64],userpass[1024],serverport[128]; }; -struct basilisk_swap -{ - void *ctx; struct iguana_info bobcoin,alicecoin; - void (*balancingtrade)(struct basilisk_swap *swap,int32_t iambob); - int32_t subsock,pushsock,connected,aliceunconf,depositunconf,paymentunconf; uint32_t lasttime,aborted; - FILE *fp; - bits256 persistent_privkey,persistent_pubkey; - struct basilisk_swapinfo I; - struct basilisk_rawtx bobdeposit,bobpayment,alicepayment,myfee,otherfee,aliceclaim,alicespend,bobreclaim,bobspend,bobrefund,alicereclaim; - bits256 privkeys[INSTANTDEX_DECKSIZE]; - struct basilisk_swapmessage *messages; int32_t nummessages; - char Bdeposit[64],Bpayment[64]; - uint64_t otherdeck[INSTANTDEX_DECKSIZE][2],deck[INSTANTDEX_DECKSIZE][2]; - uint8_t persistent_pubkey33[33],changermd160[20],pad[15],verifybuf[65536]; - -}; +struct _LP_utxoinfo { bits256 txid; uint64_t value; int32_t vout; }; + +struct LP_utxostats { uint32_t lasttime,errors,swappending,published,spentflag,lastspentcheck; }; + +struct LP_utxobob { struct _LP_utxoinfo utxo,deposit; }; + +struct LP_utxoalice { struct _LP_utxoinfo utxo,fee; }; + +struct LP_utxoswap { bits256 otherpubkey,mypub; void *swap; uint64_t satoshis; double profitmargin; }; struct LP_utxoinfo { UT_hash_handle hh,hh2; - bits256 txid,txid2,feetxid,otherpubkey,mypub; - void *swap; - uint64_t value,satoshis,value2; + bits256 pubkey; + struct _LP_utxoinfo payment,deposit,fee; + struct LP_utxostats T; + struct LP_utxoswap S; + //struct LP_utxonetwork N; + int32_t iambob,iamlp; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; uint8_t key2[sizeof(bits256) + sizeof(int32_t)]; - int32_t vout,vout2,pair; - uint32_t lasttime,errors,swappending,published,spentflag,lastspentcheck; - double profitmargin; - char ipaddr[64],coinaddr[64],spendscript[256],coin[16]; - uint16_t port; + char coin[16],coinaddr[64],spendscript[256]; }; struct LP_peerinfo @@ -197,13 +189,33 @@ struct LP_quoteinfo char srccoin[16],coinaddr[64],destcoin[16],destaddr[64]; }; +struct LP_endpoint { int32_t pair; char ipaddr[64]; uint16_t port; }; + +struct basilisk_swap +{ + void *ctx; struct iguana_info bobcoin,alicecoin; struct LP_utxoinfo *utxo; + struct LP_endpoint N; + void (*balancingtrade)(struct basilisk_swap *swap,int32_t iambob); + int32_t subsock,pushsock,connected,aliceunconf,depositunconf,paymentunconf; uint32_t lasttime,aborted; + FILE *fp; + bits256 persistent_privkey,persistent_pubkey; + struct basilisk_swapinfo I; + struct basilisk_rawtx bobdeposit,bobpayment,alicepayment,myfee,otherfee,aliceclaim,alicespend,bobreclaim,bobspend,bobrefund,alicereclaim; + bits256 privkeys[INSTANTDEX_DECKSIZE]; + struct basilisk_swapmessage *messages; int32_t nummessages; + char Bdeposit[64],Bpayment[64]; + uint64_t otherdeck[INSTANTDEX_DECKSIZE][2],deck[INSTANTDEX_DECKSIZE][2]; + uint8_t persistent_pubkey33[33],changermd160[20],pad[15],verifybuf[65536]; + +}; + void basilisk_dontforget_update(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx); uint32_t basilisk_requestid(struct basilisk_request *rp); uint32_t basilisk_quoteid(struct basilisk_request *rp); struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp,struct LP_quoteinfo *qp); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend); -double LP_query(char *method,struct LP_quoteinfo *qp,char *ipaddr,uint16_t port,char *base,char *rel,bits256 mypub); +double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); void LP_quotesinit(char *base,char *rel); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 754ca56bc..b2d4e7369 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -17,13 +17,13 @@ // LP_nativeDEX.c // marketmaker // -// jl777: fix price calcs based on specific txfees +// jl777: profitmargin per coin, ignore peers with errors #include #include "LP_include.h" #include "LP_network.c" -struct LP_utxoinfo *LP_utxoinfos,*LP_utxoinfos2; +struct LP_utxoinfo *LP_utxoinfos[2],*LP_utxoinfos2[2]; struct LP_peerinfo *LP_peerinfos,*LP_mypeer; char *activecoins[] = { "BTC", "KMD" }; @@ -32,11 +32,11 @@ char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", -portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex; +portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex; int32_t LP_mypubsock = -1; -int32_t Client_connections; -int32_t USERPASS_COUNTER,IAMCLIENT = 0; +int32_t USERPASS_COUNTER,IAMLP = 0; double LP_profitratio = 1.; +bits256 LP_mypubkey; // stubs int32_t basilisk_istrustedbob(struct basilisk_swap *swap) @@ -76,26 +76,124 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_peers.c" #include "LP_utxos.c" #include "LP_quotes.c" +#include "LP_forwarding.c" #include "LP_commands.c" -void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,int32_t pullsock,uint16_t myport,int32_t amclient,char *passphrase,double profitmargin,cJSON *coins) +int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { - //static uint16_t tmpport; - char *retstr; uint8_t r; int32_t i,n,j,len,recvsize,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now; struct LP_utxoinfo *utxo,*utmp; void *ptr; cJSON *argjson,*item; - //if ( amclient != 0 ) - // myport += amclient * 10; + int32_t recvsize,len,datalen,nonz = 0; void *ptr; char *retstr,*jsonstr=0; cJSON *argjson; + while ( (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + { + nonz++; + if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) + { + datalen >>= 1; + jsonstr = malloc(datalen + 1); + decode_hex((void *)jsonstr,datalen,(char *)ptr); + jsonstr[datalen] = 0; + } else jsonstr = (char *)ptr; + if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) + { + len = (int32_t)strlen(jsonstr) + 1; + portable_mutex_lock(&LP_commandmutex); + if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) == 0 ) + { + if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) + { + printf("%s PULL.[%d] %s\n",myipaddr != 0 ? myipaddr : "127.0.0.1",recvsize,(char *)ptr); + free(retstr); + } + } + portable_mutex_unlock(&LP_commandmutex); + free_json(argjson); + } + if ( (void *)jsonstr != ptr ) + free(jsonstr); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } + return(nonz); +} + +int32_t LP_subsock_check(struct LP_peerinfo *peer) +{ + int32_t recvsize,nonz = 0; char *retstr; void *ptr; cJSON *argjson; + while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) + { + nonz++; + if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) + { + portable_mutex_lock(&LP_commandmutex); + if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) + { + //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + free(retstr); + } + portable_mutex_unlock(&LP_commandmutex); + free_json(argjson); + } else printf("error parsing.(%s)\n",(char *)ptr); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; + } + return(nonz); +} + +void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitmargin) +{ + struct _LP_utxoinfo u; char str[65]; uint32_t now = (uint32_t)time(NULL); + //printf("%s lag.%d\n",bits256_str(str,utxo->txid),now-utxo->lastspentcheck); + if ( utxo->T.spentflag == 0 && now > utxo->T.lastspentcheck+60 ) + { + u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; + utxo->T.lastspentcheck = now; + if ( LP_txvalue(utxo->coin,utxo->payment.txid,utxo->payment.vout) == 0 ) + { + printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,dstr(utxo->payment.value)); + LP_spentnotify(utxo,0); + } + else if ( LP_txvalue(utxo->coin,u.txid,u.vout) == 0 ) + { + printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,u.txid),u.vout,dstr(u.value)); + LP_spentnotify(utxo,1); + } + else if ( LP_ismine(utxo) != 0 ) + { + if ( strcmp(utxo->coin,"KMD") == 0 ) + LP_priceping(pubsock,utxo,"BTC",profitmargin); + else LP_priceping(pubsock,utxo,"KMD",profitmargin); + } + } +} + +void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) +{ + int32_t iambob; struct LP_utxoinfo *utxo,*tmp; + LP_utxopurge(0); + for (iambob=0; iambob<=1; iambob++) + { + LP_privkey_updates(pubsock,passphrase,iambob); + HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) + { + LP_utxo_spentcheck(pubsock,utxo,profitmargin); + } + } +} + +void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins) +{ + char *retstr; uint8_t r; int32_t i,n,j,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } - if ( amclient == 0 ) + if ( IAMLP != 0 ) { for (i=0; i 25 ) continue; - LP_peersquery(amclient,mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport,profitmargin); + LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport,profitmargin); } } else @@ -104,12 +202,9 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i for (j=0; jipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) { - printf("query utxo from %s\n",peer->ipaddr); - LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); + //printf("query utxo from %s\n",peer->ipaddr); + LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } } - if ( amclient != 0 ) + if ( IAMLP == 0 ) { while ( 1 ) { + now = (uint32_t)time(NULL); + if ( lastforward < now-LP_KEEPALIVE ) + { + LP_forwarding_register(LP_mypubkey,pushaddr); + lastforward = now; + } nonz = n = 0; - if ( (++counter % 3600) == 0 ) - LP_privkey_updates(mypeer,pubsock,passphrase,amclient); + if ( (++counter % 5000) == 0 ) + LP_utxo_updates(pubsock,passphrase,profitmargin); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - n++; - while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) + nonz += LP_subsock_check(peer); + } + if ( pullsock >= 0 ) + { + if ( (n= LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin)) > 0 ) { - nonz++; - if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) - { - portable_mutex_lock(&LP_commandmutex); - if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) - { - //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); - free(retstr); - } - portable_mutex_unlock(&LP_commandmutex); - //printf("subloop.(%s)\n",jprint(argjson,0)); - free_json(argjson); - } else printf("error parsing.(%s)\n",(char *)ptr); - if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0; + nonz += n; + lastforward = now; } } if ( nonz == 0 ) @@ -173,41 +265,8 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i while ( 1 ) { nonz = 0; - if ( (++counter % 2000) == 0 ) - { - LP_privkey_updates(mypeer,pubsock,passphrase,amclient); - } if ( (counter % 500) == 0 ) - { - char str[65]; - //printf("start utxos updates\n"); - HASH_ITER(hh,LP_utxoinfos,utxo,utmp) - { - now = (uint32_t)time(NULL); - //printf("%s lag.%d\n",bits256_str(str,utxo->txid),now-utxo->lastspentcheck); - if ( utxo->spentflag == 0 && now > utxo->lastspentcheck+60 ) - { - utxo->lastspentcheck = now; - if ( LP_txvalue(utxo->coin,utxo->txid,utxo->vout) == 0 ) - { - printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid),utxo->vout,dstr(utxo->value)); - LP_spentnotify(utxo,0); - } - else if ( LP_txvalue(utxo->coin,utxo->txid2,utxo->vout2) == 0 ) - { - printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->txid2),utxo->vout2,dstr(utxo->value2)); - LP_spentnotify(utxo,1); - } - else if ( LP_ismine(utxo) != 0 ) - { - if ( strcmp(utxo->coin,"KMD") == 0 ) - LP_priceping(pubsock,utxo,"BTC",profitmargin); - else LP_priceping(pubsock,utxo,"KMD",profitmargin); - } - } - } - //printf("done utxos updates\n"); - } + LP_utxo_updates(pubsock,passphrase,profitmargin); now = (uint32_t)time(NULL); //printf("start peers updates\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) @@ -219,7 +278,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i if ( peer->numpeers != mypeer->numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) - LP_peersquery(amclient,mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); + LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); } if ( peer->numutxos != mypeer->numutxos && now > peer->lastutxos+60 ) { @@ -229,47 +288,12 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i lastn = LP_PROPAGATION_SLACK * 2; printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) - LP_utxosquery(0,mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer->ipaddr,myport,profitmargin); - } - while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) - { - nonz++; - if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) - { - portable_mutex_lock(&LP_commandmutex); - if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) - { - //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); - free(retstr); - } - portable_mutex_unlock(&LP_commandmutex); - free_json(argjson); - } else printf("error parsing.(%s)\n",(char *)ptr); - if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0; + LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer->ipaddr,myport,profitmargin); } + nonz += LP_subsock_check(peer); } - while ( pullsock >= 0 && (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) - { - nonz++; - if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) - { - len = (int32_t)strlen((char *)ptr) + 1; - portable_mutex_lock(&LP_commandmutex); - if ( LP_command(mypeer,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) == 0 ) - { - if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) - { - printf("%s PULL.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); - free(retstr); - } - } - portable_mutex_unlock(&LP_commandmutex); - free_json(argjson); - } - if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0; - } + if ( pullsock >= 0 ) + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); if ( nonz == 0 ) usleep(100000); //printf("nonz.%d in mainloop\n",nonz); @@ -280,7 +304,7 @@ void LP_mainloop(struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,i void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128]; - IAMCLIENT = amclient; + IAMLP = !amclient; LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); srand((int32_t)n); @@ -291,58 +315,70 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit portable_mutex_init(&LP_commandmutex); portable_mutex_init(&LP_swaplistmutex); portable_mutex_init(&LP_cachemutex); - if ( amclient == 0 ) + portable_mutex_init(&LP_forwardmutex); + if ( profitmargin == 0. || profitmargin == 0.01 ) { - if ( profitmargin == 0. || profitmargin == 0.01 ) + profitmargin = 0.01 + (double)(rand() % 100)/100000; + printf("default profit margin %f\n",profitmargin); + } + if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) + { + if ( (myipaddr= OS_filestr(&filesize,"/tmp/myipaddr")) != 0 && myipaddr[0] != 0 ) + { + n = strlen(myipaddr); + if ( myipaddr[n-1] == '\n' ) + myipaddr[--n] = 0; + } else printf("error getting myipaddr\n"); + } else printf("error issuing curl\n"); + nanomsg_tcpname(pushaddr,myipaddr,mypullport); + if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) + { + if ( nn_bind(pullsock,pushaddr) >= 0 ) { - profitmargin = 0.01 + (double)(rand() % 100)/100000; - printf("default profit margin %f\n",profitmargin); + timeout = 1; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + maxsize = 1024 * 1024; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } - if ( system("curl -s4 checkip.amazonaws.com > /tmp/myipaddr") == 0 ) + } + if ( IAMLP != 0 ) + { + if ( myipaddr != 0 ) { - if ( (myipaddr= OS_filestr(&filesize,"/tmp/myipaddr")) != 0 && myipaddr[0] != 0 ) + pubsock = -1; + nanomsg_tcpname(subaddr,myipaddr,mypubport); + printf(">>>>>>>>> myipaddr.%s (%s %s)\n",myipaddr,pushaddr,subaddr); + if ( (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) { - n = strlen(myipaddr); - if ( myipaddr[n-1] == '\n' ) - myipaddr[--n] = 0; - pullsock = pubsock = -1; - nanomsg_tcpname(pushaddr,myipaddr,mypullport); - nanomsg_tcpname(subaddr,myipaddr,mypubport); - printf(">>>>>>>>> myipaddr.%s (%s %s)\n",myipaddr,pushaddr,subaddr); - if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) + if ( nn_bind(pubsock,subaddr) >= 0 ) + { + timeout = 10; + nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + } + else { - if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) - { - timeout = 10; - nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - timeout = 1; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - timeout = 1; - maxsize = 1024 * 1024; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - } - else - { - printf("error binding to (%s).%d (%s).%d\n",pushaddr,pullsock,subaddr,pubsock); - if ( pullsock >= 0 ) - nn_close(pullsock), pullsock = -1; - if ( pubsock >= 0 ) - nn_close(pubsock), pubsock = -1; - } - } else printf("error getting sockets %d %d\n",pullsock,pubsock); - LP_mypubsock = pubsock; - LP_mypeer = mypeer = LP_addpeer(amclient,mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); - //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); - } else printf("error getting myipaddr\n"); - } else printf("error issuing curl\n"); + printf("error binding to (%s).%d (%s).%d\n",pushaddr,pullsock,subaddr,pubsock); + if ( pubsock >= 0 ) + nn_close(pubsock), pubsock = -1; + } + } else printf("error getting sockets %d %d\n",pullsock,pubsock); + LP_mypubsock = pubsock; + LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); + //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); + } if ( myipaddr == 0 || mypeer == 0 ) { printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); exit(-1); } - //printf("utxos.(%s)\n",LP_utxos(mypeer,"",10000)); } - LP_mainloop(mypeer,mypubport,pubsock,pullsock,myport,amclient,passphrase,profitmargin,jobj(argjson,"coins")); + else if ( myipaddr == 0 ) + { + printf("couldnt get myipaddr\n"); + exit(-1); + } +LP_mainloop(myipaddr,mypeer,mypubport,pubsock,pushaddr,pullsock,myport,passphrase,profitmargin,jobj(argjson,"coins")); } diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 1cd4c9056..2309e5c20 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -47,13 +47,9 @@ char *LP_peers() return(jprint(peersjson,1)); } -struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) +struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) { - uint32_t ipbits; int32_t pushsock,subsock,timeout,enabled; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; - /*if ( strcmp(ipaddr,"173.208.149.42") == 0 ) - return(0); - if ( strncmp(ipaddr,"5.9.253",strlen("5.9.253")) != 0 ) - return(0);*/ + uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) @@ -73,9 +69,6 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 peer = calloc(1,sizeof(*peer)); peer->pushsock = peer->subsock = pushsock = subsock = -1; strcpy(peer->ipaddr,ipaddr); - if ( amclient == 0 ) - enabled = 1; - else enabled = 1;//(rand() % (1 << Client_connections)) == 0; if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { timeout = 1000; @@ -86,7 +79,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 printf("connected to push.(%s) %d\n",pushaddr,pushsock); peer->connected = (uint32_t)time(NULL); peer->pushsock = pushsock; - if ( enabled != 0 && (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + if ( (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) { timeout = 1; nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); @@ -96,7 +89,6 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 { peer->subsock = subsock; printf("connected to sub.(%s) %d\n",subaddr,peer->subsock); - Client_connections += amclient; } else nn_close(subsock); } } @@ -125,7 +117,7 @@ struct LP_peerinfo *LP_addpeer(int32_t amclient,struct LP_peerinfo *mypeer,int32 return(peer); } -int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; if ( (array= cJSON_Parse(retstr)) != 0 ) @@ -144,7 +136,7 @@ int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) { - peer = LP_addpeer(amclient,mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); } if ( peer != 0 ) { @@ -160,7 +152,7 @@ int32_t LP_peersparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs return(n); } -void LP_peersquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) +void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); @@ -170,9 +162,9 @@ void LP_peersquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock { //printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); - LP_peersparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); + LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); - if ( amclient == 0 ) + if ( IAMLP != 0 ) { HASH_ITER(hh,LP_peerinfos,peer,tmp) { diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 943b103e2..7f7b7ade9 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -125,13 +125,13 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) qp->txfee = 10000; - if ( qp->txfee >= utxo->satoshis || qp->txfee >= utxo->value2 || utxo->value2 < LP_DEPOSITSATOSHIS(utxo->satoshis) ) + if ( utxo->iambob == 0 || qp->txfee >= utxo->S.satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(utxo->S.satoshis) ) return(-1); - qp->txid = utxo->txid; - qp->vout = utxo->vout; - qp->txid2 = utxo->txid2; - qp->vout2 = utxo->vout2; - qp->satoshis = utxo->satoshis - qp->txfee; + qp->txid = utxo->payment.txid; + qp->vout = utxo->payment.vout; + qp->txid2 = utxo->deposit.txid; + qp->vout2 = utxo->deposit.vout; + qp->satoshis = utxo->S.satoshis - qp->txfee; qp->destsatoshis = qp->satoshis * price; if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) qp->desttxfee = 10000; @@ -140,7 +140,7 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * qp->destsatoshis -= qp->desttxfee; safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); - qp->srchash = LP_pubkey(LP_privkey(utxo->coinaddr)); + qp->srchash = utxo->pubkey; return(0); } @@ -224,7 +224,7 @@ cJSON *LP_tradecandidates(char *base) safecopy(coinstr,jstr(item,"base"),sizeof(coinstr)); if ( strcmp(coinstr,base) == 0 ) { - if ( LP_iseligible(Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) != 0 ) + if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) != 0 ) { if ( LP_arrayfind(retarray,Q.txid,Q.vout) < 0 ) { @@ -265,8 +265,8 @@ void LP_quotesinit(char *base,char *rel) item = jitem(array,i); LP_quoteparse(&Q,item); if ( iter == 0 ) - LP_query("price",&Q,jstr(item,"ipaddr"),jint(item,"port"),base,rel,zero); - else LP_query("price",&Q,jstr(item,"ipaddr"),jint(item,"port"),rel,base,zero); + LP_query("price",&Q,base,rel,zero); + else LP_query("price",&Q,rel,base,zero); } } free_json(array); @@ -293,7 +293,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) LP_quoteparse(&Q[i],item); if ( (price= jdouble(item,"price")) == 0. ) { - price = LP_query("price",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,zero); + price = LP_query("price",&Q[i],base,myutxo->coin,zero); Q[i].destsatoshis = price * Q[i].satoshis; } if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) @@ -306,7 +306,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) besti = -1; for (i=0; isatoshis >= Q[i].destsatoshis+Q[i].desttxfee ) + if ( (price= prices[i]) != 0. && myutxo->S.satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) { metric = price / bestprice; printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); @@ -320,7 +320,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) bestmetric = metric; } } - } else printf("(%f %f) ",dstr(myutxo->satoshis),dstr(Q[i].destsatoshis)); + } else printf("(%f %f) ",dstr(myutxo->S.satoshis),dstr(Q[i].destsatoshis)); } printf("metrics, best %f\n",bestmetric); if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) @@ -332,23 +332,23 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) printf("bestprice %f vs maxprice %f\n",bestprice,maxprice); if ( maxprice == 0. || bestprice <= maxprice ) { - Q[i].desttxid = myutxo->txid; - Q[i].destvout = myutxo->vout; - Q[i].feetxid = myutxo->txid2; - Q[i].feevout = myutxo->vout2; + Q[i].desttxid = myutxo->payment.txid; + Q[i].destvout = myutxo->payment.vout; + Q[i].feetxid = myutxo->fee.txid; + Q[i].feevout = myutxo->fee.vout; strcpy(Q[i].destaddr,myutxo->coinaddr); - price = LP_query("request",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); + price = LP_query("request",&Q[i],base,myutxo->coin,myutxo->S.mypub); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); jaddnum(bestitem,"price",prices[i]); if ( price <= maxprice ) { - Q[i].desttxid = myutxo->txid; - Q[i].destvout = myutxo->vout; - Q[i].feetxid = myutxo->txid2; - Q[i].feevout = myutxo->vout2; + Q[i].desttxid = myutxo->payment.txid; + Q[i].destvout = myutxo->payment.vout; + Q[i].feetxid = myutxo->fee.txid; + Q[i].feevout = myutxo->fee.vout; strcpy(Q[i].destaddr,myutxo->coinaddr); - price = LP_query("connect",&Q[i],jstr(item,"ipaddr"),jint(item,"port"),base,myutxo->coin,myutxo->mypub); + price = LP_query("connect",&Q[i],base,myutxo->coin,myutxo->S.mypub); LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); jaddstr(bestitem,"status","connected"); jaddnum(bestitem,"requestid",R.requestid); @@ -376,9 +376,9 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin) { double price,bid,ask; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; - if ( (now= (uint32_t)time(NULL)) > utxo->swappending ) - utxo->swappending = 0; - if ( now > utxo->published+60 && utxo->swappending == 0 && utxo->pair < 0 && utxo->swap == 0 && (price= LP_myprice(&bid,&ask,utxo->coin,rel)) != 0. ) + if ( (now= (uint32_t)time(NULL)) > utxo->T.swappending ) + utxo->T.swappending = 0; + if ( now > utxo->T.published+60 && utxo->T.swappending == 0 && utxo->S.swap == 0 && (price= LP_myprice(&bid,&ask,utxo->coin,rel)) != 0. ) { if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); @@ -388,7 +388,7 @@ int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double p retstr = jprint(retjson,1); //printf("PING.(%s)\n",retstr); LP_send(pubsock,retstr,1); - utxo->published = now; + utxo->T.published = now; return(0); } return(-1); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 31e1e0255..f5e915a70 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,12 +52,28 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notified?ipaddr=%s&port=%u&profit=%.6f&coin=%s&txid=%s&vout=%d&valuesats=%llu&txid2=%s&vout2=%d&valuesats2=%llu&script=%s&address=%s×tamp=%u",destip,destport,utxo->ipaddr,utxo->port,utxo->profitmargin,utxo->coin,bits256_str(str,utxo->txid),utxo->vout,(long long)utxo->value,bits256_str(str2,utxo->txid2),utxo->vout2,(long long)utxo->value2,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); + sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&valuesats=%llu&txid2=%s&vout2=%d&valuesats2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str2,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); } +char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *pushaddr) +{ + char url[512],str[65]; + sprintf(url,"http://%s:%u/api/stats/register?pubkey=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr); + //printf("getutxo.(%s)\n",url); + return(issue_curl(url)); +} + +char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) +{ + char url[512],str[65]; + sprintf(url,"http://%s:%u/api/stats/register?pubkey=%s",destip,destport,bits256_str(str,pubkey)); + //printf("getutxo.(%s)\n",url); + return(issue_curl(url)); +} + cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) { char *retstr; cJSON *retjson = 0; diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 35ce8f62f..fa674cf7a 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -17,22 +17,12 @@ // LP_swap.c // marketmaker // + /* - resume handling: list of tx broadcast, tx pending + required items, reconnect state machine or have statemachine assume off by one or state/otherstate specific handling make sure to broadcast deposit before claiming refund, or to just skip it if neither is done */ -// Todo: monitor blockchains, ie complete extracting scriptsig -// mode to autocreate required outputs -// more better LP commands - -// depends on just three external functions: -// - basilisk_sendrawtransaction(coin,signedtx); -// - basilisk_value(rawtx->coin,0,0,myinfo->myaddr.persistent,argjson,0) -// basilisk_bitcoinrawtx(rawtx->coin,"",basilisktag,jint(valsobj,"timeout"),valsobj,V) - - // included from basilisk.c /* https://bitcointalk.org/index.php?topic=1340621.msg13828271#msg13828271 https://bitcointalk.org/index.php?topic=1364951 @@ -148,6 +138,10 @@ void basilisk_swap_finished(struct basilisk_swap *swap) free(swap->messages[i].data), swap->messages[i].data = 0; free(swap->messages), swap->messages = 0; swap->nummessages = 0; + if ( swap->N.pair >= 0 ) + nn_close(swap->N.pair); + if ( swap->utxo != 0 ) + swap->utxo->S.swap = 0; } uint32_t basilisk_quoteid(struct basilisk_request *rp) @@ -575,7 +569,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend) { - uint8_t sendbuf[32768]; int32_t sendlen; + uint8_t sendbuf[32768]; int32_t sendlen,retval = -1; if ( LP_swapdata_rawtx(swap,data,maxlen,rawtx) != 0 ) { if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) @@ -603,7 +597,15 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 basilisk_dontforget_update(swap,rawtx); //printf("sendlen.%d datalen.%d redeemlen.%d\n",sendlen,rawtx->datalen,rawtx->redeemlen); if ( suppress_swapsend == 0 ) - return(LP_swapsend(pairsock,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs)); + { + retval = LP_swapsend(pairsock,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs); + if ( LP_waitmempool(rawtx->coin->symbol,rawtx->I.signedtxid,10) < 0 ) + { + char str[65]; printf("failed to find %s %s in the mempool?\n",rawtx->name,bits256_str(str,rawtx->I.actualtxid)); + retval = -1; + } + return(retval); + } else { printf("suppress swapsend %x\n",msgbits); @@ -645,22 +647,20 @@ int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t } else return(-1); } -void LP_bobloop(void *_utxo) +void LP_bobloop(void *_swap) { - uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap; struct LP_utxoinfo *utxo = _utxo; + uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = _swap; fprintf(stderr,"start swap iambob\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + 10; - while ( (swap= utxo->swap) == 0 && time(NULL) < expiration ) - sleep(1); - if ( (utxo->swap= swap) != 0 ) + if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",10,utxo->pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",10,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); - else if ( LP_waitsend("choosei",10,utxo->pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + else if ( LP_waitsend("choosei",10,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); - else if ( LP_waitsend("mostprivs",10,utxo->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + else if ( LP_waitsend("mostprivs",10,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error waitsend mostprivs\n"); else if ( basilisk_bobscripts_set(swap,1,1) < 0 ) printf("error bobscripts deposit\n"); @@ -671,11 +671,11 @@ void LP_bobloop(void *_utxo) basilisk_bobdeposit_refund(swap,swap->I.putduration); //printf("depositlen.%d\n",swap->bobdeposit.I.datalen); LP_swapsfp_update(&swap->I.req); - if ( LP_waitfor(utxo->pair,swap,10,LP_verify_otherfee) < 0 ) + if ( LP_waitfor(swap->N.pair,swap,10,LP_verify_otherfee) < 0 ) printf("error waiting for alicefee\n"); - else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0) == 0 ) + else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0) == 0 ) printf("error sending bobdeposit\n"); - else if ( LP_waitfor(utxo->pair,swap,10,LP_verify_alicepayment) < 0 ) + else if ( LP_waitfor(swap->N.pair,swap,10,LP_verify_alicepayment) < 0 ) printf("error waiting for alicepayment\n"); else { @@ -689,45 +689,41 @@ void LP_bobloop(void *_utxo) } if ( basilisk_bobscripts_set(swap,0,1) < 0 ) printf("error bobscripts payment\n"); - else if ( LP_swapdata_rawtxsend(utxo->pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) + else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) printf("error sending bobpayment\n"); LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); } } basilisk_swap_finished(swap); - free(utxo->swap); + free(swap); } else printf("swap timed out\n"); - utxo->swap = 0; - nn_close(utxo->pair); - utxo->pair = -1; } -void LP_aliceloop(void *_qp) +void LP_aliceloop(void *_swap) { - uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = 0; struct LP_quoteinfo *qp = _qp; - fprintf(stderr,"start swap iamalice pair.%d\n",qp->pair); + uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = _swap; maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + 10; - swap = LP_swapinit(0,0,qp->privkey,&qp->R,qp); if ( swap != 0 ) { - if ( LP_sendwait("pubkeys",10,qp->pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); + if ( LP_sendwait("pubkeys",10,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); - else if ( LP_sendwait("choosei",10,qp->pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + else if ( LP_sendwait("choosei",10,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); - else if ( LP_sendwait("mostprivs",10,qp->pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + else if ( LP_sendwait("mostprivs",10,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error LP_sendwait mostprivs\n"); - else if ( basilisk_alicetxs(qp->pair,swap,data,maxlen) != 0 ) + else if ( basilisk_alicetxs(swap->N.pair,swap,data,maxlen) != 0 ) printf("basilisk_alicetxs error\n"); else { LP_swapsfp_update(&swap->I.req); - if ( LP_swapdata_rawtxsend(qp->pair,swap,0x80,data,maxlen,&swap->myfee,0x40,0) == 0 ) + if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x80,data,maxlen,&swap->myfee,0x40,0) == 0 ) printf("error sending alicefee\n"); - else if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobdeposit) < 0 ) + else if ( LP_waitfor(swap->N.pair,swap,10,LP_verify_bobdeposit) < 0 ) printf("error waiting for bobdeposit\n"); - else if ( LP_swapdata_rawtxsend(qp->pair,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0) == 0 ) + else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0) == 0 ) printf("error sending alicepayment\n"); else { @@ -736,7 +732,7 @@ void LP_aliceloop(void *_qp) printf("waiting for alicepayment to confirm\n"); sleep(3); } - if ( LP_waitfor(qp->pair,swap,10,LP_verify_bobpayment) < 0 ) + if ( LP_waitfor(swap->N.pair,swap,10,LP_verify_bobpayment) < 0 ) printf("error waiting for bobpayment\n"); else { @@ -745,7 +741,7 @@ void LP_aliceloop(void *_qp) printf("waiting for bobpayment to confirm\n"); sleep(3); } - if ( LP_swapdata_rawtxsend(qp->pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) + if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) printf("error sending alicespend\n"); while ( LP_numconfirms(swap,&swap->alicespend) < 1 ) { @@ -759,8 +755,8 @@ void LP_aliceloop(void *_qp) basilisk_swap_finished(swap); free(swap); } - nn_close(qp->pair); - free(qp); + free(data); + nn_close(swap->N.pair); } bits256 instantdex_derivekeypair(void *ctx,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 5c0c05dfd..a2ccbc9d5 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -189,35 +189,52 @@ int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 se else return(0); } -int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +int32_t LP_mempoolscan(char *symbol,bits256 txid) { - int32_t numconfirms = 100; -#ifndef BASILISK_DISABLEWAITTX - cJSON *txobj,*array; int32_t i,n; - numconfirms = -1; - if ( (txobj= LP_gettx(rawtx->coin->symbol,rawtx->I.signedtxid)) != 0 ) - { - numconfirms = jint(txobj,"confirmations"); - free_json(txobj); - } - else if ( (array= LP_getmempool(rawtx->coin->symbol)) != 0 ) + int32_t i,n; cJSON *array; + if ( (array= LP_getmempool(symbol)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; iI.signedtxid,jbits256i(array,i)) == 0 ) + if ( bits256_cmp(txid,jbits256i(array,i)) == 0 ) { - numconfirms = 0; printf("found tx in mempool slot.%d\n",i); - break; + return(i); } } free_json(array); } + return(-1); +} + +int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) +{ + int32_t numconfirms = 100; +#ifndef BASILISK_DISABLEWAITTX + cJSON *txobj; + numconfirms = -1; + if ( (txobj= LP_gettx(rawtx->coin->symbol,rawtx->I.signedtxid)) != 0 ) + { + numconfirms = jint(txobj,"confirmations"); + free_json(txobj); + } else if ( LP_mempoolscan(rawtx->coin->symbol,rawtx->I.signedtxid) >= 0 ) + numconfirms = 0; #endif return(numconfirms); } +int32_t LP_waitmempool(char *symbol,bits256 txid,int32_t duration) +{ + uint32_t expiration = (uint32_t)time(NULL) + duration; + while ( time(NULL) < expiration ) + { + if ( LP_mempoolscan(symbol,txid) >= 0 ) + return(0); + } + return(-1); +} + int32_t iguana_msgtx_Vset(uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,struct vin_info *V) { int32_t vini,j,scriptlen,p2shlen,userdatalen,siglen,plen,need_op0=0,len = 0; uint8_t *script,*redeemscript=0,*userdata=0; struct vin_info *vp; @@ -1530,7 +1547,7 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da printf("%02x",swap->aliceclaim.txbytes[i]); printf(" <- aliceclaim\n"); //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); - return(retval); + return(LP_waitmempool(swap->bobcoin.symbol,swap->bobdeposit.I.signedtxid,10)); } else printf("error signing aliceclaim suppress.%d vin.(%s)\n",swap->aliceclaim.I.suppress_pubkeys,swap->bobdeposit.I.destaddr); } printf("error with bobdeposit\n"); @@ -1548,7 +1565,8 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) swap->aliceunconf = 1; basilisk_dontforget_update(swap,&swap->alicepayment); - printf("import alicepayment address.(%s)\n",swap->alicepayment.p2shaddr); + return(LP_waitmempool(swap->alicecoin.symbol,swap->alicepayment.I.signedtxid,10)); + //printf("import alicepayment address.(%s)\n",swap->alicepayment.p2shaddr); //LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.p2shaddr); return(0); } @@ -1594,8 +1612,7 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da printf("%02x",swap->alicespend.txbytes[i]); printf(" <- alicespend\n\n"); swap->I.alicespent = 1; - //basilisk_txlog(swap,&swap->alicespend,-1); - return(retval); + return(LP_waitmempool(swap->bobcoin.symbol,swap->bobpayment.I.signedtxid,10)); } else printf("error signing aliceclaim suppress.%d vin.(%s)\n",swap->alicespend.I.suppress_pubkeys,swap->bobpayment.I.destaddr); } printf("error validating bobpayment\n"); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 02db3e90c..b0713e810 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -20,75 +20,212 @@ int32_t LP_ismine(struct LP_utxoinfo *utxo) { - if ( strcmp(utxo->ipaddr,"127.0.0.1") == 0 ) + if ( bits256_cmp(utxo->pubkey,LP_mypubkey) != 0 ) return(1); else if ( LP_mypeer == 0 ) return(0); - else if ( strcmp(utxo->ipaddr,LP_mypeer->ipaddr) == 0 && utxo->port == LP_mypeer->port )\ + else return(0); +} + +int32_t LP_isavailable(struct LP_utxoinfo *utxo) +{ + if ( utxo->T.swappending == 0 && utxo->S.swap == 0 ) return(1); else return(0); } int32_t LP_isunspent(struct LP_utxoinfo *utxo) { - if ( utxo->spentflag == 0 && utxo->swappending == 0 ) + if ( utxo->T.spentflag == 0 && LP_isavailable(utxo) > 0 ) return(1); else return(0); } -struct LP_utxoinfo *LP_utxofind(bits256 txid,int32_t vout) +void LP_utxosetkey(uint8_t *key,bits256 txid,int32_t vout) { - struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; memcpy(key,txid.bytes,sizeof(txid)); memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); +} + +struct LP_utxoinfo *_LP_utxofind(int32_t iambob,bits256 txid,int32_t vout) +{ + struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; + LP_utxosetkey(key,txid,vout); + HASH_FIND(hh,LP_utxoinfos[iambob],key,sizeof(key),utxo); + return(utxo); +} + +struct LP_utxoinfo *_LP_utxo2find(int32_t iambob,bits256 txid2,int32_t vout2) +{ + struct LP_utxoinfo *utxo=0; uint8_t key2[sizeof(txid2) + sizeof(vout2)]; + LP_utxosetkey(key2,txid2,vout2); + HASH_FIND(hh2,LP_utxoinfos2[iambob],key2,sizeof(key2),utxo); + return(utxo); +} + +struct LP_utxoinfo *LP_utxofind(int32_t iambob,bits256 txid,int32_t vout) +{ + struct LP_utxoinfo *utxo=0; portable_mutex_lock(&LP_utxomutex); - HASH_FIND(hh,LP_utxoinfos,key,sizeof(key),utxo); + utxo = _LP_utxofind(iambob,txid,vout); portable_mutex_unlock(&LP_utxomutex); return(utxo); } -struct LP_utxoinfo *_LP_utxo2find(bits256 txid,int32_t vout) +struct LP_utxoinfo *LP_utxo2find(int32_t iambob,bits256 txid2,int32_t vout2) { - struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; - memcpy(key,txid.bytes,sizeof(txid)); - memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); - HASH_FIND(hh2,LP_utxoinfos2,key,sizeof(key),utxo); + struct LP_utxoinfo *utxo=0; + portable_mutex_lock(&LP_utxomutex); + utxo = _LP_utxo2find(iambob,txid2,vout2); + portable_mutex_unlock(&LP_utxomutex); return(utxo); } -struct LP_utxoinfo *LP_utxo2find(bits256 txid,int32_t vout) +int32_t LP_utxoaddptrs(struct LP_utxoinfo *ptrs[],int32_t n,struct LP_utxoinfo *utxo) { - struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; - memcpy(key,txid.bytes,sizeof(txid)); - memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); + int32_t i; + for (i=0; ipayment.txid,refutxo->payment.vout)) != 0 && utxo != refutxo ) + n = LP_utxoaddptrs(ptrs,n,utxo); + if ( (utxo= _LP_utxo2find(iambob,refutxo->payment.txid,refutxo->payment.vout)) != 0 && utxo != refutxo ) + n = LP_utxoaddptrs(ptrs,n,utxo); + u = (refutxo->iambob != 0) ? refutxo->deposit : refutxo->fee; + if ( (utxo= _LP_utxofind(iambob,u.txid,u.vout)) != 0 && utxo != refutxo ) + n = LP_utxoaddptrs(ptrs,n,utxo); + if ( (utxo= _LP_utxo2find(iambob,u.txid,u.vout)) != 0 && utxo != refutxo ) + n = LP_utxoaddptrs(ptrs,n,utxo); + } portable_mutex_unlock(&LP_utxomutex); - return(utxo); + if ( n > 0 ) + printf("LP_utxocollisions n.%d\n",n); + return(n); +} + +void _LP_availableset(struct LP_utxoinfo *utxo) +{ + if ( utxo != 0 ) + { + memset(&utxo->S.otherpubkey,0,sizeof(utxo->S.otherpubkey)); + utxo->S.swap = 0; + utxo->T.swappending = 0; + } +} + +void _LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) +{ + if ( utxo != 0 ) + { + utxo->T.swappending = (uint32_t)(time(NULL) + LP_RESERVETIME); + utxo->S.otherpubkey = otherpubkey; + } +} + +void LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) +{ + struct LP_utxoinfo *ptrs[8]; int32_t i,n; + memset(ptrs,0,sizeof(ptrs)); + if ( (n= LP_utxocollisions(ptrs,utxo)) > 0 ) + { + for (i=0; ipayment.txid),utxo->payment.vout,n); + _LP_unavailableset(utxo,otherpubkey); +} + +void LP_availableset(struct LP_utxoinfo *utxo) +{ + struct LP_utxoinfo *ptrs[8]; int32_t i,n; + memset(ptrs,0,sizeof(ptrs)); + if ( (n= LP_utxocollisions(ptrs,utxo)) > 0 ) + { + for (i=0; ipayment.txid),utxo->payment.vout,n); + _LP_availableset(utxo); +} + +int32_t LP_utxopurge(int32_t allutxos) +{ + struct LP_utxoinfo *utxo,*tmp; int32_t iambob,n = 0; + portable_mutex_lock(&LP_utxomutex); + for (iambob=0; iambob<=1; iambob++) + { + HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) + { + if ( allutxos != 0 || LP_ismine(utxo) == 0 ) + { + if ( LP_isavailable(utxo) == 0 ) + { + HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); + free(utxo); + } else n++; + } else n++; + } + HASH_ITER(hh,LP_utxoinfos2[iambob],utxo,tmp) + { + if ( allutxos != 0 || LP_ismine(utxo) == 0 ) + { + if ( LP_isavailable(utxo) == 0 ) + { + HASH_DELETE(hh,LP_utxoinfos2[iambob],utxo); + free(utxo); + } else n++; + } else n++; + } + } + portable_mutex_unlock(&LP_utxomutex); + return(n); } cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { + struct _LP_utxoinfo u; jaddstr(item,"coin",utxo->coin); jaddnum(item,"now",time(NULL)); jaddstr(item,"address",utxo->coinaddr); - jaddbits256(item,"txid",utxo->txid); - jaddnum(item,"vout",utxo->vout); - jadd64bits(item,"value",utxo->value); - jadd64bits(item,"satoshis",utxo->satoshis); - jaddbits256(item,"txid2",utxo->txid2); - jaddnum(item,"vout2",utxo->vout2); - jadd64bits(item,"value2",utxo->value2); - if ( utxo->swappending != 0 ) - jaddnum(item,"pending",utxo->swappending); - if ( bits256_nonz(utxo->otherpubkey) != 0 ) - jaddbits256(item,"desthash",utxo->otherpubkey); - if ( utxo->pair >= 0 ) - jaddnum(item,"socket",utxo->pair); - if ( utxo->swap != 0 ) + jaddbits256(item,"txid",utxo->payment.txid); + jaddnum(item,"vout",utxo->payment.vout); + jadd64bits(item,"value",utxo->payment.value); + jadd64bits(item,"satoshis",utxo->S.satoshis); + u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; + if ( bits256_nonz(u.txid) != 0 ) + { + jaddbits256(item,"txid2",u.txid); + jaddnum(item,"vout2",u.vout); + jadd64bits(item,"value2",u.value); + } + if ( utxo->T.swappending != 0 ) + jaddnum(item,"pending",utxo->T.swappending); + if ( utxo->iambob != 0 ) + { + jaddbits256(item,"srchash",LP_mypubkey); + if ( bits256_nonz(utxo->S.otherpubkey) != 0 ) + jaddbits256(item,"desthash",utxo->S.otherpubkey); + } + else + { + jaddbits256(item,"desthash",LP_mypubkey); + if ( bits256_nonz(utxo->S.otherpubkey) != 0 ) + jaddbits256(item,"srchash",utxo->S.otherpubkey); + } + if ( utxo->S.swap != 0 ) jaddstr(item,"swap","in progress"); - if ( utxo->spentflag != 0 ) - jaddnum(item,"spent",utxo->spentflag); + if ( utxo->T.spentflag != 0 ) + jaddnum(item,"spent",utxo->T.spentflag); return(item); } @@ -96,26 +233,25 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) { cJSON *item = cJSON_CreateObject(); item = LP_inventoryjson(item,utxo); - jaddstr(item,"ipaddr",utxo->ipaddr); - jaddnum(item,"port",utxo->port); - jaddnum(item,"profit",utxo->profitmargin); + jaddbits256(item,"pubkey",utxo->pubkey); + jaddnum(item,"profit",utxo->S.profitmargin); jaddstr(item,"base",utxo->coin); jaddstr(item,"script",utxo->spendscript); return(item); } -char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) +char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *coin,int32_t lastn) { int32_t i,firsti; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); i = 0; if ( lastn >= mypeer->numutxos ) firsti = -1; else firsti = (mypeer->numutxos - lastn); - HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { if ( i++ < firsti ) continue; - if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) && utxo->spentflag == 0 )//&& LP_ismine(utxo) != 0 ) + if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) != 0 ) { jaddi(utxosjson,LP_utxojson(utxo)); } @@ -125,20 +261,23 @@ char *LP_utxos(struct LP_peerinfo *mypeer,char *coin,int32_t lastn) void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) { - cJSON *argjson; - utxo->spentflag = (uint32_t)time(NULL); + cJSON *argjson; struct _LP_utxoinfo u; + utxo->T.spentflag = (uint32_t)time(NULL); if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) LP_mypeer->numutxos--; if ( LP_mypubsock >= 0 ) { argjson = cJSON_CreateObject(); jaddstr(argjson,"method","checktxid"); - jaddbits256(argjson,"txid",utxo->txid); - jaddnum(argjson,"vout",utxo->vout); + jaddbits256(argjson,"txid",utxo->payment.txid); + jaddnum(argjson,"vout",utxo->payment.vout); if ( selector != 0 ) { - jaddbits256(argjson,"checktxid",utxo->txid2); - jaddnum(argjson,"checkvout",utxo->vout2); + if ( bits256_nonz(utxo->deposit.txid) != 0 ) + u = utxo->deposit; + else u = utxo->fee; + jaddbits256(argjson,"checktxid",u.txid); + jaddnum(argjson,"checkvout",u.vout); } LP_send(LP_mypubsock,jprint(argjson,1),1); } @@ -146,35 +285,41 @@ void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) char *LP_spentcheck(cJSON *argjson) { - bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; + bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; int32_t iambob,retval = 0; txid = jbits256(argjson,"txid"); vout = jint(argjson,"vout"); - if ( (utxo= LP_utxofind(txid,vout)) != 0 && utxo->spentflag == 0 ) + for (iambob=0; iambob<=1; iambob++) { - if ( jobj(argjson,"check") == 0 ) - checktxid = txid, checkvout = vout; - else + if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 && utxo->T.spentflag == 0 ) { - checktxid = jbits256(argjson,"checktxid"); - checkvout = jint(argjson,"checkvout"); + if ( jobj(argjson,"check") == 0 ) + checktxid = txid, checkvout = vout; + else + { + checktxid = jbits256(argjson,"checktxid"); + checkvout = jint(argjson,"checkvout"); + } + if ( LP_txvalue(utxo->coin,checktxid,checkvout) == 0 ) + { + //if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) + // LP_mypeer->numutxos--; + utxo->T.spentflag = (uint32_t)time(NULL); + retval++; + //printf("indeed txid was spent\n"); + } } - if ( LP_txvalue(utxo->coin,checktxid,checkvout) == 0 ) - { - if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) - LP_mypeer->numutxos--; - utxo->spentflag = (uint32_t)time(NULL); - //printf("indeed txid was spent\n"); - return(clonestr("{\"result\":\"marked as spent\"}")); - } else return(clonestr("{\"error\":\"txid is still unspent?\"}")); - } else return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); + } + if ( retval > 0 ) + return(clonestr("{\"result\":\"marked as spent\"}")); + return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); } -int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) +int32_t LP_iseligible(int32_t iambob,char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) { uint64_t val,val2,threshold; if ( (val= LP_txvalue(coin,txid,vout)) >= satoshis ) { - threshold = (IAMCLIENT == 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); + threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); if ( (val2= LP_txvalue(coin,txid2,vout2)) >= threshold ) { //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); @@ -184,66 +329,65 @@ int32_t LP_iseligible(char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bit return(0); } -struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,char *ipaddr,uint16_t port,double profitmargin) +struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - uint64_t tmpsatoshis; struct LP_utxoinfo *utxo = 0; + uint64_t tmpsatoshis; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } - if ( IAMCLIENT == 0 && value2 < 9 * (value >> 3) + 100000 ) + if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) tmpsatoshis = (((value2-100000) / 9) << 3); else tmpsatoshis = value; - if ( LP_iseligible(coin,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) + if ( LP_iseligible(iambob,coin,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("LP_addutxo got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); } - if ( IAMCLIENT == 0 && strcmp(ipaddr,"127.0.0.1") == 0 ) - { - //printf("LP node got localhost utxo\n"); - return(0); - } - if ( (utxo= LP_utxofind(txid,vout)) != 0 || (utxo= LP_utxo2find(txid,vout)) != 0 ) + if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 || (utxo= LP_utxo2find(iambob,txid,vout)) != 0 ) { //printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); - if ( bits256_cmp(txid,utxo->txid) != 0 || bits256_cmp(txid2,utxo->txid2) != 0 || vout != utxo->vout || value != utxo->value || tmpsatoshis != utxo->satoshis || vout2 != utxo->vout2 || value2 != utxo->value2 || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || strcmp(ipaddr,utxo->ipaddr) != 0 || port != utxo->port ) + u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; + if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { - utxo->errors++; - char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->txid),bits256_cmp(txid,utxo->txid) != 0,bits256_cmp(txid2,utxo->txid2) != 0,vout != utxo->vout,tmpsatoshis != utxo->satoshis,vout2 != utxo->vout2,value2 != utxo->value2,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,strcmp(ipaddr,utxo->ipaddr) != 0,port != utxo->port,value != utxo->value); + utxo->T.errors++; + char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->payment.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value); } else if ( profitmargin != 0. ) - utxo->profitmargin = profitmargin; + utxo->S.profitmargin = profitmargin; } else { utxo = calloc(1,sizeof(*utxo)); - utxo->pair = -1; - utxo->profitmargin = profitmargin; - strcpy(utxo->ipaddr,ipaddr); - utxo->port = port; + utxo->S.profitmargin = profitmargin; + utxo->pubkey = pubkey; safecopy(utxo->coin,coin,sizeof(utxo->coin)); safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); - utxo->txid = txid; - utxo->vout = vout; - utxo->value = value; - utxo->satoshis = tmpsatoshis; - utxo->txid2 = txid2; - utxo->vout2 = vout2; - utxo->value2 = value2; - memcpy(utxo->key,txid.bytes,sizeof(txid)); - memcpy(&utxo->key[sizeof(txid)],&vout,sizeof(vout)); - memcpy(utxo->key2,txid2.bytes,sizeof(txid2)); - memcpy(&utxo->key2[sizeof(txid2)],&vout2,sizeof(vout2)); - char str[65],str2[65]; printf("amclient.%d %s:%u %s LP_addutxo.(%.8f %.8f) numutxos.%d %s %s\n",IAMCLIENT,ipaddr,port,utxo->coin,dstr(value),dstr(value2),mypeer!=0?mypeer->numutxos:0,bits256_str(str,utxo->txid),bits256_str(str2,txid2)); + utxo->payment.txid = txid; + utxo->payment.vout = vout; + utxo->payment.value = value; + utxo->S.satoshis = tmpsatoshis; + if ( (utxo->iambob= iambob) != 0 ) + { + utxo->deposit.txid = txid2; + utxo->deposit.vout = vout2; + utxo->deposit.value = value2; + } + else + { + utxo->fee.txid = txid2; + utxo->fee.vout = vout2; + utxo->fee.value = value2; + } + LP_utxosetkey(utxo->key,txid,vout); + LP_utxosetkey(utxo->key2,txid2,vout2); + char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); - HASH_ADD_KEYPTR(hh,LP_utxoinfos,utxo->key,sizeof(utxo->key),utxo); - if ( _LP_utxo2find(txid2,vout2) == 0 ) - HASH_ADD_KEYPTR(hh2,LP_utxoinfos2,utxo->key2,sizeof(utxo->key2),utxo); - if ( mypeer != 0 ) - mypeer->numutxos++; + HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); + if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) + HASH_ADD_KEYPTR(hh2,LP_utxoinfos2[iambob],utxo->key2,sizeof(utxo->key2),utxo); portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); @@ -251,10 +395,10 @@ struct LP_utxoinfo *LP_addutxo(int32_t amclient,struct LP_peerinfo *mypeer,int32 return(utxo); } -int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { - struct LP_peerinfo *peer,*destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; - if ( amclient != 0 ) + struct LP_peerinfo *destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + if ( IAMLP == 0 ) { printf("LP_utxosparse not for clientside\n"); return(-1); @@ -273,16 +417,16 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs if ( (subport= juint(item,"sub")) == 0 ) subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); - if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(amclient,mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + //if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) + // peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); //printf("parse.(%s)\n",jprint(item,0)); - utxo = LP_addutxo(amclient,mypeer,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),j64bits(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),j64bits(item,"value2"),jstr(item,"script"),jstr(item,"address"),argipaddr,argport,jdouble(item,"profit")); + utxo = LP_addutxo(1,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),j64bits(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),j64bits(item,"value2"),jstr(item,"script"),jstr(item,"address"),jbits256(item,"pubkey"),jdouble(item,"profit")); if ( utxo != 0 ) { - utxo->lasttime = now; + utxo->T.lasttime = now; } } } // else printf("skip.(%s)\n",jprint(item,0)); @@ -297,10 +441,10 @@ int32_t LP_utxosparse(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubs return(n); } -void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) +void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { char *retstr; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now; - if ( amclient != 0 ) + if ( IAMLP == 0 ) { printf("LP_utxosquery not for clientside\n"); return; @@ -313,7 +457,7 @@ void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) { now = (uint32_t)time(NULL); - LP_utxosparse(amclient,mypeer,mypubsock,destipaddr,destport,retstr,now); + LP_utxosparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); i = 0; if ( lastn >= mypeer->numutxos ) @@ -337,16 +481,17 @@ void LP_utxosquery(int32_t amclient,struct LP_peerinfo *mypeer,int32_t mypubsock peer->errors++; } -char *LP_inventory(char *symbol) +char *LP_inventory(char *symbol,int32_t iambob) { - struct LP_utxoinfo *utxo,*tmp; char *myipaddr; cJSON *array = cJSON_CreateArray(); + struct LP_utxoinfo *utxo,*tmp; char *myipaddr; cJSON *array; + array = cJSON_CreateArray(); if ( LP_mypeer != 0 ) myipaddr = LP_mypeer->ipaddr; else myipaddr = "127.0.0.1"; - HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { //char str[65]; printf("iterate %s\n",bits256_str(str,utxo->txid)); - if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && (IAMCLIENT != 0 || LP_ismine(utxo) != 0) ) + if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) != 0 ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } return(jprint(array,1)); @@ -381,10 +526,10 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) return(mini); } -uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t amclient) +uint64_t LP_privkey_init(int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t iambob) { static uint32_t counter; - char *script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 userpass,userpub,txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + char *script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 userpass,userpub,txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey,mypub; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); if ( coin == 0 ) { printf("cant add privkey for %s, coin not active\n",symbol); @@ -413,6 +558,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb } bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); + LP_mypubkey = mypub = curve25519(privkey,curve25519_basepoint9()); if ( coin->inactive == 0 && (array= LP_listunspent(symbol,coin->smartaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) @@ -438,7 +584,7 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb script = jstr(item,"scriptPubKey"); depositval = values[i]; values[i] = 0, used++; - if ( amclient != 0 ) + if ( iambob == 0 ) targetval = (depositval / 776) + 100000; else targetval = (depositval / 9) * 8 + 100000; //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); @@ -451,15 +597,19 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb { value = values[i]; values[i] = 0, used++; - if ( amclient == 0 ) + if ( iambob != 0 ) { - if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,LP_peerinfos[0].ipaddr,LP_peerinfos[0].port,LP_peerinfos[0].profitmargin)) != 0 ) - utxo->mypub = curve25519(privkey,curve25519_basepoint9()); + if ( (utxo= LP_addutxo(1,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_peerinfos[0].profitmargin)) != 0 ) + { + //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); + } } else { - if ( (utxo= LP_addutxo(amclient,mypeer,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,"127.0.0.1",0,0)) != 0 ) - utxo->mypub = curve25519(privkey,curve25519_basepoint9()); + if ( (utxo= LP_addutxo(0,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0)) != 0 ) + { + //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); + } } total += value; } @@ -474,13 +624,13 @@ uint64_t LP_privkey_init(struct LP_peerinfo *mypeer,int32_t mypubsock,char *symb return(total); } -void LP_privkey_updates(struct LP_peerinfo *mypeer,int32_t pubsock,char *passphrase,int32_t amclient) +void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t iambob) { int32_t i; for (i=0; i Date: Sun, 11 Jun 2017 11:04:56 +0300 Subject: [PATCH 1229/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b0713e810..71417da7c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -352,7 +352,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *coin,bits2 if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { utxo->T.errors++; - char str[65],str2[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d\n",bits256_str(str,txid),bits256_str(str2,utxo->payment.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value); + char str[65],str2[65],str3[65],str4[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,txid),bits256_str(str2,utxo->payment.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); } else if ( profitmargin != 0. ) utxo->S.profitmargin = profitmargin; From 84505ec66c04b33c0adb7edba6eae62626fd3103 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 11:13:19 +0300 Subject: [PATCH 1230/2705] Test --- iguana/exchanges/LP_coins.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index c06acd1a1..4bda50ec5 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -250,7 +250,9 @@ struct iguana_info *LP_coinfind(char *symbol) assetname = symbol; } LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); - return(LP_coinadd(&cdata)); + if ( (coin= LP_coinadd(&cdata)) != 0 && strcmp(symbol,"KMD") == 0 ) + coin->inactive = 0; + return(coin); } // "coins":[{"coin":"", "rpcport":pppp}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }] From e4277bf688157bd92d9a5b30bae118a287eef8a0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 11:15:53 +0300 Subject: [PATCH 1231/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 71417da7c..8c2156b2b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -332,6 +332,7 @@ int32_t LP_iseligible(int32_t iambob,char *coin,bits256 txid,int32_t vout,uint64 struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { uint64_t tmpsatoshis; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); From 970455b7e6ccca3769428daf4256a8d9bd53c8ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 11:16:44 +0300 Subject: [PATCH 1232/2705] tEst --- crypto777/bitcoind_RPC.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index 975208ddd..47e4e6d45 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -136,7 +136,7 @@ char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char * else specialcase = 0; if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7776"); - if ( specialcase != 0 && (0) ) + //if ( specialcase != 0 && (0) ) printf("<<<<<<<<<<< bitcoind_RPC: userpass.(%s) url.(%s) command.(%s) params.(%s)\n",userpass,url,command,params); try_again: if ( retstrp != 0 ) From 33253df15e94199bc80d83ebf08784ee5950332a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 11:21:33 +0300 Subject: [PATCH 1233/2705] Test --- crypto777/bitcoind_RPC.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 1 - iguana/exchanges/LP_rpc.c | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index 47e4e6d45..975208ddd 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -136,7 +136,7 @@ char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char * else specialcase = 0; if ( url[0] == 0 ) strcpy(url,"http://127.0.0.1:7776"); - //if ( specialcase != 0 && (0) ) + if ( specialcase != 0 && (0) ) printf("<<<<<<<<<<< bitcoind_RPC: userpass.(%s) url.(%s) command.(%s) params.(%s)\n",userpass,url,command,params); try_again: if ( retstrp != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b2d4e7369..594ed3d29 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -365,7 +365,6 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting sockets %d %d\n",pullsock,pubsock); LP_mypubsock = pubsock; LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); - //printf("my ipaddr.(%s) peers.(%s)\n",ipaddr,retstr!=0?retstr:""); } if ( myipaddr == 0 || mypeer == 0 ) { diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index f5e915a70..b97409744 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -79,11 +79,11 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) char *retstr; cJSON *retjson = 0; if ( coin != 0 ) { - //printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); + printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) { - //printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); + printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); retjson = cJSON_Parse(retstr); free(retstr); } From dd085a31664814a154b897d3cc4b426a01aab11d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 11:24:03 +0300 Subject: [PATCH 1234/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++++ iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 594ed3d29..8142583b0 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -219,10 +219,14 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in LP_priceinfoadd(jstr(item,"coin")); } } + printf("update alice\n"); LP_privkey_updates(pubsock,passphrase,0); + printf("update bob\n"); LP_privkey_updates(pubsock,passphrase,1); + printf("update swaps\n"); if ( (retstr= basilisk_swaplist()) != 0 ) free(retstr); + printf("update peers\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( strcmp(peer->ipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) @@ -231,6 +235,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } } + printf("mainloop\n"); if ( IAMLP == 0 ) { while ( 1 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index b97409744..a2faa85c2 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -89,7 +89,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) } //usleep(1000); //printf("dpow_gettxout.(%s)\n",retstr); - } + } else printf("bitcoin_json cant talk to NULL coin\n"); return(retjson); } From 63f6ad30fa1dedd1169b35b4f955e8ca4599b81a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 11:26:17 +0300 Subject: [PATCH 1235/2705] Test --- iguana/exchanges/LP_utxos.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 8c2156b2b..6c9f87e5f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -329,19 +329,19 @@ int32_t LP_iseligible(int32_t iambob,char *coin,bits256 txid,int32_t vout,uint64 return(0); } -struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *coin,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) +struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { uint64_t tmpsatoshis; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; - char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); - if ( coin == 0 || coin[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) + char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); + if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { - printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", coin == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); + printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) tmpsatoshis = (((value2-100000) / 9) << 3); else tmpsatoshis = value; - if ( LP_iseligible(iambob,coin,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) + if ( LP_iseligible(iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("LP_addutxo got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); @@ -350,10 +350,10 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *coin,bits2 { //printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; - if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(coin,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) + if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { utxo->T.errors++; - char str[65],str2[65],str3[65],str4[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,txid),bits256_str(str2,utxo->payment.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(coin,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); + char str[65],str2[65],str3[65],str4[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,txid),bits256_str(str2,utxo->payment.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); } else if ( profitmargin != 0. ) utxo->S.profitmargin = profitmargin; @@ -363,7 +363,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *coin,bits2 utxo = calloc(1,sizeof(*utxo)); utxo->S.profitmargin = profitmargin; utxo->pubkey = pubkey; - safecopy(utxo->coin,coin,sizeof(utxo->coin)); + safecopy(utxo->coin,symbol,sizeof(utxo->coin)); safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); utxo->payment.txid = txid; From 83c2a64c252f51267616e6793e28ead649383896 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 12:02:04 +0300 Subject: [PATCH 1236/2705] Test --- iguana/exchanges/LP_commands.c | 15 +++++- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 4 +- iguana/exchanges/LP_utxos.c | 81 ++++++++++++++++++-------------- 4 files changed, 63 insertions(+), 39 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 5972a432a..9625908f3 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -304,8 +304,19 @@ forward(pubkey,hexstr)\n\ return(clonestr("{\"error\":\"coin is disabled\"}")); if ( strcmp(method,"inventory") == 0 ) { - LP_privkey_init(-1,coin,0,USERPASS_WIFSTR,0); - return(LP_inventory(coin,jobj(argjson,"client") != 0 ? jint(argjson,"client") : 0)); + struct iguana_info *ptr; bits256 privkey,pubkey; uint8_t pubkey33[33]; + if ( (ptr= LP_coinfind(coin)) != 0 ) + { + privkey = LP_privkeycalc(pubkey33,&pubkey,ptr,"",USERPASS_WIFSTR); + LP_utxopurge(0); + LP_privkey_init(-1,ptr,privkey,pubkey,pubkey33,0); + LP_privkey_init(-1,ptr,privkey,pubkey,pubkey33,1); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","success"); + jadd(retjson,"alice",LP_inventory(coin,0)); + jadd(retjson,"bob",LP_inventory(coin,1)); + return(jprint(retjson,1)); + } } else if ( (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) { diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 2dd260294..aea5d91e9 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -49,7 +49,7 @@ char *LP_lookup(bits256 pubkey) char *LP_register(bits256 pubkey,char *pushaddr) { struct LP_forwardinfo *ptr=0; int32_t pushsock; - if ( is_ipaddr(pushaddr) == 0 ) + if ( is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) return(clonestr("{\"error\":\"illegal ipaddr\"}")); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 8142583b0..15f88dea8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -247,7 +247,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in lastforward = now; } nonz = n = 0; - if ( (++counter % 5000) == 0 ) + if ( (++counter % 6000) == 0 ) LP_utxo_updates(pubsock,passphrase,profitmargin); HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -270,7 +270,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in while ( 1 ) { nonz = 0; - if ( (counter % 500) == 0 ) + if ( (counter % 600) == 0 ) LP_utxo_updates(pubsock,passphrase,profitmargin); now = (uint32_t)time(NULL); //printf("start peers updates\n"); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6c9f87e5f..7ce7588cd 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -482,7 +482,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr peer->errors++; } -char *LP_inventory(char *symbol,int32_t iambob) +cJSON *LP_inventory(char *symbol,int32_t iambob) { struct LP_utxoinfo *utxo,*tmp; char *myipaddr; cJSON *array; array = cJSON_CreateArray(); @@ -495,7 +495,7 @@ char *LP_inventory(char *symbol,int32_t iambob) if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) != 0 ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } - return(jprint(array,1)); + return(array); } int32_t LP_maxvalue(uint64_t *values,int32_t n) @@ -527,40 +527,16 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) return(mini); } -uint64_t LP_privkey_init(int32_t mypubsock,char *symbol,char *passphrase,char *wifstr,int32_t iambob) +uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 myprivkey,bits256 mypub,uint8_t *pubkey33,int32_t iambob) { - static uint32_t counter; - char *script; struct LP_utxoinfo *utxo; cJSON *array,*item,*retjson; bits256 userpass,userpub,txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; bits256 privkey,pubkey,mypub; uint8_t pubkey33[33],tmptype,rmd160[20]; struct iguana_info *coin = LP_coinfind(symbol); + char *script; struct LP_utxoinfo *utxo; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; if ( coin == 0 ) { - printf("cant add privkey for %s, coin not active\n",symbol); + printf("coin not active\n"); return(0); } //printf("privkey init.(%s) %s\n",symbol,coin->symbol); - if ( passphrase != 0 ) - conv_NXTpassword(privkey.bytes,pubkey.bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); - else privkey = iguana_wif2privkey(wifstr); - iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); - if ( coin->counter == 0 ) - { - char tmpstr[128]; - coin->counter++; - bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - if ( counter++ == 0 ) - { - bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); - conv_NXTpassword(userpass.bytes,pubkey.bytes,(uint8_t *)tmpstr,(int32_t)strlen(tmpstr)); - userpub = curve25519(userpass,curve25519_basepoint9()); - printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); - } - printf("%s (%s) %d wif.(%s) (%s)\n",symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); - if ( coin->inactive == 0 && (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) - printf("importprivkey -> (%s)\n",jprint(retjson,1)); - } - bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); - LP_privkeyadd(privkey,rmd160); - LP_mypubkey = mypub = curve25519(privkey,curve25519_basepoint9()); - if ( coin->inactive == 0 && (array= LP_listunspent(symbol,coin->smartaddr)) != 0 ) + if ( coin->inactive == 0 && (array= LP_listunspent(coin->symbol,coin->smartaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { @@ -600,14 +576,14 @@ uint64_t LP_privkey_init(int32_t mypubsock,char *symbol,char *passphrase,char *w values[i] = 0, used++; if ( iambob != 0 ) { - if ( (utxo= LP_addutxo(1,mypubsock,symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_peerinfos[0].profitmargin)) != 0 ) + if ( (utxo= LP_addutxo(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_peerinfos[0].profitmargin)) != 0 ) { //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); } } else { - if ( (utxo= LP_addutxo(0,mypubsock,symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0)) != 0 ) + if ( (utxo= LP_addutxo(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0)) != 0 ) { //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); } @@ -625,13 +601,50 @@ uint64_t LP_privkey_init(int32_t mypubsock,char *symbol,char *passphrase,char *w return(total); } +bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *coin,char *passphrase,char *wifstr) +{ + static uint32_t counter; + bits256 privkey,userpub,userpass; char tmpstr[128]; cJSON *retjson; uint8_t tmptype,rmd160[20]; + if ( passphrase != 0 ) + conv_NXTpassword(privkey.bytes,pubkeyp->bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); + else privkey = iguana_wif2privkey(wifstr); + iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); + if ( coin->counter == 0 ) + { + coin->counter++; + bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); + bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); + LP_privkeyadd(privkey,rmd160); + printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); + if ( counter++ == 0 ) + { + bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); + conv_NXTpassword(userpass.bytes,pubkeyp->bytes,(uint8_t *)USERPASS_WIFSTR,(int32_t)strlen(USERPASS_WIFSTR)); + userpub = curve25519(userpass,curve25519_basepoint9()); + printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); + } + if ( coin->inactive == 0 && (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) + printf("importprivkey -> (%s)\n",jprint(retjson,1)); + } + LP_mypubkey = *pubkeyp = curve25519(privkey,curve25519_basepoint9()); + return(privkey); +} + void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t iambob) { - int32_t i; + int32_t i; struct iguana_info *coin; bits256 pubkey,privkey; uint8_t pubkey33[33]; + memset(privkey.bytes,0,sizeof(privkey)); + pubkey = privkey; for (i=0; ismartaddr[0] == 0 ) + privkey = LP_privkeycalc(pubkey33,&pubkey,coin,passphrase,""); + if ( coin->inactive == 0 ) + LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33,iambob); + } } } From 56aa3712bbdbd981d8e3e3dbd799bff782755c8d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 12:09:07 +0300 Subject: [PATCH 1237/2705] Test --- iguana/exchanges/LP_commands.c | 3 +- iguana/exchanges/LP_nativeDEX.c | 16 ++---- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_utxos.c | 96 +++++++++++++++++---------------- 4 files changed, 56 insertions(+), 61 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9625908f3..160bc1b40 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -309,8 +309,7 @@ forward(pubkey,hexstr)\n\ { privkey = LP_privkeycalc(pubkey33,&pubkey,ptr,"",USERPASS_WIFSTR); LP_utxopurge(0); - LP_privkey_init(-1,ptr,privkey,pubkey,pubkey33,0); - LP_privkey_init(-1,ptr,privkey,pubkey,pubkey33,1); + LP_privkey_init(-1,ptr,privkey,pubkey,pubkey33); retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); jadd(retjson,"alice",LP_inventory(coin,0)); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 15f88dea8..abcdb6915 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -167,16 +167,8 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) { - int32_t iambob; struct LP_utxoinfo *utxo,*tmp; LP_utxopurge(0); - for (iambob=0; iambob<=1; iambob++) - { - LP_privkey_updates(pubsock,passphrase,iambob); - HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) - { - LP_utxo_spentcheck(pubsock,utxo,profitmargin); - } - } + LP_privkey_updates(pubsock,passphrase); } void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins) @@ -219,10 +211,8 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in LP_priceinfoadd(jstr(item,"coin")); } } - printf("update alice\n"); - LP_privkey_updates(pubsock,passphrase,0); - printf("update bob\n"); - LP_privkey_updates(pubsock,passphrase,1); + printf("update utxos\n"); + LP_privkey_updates(pubsock,passphrase); printf("update swaps\n"); if ( (retstr= basilisk_swaplist()) != 0 ) free(retstr); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index a2faa85c2..cc53fdc2a 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -83,7 +83,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) { - printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); + //printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); retjson = cJSON_Parse(retstr); free(retstr); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7ce7588cd..a9940cd12 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -527,73 +527,79 @@ int32_t LP_nearestvalue(uint64_t *values,int32_t n,uint64_t targetval) return(mini); } -uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 myprivkey,bits256 mypub,uint8_t *pubkey33,int32_t iambob) +uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 myprivkey,bits256 mypub,uint8_t *pubkey33) { - char *script; struct LP_utxoinfo *utxo; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,vout,depositvout; uint64_t *values,satoshis,depositval,targetval,value,total = 0; + char *script; struct LP_utxoinfo *utxo; cJSON *array,*item; bits256 txid,deposittxid; int32_t used,i,n,iambob,vout,depositvout; uint64_t *values=0,satoshis,depositval,targetval,value,total = 0; if ( coin == 0 ) { printf("coin not active\n"); return(0); } - //printf("privkey init.(%s) %s\n",symbol,coin->symbol); + printf("privkey init.(%s)\n",coin->symbol); if ( coin->inactive == 0 && (array= LP_listunspent(coin->symbol,coin->smartaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { - values = calloc(n,sizeof(*values)); - for (i=0; i= 0 ) + if ( iambob == 0 ) + values = calloc(n,sizeof(*values)); + else memset(values,0,n * sizeof(*values)); + for (i=0; i= 0 ) + satoshis = SATOSHIDEN * jdouble(item,"amount"); + values[i] = satoshis; + //printf("%.8f ",dstr(satoshis)); + } + //printf("array.%d\n",n); + used = 0; + while ( used < n-1 ) + { + //printf("used.%d of n.%d\n",used,n); + if ( (i= LP_maxvalue(values,n)) >= 0 ) { item = jitem(array,i); - txid = jbits256(item,"txid"); - vout = juint(item,"vout"); - if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 ) + deposittxid = jbits256(item,"txid"); + depositvout = juint(item,"vout"); + script = jstr(item,"scriptPubKey"); + depositval = values[i]; + values[i] = 0, used++; + if ( iambob == 0 ) + targetval = (depositval / 776) + 100000; + else targetval = (depositval / 9) * 8 + 100000; + //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); + if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) { - value = values[i]; - values[i] = 0, used++; - if ( iambob != 0 ) + item = jitem(array,i); + txid = jbits256(item,"txid"); + vout = juint(item,"vout"); + if ( jstr(item,"scriptPubKey") != 0 && strcmp(script,jstr(item,"scriptPubKey")) == 0 ) { - if ( (utxo= LP_addutxo(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_peerinfos[0].profitmargin)) != 0 ) + value = values[i]; + values[i] = 0, used++; + if ( iambob != 0 ) { - //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); + if ( (utxo= LP_addutxo(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_peerinfos[0].profitmargin)) != 0 ) + { + //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); + } } - } - else - { - if ( (utxo= LP_addutxo(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0)) != 0 ) + else { - //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); + if ( (utxo= LP_addutxo(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0)) != 0 ) + { + //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); + } } + total += value; } - total += value; } - } - } else break; + } else break; + } + if ( iambob == 1 ) + free(values); } - free(values); } free_json(array); } @@ -630,7 +636,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co return(privkey); } -void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t iambob) +void LP_privkey_updates(int32_t pubsock,char *passphrase) { int32_t i; struct iguana_info *coin; bits256 pubkey,privkey; uint8_t pubkey33[33]; memset(privkey.bytes,0,sizeof(privkey)); @@ -643,7 +649,7 @@ void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t iambob) if ( bits256_nonz(privkey) == 0 || coin->smartaddr[0] == 0 ) privkey = LP_privkeycalc(pubkey33,&pubkey,coin,passphrase,""); if ( coin->inactive == 0 ) - LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33,iambob); + LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33); } } } From f327475bb71a6bf7563745b7e0d5320fec35e767 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 12:10:56 +0300 Subject: [PATCH 1238/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index abcdb6915..558867e62 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -251,7 +251,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in lastforward = now; } } - if ( nonz == 0 ) + //if ( nonz == 0 ) usleep(200000); } } @@ -289,7 +289,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } if ( pullsock >= 0 ) nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); - if ( nonz == 0 ) + //if ( nonz == 0 ) usleep(100000); //printf("nonz.%d in mainloop\n",nonz); } From 25be0292d7781cff44ea18b60832ebc541e01eb5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 12:12:36 +0300 Subject: [PATCH 1239/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 558867e62..ceea4a5be 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -237,7 +237,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in lastforward = now; } nonz = n = 0; - if ( (++counter % 6000) == 0 ) + if ( (counter % 6000) == 0 ) LP_utxo_updates(pubsock,passphrase,profitmargin); HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -251,8 +251,9 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in lastforward = now; } } - //if ( nonz == 0 ) + if ( nonz == 0 ) usleep(200000); + counter++; } } else @@ -289,8 +290,9 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } if ( pullsock >= 0 ) nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); - //if ( nonz == 0 ) + if ( nonz == 0 ) usleep(100000); + counter++; //printf("nonz.%d in mainloop\n",nonz); } } From a3228c9b3ba2cc0f51bdc1b352497e488b0c5850 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 12:14:18 +0300 Subject: [PATCH 1240/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a9940cd12..87f5d0b78 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -624,7 +624,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( counter++ == 0 ) { - bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); + bitcoin_priv2wif(USERPASS_WIFSTR,privkey,0); conv_NXTpassword(userpass.bytes,pubkeyp->bytes,(uint8_t *)USERPASS_WIFSTR,(int32_t)strlen(USERPASS_WIFSTR)); userpub = curve25519(userpass,curve25519_basepoint9()); printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); From 2bbb5ef8e6527a83d9c1351f5a0856b17086f049 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 12:59:28 +0300 Subject: [PATCH 1241/2705] Test --- iguana/exchanges/LP_commands.c | 31 ++++++++++-- iguana/exchanges/LP_transaction.c | 81 ++++++++++++++++++++++--------- iguana/exchanges/LP_utxos.c | 21 ++++++-- 3 files changed, 101 insertions(+), 32 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 160bc1b40..d8a89b65e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -120,11 +120,21 @@ int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson, char *LP_connected(cJSON *argjson) // alice { - cJSON *retjson; int32_t pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; - retjson = cJSON_CreateObject(); + cJSON *retjson; bits256 spendtxid; int32_t spendvini,selector,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; LP_quoteparse(&Q,argjson); if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) { + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) + { + char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(clonestr("{\"error\",\"src txid in mempool\"}")); + } + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) + { + char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(clonestr("{\"error\",\"dest txid in mempool\"}")); + } + retjson = cJSON_CreateObject(); if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) jaddstr(retjson,"error","couldnt create pairsock"); else if ( nn_connect(pairsock,pairstr) >= 0 ) @@ -145,19 +155,25 @@ char *LP_connected(cJSON *argjson) // alice jaddnum(retjson,"quoteid",Q.R.quoteid); } else jaddstr(retjson,"error","couldnt aliceloop"); } - } else jaddstr(retjson,"result","update stats"); - return(jprint(retjson,1)); + return(jprint(retjson,1)); + } else return(clonestr("{\"result\",\"update stats\"}")); } int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid; struct LP_utxoinfo *utxo; int32_t retval = -1; struct LP_quoteinfo Q; + char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) != 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { printf("LP_command.(%s)\n",jprint(argjson,0)); + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) + { + char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + utxo->T.spentflag = (uint32_t)time(NULL); + return(0); + } if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) utxo->T.swappending = 0; if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) // bob @@ -200,6 +216,11 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d else if ( strcmp(method,"connect") == 0 ) // bob { retval = 4; + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,jstr(argjson,"destcoin"),jbits256(argjson,"desttxid"),jint(argjson,"destvout"),jbits256(argjson,"feetxid"),jint(argjson,"feevout"))) >= 0 ) + { + char str[65]; printf("LP_tradecommand fee selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(0); + } if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) LP_connectstart(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); else printf("swap %p when connect came in (%s)\n",utxo->S.swap,jprint(argjson,0)); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index a2ccbc9d5..43f0978ed 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -126,9 +126,45 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) return(value); } +int32_t LP_vinscan(bits256 *spendtxidp,int32_t *spendvinip,char *symbol,bits256 txid,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) +{ + cJSON *txobj,*vins,*vin; bits256 spenttxid; int32_t j,numvins,spentvout,retval = -1; + if ( (txobj= LP_gettx(symbol,txid)) != 0 ) + { + if ( bits256_cmp(txid,jbits256(txobj,"txid")) != 0 ) + { + printf("txid mismatch error\n"); + return(-2); + } + vins = jarray(&numvins,txobj,"vin"); + for (j=0; j 0 ) @@ -155,28 +191,8 @@ int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 se for (i=0; i= 0 ) + break; } } free_json(blockjson); @@ -208,6 +224,25 @@ int32_t LP_mempoolscan(char *symbol,bits256 txid) return(-1); } +int32_t LP_mempool_vinscan(bits256 *spendtxidp,int32_t *spendvinp,char *symbol,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) +{ + int32_t i,n; cJSON *array; bits256 mempooltxid; + if ( (array= LP_getmempool(symbol)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i= 0 ) + return(i); + } + free_json(array); + } + } + return(-1); +} + int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) { int32_t numconfirms = 100; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 87f5d0b78..4092c45d4 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -81,6 +81,14 @@ struct LP_utxoinfo *LP_utxo2find(int32_t iambob,bits256 txid2,int32_t vout2) return(utxo); } +struct LP_utxoinfo *LP_utxofinds(int32_t iambob,bits256 txid,int32_t vout,bits256 txid2,int32_t vout2) +{ + struct LP_utxoinfo *utxo; + if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 || (utxo= LP_utxofind(iambob,txid2,vout2)) != 0 || (utxo= LP_utxo2find(iambob,txid,vout)) != 0 || (utxo= LP_utxo2find(iambob,txid2,vout2)) != 0 ) + return(utxo); + else return(0); +} + int32_t LP_utxoaddptrs(struct LP_utxoinfo *ptrs[],int32_t n,struct LP_utxoinfo *utxo) { int32_t i; @@ -331,22 +339,27 @@ int32_t LP_iseligible(int32_t iambob,char *coin,bits256 txid,int32_t vout,uint64 struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - uint64_t tmpsatoshis; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + uint64_t tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } - if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) - tmpsatoshis = (((value2-100000) / 9) << 3); + if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding + tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; if ( LP_iseligible(iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("LP_addutxo got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); } - if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 || (utxo= LP_utxo2find(iambob,txid,vout)) != 0 ) + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) + { + printf("LP_addutxo selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(0); + } + if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { //printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; From deb21aba064ac491212a1e58875b335795219644 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:06:42 +0300 Subject: [PATCH 1242/2705] Test --- iguana/exchanges/utxos | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 iguana/exchanges/utxos diff --git a/iguana/exchanges/utxos b/iguana/exchanges/utxos new file mode 100755 index 000000000..a84c72fb0 --- /dev/null +++ b/iguana/exchanges/utxos @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"getutxos\",\"coin\":\"REVS\"}" From e6ee70e49f7c5c9ea55b98b9c52c6504c87be407 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:16:36 +0300 Subject: [PATCH 1243/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index cc53fdc2a..b7e682280 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -79,7 +79,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) char *retstr; cJSON *retjson = 0; if ( coin != 0 ) { - printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); + //printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 4092c45d4..2c9f35613 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -548,7 +548,7 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr printf("coin not active\n"); return(0); } - printf("privkey init.(%s)\n",coin->symbol); + printf("privkey init.(%s) %s\n",coin->symbol,coin->smartaddr); if ( coin->inactive == 0 && (array= LP_listunspent(coin->symbol,coin->smartaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) From b088dfc310d3fb2941bdfffcfe020877fa29bc87 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:19:06 +0300 Subject: [PATCH 1244/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 2c9f35613..2e0b1b2ca 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -361,7 +361,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit } if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { - //printf("%.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->value),dstr(utxo->value2),dstr(utxo->satoshis)); + printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis)); u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { From 0ab9095467d89400f3949d3a71344b9eea98f22f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:24:35 +0300 Subject: [PATCH 1245/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- iguana/exchanges/LP_utxos.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 4bda50ec5..821acca4c 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -65,7 +65,7 @@ void LP_userpassfp(char *symbol,char *username,char *password,FILE *fp) strcpy(username,rpcuser); strcpy(password,rpcpassword); } - printf("%s rpcuser.(%s) rpcpassword.(%s)\n",symbol,rpcuser,rpcpassword); + //printf("%s rpcuser.(%s) rpcpassword.(%s)\n",symbol,rpcuser,rpcpassword); if ( rpcuser != 0 ) free(rpcuser); if ( rpcpassword != 0 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 2e0b1b2ca..bcc7fe2cf 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -339,8 +339,7 @@ int32_t LP_iseligible(int32_t iambob,char *coin,bits256 txid,int32_t vout,uint64 struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - uint64_t tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; - char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); + char str[65]; uint64_t tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); @@ -361,6 +360,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit } if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { + char str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis)); u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) @@ -634,7 +634,8 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); - printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); + if ( coin->pubtype != 188 || strcmp(coin->symbol,"KMD") == 0 ) + printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( counter++ == 0 ) { bitcoin_priv2wif(USERPASS_WIFSTR,privkey,0); From def766389606996b83010e05b7a82b5d5aa630bd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:27:52 +0300 Subject: [PATCH 1246/2705] Test --- iguana/exchanges/LP_utxos.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index bcc7fe2cf..6d62bd586 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -168,16 +168,18 @@ void LP_availableset(struct LP_utxoinfo *utxo) int32_t LP_utxopurge(int32_t allutxos) { - struct LP_utxoinfo *utxo,*tmp; int32_t iambob,n = 0; + char str[65]; struct LP_utxoinfo *utxo,*tmp; int32_t iambob,n = 0; portable_mutex_lock(&LP_utxomutex); for (iambob=0; iambob<=1; iambob++) { HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { + printf("purge.(%s) ?\n",bits256_str(str,utxo->payment.txid)); if ( allutxos != 0 || LP_ismine(utxo) == 0 ) { if ( LP_isavailable(utxo) == 0 ) { + printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); free(utxo); } else n++; @@ -185,10 +187,12 @@ int32_t LP_utxopurge(int32_t allutxos) } HASH_ITER(hh,LP_utxoinfos2[iambob],utxo,tmp) { + printf("purge.(%s) ?\n",bits256_str(str,utxo->payment.txid)); if ( allutxos != 0 || LP_ismine(utxo) == 0 ) { if ( LP_isavailable(utxo) == 0 ) { + printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos2[iambob],utxo); free(utxo); } else n++; @@ -634,7 +638,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); - if ( coin->pubtype != 188 || strcmp(coin->symbol,"KMD") == 0 ) + if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( counter++ == 0 ) { From fe11a9389a1e0c86d8f21f1c48dc472c2dd851cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:29:44 +0300 Subject: [PATCH 1247/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 8 +++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index d8a89b65e..b58af9f37 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -165,7 +165,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d if ( (method= jstr(argjson,"method")) != 0 ) { txid = jbits256(argjson,"txid"); - if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) != 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) + if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { printf("LP_command.(%s)\n",jprint(argjson,0)); if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) @@ -285,7 +285,7 @@ forward(pubkey,hexstr)\n\ { HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { - if ( LP_ismine(utxo) != 0 && (strcmp(utxo->coin,base) == 0 || strcmp(utxo->coin,rel) == 0) ) + if ( LP_ismine(utxo) > 0 && (strcmp(utxo->coin,base) == 0 || strcmp(utxo->coin,rel) == 0) ) LP_priceping(LP_mypubsock,utxo,rel,LP_profitratio - 1.); //else printf("notmine.(%s %s)\n",utxo->coin,bits256_str(str,utxo->txid)); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ceea4a5be..bdc960503 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -156,7 +156,7 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,u.txid),u.vout,dstr(u.value)); LP_spentnotify(utxo,1); } - else if ( LP_ismine(utxo) != 0 ) + else if ( LP_ismine(utxo) > 0 ) { if ( strcmp(utxo->coin,"KMD") == 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6d62bd586..16edcf807 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -20,10 +20,8 @@ int32_t LP_ismine(struct LP_utxoinfo *utxo) { - if ( bits256_cmp(utxo->pubkey,LP_mypubkey) != 0 ) + if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 ) return(1); - else if ( LP_mypeer == 0 ) - return(0); else return(0); } @@ -263,7 +261,7 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *coin,int32_t last { if ( i++ < firsti ) continue; - if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) != 0 ) + if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) > 0 ) { jaddi(utxosjson,LP_utxojson(utxo)); } @@ -509,7 +507,7 @@ cJSON *LP_inventory(char *symbol,int32_t iambob) HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { //char str[65]; printf("iterate %s\n",bits256_str(str,utxo->txid)); - if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) != 0 ) + if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) > 0 ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); } return(array); From d44a7b5f913a42e4e69c0f8ce5df1e4d797df4c2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:31:49 +0300 Subject: [PATCH 1248/2705] Test --- iguana/exchanges/LP_utxos.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 16edcf807..f45a396f4 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -167,15 +167,16 @@ void LP_availableset(struct LP_utxoinfo *utxo) int32_t LP_utxopurge(int32_t allutxos) { char str[65]; struct LP_utxoinfo *utxo,*tmp; int32_t iambob,n = 0; + printf("LP_utxopurge mypub.(%s)\n",bits256_str(str,LP_mypubkey)); portable_mutex_lock(&LP_utxomutex); for (iambob=0; iambob<=1; iambob++) { HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { - printf("purge.(%s) ?\n",bits256_str(str,utxo->payment.txid)); - if ( allutxos != 0 || LP_ismine(utxo) == 0 ) + if ( LP_isavailable(utxo) > 0 ) { - if ( LP_isavailable(utxo) == 0 ) + printf("purge.(%s) ?\n",bits256_str(str,utxo->payment.txid)); + if ( allutxos != 0 || LP_ismine(utxo) == 0 ) { printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); @@ -185,10 +186,10 @@ int32_t LP_utxopurge(int32_t allutxos) } HASH_ITER(hh,LP_utxoinfos2[iambob],utxo,tmp) { - printf("purge.(%s) ?\n",bits256_str(str,utxo->payment.txid)); - if ( allutxos != 0 || LP_ismine(utxo) == 0 ) + if ( LP_isavailable(utxo) > 0 ) { - if ( LP_isavailable(utxo) == 0 ) + printf("purge.(%s) ?\n",bits256_str(str,utxo->payment.txid)); + if ( allutxos != 0 || LP_ismine(utxo) == 0 ) { printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos2[iambob],utxo); From a47be5316f5231a522d2c5a676c8b198578484b5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:34:06 +0300 Subject: [PATCH 1249/2705] Test --- iguana/exchanges/LP_utxos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index f45a396f4..900cec382 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -20,6 +20,7 @@ int32_t LP_ismine(struct LP_utxoinfo *utxo) { + char str[65],str2[65]; printf("cmp.(%s) vs (%s)\n",bits256_str(str,utxo->pubkey),bits256_str(str2,LP_mypubkey)); if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 ) return(1); else return(0); @@ -188,7 +189,7 @@ int32_t LP_utxopurge(int32_t allutxos) { if ( LP_isavailable(utxo) > 0 ) { - printf("purge.(%s) ?\n",bits256_str(str,utxo->payment.txid)); + printf("purge2.(%s) ?\n",bits256_str(str,utxo->payment.txid)); if ( allutxos != 0 || LP_ismine(utxo) == 0 ) { printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); From 2c03f950dce4ee24e5ac7b05ce553d198626e3c5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:35:24 +0300 Subject: [PATCH 1250/2705] Test --- iguana/exchanges/LP_utxos.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 900cec382..bd823e6cf 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -20,7 +20,6 @@ int32_t LP_ismine(struct LP_utxoinfo *utxo) { - char str[65],str2[65]; printf("cmp.(%s) vs (%s)\n",bits256_str(str,utxo->pubkey),bits256_str(str2,LP_mypubkey)); if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 ) return(1); else return(0); @@ -176,8 +175,7 @@ int32_t LP_utxopurge(int32_t allutxos) { if ( LP_isavailable(utxo) > 0 ) { - printf("purge.(%s) ?\n",bits256_str(str,utxo->payment.txid)); - if ( allutxos != 0 || LP_ismine(utxo) == 0 ) + if ( allutxos != 0 || LP_ismine(utxo) > 0 ) { printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); @@ -189,8 +187,7 @@ int32_t LP_utxopurge(int32_t allutxos) { if ( LP_isavailable(utxo) > 0 ) { - printf("purge2.(%s) ?\n",bits256_str(str,utxo->payment.txid)); - if ( allutxos != 0 || LP_ismine(utxo) == 0 ) + if ( allutxos != 0 || LP_ismine(utxo) > 0 ) { printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos2[iambob],utxo); From c144a6fd611d6f65e48cb4cf57ee1050e2e451f1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:37:26 +0300 Subject: [PATCH 1251/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index bd823e6cf..98b0fb24a 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -179,7 +179,7 @@ int32_t LP_utxopurge(int32_t allutxos) { printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); - free(utxo); + //free(utxo); let the LP_utxoinfos2 free the utxo } else n++; } else n++; } From 2e2e4b11c42a80fc4cc426fc1ae4033125f9aca0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:38:36 +0300 Subject: [PATCH 1252/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 98b0fb24a..a3b1d2197 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -177,7 +177,7 @@ int32_t LP_utxopurge(int32_t allutxos) { if ( allutxos != 0 || LP_ismine(utxo) > 0 ) { - printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); + printf("iambob.%d delete.(%s)\n",iambob,bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); //free(utxo); let the LP_utxoinfos2 free the utxo } else n++; @@ -189,7 +189,7 @@ int32_t LP_utxopurge(int32_t allutxos) { if ( allutxos != 0 || LP_ismine(utxo) > 0 ) { - printf("delete.(%s)\n",bits256_str(str,utxo->payment.txid)); + printf("iambob.%d delete2.(%s)\n",iambob,bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos2[iambob],utxo); free(utxo); } else n++; From c2a9dc0c3303b8c669f081e823edf88f3c95d94b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:39:25 +0300 Subject: [PATCH 1253/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a3b1d2197..54bffe557 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -190,7 +190,7 @@ int32_t LP_utxopurge(int32_t allutxos) if ( allutxos != 0 || LP_ismine(utxo) > 0 ) { printf("iambob.%d delete2.(%s)\n",iambob,bits256_str(str,utxo->payment.txid)); - HASH_DELETE(hh,LP_utxoinfos2[iambob],utxo); + HASH_DELETE(hh2,LP_utxoinfos2[iambob],utxo); free(utxo); } else n++; } else n++; From b67f36a18e4e6c6101ac9eaa328424fd91b29197 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:40:11 +0300 Subject: [PATCH 1254/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 54bffe557..c61b5c8e3 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -179,7 +179,7 @@ int32_t LP_utxopurge(int32_t allutxos) { printf("iambob.%d delete.(%s)\n",iambob,bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); - //free(utxo); let the LP_utxoinfos2 free the utxo + free(utxo); } else n++; } else n++; } From 7e2aa405bda3dd518146c0a4e4dcc82da884ff23 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:41:41 +0300 Subject: [PATCH 1255/2705] Test --- iguana/exchanges/LP_utxos.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index c61b5c8e3..158b89185 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -179,7 +179,7 @@ int32_t LP_utxopurge(int32_t allutxos) { printf("iambob.%d delete.(%s)\n",iambob,bits256_str(str,utxo->payment.txid)); HASH_DELETE(hh,LP_utxoinfos[iambob],utxo); - free(utxo); + //free(utxo); let the LP_utxoinfos2 free the utxo, should be 1:1 } else n++; } else n++; } @@ -398,7 +398,10 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit } LP_utxosetkey(utxo->key,txid,vout); LP_utxosetkey(utxo->key2,txid2,vout2); - char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); + if ( LP_ismine(utxo) == 0 ) + { + char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); + } portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) From 8e2c6da7c72a6bf76fbcfc4db051d1ade5ab0f51 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:43:38 +0300 Subject: [PATCH 1256/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index b58af9f37..134ed5f2f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -329,7 +329,7 @@ forward(pubkey,hexstr)\n\ if ( (ptr= LP_coinfind(coin)) != 0 ) { privkey = LP_privkeycalc(pubkey33,&pubkey,ptr,"",USERPASS_WIFSTR); - LP_utxopurge(0); + //LP_utxopurge(0); LP_privkey_init(-1,ptr,privkey,pubkey,pubkey33); retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index bdc960503..230c617be 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -167,7 +167,7 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) { - LP_utxopurge(0); + //LP_utxopurge(0); LP_privkey_updates(pubsock,passphrase); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 158b89185..7682fb5d2 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -398,10 +398,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit } LP_utxosetkey(utxo->key,txid,vout); LP_utxosetkey(utxo->key2,txid2,vout2); - if ( LP_ismine(utxo) == 0 ) - { - char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); - } + char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) From c2a1b92672a6061c95e06d09a6fe7f73113fb258 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:44:31 +0300 Subject: [PATCH 1257/2705] Test --- iguana/exchanges/LP_utxos.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7682fb5d2..9522ce158 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -361,8 +361,11 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit } if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { - char str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); - printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis)); + if ( LP_ismine(utxo) == 0 ) + { + char str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); + printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis)); + } u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { From 8dfadcdd235d720e3a498e26dda6d7c2fafb9ae6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:47:09 +0300 Subject: [PATCH 1258/2705] test --- iguana/exchanges/LP_utxos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 9522ce158..61f1399e2 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -508,9 +508,10 @@ cJSON *LP_inventory(char *symbol,int32_t iambob) else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { - //char str[65]; printf("iterate %s\n",bits256_str(str,utxo->txid)); + char str[65]; printf("iambob.%d iterate %s\n",iambob,bits256_str(str,utxo->payment.txid)); if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) > 0 ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); + else printf("skip %s %d %d %d %d\n",bits256_str(str,utxo->payment.txid),LP_isunspent(utxo) != 0,strcmp(symbol,utxo->coin) == 0,utxo->iambob == iambob,LP_ismine(utxo) > 0); } return(array); } From d78922b250a80d789b62ff9ce49ebd9dd092f151 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:48:28 +0300 Subject: [PATCH 1259/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 61f1399e2..03150a60b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -511,7 +511,7 @@ cJSON *LP_inventory(char *symbol,int32_t iambob) char str[65]; printf("iambob.%d iterate %s\n",iambob,bits256_str(str,utxo->payment.txid)); if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) > 0 ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); - else printf("skip %s %d %d %d %d\n",bits256_str(str,utxo->payment.txid),LP_isunspent(utxo) != 0,strcmp(symbol,utxo->coin) == 0,utxo->iambob == iambob,LP_ismine(utxo) > 0); + else printf("skip %s %d %d %d %d\n",bits256_str(str,utxo->pubkey),LP_isunspent(utxo) != 0,strcmp(symbol,utxo->coin) == 0,utxo->iambob == iambob,LP_ismine(utxo) > 0); } return(array); } From 362c694d2c36c2a644a57aa4e97b028e4e96bfd7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:49:24 +0300 Subject: [PATCH 1260/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 03150a60b..a360d9290 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -508,7 +508,7 @@ cJSON *LP_inventory(char *symbol,int32_t iambob) else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { - char str[65]; printf("iambob.%d iterate %s\n",iambob,bits256_str(str,utxo->payment.txid)); + char str[65]; printf("iambob.%d iterate %s\n",iambob,bits256_str(str,LP_mypubkey)); if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) > 0 ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); else printf("skip %s %d %d %d %d\n",bits256_str(str,utxo->pubkey),LP_isunspent(utxo) != 0,strcmp(symbol,utxo->coin) == 0,utxo->iambob == iambob,LP_ismine(utxo) > 0); From d3bd40dced20bd6d741b6c87f14b20e5ed0bbb0a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:52:16 +0300 Subject: [PATCH 1261/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a360d9290..74f70a336 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -652,6 +652,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co printf("importprivkey -> (%s)\n",jprint(retjson,1)); } LP_mypubkey = *pubkeyp = curve25519(privkey,curve25519_basepoint9()); + char str[65],str2[65]; printf("privkey.(%s) -> LP_mypubkey.(%s)\n",bits256_str(str,privkey),bits256_str(str2,LP_mypubkey)); return(privkey); } From cb4674acccb351f5255bbd393e7f758b01904379 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:54:38 +0300 Subject: [PATCH 1262/2705] Test --- iguana/exchanges/LP_utxos.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 74f70a336..ded23d717 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -628,10 +628,14 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *coin,char *passphrase,char *wifstr) { static uint32_t counter; - bits256 privkey,userpub,userpass; char tmpstr[128]; cJSON *retjson; uint8_t tmptype,rmd160[20]; + bits256 privkey,userpub,userpass; char tmpstr[128],str[65],str2[65]; cJSON *retjson; uint8_t tmptype,rmd160[20]; if ( passphrase != 0 ) conv_NXTpassword(privkey.bytes,pubkeyp->bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); - else privkey = iguana_wif2privkey(wifstr); + else + { + privkey = iguana_wif2privkey(wifstr); + printf("WIF.(%s) -> %s\n",wifstr,bits256_str(str,privkey)); + } iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); if ( coin->counter == 0 ) { @@ -652,7 +656,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co printf("importprivkey -> (%s)\n",jprint(retjson,1)); } LP_mypubkey = *pubkeyp = curve25519(privkey,curve25519_basepoint9()); - char str[65],str2[65]; printf("privkey.(%s) -> LP_mypubkey.(%s)\n",bits256_str(str,privkey),bits256_str(str2,LP_mypubkey)); + printf("privkey.(%s) -> LP_mypubkey.(%s)\n",bits256_str(str,privkey),bits256_str(str2,LP_mypubkey)); return(privkey); } From 3030f487a6ee3d16fbe3cac70a8f68f4f499fa96 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:55:13 +0300 Subject: [PATCH 1263/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index ded23d717..e0ed536ff 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -647,7 +647,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( counter++ == 0 ) { - bitcoin_priv2wif(USERPASS_WIFSTR,privkey,0); + bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); conv_NXTpassword(userpass.bytes,pubkeyp->bytes,(uint8_t *)USERPASS_WIFSTR,(int32_t)strlen(USERPASS_WIFSTR)); userpub = curve25519(userpass,curve25519_basepoint9()); printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); From e49ccd8e55246b59e9a2e25b9537a1549d275710 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:56:53 +0300 Subject: [PATCH 1264/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e0ed536ff..e80836a9e 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -629,7 +629,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co { static uint32_t counter; bits256 privkey,userpub,userpass; char tmpstr[128],str[65],str2[65]; cJSON *retjson; uint8_t tmptype,rmd160[20]; - if ( passphrase != 0 ) + if ( passphrase != 0 && passphrase[0] != 0 ) conv_NXTpassword(privkey.bytes,pubkeyp->bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else { From cf2c02db0617ac2b868c1914a73d4bc238be82da Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 13:58:11 +0300 Subject: [PATCH 1265/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e80836a9e..ab60ceebe 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -634,7 +634,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co else { privkey = iguana_wif2privkey(wifstr); - printf("WIF.(%s) -> %s\n",wifstr,bits256_str(str,privkey)); + //printf("WIF.(%s) -> %s\n",wifstr,bits256_str(str,privkey)); } iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); if ( coin->counter == 0 ) @@ -656,7 +656,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co printf("importprivkey -> (%s)\n",jprint(retjson,1)); } LP_mypubkey = *pubkeyp = curve25519(privkey,curve25519_basepoint9()); - printf("privkey.(%s) -> LP_mypubkey.(%s)\n",bits256_str(str,privkey),bits256_str(str2,LP_mypubkey)); + //printf("privkey.(%s) -> LP_mypubkey.(%s)\n",bits256_str(str,privkey),bits256_str(str2,LP_mypubkey)); return(privkey); } From eba2f83cb9c05a9c7f9f25db64fd22d389153601 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 14:09:20 +0300 Subject: [PATCH 1266/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 230c617be..087ed1c75 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -282,7 +282,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; if ( lastn < LP_PROPAGATION_SLACK * 2 ) lastn = LP_PROPAGATION_SLACK * 2; - printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); + // printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer->ipaddr,myport,profitmargin); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index ab60ceebe..0a60303ba 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -310,8 +310,8 @@ char *LP_spentcheck(cJSON *argjson) } if ( LP_txvalue(utxo->coin,checktxid,checkvout) == 0 ) { - //if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) - // LP_mypeer->numutxos--; + if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) + LP_mypeer->numutxos--; utxo->T.spentflag = (uint32_t)time(NULL); retval++; //printf("indeed txid was spent\n"); @@ -409,6 +409,8 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); + if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) + LP_mypeer->numutxos++; } return(utxo); } @@ -508,10 +510,10 @@ cJSON *LP_inventory(char *symbol,int32_t iambob) else myipaddr = "127.0.0.1"; HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { - char str[65]; printf("iambob.%d iterate %s\n",iambob,bits256_str(str,LP_mypubkey)); + //char str[65]; printf("iambob.%d iterate %s\n",iambob,bits256_str(str,LP_mypubkey)); if ( LP_isunspent(utxo) != 0 && strcmp(symbol,utxo->coin) == 0 && utxo->iambob == iambob && LP_ismine(utxo) > 0 ) jaddi(array,LP_inventoryjson(cJSON_CreateObject(),utxo)); - else printf("skip %s %d %d %d %d\n",bits256_str(str,utxo->pubkey),LP_isunspent(utxo) != 0,strcmp(symbol,utxo->coin) == 0,utxo->iambob == iambob,LP_ismine(utxo) > 0); + //else printf("skip %s %d %d %d %d\n",bits256_str(str,utxo->pubkey),LP_isunspent(utxo) != 0,strcmp(symbol,utxo->coin) == 0,utxo->iambob == iambob,LP_ismine(utxo) > 0); } return(array); } @@ -553,7 +555,7 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr printf("coin not active\n"); return(0); } - printf("privkey init.(%s) %s\n",coin->symbol,coin->smartaddr); + //printf("privkey init.(%s) %s\n",coin->symbol,coin->smartaddr); if ( coin->inactive == 0 && (array= LP_listunspent(coin->symbol,coin->smartaddr)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) From aa3d38739be5ea9d832b22ebb7377ce4b09e972b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 14:23:06 +0300 Subject: [PATCH 1267/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 13 ++++++++++++- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 087ed1c75..426aad3ce 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -173,7 +173,7 @@ void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins) { - char *retstr; uint8_t r; int32_t i,n,j,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; + char *retstr; uint8_t r; int32_t i,n,j,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; struct LP_utxoinfo *utxo,*utmp; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); @@ -288,6 +288,17 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } nonz += LP_subsock_check(peer); } + if ( (counter % 100) == 0 ) + { + HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) + { + LP_utxo_spentcheck(pubsock,utxo,profitmargin); + } + HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp) + { + LP_utxo_spentcheck(pubsock,utxo,profitmargin); + } + } if ( pullsock >= 0 ) nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); if ( nonz == 0 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0a60303ba..4eab2d5f6 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -630,7 +630,7 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *coin,char *passphrase,char *wifstr) { static uint32_t counter; - bits256 privkey,userpub,userpass; char tmpstr[128],str[65],str2[65]; cJSON *retjson; uint8_t tmptype,rmd160[20]; + bits256 privkey,userpub,userpass; char tmpstr[128]; cJSON *retjson; uint8_t tmptype,rmd160[20]; if ( passphrase != 0 && passphrase[0] != 0 ) conv_NXTpassword(privkey.bytes,pubkeyp->bytes,(uint8_t *)passphrase,(int32_t)strlen(passphrase)); else From 5571e9b4fb59fea43f40ef0e71af1b35454cb870 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 14:39:41 +0300 Subject: [PATCH 1268/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 134ed5f2f..2f1de8e18 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -258,6 +258,7 @@ register(pubkey,pushaddr)\n\ lookup(pubkey)\n\ forward(pubkey,hexstr)\n\ \"}")); + printf("CMD.(%s)\n",jprint(argjson,0)); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) { if ( USERPASS_COUNTER == 0 ) @@ -387,7 +388,6 @@ forward(pubkey,hexstr)\n\ } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); } } - //printf("CMD.(%s)\n",jprint(argjson,0)); if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) retstr = LP_quotereceived(argjson); else if ( strcmp(method,"connected") == 0 ) From af64ea9ea13aea21feb09a2f2070da4421484623 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 14:45:01 +0300 Subject: [PATCH 1269/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_rpc.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index aea5d91e9..69163f4f7 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -49,7 +49,7 @@ char *LP_lookup(bits256 pubkey) char *LP_register(bits256 pubkey,char *pushaddr) { struct LP_forwardinfo *ptr=0; int32_t pushsock; - if ( is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) + if ( strlen(pushaddr) <= strlen("tcp://") || is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) return(clonestr("{\"error\":\"illegal ipaddr\"}")); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 426aad3ce..fc533884a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -225,7 +225,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } } - printf("mainloop\n"); + printf("mainloop pushaddr.(%s)\n",pushaddr); if ( IAMLP == 0 ) { while ( 1 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index b7e682280..b489a8c51 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -61,6 +61,8 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *pushaddr) { char url[512],str[65]; + if ( strncmp("tcp://",pushaddr,strlen("tcp://")) != 0 || strlen(pushaddr) <= strlen("tcp://") ) + return(clonestr("{\"error\":\"illegal pushaddr\"}")); sprintf(url,"http://%s:%u/api/stats/register?pubkey=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr); //printf("getutxo.(%s)\n",url); return(issue_curl(url)); From 2c506345ae4d997e444110f34cae1a7ec3ead6f3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 14:49:16 +0300 Subject: [PATCH 1270/2705] Test --- iguana/exchanges/LP_commands.c | 6 +++--- iguana/exchanges/LP_utxos.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2f1de8e18..2bbee302d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -258,7 +258,7 @@ register(pubkey,pushaddr)\n\ lookup(pubkey)\n\ forward(pubkey,hexstr)\n\ \"}")); - printf("CMD.(%s)\n",jprint(argjson,0)); + //printf("CMD.(%s)\n",jprint(argjson,0)); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) { if ( USERPASS_COUNTER == 0 ) @@ -404,9 +404,9 @@ forward(pubkey,hexstr)\n\ retstr = LP_peers(); else if ( IAMLP != 0 ) { - if ( strcmp(method,"getutxos") == 0 && (coin= jstr(argjson,"coin")) != 0 ) + if ( strcmp(method,"getutxos") == 0 ) { - retstr = LP_utxos(1,LP_mypeer,coin,jint(argjson,"lastn")); + retstr = LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn")); //printf("RETURN. %d utxos\n",cJSON_GetArraySize(cJSON_Parse(retstr))); } else if ( strcmp(method,"register") == 0 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 4eab2d5f6..81eca4751 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -249,7 +249,7 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) return(item); } -char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *coin,int32_t lastn) +char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t lastn) { int32_t i,firsti; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); i = 0; @@ -260,7 +260,7 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *coin,int32_t last { if ( i++ < firsti ) continue; - if ( (coin == 0 || coin[0] == 0 || strcmp(coin,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) > 0 ) + if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) > 0 ) { jaddi(utxosjson,LP_utxojson(utxo)); } From 1eac4aaa3500c21499f4b37b891d66b33bb7505a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 15:09:15 +0300 Subject: [PATCH 1271/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fc533884a..04b53640f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -217,14 +217,6 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in if ( (retstr= basilisk_swaplist()) != 0 ) free(retstr); printf("update peers\n"); - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - if ( strcmp(peer->ipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) - { - //printf("query utxo from %s\n",peer->ipaddr); - LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); - } - } printf("mainloop pushaddr.(%s)\n",pushaddr); if ( IAMLP == 0 ) { @@ -258,6 +250,14 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } else { + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( strcmp(peer->ipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) + { + //printf("query utxo from %s\n",peer->ipaddr); + LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); + } + } while ( 1 ) { nonz = 0; From 46b17290491abf0d0f33a1bce38d9a3deaadf03e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 15:12:58 +0300 Subject: [PATCH 1272/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2bbee302d..542f04704 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -348,7 +348,7 @@ forward(pubkey,hexstr)\n\ if ( jobj(argjson,"vout") == 0 ) return(clonestr("{\"error\":\"missing vout\"}")); vout = jint(argjson,"vout"); - if ( (utxo= LP_utxofind(1,txid,vout)) == 0 ) + if ( (utxo= LP_utxofind(0,txid,vout)) == 0 ) return(clonestr("{\"error\":\"txid/vout not found\"}")); if ( strcmp(method,"candidates") == 0 ) return(jprint(LP_tradecandidates(coin),1)); From a5f7f4250dff8931b486714fcf89610c8ab80dd4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 15:44:43 +0300 Subject: [PATCH 1273/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 34 +++++++++++++++++++-------------- iguana/exchanges/run | 2 +- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 04b53640f..a174c3c7c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -30,7 +30,7 @@ char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; -char *default_LPnodes[] = { "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", +char *default_LPnodes[] = { "5.9.253.196" };//, "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex; int32_t LP_mypubsock = -1; @@ -171,9 +171,9 @@ void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) LP_privkey_updates(pubsock,passphrase); } -void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins) +void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) { - char *retstr; uint8_t r; int32_t i,n,j,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; struct LP_utxoinfo *utxo,*utmp; + char *retstr,*lpnode; uint8_t r; int32_t i,n,j,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; struct LP_utxoinfo *utxo,*utmp; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); @@ -181,21 +181,27 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } if ( IAMLP != 0 ) { - for (i=0; i 25 ) - continue; - LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport,profitmargin); - } + for (i=0; i 25 ) + continue; + LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport,profitmargin); + } + } else LP_peersquery(mypeer,pubsock,seednode,myport,mypeer->ipaddr,myport,profitmargin); } else { - OS_randombytes((void *)&r,sizeof(r)); - for (j=0; j Date: Sun, 11 Jun 2017 15:50:27 +0300 Subject: [PATCH 1274/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 81eca4751..8718508e4 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -600,7 +600,7 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr values[i] = 0, used++; if ( iambob != 0 ) { - if ( (utxo= LP_addutxo(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_peerinfos[0].profitmargin)) != 0 ) + if ( (utxo= LP_addutxo(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_mypeer != 0 ? LP_mypeer->profitmargin : 0.01)) != 0 ) { //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); } From e1fd0ac5d30c509b696eb38c5c0d463e34a74837 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 15:57:12 +0300 Subject: [PATCH 1275/2705] Test --- iguana/exchanges/LP_utxos.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 8718508e4..9ec09fee6 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -565,6 +565,8 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr if ( iambob == 0 ) values = calloc(n,sizeof(*values)); else memset(values,0,n * sizeof(*values)); + if ( iambob == 0 && IAMLP != 0 ) + continue; for (i=0; i Date: Sun, 11 Jun 2017 16:01:32 +0300 Subject: [PATCH 1276/2705] Test --- iguana/exchanges/LP_peers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 2309e5c20..145bcfde3 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -65,7 +65,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char } else { - //printf("LPaddpeer %s\n",ipaddr); + printf("LPaddpeer %s\n",ipaddr); peer = calloc(1,sizeof(*peer)); peer->pushsock = peer->subsock = pushsock = subsock = -1; strcpy(peer->ipaddr,ipaddr); @@ -160,7 +160,7 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr return; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer!=0?mypeer->numpeers:0,mypeer!=0?mypeer->numutxos:0)) != 0 ) { - //printf("got.(%s)\n",retstr); + printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); From 5f3e2b8373a556bb737078ed99cec52d3cfced8b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 16:07:52 +0300 Subject: [PATCH 1277/2705] Test --- iguana/exchanges/LP_forwarding.c | 8 ++++++++ iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 69163f4f7..2fc99302f 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -41,6 +41,8 @@ struct LP_forwardinfo *LP_forwardfind(bits256 pubkey) char *LP_lookup(bits256 pubkey) { + if ( bits256_nonz(pubkey) == 0 ) + return(clonestr("{\"error\":\"illegal pubkey\"}")); if ( LP_forwardfind(pubkey) != 0 ) return(clonestr("{\"result\":\"success\",\"forwarding\":1}")); else return(clonestr("{\"error\":\"notfound\"}")); @@ -49,6 +51,8 @@ char *LP_lookup(bits256 pubkey) char *LP_register(bits256 pubkey,char *pushaddr) { struct LP_forwardinfo *ptr=0; int32_t pushsock; + if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) + return(clonestr("{\"error\":\"illegal ipaddr\"}")); if ( strlen(pushaddr) <= strlen("tcp://") || is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) return(clonestr("{\"error\":\"illegal ipaddr\"}")); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) @@ -111,6 +115,8 @@ char *LP_forward(bits256 pubkey,char *hexstr) void LP_forwarding_register(bits256 pubkey,char *pushaddr) { char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t retval = -1; + if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) + return; HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) @@ -131,6 +137,8 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr) int32_t LP_pubkey_send(bits256 pubkey,char *jsonstr,int32_t freeflag) { struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson; + if ( jsonstr == 0 || jsonstr[0] == 0 || bits256_nonz(pubkey) == 0 ) + return(-1); if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) { return(LP_send(ptr->pushsock,jsonstr,1)); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index b489a8c51..6724dac27 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -71,7 +71,7 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *push char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) { char url[512],str[65]; - sprintf(url,"http://%s:%u/api/stats/register?pubkey=%s",destip,destport,bits256_str(str,pubkey)); + sprintf(url,"http://%s:%u/api/stats/lookup?pubkey=%s",destip,destport,bits256_str(str,pubkey)); //printf("getutxo.(%s)\n",url); return(issue_curl(url)); } From 0c993985df7bb8c9120e1fd85270e0d6321844e4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 11 Jun 2017 16:38:16 +0300 Subject: [PATCH 1278/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_nativeDEX.c | 23 ++++++++++++++++++++++- iguana/exchanges/LP_quotes.c | 21 --------------------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 542f04704..48ae74b70 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -286,7 +286,7 @@ forward(pubkey,hexstr)\n\ { HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { - if ( LP_ismine(utxo) > 0 && (strcmp(utxo->coin,base) == 0 || strcmp(utxo->coin,rel) == 0) ) + if ( LP_ismine(utxo) > 0 && strcmp(utxo->coin,base) == 0 )//|| strcmp(utxo->coin,rel) == 0) ) LP_priceping(LP_mypubsock,utxo,rel,LP_profitratio - 1.); //else printf("notmine.(%s %s)\n",utxo->coin,bits256_str(str,utxo->txid)); } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index dd2422cdf..3648309f7 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -218,5 +218,6 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); void LP_quotesinit(char *base,char *rel); +int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin); #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a174c3c7c..a9f2cf819 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -138,6 +138,27 @@ int32_t LP_subsock_check(struct LP_peerinfo *peer) return(nonz); } +int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin) +{ + double price,bid,ask; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; + if ( (now= (uint32_t)time(NULL)) > utxo->T.swappending ) + utxo->T.swappending = 0; + if ( now > utxo->T.published+60 && utxo->T.swappending == 0 && utxo->S.swap == 0 && (price= LP_myprice(&bid,&ask,utxo->coin,rel)) != 0. ) + { + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + Q.timestamp = (uint32_t)time(NULL); + retjson = LP_quotejson(&Q); + jaddstr(retjson,"method","quote"); + retstr = jprint(retjson,1); + //printf("PING.(%s)\n",retstr); + LP_send(pubsock,retstr,1); + utxo->T.published = now; + return(0); + } + return(-1); +} + void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitmargin) { struct _LP_utxoinfo u; char str[65]; uint32_t now = (uint32_t)time(NULL); @@ -173,7 +194,7 @@ void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) { - char *retstr,*lpnode; uint8_t r; int32_t i,n,j,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; struct LP_utxoinfo *utxo,*utmp; + char *retstr; uint8_t r; int32_t i,n,j,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; struct LP_utxoinfo *utxo,*utmp; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 7f7b7ade9..5d31ae262 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -373,27 +373,6 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) return(bestitem); } -int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin) -{ - double price,bid,ask; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; - if ( (now= (uint32_t)time(NULL)) > utxo->T.swappending ) - utxo->T.swappending = 0; - if ( now > utxo->T.published+60 && utxo->T.swappending == 0 && utxo->S.swap == 0 && (price= LP_myprice(&bid,&ask,utxo->coin,rel)) != 0. ) - { - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - Q.timestamp = (uint32_t)time(NULL); - retjson = LP_quotejson(&Q); - jaddstr(retjson,"method","quote"); - retstr = jprint(retjson,1); - //printf("PING.(%s)\n",retstr); - LP_send(pubsock,retstr,1); - utxo->T.published = now; - return(0); - } - return(-1); -} - From d50603b12a20672f92672c81b6a4cab880fdd747 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 07:53:44 +0300 Subject: [PATCH 1279/2705] Test --- iguana/exchanges/LP_forwarding.c | 15 ++++++++++----- iguana/exchanges/LP_nativeDEX.c | 12 +++++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 2fc99302f..947942b64 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -26,7 +26,7 @@ struct LP_forwardinfo int32_t pushsock; uint32_t lasttime; } *LP_forwardinfos; -#define LP_KEEPALIVE 300 +#define LP_KEEPALIVE (3600 * 24) struct LP_forwardinfo *LP_forwardfind(bits256 pubkey) { @@ -69,6 +69,7 @@ char *LP_register(bits256 pubkey,char *pushaddr) } else { + char str[65]; printf("registered (%s) -> (%s)\n",bits256_str(str,pubkey),pushaddr); ptr = calloc(1,sizeof(*ptr)); ptr->pubkey = pubkey; strcpy(ptr->pushaddr,pushaddr); @@ -112,13 +113,15 @@ char *LP_forward(bits256 pubkey,char *hexstr) } else return(clonestr("{\"error\":\"notfound\"}")); } -void LP_forwarding_register(bits256 pubkey,char *pushaddr) +void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t broadcastflag) { - char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t retval = -1; + char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) return; HASH_ITER(hh,LP_peerinfos,peer,tmp) { + if ( broadcastflag == 0 && (rand() % 100) < 66 ) + continue; if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) @@ -129,8 +132,9 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr) } free(retstr); } - if ( retval == 0 ) + if ( broadcastflag == 0 && retval == 0 ) break; + n++; } } @@ -149,7 +153,7 @@ int32_t LP_pubkey_send(bits256 pubkey,char *jsonstr,int32_t freeflag) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { - if ( jint(retjson,"forwarding") != 0 ) + if ( jint(retjson,"forwarding") != 0 && peer->pushsock >= 0 ) retval = 0; free_json(retjson); } @@ -157,6 +161,7 @@ int32_t LP_pubkey_send(bits256 pubkey,char *jsonstr,int32_t freeflag) } if ( retval == 0 ) { + printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); len = (int32_t)strlen(jsonstr) + 1; hexstr = malloc(len*2 + 1); init_hexbytes_noT(hexstr,(uint8_t *)jsonstr,len); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a9f2cf819..01f57cd1a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -30,7 +30,7 @@ char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; -char *default_LPnodes[] = { "5.9.253.196" };//, "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; //"5.9.253.195", +char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196" , "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex; int32_t LP_mypubsock = -1; @@ -179,6 +179,7 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma } else if ( LP_ismine(utxo) > 0 ) { + // jl777: iterated Q's if ( strcmp(utxo->coin,"KMD") == 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); else LP_priceping(pubsock,utxo,"KMD",profitmargin); @@ -250,9 +251,9 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in while ( 1 ) { now = (uint32_t)time(NULL); - if ( lastforward < now-LP_KEEPALIVE ) + if ( lastforward < now-600 ) { - LP_forwarding_register(LP_mypubkey,pushaddr); + LP_forwarding_register(LP_mypubkey,pushaddr,0); lastforward = now; } nonz = n = 0; @@ -291,6 +292,11 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in if ( (counter % 600) == 0 ) LP_utxo_updates(pubsock,passphrase,profitmargin); now = (uint32_t)time(NULL); + if ( lastforward < now-3600 ) + { + LP_forwarding_register(LP_mypubkey,pushaddr,1); + lastforward = now; + } //printf("start peers updates\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { From a772da027414ab964c9ebcd5840a335322c0eb6b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:03:39 +0300 Subject: [PATCH 1280/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 01f57cd1a..1e4061be7 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -251,9 +251,9 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in while ( 1 ) { now = (uint32_t)time(NULL); - if ( lastforward < now-600 ) + if ( lastforward < now-3600 ) { - LP_forwarding_register(LP_mypubkey,pushaddr,0); + LP_forwarding_register(LP_mypubkey,pushaddr,1); lastforward = now; } nonz = n = 0; From 6a4c3774abad830d538042cabb7609291d474452 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:06:24 +0300 Subject: [PATCH 1281/2705] Test --- iguana/exchanges/LP_forwarding.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 947942b64..30faea10e 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -117,13 +117,17 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t broadcastflag) { char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) + { + printf("LP_forwarding_register illegal pushaddr or null pubkey\n"); return; + } HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( broadcastflag == 0 && (rand() % 100) < 66 ) continue; if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) { + printf("LP_register.(%s) returned.(%s)\n",peer->ipaddr,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( jint(retjson,"registered") != 0 ) From d2c74e8319f78f8e0ff65f880f4d96825c7be585 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:08:17 +0300 Subject: [PATCH 1282/2705] test --- iguana/exchanges/LP_forwarding.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 30faea10e..a53f0f6ed 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -52,7 +52,7 @@ char *LP_register(bits256 pubkey,char *pushaddr) { struct LP_forwardinfo *ptr=0; int32_t pushsock; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) - return(clonestr("{\"error\":\"illegal ipaddr\"}")); + return(clonestr("{\"error\":\"illegal ipaddr or null pubkey\"}")); if ( strlen(pushaddr) <= strlen("tcp://") || is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) return(clonestr("{\"error\":\"illegal ipaddr\"}")); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) @@ -127,7 +127,7 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t broadcastflag) continue; if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) { - printf("LP_register.(%s) returned.(%s)\n",peer->ipaddr,retstr); + printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( jint(retjson,"registered") != 0 ) From b21d7e5ffcebf5e07a15b7067a49d67cbd488687 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:12:20 +0300 Subject: [PATCH 1283/2705] Test --- iguana/exchanges/LP_forwarding.c | 5 +++-- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index a53f0f6ed..19979838e 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -53,8 +53,9 @@ char *LP_register(bits256 pubkey,char *pushaddr) struct LP_forwardinfo *ptr=0; int32_t pushsock; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) return(clonestr("{\"error\":\"illegal ipaddr or null pubkey\"}")); - if ( strlen(pushaddr) <= strlen("tcp://") || is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) - return(clonestr("{\"error\":\"illegal ipaddr\"}")); + //if ( strlen(pushaddr) <= strlen("tcp://") || is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) + // return(clonestr("{\"error\":\"illegal ipaddr\"}")); + char str[65]; printf("register.(%s) %s\n",pushaddr,bits256_str(str,pubkey)); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { ptr->lasttime = (uint32_t)time(NULL); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 6724dac27..cbc253e2b 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -63,7 +63,7 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *push char url[512],str[65]; if ( strncmp("tcp://",pushaddr,strlen("tcp://")) != 0 || strlen(pushaddr) <= strlen("tcp://") ) return(clonestr("{\"error\":\"illegal pushaddr\"}")); - sprintf(url,"http://%s:%u/api/stats/register?pubkey=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr); + sprintf(url,"http://%s:%u/api/stats/register?pubkey=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr+strlen("tcp://")); //printf("getutxo.(%s)\n",url); return(issue_curl(url)); } From 8a2c84b45b55637307b932876cb44d122c6d5e0c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:14:36 +0300 Subject: [PATCH 1284/2705] Test --- iguana/exchanges/LP_forwarding.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 19979838e..a1c2c516e 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -48,13 +48,14 @@ char *LP_lookup(bits256 pubkey) else return(clonestr("{\"error\":\"notfound\"}")); } -char *LP_register(bits256 pubkey,char *pushaddr) +char *LP_register(bits256 pubkey,char *ipaddr) { - struct LP_forwardinfo *ptr=0; int32_t pushsock; - if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) + struct LP_forwardinfo *ptr=0; int32_t pushsock; char pushaddr[64]; + if ( ipaddr == 0 || ipaddr[0] == 0 || is_ipaddr(ipaddr) == 0 || bits256_nonz(pubkey) == 0 ) return(clonestr("{\"error\":\"illegal ipaddr or null pubkey\"}")); //if ( strlen(pushaddr) <= strlen("tcp://") || is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) // return(clonestr("{\"error\":\"illegal ipaddr\"}")); + sprintf(pushaddr,"tcp://%s",ipaddr); char str[65]; printf("register.(%s) %s\n",pushaddr,bits256_str(str,pubkey)); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { From aee82ec3c40e06eb04b1d415569b831bd7df92d5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:16:37 +0300 Subject: [PATCH 1285/2705] Test --- iguana/exchanges/LP_forwarding.c | 9 +++------ iguana/exchanges/LP_nativeDEX.c | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index a1c2c516e..a1adb0d91 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -115,7 +115,7 @@ char *LP_forward(bits256 pubkey,char *hexstr) } else return(clonestr("{\"error\":\"notfound\"}")); } -void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t broadcastflag) +void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) { char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) @@ -125,22 +125,19 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t broadcastflag) } HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( broadcastflag == 0 && (rand() % 100) < 66 ) - continue; if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) { printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { - if ( jint(retjson,"registered") != 0 ) + if ( jint(retjson,"registered") != 0 && ++n >= max ) retval = 0; free_json(retjson); } free(retstr); } - if ( broadcastflag == 0 && retval == 0 ) + if ( retval == 0 ) break; - n++; } } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1e4061be7..f4f625476 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -253,7 +253,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in now = (uint32_t)time(NULL); if ( lastforward < now-3600 ) { - LP_forwarding_register(LP_mypubkey,pushaddr,1); + LP_forwarding_register(LP_mypubkey,pushaddr,10); lastforward = now; } nonz = n = 0; @@ -294,7 +294,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in now = (uint32_t)time(NULL); if ( lastforward < now-3600 ) { - LP_forwarding_register(LP_mypubkey,pushaddr,1); + LP_forwarding_register(LP_mypubkey,pushaddr,10); lastforward = now; } //printf("start peers updates\n"); From 46bd3b309e3fbf032b1792c321997ae7f2e86b97 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:44:51 +0300 Subject: [PATCH 1286/2705] Test --- iguana/exchanges/LP_commands.c | 22 +++++++--- iguana/exchanges/LP_forwarding.c | 69 +++++++++++++++++--------------- 2 files changed, 53 insertions(+), 38 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 48ae74b70..36558c11d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -41,7 +41,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits25 jaddstr(reqjson,"method",method); if ( strcmp(method,"price") != 0 ) printf("QUERY.(%s)\n",jprint(reqjson,0)); - LP_pubkey_send(qp->srchash,jprint(reqjson,1),1); + LP_forward(qp->srchash,jprint(reqjson,1),1); for (i=0; i<30; i++) { if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) != 0. ) @@ -99,7 +99,7 @@ int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson, retstr = jprint(retjson,1); if ( pubsock >= 0 ) LP_send(pubsock,retstr,1); - else LP_pubkey_send(utxo->S.otherpubkey,retstr,1); + else LP_forward(utxo->S.otherpubkey,retstr,1); retval = 0; } else printf("error launching swaploop\n"); } else printf("printf error nn_connect to %s\n",pairstr); @@ -208,7 +208,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d retstr = jprint(retjson,1); if ( pubsock >= 0 ) LP_send(pubsock,retstr,1); - else LP_pubkey_send(utxo->S.otherpubkey,retstr,1); + else LP_forward(utxo->S.otherpubkey,retstr,1); utxo->T.published = (uint32_t)time(NULL); } else printf("null price\n"); } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); @@ -400,6 +400,18 @@ forward(pubkey,hexstr)\n\ retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"orderbook") == 0 ) retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); + else if ( strcmp(method,"forward") == 0 ) + { + cJSON *reqjson = jduplicate(argjson); + jdelete(reqjson,"method"); + if ( jstr(reqjson,"method2") != 0 && strncmp("forward",jstr(reqjson,"method2"),strlen("forward")) != 0 ) + { + jaddstr(reqjson,"method",jstr(argjson,"method2")); + if ( LP_forward(jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) + retstr = clonestr("{\"result\":\"success\"}"); + else retstr = clonestr("{\"error\":\"error forwarding\"}"); + } else retstr = clonestr("{\"error\":\"cant recurse forwards\"}"); + } else if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); else if ( IAMLP != 0 ) @@ -413,8 +425,8 @@ forward(pubkey,hexstr)\n\ retstr = LP_register(jbits256(argjson,"pubkey"),jstr(argjson,"pushaddr")); else if ( strcmp(method,"lookup") == 0 ) retstr = LP_lookup(jbits256(argjson,"pubkey")); - else if ( strcmp(method,"forward") == 0 ) - retstr = LP_forward(jbits256(argjson,"pubkey"),jstr(argjson,"hexstr")); + else if ( strcmp(method,"forwardhex") == 0 ) + retstr = LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hexstr")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( strcmp(method,"notified") == 0 ) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index a1adb0d91..da9e04eb5 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -60,7 +60,7 @@ char *LP_register(bits256 pubkey,char *ipaddr) if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { ptr->lasttime = (uint32_t)time(NULL); - return(clonestr("{\"error\":\"already registered\"}")); + return(clonestr("{\"error\":\"already registered\",\"registered\":1}")); } else if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) return(clonestr("{\"error\":\"out of sockets\"}")); @@ -84,7 +84,33 @@ char *LP_register(bits256 pubkey,char *ipaddr) } } -char *LP_forward(bits256 pubkey,char *hexstr) +void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) +{ + char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; + if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) + { + printf("LP_forwarding_register illegal pushaddr or null pubkey\n"); + return; + } + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) + { + //printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( jint(retjson,"registered") != 0 && ++n >= max ) + retval = 0; + free_json(retjson); + } + free(retstr); + } + if ( retval == 0 ) + break; + } +} + +char *LP_forwardhex(bits256 pubkey,char *hexstr) { struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; cJSON *retjson; if ( hexstr == 0 || hexstr[0] == 0 ) @@ -115,35 +141,9 @@ char *LP_forward(bits256 pubkey,char *hexstr) } else return(clonestr("{\"error\":\"notfound\"}")); } -void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) +int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) { - char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; - if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) - { - printf("LP_forwarding_register illegal pushaddr or null pubkey\n"); - return; - } - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) - { - printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( jint(retjson,"registered") != 0 && ++n >= max ) - retval = 0; - free_json(retjson); - } - free(retstr); - } - if ( retval == 0 ) - break; - } -} - -int32_t LP_pubkey_send(bits256 pubkey,char *jsonstr,int32_t freeflag) -{ - struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson; + struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson,*reqjson; if ( jsonstr == 0 || jsonstr[0] == 0 || bits256_nonz(pubkey) == 0 ) return(-1); if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) @@ -162,7 +162,7 @@ int32_t LP_pubkey_send(bits256 pubkey,char *jsonstr,int32_t freeflag) } free(retstr); } - if ( retval == 0 ) + if ( retval == 0 && peer->pushsock >= 0 ) { printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); len = (int32_t)strlen(jsonstr) + 1; @@ -170,8 +170,11 @@ int32_t LP_pubkey_send(bits256 pubkey,char *jsonstr,int32_t freeflag) init_hexbytes_noT(hexstr,(uint8_t *)jsonstr,len); if ( freeflag != 0 ) free(jsonstr); - if ( peer->pushsock >= 0 ) - return(LP_send(peer->pushsock,hexstr,1)); + reqjson = cJSON_CreateObject(); + jaddstr(reqjson,"method","forwardhex"); + jaddstr(reqjson,"hex",hexstr); + free(hexstr); + return(LP_send(peer->pushsock,jprint(reqjson,1),1)); } } return(-1); From 0bf5ffd008393e94267c27dddb5534f5c3d6eb86 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:50:40 +0300 Subject: [PATCH 1287/2705] Test --- iguana/exchanges/forward | 1 + 1 file changed, 1 insertion(+) create mode 100755 iguana/exchanges/forward diff --git a/iguana/exchanges/forward b/iguana/exchanges/forward new file mode 100755 index 000000000..23be25a46 --- /dev/null +++ b/iguana/exchanges/forward @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7779" --data "{\"pubkey\":\"6578099f6474d9b8bd66a7a136b922029a989818ec0309aee962dd6ac1862b74\",\"method\":\"forward\",\"method2\":\"inventory\",\"coin\":\"REVS\"}" From 85f80a64aa016e8ae184659a81261a35e6a20ba7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:54:09 +0300 Subject: [PATCH 1288/2705] Test --- iguana/exchanges/LP_commands.c | 3 ++- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 36558c11d..948304fb7 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -167,7 +167,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { - printf("LP_command.(%s)\n",jprint(argjson,0)); + printf("LP_tradecommand.(%s)\n",jprint(argjson,0)); if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) { char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); @@ -403,6 +403,7 @@ forward(pubkey,hexstr)\n\ else if ( strcmp(method,"forward") == 0 ) { cJSON *reqjson = jduplicate(argjson); + printf("FORWARDED.(%s)\n",jprint(argjson,0)); jdelete(reqjson,"method"); if ( jstr(reqjson,"method2") != 0 && strncmp("forward",jstr(reqjson,"method2"),strlen("forward")) != 0 ) { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f4f625476..1f19f1261 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -100,13 +100,13 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double { if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - printf("%s PULL.[%d] %s\n",myipaddr != 0 ? myipaddr : "127.0.0.1",recvsize,(char *)ptr); + printf("%s PULL.[%d] %s\n",myipaddr != 0 ? myipaddr : "127.0.0.1",recvsize,jsonstr); free(retstr); } } portable_mutex_unlock(&LP_commandmutex); free_json(argjson); - } + } else printf("error parsing(%s)\n",jsonstr); if ( (void *)jsonstr != ptr ) free(jsonstr); if ( ptr != 0 ) From 66bb39799ad758bd932f37ef685aa852191d6739 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 08:55:39 +0300 Subject: [PATCH 1289/2705] Test --- iguana/exchanges/forward | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/forward b/iguana/exchanges/forward index 23be25a46..82225fccd 100755 --- a/iguana/exchanges/forward +++ b/iguana/exchanges/forward @@ -1 +1,2 @@ -curl --url "http://127.0.0.1:7779" --data "{\"pubkey\":\"6578099f6474d9b8bd66a7a136b922029a989818ec0309aee962dd6ac1862b74\",\"method\":\"forward\",\"method2\":\"inventory\",\"coin\":\"REVS\"}" +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"pubkey\":\"6578099f6474d9b8bd66a7a136b922029a989818ec0309aee962dd6ac1862b74\",\"method\":\"forward\",\"method2\":\"inventory\",\"coin\":\"REVS\"}" From b96c72fb35f72607733755bbf7780395943b93a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:01:06 +0300 Subject: [PATCH 1290/2705] Test --- iguana/exchanges/LP_commands.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 948304fb7..7c8418a64 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -402,13 +402,10 @@ forward(pubkey,hexstr)\n\ retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"forward") == 0 ) { - cJSON *reqjson = jduplicate(argjson); printf("FORWARDED.(%s)\n",jprint(argjson,0)); - jdelete(reqjson,"method"); - if ( jstr(reqjson,"method2") != 0 && strncmp("forward",jstr(reqjson,"method2"),strlen("forward")) != 0 ) + if ( jstr(argjson,"method2") != 0 && strncmp("forward",jstr(argjson,"method2"),strlen("forward")) != 0 ) { - jaddstr(reqjson,"method",jstr(argjson,"method2")); - if ( LP_forward(jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) + if ( LP_forward(jbits256(argjson,"pubkey"),jprint(argjson,1),1) > 0 ) retstr = clonestr("{\"result\":\"success\"}"); else retstr = clonestr("{\"error\":\"error forwarding\"}"); } else retstr = clonestr("{\"error\":\"cant recurse forwards\"}"); From 1a11b13757b51650a7060d145c0eadc19ad3c3e3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:03:25 +0300 Subject: [PATCH 1291/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1f19f1261..ca676ecd8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -81,7 +81,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { - int32_t recvsize,len,datalen,nonz = 0; void *ptr; char *retstr,*jsonstr=0; cJSON *argjson; + int32_t recvsize,len,datalen=0,nonz = 0; void *ptr; char *retstr,*jsonstr=0; cJSON *argjson; while ( (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; @@ -92,6 +92,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; + printf("PULLED %d, datalen.%d (%s)\n",recvsize,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { len = (int32_t)strlen(jsonstr) + 1; From 73a7cae0b9a70507a5135503e6186dff674d4c70 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:05:37 +0300 Subject: [PATCH 1292/2705] Test --- iguana/exchanges/LP_commands.c | 7 +++++-- iguana/exchanges/LP_forwarding.c | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7c8418a64..948304fb7 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -402,10 +402,13 @@ forward(pubkey,hexstr)\n\ retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"forward") == 0 ) { + cJSON *reqjson = jduplicate(argjson); printf("FORWARDED.(%s)\n",jprint(argjson,0)); - if ( jstr(argjson,"method2") != 0 && strncmp("forward",jstr(argjson,"method2"),strlen("forward")) != 0 ) + jdelete(reqjson,"method"); + if ( jstr(reqjson,"method2") != 0 && strncmp("forward",jstr(reqjson,"method2"),strlen("forward")) != 0 ) { - if ( LP_forward(jbits256(argjson,"pubkey"),jprint(argjson,1),1) > 0 ) + jaddstr(reqjson,"method",jstr(argjson,"method2")); + if ( LP_forward(jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) retstr = clonestr("{\"result\":\"success\"}"); else retstr = clonestr("{\"error\":\"error forwarding\"}"); } else retstr = clonestr("{\"error\":\"cant recurse forwards\"}"); diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index da9e04eb5..85b087a18 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -173,6 +173,7 @@ int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) reqjson = cJSON_CreateObject(); jaddstr(reqjson,"method","forwardhex"); jaddstr(reqjson,"hex",hexstr); + jaddbits256(reqjson,"pubkey",pubkey); free(hexstr); return(LP_send(peer->pushsock,jprint(reqjson,1),1)); } From 93f7c280a6b2642723b09ee3b2c26f39af5e4428 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:09:48 +0300 Subject: [PATCH 1293/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ca676ecd8..9c465acaa 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -97,7 +97,13 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double { len = (int32_t)strlen(jsonstr) + 1; portable_mutex_lock(&LP_commandmutex); - if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) == 0 ) + if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) + { + printf("forwardhex\n"); + if ( (retstr= LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hexstr"))) != 0 ) + free(retstr); + } + else if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) == 0 ) { if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { From 3635afd48f1164d4919d858d84298cc79a17a15d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:12:00 +0300 Subject: [PATCH 1294/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 85b087a18..202694e41 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -122,6 +122,7 @@ char *LP_forwardhex(bits256 pubkey,char *hexstr) datalen = (int32_t)strlen(hexstr) >> 1; data = malloc(datalen); decode_hex(data,datalen,hexstr); + printf("forwardhex.(%s)\n",(char *)data); sentbytes = LP_send(ptr->pushsock,(char *)data,1); } retjson = cJSON_CreateObject(); @@ -139,6 +140,7 @@ char *LP_forwardhex(bits256 pubkey,char *hexstr) return(jprint(retjson,1)); } } else return(clonestr("{\"error\":\"notfound\"}")); + printf("couldnt find pubkey\n"); } int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) From 9ac6fd473dc0f77fff693390037a04cc8e2928ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:13:40 +0300 Subject: [PATCH 1295/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 948304fb7..70a360320 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -427,7 +427,7 @@ forward(pubkey,hexstr)\n\ else if ( strcmp(method,"lookup") == 0 ) retstr = LP_lookup(jbits256(argjson,"pubkey")); else if ( strcmp(method,"forwardhex") == 0 ) - retstr = LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hexstr")); + retstr = LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hex")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( strcmp(method,"notified") == 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9c465acaa..31fc0e746 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -100,7 +100,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) { printf("forwardhex\n"); - if ( (retstr= LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hexstr"))) != 0 ) + if ( (retstr= LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) free(retstr); } else if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) == 0 ) From 00b10462985ab894444ebfa34fcf7def38526657 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:15:12 +0300 Subject: [PATCH 1296/2705] Test --- iguana/exchanges/forward | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/forward b/iguana/exchanges/forward index 82225fccd..966e6af67 100755 --- a/iguana/exchanges/forward +++ b/iguana/exchanges/forward @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"pubkey\":\"6578099f6474d9b8bd66a7a136b922029a989818ec0309aee962dd6ac1862b74\",\"method\":\"forward\",\"method2\":\"inventory\",\"coin\":\"REVS\"}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"pubkey\":\"6578099f6474d9b8bd66a7a136b922029a989818ec0309aee962dd6ac1862b74\",\"method\":\"forward\",\"method2\":\"getprice\",\"base\":\"REVS\",\"rel\":\"KMD\"}" From 549b5f7f32d37927458ab17d0135469b6c34c272 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:19:36 +0300 Subject: [PATCH 1297/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 70a360320..35dfdcf69 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -162,7 +162,7 @@ char *LP_connected(cJSON *argjson) // alice int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; - if ( (method= jstr(argjson,"method")) != 0 ) + if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 || strcmp(method,"price") == 0 || strcmp(method,"connect") == 0) ) { txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 31fc0e746..145bd3189 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -103,7 +103,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double if ( (retstr= LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) free(retstr); } - else if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) == 0 ) + else if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) <= 0 ) { if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { From a7190071c3429adf8bf007ae250092554b5e1caf Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:20:34 +0300 Subject: [PATCH 1298/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 145bd3189..0f09b308f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -107,7 +107,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double { if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - printf("%s PULL.[%d] %s\n",myipaddr != 0 ? myipaddr : "127.0.0.1",recvsize,jsonstr); + printf("%s PULL.[%d] %s -> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",recvsize,jsonstr,retstr); free(retstr); } } From ed0f1f14b22bbdd42bb164be79a81e210f52740a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:25:16 +0300 Subject: [PATCH 1299/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 ++++-- iguana/exchanges/LP_prices.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0f09b308f..c7ee74b82 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -108,7 +108,9 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { printf("%s PULL.[%d] %s -> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",recvsize,jsonstr,retstr); - free(retstr); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + else free(retstr); } } portable_mutex_unlock(&LP_commandmutex); @@ -133,7 +135,7 @@ int32_t LP_subsock_check(struct LP_peerinfo *peer) portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - //printf("%s RECV.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 3122cd252..1f211fd91 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -375,6 +375,8 @@ char *LP_pricestr(char *base,char *rel) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); + jaddstr(retjson,"method","postprice"); + jaddbits256(retjson,"pubkey",LP_mypubkey); jaddstr(retjson,"base",base); jaddstr(retjson,"rel",rel); jaddnum(retjson,"price",price); From abf2ce9fe3a167fced68c28475f460ab07e5cf26 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:47:59 +0300 Subject: [PATCH 1300/2705] Test --- iguana/exchanges/LP_commands.c | 19 +++++++++++++++---- iguana/exchanges/LP_nativeDEX.c | 11 +++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 35dfdcf69..36ff82c1e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -230,6 +230,18 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d return(retval); } +cJSON *LP_dereference(cJSON *argjson,char *excludemethod) +{ + cJSON *reqjson = 0; + if ( jstr(argjson,"method2") != 0 && strncmp(excludemethod,jstr(argjson,"method2"),strlen(excludemethod)) != 0 ) + { + reqjson = jduplicate(argjson); + jdelete(reqjson,"method"); + jaddstr(reqjson,"method",jstr(argjson,"method2")); + } + return(reqjson); +} + char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; @@ -402,16 +414,15 @@ forward(pubkey,hexstr)\n\ retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"forward") == 0 ) { - cJSON *reqjson = jduplicate(argjson); + cJSON *reqjson; printf("FORWARDED.(%s)\n",jprint(argjson,0)); - jdelete(reqjson,"method"); - if ( jstr(reqjson,"method2") != 0 && strncmp("forward",jstr(reqjson,"method2"),strlen("forward")) != 0 ) + if ( (reqjson= LP_dereference(argjson,"forward")) != 0 ) { - jaddstr(reqjson,"method",jstr(argjson,"method2")); if ( LP_forward(jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) retstr = clonestr("{\"result\":\"success\"}"); else retstr = clonestr("{\"error\":\"error forwarding\"}"); } else retstr = clonestr("{\"error\":\"cant recurse forwards\"}"); + } else if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c7ee74b82..23bf74cf1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -81,7 +81,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { - int32_t recvsize,len,datalen=0,nonz = 0; void *ptr; char *retstr,*jsonstr=0; cJSON *argjson; + int32_t recvsize,len,datalen=0,nonz = 0; void *ptr; char *retstr,*jsonstr=0; cJSON *argjson,*reqjson; while ( (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; @@ -99,10 +99,17 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double portable_mutex_lock(&LP_commandmutex); if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) { - printf("forwardhex\n"); if ( (retstr= LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) free(retstr); } + else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) + { + if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) + { + printf("publish.(%s)\n",jprint(reqjson,0)); + LP_send(pubsock,jprint(reqjson,1),1); + } + } else if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) <= 0 ) { if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) From f33927db8b0dfbca695c41356497f5b17b25f4d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:52:21 +0300 Subject: [PATCH 1301/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 23bf74cf1..6a374e39e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -104,6 +104,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double } else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) { + jdelete(argjson,"method2"); if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) { printf("publish.(%s)\n",jprint(reqjson,0)); From c829ec9584799fe14f862876a13c6e2aa7fba748 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:53:34 +0300 Subject: [PATCH 1302/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6a374e39e..3fa9306a9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -105,6 +105,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) { jdelete(argjson,"method2"); + printf("pub?.(%s)\n",jprint(argjson,0)); if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) { printf("publish.(%s)\n",jprint(reqjson,0)); From 615e66effc9dce2654cfa6367215277d39307f68 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 09:55:25 +0300 Subject: [PATCH 1303/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3fa9306a9..c40a89892 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -104,7 +104,9 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double } else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) { - jdelete(argjson,"method2"); + if ( jobj(argjson,"method2") != 0 ) + jdelete(argjson,"method2"); + jaddstr(argjson,"method2","broadcast"); printf("pub?.(%s)\n",jprint(argjson,0)); if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) { From f149016d07b06e5acc8069a1efaf571dd69aa88d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 10:02:23 +0300 Subject: [PATCH 1304/2705] Test --- iguana/exchanges/LP_commands.c | 8 +++++++- iguana/exchanges/LP_forwarding.c | 6 ++++++ iguana/exchanges/LP_prices.c | 6 ++++++ iguana/exchanges/pub | 2 ++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100755 iguana/exchanges/pub diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 36ff82c1e..2d187b206 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -268,7 +268,9 @@ orderbook(base, rel)\n\ getprice(base, rel)\n\ register(pubkey,pushaddr)\n\ lookup(pubkey)\n\ -forward(pubkey,hexstr)\n\ +forward(pubkey,method2,)\n\ +forward(pubkey,method2=publish,)\n\ +forwardhex(pubkey,hex)\n\ \"}")); //printf("CMD.(%s)\n",jprint(argjson,0)); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) @@ -408,6 +410,10 @@ forward(pubkey,hexstr)\n\ retstr = LP_spentcheck(argjson); else if ( strcmp(method,"getcoins") == 0 ) retstr = jprint(LP_coinsjson(),1); + else if ( strcmp(method,"postprice") == 0 ) + retstr = LP_postedprice(argjson); + else if ( strcmp(method,"broadcast") == 0 ) + retstr = LP_broadcasted(argjson); else if ( strcmp(method,"getprice") == 0 ) retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"orderbook") == 0 ) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 202694e41..3f77c0657 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -184,4 +184,10 @@ int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) } +char *LP_broadcasted(cJSON *argjson) +{ + printf("RECV BROADCAST.(%s)\n",jprint(argjson,0)); + return(clonestr("{\"result\":\"need to update broadcast messages\"}")); +} + diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 1f211fd91..9b35a607a 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -386,5 +386,11 @@ char *LP_pricestr(char *base,char *rel) } else return(clonestr("{\"error\":\"cant find baserel pair\"}")); } +char *LP_postedprice(cJSON *argjson) +{ + printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); + return(clonestr("{\"result\":\"need to update stats\"}")); +} + diff --git a/iguana/exchanges/pub b/iguana/exchanges/pub new file mode 100755 index 000000000..edafc5b98 --- /dev/null +++ b/iguana/exchanges/pub @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"pubkey\":\"6578099f6474d9b8bd66a7a136b922029a989818ec0309aee962dd6ac1862b74\",\"method\":\"forward\",\"method2\":\"publish\",\"data\":\"nonsense\"}" From a3848fdb8dddb6973b9ce8f03f2a742252a34ee3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 10:04:34 +0300 Subject: [PATCH 1305/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 3f77c0657..acccff843 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -122,7 +122,7 @@ char *LP_forwardhex(bits256 pubkey,char *hexstr) datalen = (int32_t)strlen(hexstr) >> 1; data = malloc(datalen); decode_hex(data,datalen,hexstr); - printf("forwardhex.(%s)\n",(char *)data); + //printf("forwardhex.(%s)\n",(char *)data); sentbytes = LP_send(ptr->pushsock,(char *)data,1); } retjson = cJSON_CreateObject(); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c40a89892..d5093bec8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -92,7 +92,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - printf("PULLED %d, datalen.%d (%s)\n",recvsize,datalen,jsonstr); + //printf("PULLED %d, datalen.%d (%s)\n",recvsize,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { len = (int32_t)strlen(jsonstr) + 1; @@ -107,12 +107,8 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double if ( jobj(argjson,"method2") != 0 ) jdelete(argjson,"method2"); jaddstr(argjson,"method2","broadcast"); - printf("pub?.(%s)\n",jprint(argjson,0)); if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) - { - printf("publish.(%s)\n",jprint(reqjson,0)); LP_send(pubsock,jprint(reqjson,1),1); - } } else if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) <= 0 ) { From 5d9aeb8f59a015cccfd09fcdb0fcc2e8f3998282 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 10:11:17 +0300 Subject: [PATCH 1306/2705] Test --- iguana/exchanges/LP_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2d187b206..5954685cc 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -280,6 +280,7 @@ forwardhex(pubkey,hex)\n\ USERPASS_COUNTER = 1; retjson = cJSON_CreateObject(); jaddstr(retjson,"userpass",USERPASS); + jaddbits256(retjson,"mypubkey",LP_mypubkey); jadd(retjson,"coins",LP_coinsjson()); return(jprint(retjson,1)); } From 3476bdf2945665aaa7c74319e5e554b347acbc69 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 10:21:58 +0300 Subject: [PATCH 1307/2705] Test --- iguana/exchanges/LP_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 5954685cc..869525083 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -24,6 +24,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits25 qp->desthash = mypub; strcpy(qp->srccoin,base); strcpy(qp->destcoin,rel); + qp->desthash = LP_mypubkey; if ( strcmp(method,"request") == 0 ) { qp->quotetime = (uint32_t)time(NULL); From d18709100a738dddbaa2f42c06c7dbfe00d5bff1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 10:28:51 +0300 Subject: [PATCH 1308/2705] Test --- iguana/exchanges/LP_quotes.c | 8 +++++++- iguana/exchanges/LP_transaction.c | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 5d31ae262..0721bf597 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -329,7 +329,7 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) bestprice = prices[i]; item = jitem(array,i); bestitem = LP_quotejson(&Q[i]); - printf("bestprice %f vs maxprice %f\n",bestprice,maxprice); + printf("bestprice %f vs maxprice %f (%s)\n",bestprice,maxprice,jprint(bestitem,0)); if ( maxprice == 0. || bestprice <= maxprice ) { Q[i].desttxid = myutxo->payment.txid; @@ -337,6 +337,9 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) Q[i].feetxid = myutxo->fee.txid; Q[i].feevout = myutxo->fee.vout; strcpy(Q[i].destaddr,myutxo->coinaddr); + Q[i].desthash = LP_mypubkey; + strcpy(Q[i].srccoin,base); + strcpy(Q[i].destcoin,myutxo->coin); price = LP_query("request",&Q[i],base,myutxo->coin,myutxo->S.mypub); if ( jobj(bestitem,"price") != 0 ) jdelete(bestitem,"price"); @@ -348,6 +351,9 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) Q[i].feetxid = myutxo->fee.txid; Q[i].feevout = myutxo->fee.vout; strcpy(Q[i].destaddr,myutxo->coinaddr); + Q[i].desthash = LP_mypubkey; + strcpy(Q[i].srccoin,base); + strcpy(Q[i].destcoin,myutxo->coin); price = LP_query("connect",&Q[i],base,myutxo->coin,myutxo->S.mypub); LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); jaddstr(bestitem,"status","connected"); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 43f0978ed..a5aed366b 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -227,6 +227,8 @@ int32_t LP_mempoolscan(char *symbol,bits256 txid) int32_t LP_mempool_vinscan(bits256 *spendtxidp,int32_t *spendvinp,char *symbol,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) { int32_t i,n; cJSON *array; bits256 mempooltxid; + if ( symbol == 0 || symbol[0] == 0 || bits256_nonz(searchtxid) == 0 || bits256_nonz(searchtxid2) == 0 ) + return(-1); if ( (array= LP_getmempool(symbol)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) From 5016bdc010f01b6b441d98a2116b42f0bcf8218b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 10:42:13 +0300 Subject: [PATCH 1309/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d5093bec8..27f9ac502 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -142,7 +142,7 @@ int32_t LP_subsock_check(struct LP_peerinfo *peer) portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + //printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); From 482b51225737db5be5707e2ee4194132a9cdd510 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 12 Jun 2017 12:10:33 +0300 Subject: [PATCH 1310/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/LP_rpc.c | 4 ++-- iguana/exchanges/lookup | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100755 iguana/exchanges/lookup diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 869525083..6b5555b39 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -442,9 +442,9 @@ forwardhex(pubkey,hex)\n\ //printf("RETURN. %d utxos\n",cJSON_GetArraySize(cJSON_Parse(retstr))); } else if ( strcmp(method,"register") == 0 ) - retstr = LP_register(jbits256(argjson,"pubkey"),jstr(argjson,"pushaddr")); + retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr")); else if ( strcmp(method,"lookup") == 0 ) - retstr = LP_lookup(jbits256(argjson,"pubkey")); + retstr = LP_lookup(jbits256(argjson,"client")); else if ( strcmp(method,"forwardhex") == 0 ) retstr = LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hex")); else if ( strcmp(method,"notify") == 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index cbc253e2b..5a88e6a1d 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -63,7 +63,7 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *push char url[512],str[65]; if ( strncmp("tcp://",pushaddr,strlen("tcp://")) != 0 || strlen(pushaddr) <= strlen("tcp://") ) return(clonestr("{\"error\":\"illegal pushaddr\"}")); - sprintf(url,"http://%s:%u/api/stats/register?pubkey=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr+strlen("tcp://")); + sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr+strlen("tcp://")); //printf("getutxo.(%s)\n",url); return(issue_curl(url)); } @@ -71,7 +71,7 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *push char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) { char url[512],str[65]; - sprintf(url,"http://%s:%u/api/stats/lookup?pubkey=%s",destip,destport,bits256_str(str,pubkey)); + sprintf(url,"http://%s:%u/api/stats/lookup?client=%s",destip,destport,bits256_str(str,pubkey)); //printf("getutxo.(%s)\n",url); return(issue_curl(url)); } diff --git a/iguana/exchanges/lookup b/iguana/exchanges/lookup new file mode 100755 index 000000000..af9cdd645 --- /dev/null +++ b/iguana/exchanges/lookup @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"pubkey\":\"6578099f6474d9b8bd66a7a136b922029a989818ec0309aee962dd6ac1862b74\",\"method\":\"forward\",\"method2\":\"lookup\",\"client\":\"$1\"}" From 29963727957cabba52c50ed8df5bb929a1a7cfa7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 13:05:41 +0300 Subject: [PATCH 1311/2705] Test --- iguana/exchanges/LP_commands.c | 37 ++--- iguana/exchanges/LP_forwarding.c | 28 ++-- iguana/exchanges/LP_include.h | 7 +- iguana/exchanges/LP_nativeDEX.c | 57 +++----- iguana/exchanges/LP_prices.c | 216 +++++++++++++++++++++++------ iguana/exchanges/LP_quotes.c | 52 +++++-- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_statemachine.c | 42 ++++++ iguana/exchanges/LP_utxos.c | 50 +++---- 9 files changed, 338 insertions(+), 153 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6b5555b39..a4a964ee1 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -45,7 +45,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits25 LP_forward(qp->srchash,jprint(reqjson,1),1); for (i=0; i<30; i++) { - if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) != 0. ) + if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) > SMALLVAL ) { if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) { @@ -61,7 +61,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits25 int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) { char *retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; - if ( (price= LP_price(base,rel)) != 0. ) + if ( (price= LP_price(base,rel)) > SMALLVAL ) { price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) @@ -182,7 +182,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d retval = 1; if ( LP_isavailable(utxo) > 0 ) { - if ( (price= LP_price(base,rel)) != 0. ) + if ( (price= LP_price(base,rel)) > SMALLVAL ) { price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) @@ -210,7 +210,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d if ( pubsock >= 0 ) LP_send(pubsock,retstr,1); else LP_forward(utxo->S.otherpubkey,retstr,1); - utxo->T.published = (uint32_t)time(NULL); + utxo->T.lasttime = (uint32_t)time(NULL); } else printf("null price\n"); } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); } @@ -245,7 +245,7 @@ cJSON *LP_dereference(cJSON *argjson,char *excludemethod) char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; + char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (method= jstr(argjson,"method")) == 0 ) return(clonestr("{\"error\":\"need method in request\"}")); else if ( strcmp(method,"help") == 0 ) @@ -289,31 +289,22 @@ forwardhex(pubkey,hex)\n\ return(clonestr("{\"error\":\"authentication error\"}")); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) { - //char str[65]; + double price; if ( LP_isdisabled(base,rel) != 0 ) return(clonestr("{\"error\":\"at least one of coins disabled\"}")); if ( strcmp(method,"setprice") == 0 ) { - if ( LP_mypriceset(base,rel,jdouble(argjson,"price")) < 0 ) - return(clonestr("{\"error\":\"couldnt set price\"}")); - else + if ( (price= jdouble(argjson,"price")) > SMALLVAL ) { - if ( IAMLP != 0 ) - { - HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) - { - if ( LP_ismine(utxo) > 0 && strcmp(utxo->coin,base) == 0 )//|| strcmp(utxo->coin,rel) == 0) ) - LP_priceping(LP_mypubsock,utxo,rel,LP_profitratio - 1.); - //else printf("notmine.(%s %s)\n",utxo->coin,bits256_str(str,utxo->txid)); - } - } - return(clonestr("{\"result\":\"success\"}")); - } + if ( LP_mypriceset(base,rel,price) < 0 ) + return(clonestr("{\"error\":\"couldnt set price\"}")); + else return(LP_pricepings(LP_mypubsock,base,rel,price * LP_profitratio)); + } else return(clonestr("{\"error\":\"no price\"}")); } else if ( strcmp(method,"myprice") == 0 ) { double bid,ask; - if ( LP_myprice(&bid,&ask,base,rel) != 0. ) + if ( LP_myprice(&bid,&ask,base,rel) > SMALLVAL ) { retjson = cJSON_CreateObject(); jaddstr(retjson,"base",base); @@ -417,7 +408,7 @@ forwardhex(pubkey,hex)\n\ else if ( strcmp(method,"broadcast") == 0 ) retstr = LP_broadcasted(argjson); else if ( strcmp(method,"getprice") == 0 ) - retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel")); + retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel"),0.); else if ( strcmp(method,"orderbook") == 0 ) retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); else if ( strcmp(method,"forward") == 0 ) @@ -454,7 +445,7 @@ forwardhex(pubkey,hex)\n\ if ( juint(argjson,"timestamp") > time(NULL)-60 ) { printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_addutxo(1,LP_mypubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"valuesats"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"valuesats2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit")); + LP_utxoaddjson(1,LP_mypubsock,argjson); } retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index acccff843..7b6d866b9 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -146,24 +146,30 @@ char *LP_forwardhex(bits256 pubkey,char *hexstr) int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) { struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson,*reqjson; - if ( jsonstr == 0 || jsonstr[0] == 0 || bits256_nonz(pubkey) == 0 ) + if ( jsonstr == 0 || jsonstr[0] == 0 ) return(-1); - if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) + if ( bits256_nonz(pubkey) != 0 ) { - return(LP_send(ptr->pushsock,jsonstr,1)); + if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) + { + return(LP_send(ptr->pushsock,jsonstr,1)); + } } HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( (retstr= issue_LP_lookup(peer->ipaddr,peer->port,pubkey)) != 0 ) + if ( bits256_nonz(pubkey) != 0 ) { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) + if ( (retstr= issue_LP_lookup(peer->ipaddr,peer->port,pubkey)) != 0 ) { - if ( jint(retjson,"forwarding") != 0 && peer->pushsock >= 0 ) - retval = 0; - free_json(retjson); + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( jint(retjson,"forwarding") != 0 && peer->pushsock >= 0 ) + retval = 0; + free_json(retjson); + } + free(retstr); } - free(retstr); - } + } else retval = 0; if ( retval == 0 && peer->pushsock >= 0 ) { printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); @@ -178,7 +184,7 @@ int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) jaddbits256(reqjson,"pubkey",pubkey); free(hexstr); return(LP_send(peer->pushsock,jprint(reqjson,1),1)); - } + } else retval = -1; } return(-1); } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 3648309f7..93642f146 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -147,7 +147,7 @@ struct iguana_info struct _LP_utxoinfo { bits256 txid; uint64_t value; int32_t vout; }; -struct LP_utxostats { uint32_t lasttime,errors,swappending,published,spentflag,lastspentcheck; }; +struct LP_utxostats { uint32_t lasttime,errors,swappending,spentflag,lastspentcheck; }; struct LP_utxobob { struct _LP_utxoinfo utxo,deposit; }; @@ -218,6 +218,9 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); void LP_quotesinit(char *base,char *rel); -int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin); +int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag); +int32_t LP_ismine(struct LP_utxoinfo *utxo); +int32_t LP_isavailable(struct LP_utxoinfo *utxo); + #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 27f9ac502..c1ece23e6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -32,7 +32,7 @@ char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196" , "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // -portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex; +portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex; int32_t LP_mypubsock = -1; int32_t USERPASS_COUNTER,IAMLP = 0; double LP_profitratio = 1.; @@ -154,27 +154,6 @@ int32_t LP_subsock_check(struct LP_peerinfo *peer) return(nonz); } -int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double profitmargin) -{ - double price,bid,ask; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; - if ( (now= (uint32_t)time(NULL)) > utxo->T.swappending ) - utxo->T.swappending = 0; - if ( now > utxo->T.published+60 && utxo->T.swappending == 0 && utxo->S.swap == 0 && (price= LP_myprice(&bid,&ask,utxo->coin,rel)) != 0. ) - { - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - Q.timestamp = (uint32_t)time(NULL); - retjson = LP_quotejson(&Q); - jaddstr(retjson,"method","quote"); - retstr = jprint(retjson,1); - //printf("PING.(%s)\n",retstr); - LP_send(pubsock,retstr,1); - utxo->T.published = now; - return(0); - } - return(-1); -} - void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitmargin) { struct _LP_utxoinfo u; char str[65]; uint32_t now = (uint32_t)time(NULL); @@ -193,13 +172,14 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,u.txid),u.vout,dstr(u.value)); LP_spentnotify(utxo,1); } - else if ( LP_ismine(utxo) > 0 ) + /*else if ( LP_ismine(utxo) > 0 ) { + printf("iterate through all locally generated quotes and update, or change to price feed\n"); // jl777: iterated Q's if ( strcmp(utxo->coin,"KMD") == 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); else LP_priceping(pubsock,utxo,"KMD",profitmargin); - } + }*/ } } @@ -209,9 +189,23 @@ void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) LP_privkey_updates(pubsock,passphrase); } +void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubsock,struct LP_peerinfo *peer,uint32_t now,double profitmargin,int32_t interval) +{ + int32_t lastn; + if ( now > peer->lastutxos+interval ) + { + peer->lastutxos = now; + //lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; + //if ( lastn < LP_PROPAGATION_SLACK * 2 ) + lastn = LP_PROPAGATION_SLACK * 2; + if ( mypeer == 0 || strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) + LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); + } +} + void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) { - char *retstr; uint8_t r; int32_t i,n,j,counter=0,nonz,lastn; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; struct LP_utxoinfo *utxo,*utmp; + char *retstr; uint8_t r; int32_t i,n,j,counter=0,nonz; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; struct LP_utxoinfo *utxo,*utmp; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); @@ -278,6 +272,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in HASH_ITER(hh,LP_peerinfos,peer,tmp) { nonz += LP_subsock_check(peer); + LP_peer_utxosquery(LP_mypeer,myport,pubsock,peer,now,profitmargin,600); } if ( pullsock >= 0 ) { @@ -325,17 +320,8 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); } - if ( peer->numutxos != mypeer->numutxos && now > peer->lastutxos+60 ) - { - peer->lastutxos = now; - lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; - if ( lastn < LP_PROPAGATION_SLACK * 2 ) - lastn = LP_PROPAGATION_SLACK * 2; - // printf("%s numutxos.%d vs %d lastn.%d\n",peer->ipaddr,peer->numutxos,mypeer->numutxos,lastn); - if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) - LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer->ipaddr,myport,profitmargin); - } nonz += LP_subsock_check(peer); + LP_peer_utxosquery(LP_mypeer,myport,pubsock,peer,now,profitmargin,60); } if ( (counter % 100) == 0 ) { @@ -373,6 +359,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit portable_mutex_init(&LP_swaplistmutex); portable_mutex_init(&LP_cachemutex); portable_mutex_init(&LP_forwardmutex); + portable_mutex_init(&LP_pubkeymutex); if ( profitmargin == 0. || profitmargin == 0.01 ) { profitmargin = 0.01 + (double)(rand() % 100)/100000; diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 9b35a607a..c0ad1eef0 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -18,6 +18,8 @@ // marketmaker // +struct LP_orderbookentry { bits256 txid; double price; uint64_t basesatoshis; int32_t vout; }; + #define LP_MAXPRICEINFOS 64 struct LP_priceinfo { @@ -39,6 +41,13 @@ struct LP_cacheinfo uint32_t timestamp; } *LP_cacheinfos; +struct LP_pubkeyinfo +{ + UT_hash_handle hh; + bits256 pubkey; + double matrix[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS]; +} *LP_pubkeyinfos; + int32_t LP_cachekey(uint8_t *key,char *base,char *rel,bits256 txid,int32_t vout) { uint64_t basebits,relbits; int32_t offset = 0; @@ -70,6 +79,29 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout return(ptr); } +struct LP_pubkeyinfo *LP_pubkeyfind(bits256 pubkey) +{ + struct LP_pubkeyinfo *pubp=0; + portable_mutex_lock(&LP_pubkeymutex); + HASH_FIND(hh,LP_pubkeyinfos,&pubkey,sizeof(pubkey),pubp); + portable_mutex_unlock(&LP_pubkeymutex); + return(pubp); +} + +struct LP_pubkeyinfo *LP_pubkeyadd(bits256 pubkey) +{ + struct LP_pubkeyinfo *pubp=0; + if ( (pubp= LP_pubkeyfind(pubkey)) == 0 ) + { + portable_mutex_lock(&LP_pubkeymutex); + HASH_ADD(hh,LP_pubkeyinfos,pubkey,sizeof(pubkey),pubp); + portable_mutex_unlock(&LP_pubkeymutex); + if ( (pubp= LP_pubkeyfind(pubkey)) == 0 ) + printf("pubkeyadd find error after add\n"); + } + return(pubp); +} + double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,int32_t vout) { struct LP_cacheinfo *ptr; @@ -79,7 +111,7 @@ double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,i (*qp) = ptr->Q; if ( ptr->price == 0. && ptr->Q.satoshis != 0 ) { - printf("null ptr->price? "); + printf("LP_pricecache: null ptr->price? "); ptr->price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; } //printf("found %s/%s %.8f\n",base,rel,ptr->price); @@ -136,9 +168,9 @@ double LP_myprice(double *bidp,double *askp,char *base,char *rel) *bidp = *askp = 0.; if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { - if ( (*askp= basepp->myprices[relpp->ind]) != 0. ) + if ( (*askp= basepp->myprices[relpp->ind]) > SMALLVAL ) { - if ( (val= relpp->myprices[basepp->ind]) != 0. ) + if ( (val= relpp->myprices[basepp->ind]) > SMALLVAL ) { *bidp = 1. / val; } else *bidp = *askp * 0.99; @@ -146,7 +178,7 @@ double LP_myprice(double *bidp,double *askp,char *base,char *rel) } else { - if ( (val= relpp->myprices[basepp->ind]) != 0. ) + if ( (val= relpp->myprices[basepp->ind]) > SMALLVAL ) { *bidp = 1. / val; *askp = *bidp / 0.99; @@ -159,7 +191,7 @@ double LP_myprice(double *bidp,double *askp,char *base,char *rel) int32_t LP_mypriceset(char *base,char *rel,double price) { struct LP_priceinfo *basepp,*relpp; - if ( price != 0. && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + if ( price > SMALLVAL && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { basepp->myprices[relpp->ind] = price; // ask relpp->myprices[basepp->ind] = (1. / price); // bid @@ -197,7 +229,7 @@ cJSON *LP_priceinfomatrix(int32_t usemyprices) { if ( usemyprices == 0 || (val= pp->myprices[j]) == 0. ) val = pp->relvals[j]; - if ( val != 0. ) + if ( val > SMALLVAL ) { sum += val; n++; @@ -214,8 +246,11 @@ cJSON *LP_priceinfomatrix(int32_t usemyprices) pp = LP_priceinfos; for (i=0; idiagval /= total; - jaddnum(vectorjson,pp->symbol,pp->diagval); + if ( pp->diagval > SMALLVAL ) + { + pp->diagval /= total; + jaddnum(vectorjson,pp->symbol,pp->diagval); + } } } return(vectorjson); @@ -269,8 +304,8 @@ struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout, static int _cmp_orderbook(const void *a,const void *b) { int32_t retval = 0; -#define ptr_a (*(struct LP_cacheinfo **)a)->price -#define ptr_b (*(struct LP_cacheinfo **)b)->price +#define ptr_a (*(struct LP_orderbookentry **)a)->price +#define ptr_b (*(struct LP_orderbookentry **)b)->price if ( ptr_b > ptr_a ) retval = 1; else if ( ptr_b < ptr_a ) @@ -279,8 +314,8 @@ static int _cmp_orderbook(const void *a,const void *b) { #undef ptr_a #undef ptr_b -#define ptr_a ((struct LP_cacheinfo *)a)->Q.satoshis -#define ptr_b ((struct LP_cacheinfo *)b)->Q.satoshis +#define ptr_a ((struct LP_orderbookentry *)a)->basesatoshis +#define ptr_b ((struct LP_orderbookentry *)b)->basesatoshis if ( ptr_b > ptr_a ) return(1); else if ( ptr_b < ptr_a ) @@ -297,23 +332,88 @@ static int _cmp_orderbookrev(const void *a,const void *b) return(-_cmp_orderbook(a,b)); } -cJSON *LP_orderbookjson(struct LP_cacheinfo *ptr,int32_t polarity) +cJSON *LP_orderbookjson(struct LP_orderbookentry *op) { - double price; cJSON *item = cJSON_CreateObject(); - if ( ptr->Q.satoshis != 0 && ptr->Q.destsatoshis != 0 ) + cJSON *item = cJSON_CreateObject(); + if ( op->price > SMALLVAL ) { - price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; - jaddnum(item,"price",polarity > 0 ? price : 1. / price); - jaddnum(item,"volume",polarity > 0 ? dstr(ptr->Q.satoshis) : dstr(ptr->Q.destsatoshis)); - jaddbits256(item,"txid",ptr->Q.txid); - jaddnum(item,"vout",ptr->Q.vout); + jaddnum(item,"price",op->price ); + jaddnum(item,"volume",dstr(op->basesatoshis)); + jaddbits256(item,"txid",op->txid); + jaddnum(item,"vout",op->vout); } return(item); } +struct LP_orderbookentry *LP_orderbookentry(char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t basesatoshis) +{ + struct LP_orderbookentry *op; + if ( (op= calloc(1,sizeof(*op))) != 0 ) + { + op->txid = txid; + op->vout = vout; + op->price = price; + op->basesatoshis = basesatoshis; + } + return(op); +} + +int32_t LP_orderbookfind(struct LP_orderbookentry **array,int32_t num,bits256 txid,int32_t vout) +{ + int32_t i; + for (i=0; ivout == vout && bits256_cmp(array[i]->txid,txid) == 0 ) + return(i); + return(-1); +} + +int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol,double price,struct LP_orderbookentry **array,int32_t num,int32_t cachednum,bits256 pubkey) +{ + struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_orderbookentry *op; uint64_t basesatoshis; + HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) + { + if ( LP_ismine(utxo) > 0 && strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) + { + if ( LP_orderbookfind(array,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) + { + char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); + array = realloc(array,sizeof(*array) * (num+1)); + if ( strcmp(base,symbol) == 0 ) + basesatoshis = utxo->payment.value; + else basesatoshis = utxo->payment.value * price; + if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,price,basesatoshis)) != 0 ) + array[num++] = op; + if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) + { + HASH_ITER(hh,LP_peerinfos,peer,ptmp) + { + if ( (retstr= issue_LP_notifyutxo(peer->ipaddr,peer->port,utxo)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( jobj(retjson,"error") == 0 ) + utxo->T.lasttime = (uint32_t)time(NULL); + free_json(retjson); + } + free(retstr); + } + if ( utxo->T.lasttime != 0 ) + break; + } + } + } + } + } + return(num); +} + char *LP_orderbook(char *base,char *rel) { - uint32_t now,i; struct LP_cacheinfo *ptr,*tmp,**bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0; + uint32_t now,i; struct LP_priceinfo *basepp=0,*relpp=0; struct LP_pubkeyinfo *pubp,*ptmp; struct LP_cacheinfo *ptr,*tmp; struct LP_orderbookentry *op,**bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0,cachenumbids,cachenumasks,baseid,relid; + if ( (basepp= LP_priceinfofind(base)) == 0 || (relpp= LP_priceinfofind(rel)) == 0 ) + return(clonestr("{\"error\":\"base or rel not added\"}")); + baseid = basepp->ind; + relid = relpp->ind; now = (uint32_t)time(NULL); HASH_ITER(hh,LP_cacheinfos,ptr,tmp) { @@ -322,23 +422,28 @@ char *LP_orderbook(char *base,char *rel) if ( strcmp(ptr->Q.srccoin,base) == 0 && strcmp(ptr->Q.destcoin,rel) == 0 ) { asks = realloc(asks,sizeof(*asks) * (numasks+1)); - asks[numasks++] = ptr; + if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->price,ptr->Q.satoshis)) != 0 ) + asks[numasks++] = op; } else if ( strcmp(ptr->Q.srccoin,rel) == 0 && strcmp(ptr->Q.destcoin,base) == 0 ) { bids = realloc(bids,sizeof(*bids) * (numbids+1)); - bids[numbids++] = ptr; + if ( (op= LP_orderbookentry(base,rel,ptr->Q.desttxid,ptr->Q.destvout,1./ptr->price,ptr->Q.satoshis)) != 0 ) + bids[numbids++] = op; } } + cachenumbids = numbids, cachenumasks = numasks; + HASH_ITER(hh,LP_pubkeyinfos,pubp,ptmp) + { + if ( pubp->matrix[baseid][relid] > SMALLVAL ) + numasks = LP_orderbook_utxoentries(now,base,rel,base,pubp->matrix[baseid][relid],asks,numasks,cachenumasks,pubp->pubkey); + if ( pubp->matrix[relid][baseid] > SMALLVAL ) + numasks = LP_orderbook_utxoentries(now,base,rel,rel,pubp->matrix[relid][baseid],bids,numbids,cachenumbids,pubp->pubkey); + } retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); if ( numbids > 1 ) qsort(bids,numbids,sizeof(*bids),_cmp_orderbookrev); - for (i=0; i 1 ) { for (i=0; iprice); printf("sorted asks.%d\n",numasks); } + for (i=0; i SMALLVAL && origprice < price ) + price = origprice; + } + if ( price > SMALLVAL ) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); @@ -386,11 +505,24 @@ char *LP_pricestr(char *base,char *rel) } else return(clonestr("{\"error\":\"cant find baserel pair\"}")); } -char *LP_postedprice(cJSON *argjson) +void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]) { - printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); - return(clonestr("{\"result\":\"need to update stats\"}")); + LP_priceinfoupdate(base,rel,price); } +void LP_pricefeedupdate(bits256 pubkey,char *base,char *rel,double price) +{ + struct LP_priceinfo *basepp,*relpp; struct LP_pubkeyinfo *pubp; char str[65]; + printf("PRICEFEED UPDATE.(%s/%s) %.8f %s\n",base,rel,price,bits256_str(str,pubkey)); + if ( price > SMALLVAL && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + { + if ( (pubp= LP_pubkeyadd(pubkey)) != 0 ) + pubp->matrix[basepp->ind][relpp->ind] = price; + else printf("error creating pubkey entry\n"); + } else printf("error finding %s/%s %.8f\n",base,rel,price); +} + + + diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 0721bf597..a00bf6f3d 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -13,6 +13,7 @@ * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ + // // LP_quotes.c // marketmaker @@ -172,11 +173,49 @@ char *LP_quotereceived(cJSON *argjson) if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) { ptr->Q = Q; - //char str[65]; printf("received.(%s) quote %.8f\n",bits256_str(str,Q.txid),price); + char str[65]; printf("received.(%s) quote %.8f\n",bits256_str(str,Q.txid),price); return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); } +char *LP_pricepings(int32_t pubsock,char *base,char *rel,double price) +{ + bits256 zero; cJSON *reqjson = cJSON_CreateObject(); + jaddbits256(reqjson,"pubkey",LP_mypubkey); + jaddstr(reqjson,"base",base); + jaddstr(reqjson,"rel",rel); + jaddnum(reqjson,"price",price); + if ( pubsock >= 0 ) + { + jaddstr(reqjson,"method","postprice"); + LP_send(pubsock,jprint(reqjson,1),1); + } + else + { + jaddstr(reqjson,"method","forward"); + jaddstr(reqjson,"method2","postprice"); + memset(zero.bytes,0,sizeof(zero)); + LP_forward(zero,jprint(reqjson,1),1); + } + return(clonestr("{\"result\":\"success\"}")); +} + +char *LP_postedprice(cJSON *argjson) +{ + bits256 pubkey; double price; char *base,*rel,str[65]; + if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && (price= jdouble(argjson,"price")) > SMALLVAL ) + { + pubkey = jbits256(argjson,"pubkey"); + if ( bits256_nonz(pubkey) != 0 ) + { + LP_pricefeedupdate(pubkey,base,rel,price); + printf("PRICE POSTED.(%s/%s) %.8f %s\n",base,rel,price,bits256_str(str,pubkey)); + return(clonestr("{\"result\":\"success\"}")); + } + } + return(clonestr("{\"error\":\"missing fields in posted price\"}")); +} + int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) { if ( mysatoshis >= othersatoshis ) @@ -199,11 +238,6 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) cJSON *LP_tradecandidates(char *base) { struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; - /*if ( (price= LP_price(base,myutxo->coin)) == .0 ) - { - printf("no LP_price (%s -> %s)\n",base,myutxo->coin); - return(0); - }*/ totaladded = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -296,17 +330,17 @@ cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) price = LP_query("price",&Q[i],base,myutxo->coin,zero); Q[i].destsatoshis = price * Q[i].satoshis; } - if ( (prices[i]= price) != 0. && (bestprice == 0. || price < bestprice) ) + if ( (prices[i]= price) > SMALLVAL && (bestprice == 0. || price < bestprice) ) bestprice = price; char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); } - if ( bestprice != 0. ) + if ( bestprice > SMALLVAL ) { bestmetric = 0.; besti = -1; for (i=0; iS.satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) + if ( (price= prices[i]) > SMALLVAL && myutxo->S.satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) { metric = price / bestprice; printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 5a88e6a1d..a80197ccd 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&valuesats=%llu&txid2=%s&vout2=%d&valuesats2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str2,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); + sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str2,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index ed4fe4fc8..2f2c39565 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -1264,3 +1264,45 @@ int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct igu } portable_mutex_unlock(&myinfo->DEX_swapmutex); }*/ + +/*int32_t LP_priceping(int32_t pubsock,struct LP_utxoinfo *utxo,char *rel,double origprice) + { + double price,bid,ask; uint32_t now; cJSON *retjson; struct LP_quoteinfo Q; char *retstr; + if ( (now= (uint32_t)time(NULL)) > utxo->T.swappending && utxo->S.swap == 0 ) + utxo->T.swappending = 0; + if ( now > utxo->T.published+60 && LP_isavailable(utxo) && (price= LP_myprice(&bid,&ask,utxo->coin,rel)) != 0. ) + { + if ( origprice < price ) + price = origprice; + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + Q.timestamp = (uint32_t)time(NULL); + retjson = LP_quotejson(&Q); + jaddstr(retjson,"method","quote"); + retstr = jprint(retjson,1); + //printf("PING.(%s)\n",retstr); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + else + { + // verify it is in list + // push if it isnt + } + utxo->T.published = now; + return(0); + } + return(-1); + }*/ +/*if ( addflag != 0 && LP_utxofind(1,Q.txid,Q.vout) == 0 ) + { + LP_utxoadd(1,-1,Q.srccoin,Q.txid,Q.vout,Q.value,Q.txid2,Q.vout2,Q.value2,"",Q.srcaddr,Q.srchash,0.); + LP_utxoadd(0,-1,Q.destcoin,Q.desttxid,Q.destvout,Q.destvalue,Q.feetxid,Q.feevout,Q.feevalu,"",Q.destaddr,Q.desthash,0.); + }*/ + +/*struct LP_utxoinfo *utxo,*tmp; + HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) + { + if ( LP_ismine(utxo) > 0 && strcmp(utxo->coin,base) == 0 ) + LP_priceping(LP_mypubsock,utxo,rel,price * LP_profitratio); + }*/ + diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 9ec09fee6..dfe649e21 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -338,7 +338,7 @@ int32_t LP_iseligible(int32_t iambob,char *coin,bits256 txid,int32_t vout,uint64 return(0); } -struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) +struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { char str[65]; uint64_t tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) @@ -351,19 +351,19 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit else tmpsatoshis = value; if ( LP_iseligible(iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { - printf("LP_addutxo got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); + printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); } if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) { - printf("LP_addutxo selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); return(0); } if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { if ( LP_ismine(utxo) == 0 ) { - char str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); + char str2[65],str3[65]; printf("iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis)); } u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; @@ -372,7 +372,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit utxo->T.errors++; char str[65],str2[65],str3[65],str4[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,txid),bits256_str(str2,utxo->payment.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); } - else if ( profitmargin != 0. ) + else if ( profitmargin > SMALLVAL ) utxo->S.profitmargin = profitmargin; } else @@ -401,7 +401,7 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit } LP_utxosetkey(utxo->key,txid,vout); LP_utxosetkey(utxo->key2,txid2,vout2); - char str[65],str2[65],str3[65]; printf("iambob.%d %s %s LP_addutxo.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); + char str[65],str2[65],str3[65]; printf("iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) @@ -415,14 +415,14 @@ struct LP_utxoinfo *LP_addutxo(int32_t iambob,int32_t mypubsock,char *symbol,bit return(utxo); } -int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson) +{ + return(LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid2"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit"))); +} + +int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; - if ( IAMLP == 0 ) - { - printf("LP_utxosparse not for clientside\n"); - return(-1); - } if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -443,11 +443,8 @@ int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa { txid = jbits256(item,"txid"); //printf("parse.(%s)\n",jprint(item,0)); - utxo = LP_addutxo(1,mypubsock,jstr(item,"coin"),txid,jint(item,"vout"),j64bits(item,"value"),jbits256(item,"txid2"),jint(item,"vout2"),j64bits(item,"value2"),jstr(item,"script"),jstr(item,"address"),jbits256(item,"pubkey"),jdouble(item,"profit")); - if ( utxo != 0 ) - { + if ( (utxo= LP_utxoaddjson(1,mypubsock,item)) != 0 ) utxo->T.lasttime = now; - } } } // else printf("skip.(%s)\n",jprint(item,0)); } @@ -463,27 +460,20 @@ int32_t LP_utxosparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipa void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { - char *retstr; struct LP_peerinfo *peer; int32_t i,firsti; uint32_t now; - if ( IAMLP == 0 ) - { - printf("LP_utxosquery not for clientside\n"); - return; - } + char *retstr; struct LP_peerinfo *peer; uint32_t now; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); - if ( mypeer == 0 ) //(peer != 0 && peer->errors > 0) || - return; if ( coin == 0 ) coin = ""; - if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer->numpeers,mypeer->numutxos)) != 0 ) + if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer != 0 ? mypeer->numpeers : 0,mypeer != 0 ? mypeer->numutxos : 0)) != 0 ) { now = (uint32_t)time(NULL); - LP_utxosparse(mypeer,mypubsock,destipaddr,destport,retstr,now); + LP_utxosparse(mypubsock,destipaddr,destport,retstr,now); free(retstr); - i = 0; + /*i = 0; if ( lastn >= mypeer->numutxos ) firsti = -1; else firsti = (mypeer->numutxos - lastn); - /*HASH_ITER(hh,LP_utxoinfos,utxo,tmp) + HASH_ITER(hh,LP_utxoinfos,utxo,tmp) { if ( i++ < firsti ) continue; @@ -602,14 +592,14 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr values[i] = 0, used++; if ( iambob != 0 ) { - if ( (utxo= LP_addutxo(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_mypeer != 0 ? LP_mypeer->profitmargin : 0.01)) != 0 ) + if ( (utxo= LP_utxoadd(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_mypeer != 0 ? LP_mypeer->profitmargin : 0.01)) != 0 ) { //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); } } else { - if ( (utxo= LP_addutxo(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0)) != 0 ) + if ( (utxo= LP_utxoadd(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0.)) != 0 ) { //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); } From 22ad721ed60152d5140b168f56591d9d75f325e3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 13:53:50 +0300 Subject: [PATCH 1312/2705] Test --- iguana/exchanges/LP_quotes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index a00bf6f3d..f4e5b30bd 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -188,6 +188,7 @@ char *LP_pricepings(int32_t pubsock,char *base,char *rel,double price) if ( pubsock >= 0 ) { jaddstr(reqjson,"method","postprice"); + printf("pricepings.(%s)\n",jprint(reqjson,0)); LP_send(pubsock,jprint(reqjson,1),1); } else From 65c619ec3c9890052e73af5c8d7d5fb2f42d1899 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 13:59:47 +0300 Subject: [PATCH 1313/2705] Test --- iguana/exchanges/LP_quotes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index f4e5b30bd..b887de1b7 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -203,14 +203,14 @@ char *LP_pricepings(int32_t pubsock,char *base,char *rel,double price) char *LP_postedprice(cJSON *argjson) { - bits256 pubkey; double price; char *base,*rel,str[65]; + bits256 pubkey; double price; char *base,*rel; + printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && (price= jdouble(argjson,"price")) > SMALLVAL ) { pubkey = jbits256(argjson,"pubkey"); if ( bits256_nonz(pubkey) != 0 ) { LP_pricefeedupdate(pubkey,base,rel,price); - printf("PRICE POSTED.(%s/%s) %.8f %s\n",base,rel,price,bits256_str(str,pubkey)); return(clonestr("{\"result\":\"success\"}")); } } From e5fcb6c9250391d83a6e159af88811b1af5b456c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:01:23 +0300 Subject: [PATCH 1314/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c1ece23e6..b3ac6f31a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -142,7 +142,7 @@ int32_t LP_subsock_check(struct LP_peerinfo *peer) portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - //printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); From ed15575d701c6844b1bbd8cf8a5e1f255f794df8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:05:47 +0300 Subject: [PATCH 1315/2705] Test --- iguana/exchanges/LP_prices.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index c0ad1eef0..3a9c69b6e 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -82,9 +82,11 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout struct LP_pubkeyinfo *LP_pubkeyfind(bits256 pubkey) { struct LP_pubkeyinfo *pubp=0; + printf("pub find\n"); portable_mutex_lock(&LP_pubkeymutex); HASH_FIND(hh,LP_pubkeyinfos,&pubkey,sizeof(pubkey),pubp); portable_mutex_unlock(&LP_pubkeymutex); + printf("pub find.%p\n",pubp); return(pubp); } @@ -93,12 +95,15 @@ struct LP_pubkeyinfo *LP_pubkeyadd(bits256 pubkey) struct LP_pubkeyinfo *pubp=0; if ( (pubp= LP_pubkeyfind(pubkey)) == 0 ) { + printf("pub add\n"); portable_mutex_lock(&LP_pubkeymutex); HASH_ADD(hh,LP_pubkeyinfos,pubkey,sizeof(pubkey),pubp); portable_mutex_unlock(&LP_pubkeymutex); + printf("pub add.%p\n",pubp); if ( (pubp= LP_pubkeyfind(pubkey)) == 0 ) printf("pubkeyadd find error after add\n"); } + printf("pub add ret.%p\n",pubp); return(pubp); } From c0d538da8c8ae788c163b5315825983ee7f2685d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:07:05 +0300 Subject: [PATCH 1316/2705] Test --- iguana/exchanges/LP_prices.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 3a9c69b6e..62e75a351 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -97,6 +97,8 @@ struct LP_pubkeyinfo *LP_pubkeyadd(bits256 pubkey) { printf("pub add\n"); portable_mutex_lock(&LP_pubkeymutex); + pubp = calloc(1,sizeof(*pubp)); + pubp->pubkey = pubkey; HASH_ADD(hh,LP_pubkeyinfos,pubkey,sizeof(pubkey),pubp); portable_mutex_unlock(&LP_pubkeymutex); printf("pub add.%p\n",pubp); From 7711ec7574be88518708ad30a8fc14deab6c3cbb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:07:41 +0300 Subject: [PATCH 1317/2705] Test --- iguana/exchanges/LP_prices.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 62e75a351..f40d7352a 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -82,11 +82,9 @@ struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout struct LP_pubkeyinfo *LP_pubkeyfind(bits256 pubkey) { struct LP_pubkeyinfo *pubp=0; - printf("pub find\n"); portable_mutex_lock(&LP_pubkeymutex); HASH_FIND(hh,LP_pubkeyinfos,&pubkey,sizeof(pubkey),pubp); portable_mutex_unlock(&LP_pubkeymutex); - printf("pub find.%p\n",pubp); return(pubp); } @@ -95,17 +93,14 @@ struct LP_pubkeyinfo *LP_pubkeyadd(bits256 pubkey) struct LP_pubkeyinfo *pubp=0; if ( (pubp= LP_pubkeyfind(pubkey)) == 0 ) { - printf("pub add\n"); portable_mutex_lock(&LP_pubkeymutex); pubp = calloc(1,sizeof(*pubp)); pubp->pubkey = pubkey; HASH_ADD(hh,LP_pubkeyinfos,pubkey,sizeof(pubkey),pubp); portable_mutex_unlock(&LP_pubkeymutex); - printf("pub add.%p\n",pubp); if ( (pubp= LP_pubkeyfind(pubkey)) == 0 ) printf("pubkeyadd find error after add\n"); } - printf("pub add ret.%p\n",pubp); return(pubp); } From 812d1e460d16c80ae66af85577ec2704e1c37d5e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:09:23 +0300 Subject: [PATCH 1318/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_prices.c | 2 +- iguana/exchanges/LP_quotes.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b3ac6f31a..c1ece23e6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -142,7 +142,7 @@ int32_t LP_subsock_check(struct LP_peerinfo *peer) portable_mutex_lock(&LP_commandmutex); if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) { - printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); + //printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index f40d7352a..414dcc8e8 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -515,9 +515,9 @@ void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveas void LP_pricefeedupdate(bits256 pubkey,char *base,char *rel,double price) { struct LP_priceinfo *basepp,*relpp; struct LP_pubkeyinfo *pubp; char str[65]; - printf("PRICEFEED UPDATE.(%s/%s) %.8f %s\n",base,rel,price,bits256_str(str,pubkey)); if ( price > SMALLVAL && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { + printf("PRICEFEED UPDATE.(%s/%s) %.8f %s\n",base,rel,price,bits256_str(str,pubkey)); if ( (pubp= LP_pubkeyadd(pubkey)) != 0 ) pubp->matrix[basepp->ind][relpp->ind] = price; else printf("error creating pubkey entry\n"); diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index b887de1b7..c1a104e3d 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -204,7 +204,7 @@ char *LP_pricepings(int32_t pubsock,char *base,char *rel,double price) char *LP_postedprice(cJSON *argjson) { bits256 pubkey; double price; char *base,*rel; - printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); + //printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && (price= jdouble(argjson,"price")) > SMALLVAL ) { pubkey = jbits256(argjson,"pubkey"); From 85969c40744c9cd9c721e4560ec04f91351e7d2b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:13:50 +0300 Subject: [PATCH 1319/2705] Test --- iguana/exchanges/LP_prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 414dcc8e8..b15d521c4 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -440,7 +440,7 @@ char *LP_orderbook(char *base,char *rel) if ( pubp->matrix[baseid][relid] > SMALLVAL ) numasks = LP_orderbook_utxoentries(now,base,rel,base,pubp->matrix[baseid][relid],asks,numasks,cachenumasks,pubp->pubkey); if ( pubp->matrix[relid][baseid] > SMALLVAL ) - numasks = LP_orderbook_utxoentries(now,base,rel,rel,pubp->matrix[relid][baseid],bids,numbids,cachenumbids,pubp->pubkey); + numbids = LP_orderbook_utxoentries(now,base,rel,rel,pubp->matrix[relid][baseid],bids,numbids,cachenumbids,pubp->pubkey); } retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); From 70fcf731b96f18e5a963102a17b124681b338bd3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:17:48 +0300 Subject: [PATCH 1320/2705] Test --- iguana/exchanges/LP_prices.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index b15d521c4..b026dcd47 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -369,22 +369,22 @@ int32_t LP_orderbookfind(struct LP_orderbookentry **array,int32_t num,bits256 tx return(-1); } -int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol,double price,struct LP_orderbookentry **array,int32_t num,int32_t cachednum,bits256 pubkey) +int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol,double price,struct LP_orderbookentry *(**arrayp),int32_t num,int32_t cachednum,bits256 pubkey) { struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_orderbookentry *op; uint64_t basesatoshis; HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { if ( LP_ismine(utxo) > 0 && strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) { - if ( LP_orderbookfind(array,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) + if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); - array = realloc(array,sizeof(*array) * (num+1)); + *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); if ( strcmp(base,symbol) == 0 ) basesatoshis = utxo->payment.value; else basesatoshis = utxo->payment.value * price; if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,price,basesatoshis)) != 0 ) - array[num++] = op; + (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) { HASH_ITER(hh,LP_peerinfos,peer,ptmp) @@ -438,9 +438,10 @@ char *LP_orderbook(char *base,char *rel) HASH_ITER(hh,LP_pubkeyinfos,pubp,ptmp) { if ( pubp->matrix[baseid][relid] > SMALLVAL ) - numasks = LP_orderbook_utxoentries(now,base,rel,base,pubp->matrix[baseid][relid],asks,numasks,cachenumasks,pubp->pubkey); + numasks = LP_orderbook_utxoentries(now,base,rel,base,pubp->matrix[baseid][relid],&asks,numasks,cachenumasks,pubp->pubkey); if ( pubp->matrix[relid][baseid] > SMALLVAL ) - numbids = LP_orderbook_utxoentries(now,base,rel,rel,pubp->matrix[relid][baseid],bids,numbids,cachenumbids,pubp->pubkey); + numbids = LP_orderbook_utxoentries(now,base,rel,rel,pubp->matrix[relid][baseid],&bids,numbids,cachenumbids,pubp->pubkey); + printf("cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); } retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); From f14411f04dfc6284e10be4466acd3b33cde72607 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:19:39 +0300 Subject: [PATCH 1321/2705] Test --- iguana/exchanges/LP_prices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index b026dcd47..4b3bc523b 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -378,7 +378,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol, { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { - char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); + //char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); if ( strcmp(base,symbol) == 0 ) basesatoshis = utxo->payment.value; @@ -441,7 +441,7 @@ char *LP_orderbook(char *base,char *rel) numasks = LP_orderbook_utxoentries(now,base,rel,base,pubp->matrix[baseid][relid],&asks,numasks,cachenumasks,pubp->pubkey); if ( pubp->matrix[relid][baseid] > SMALLVAL ) numbids = LP_orderbook_utxoentries(now,base,rel,rel,pubp->matrix[relid][baseid],&bids,numbids,cachenumbids,pubp->pubkey); - printf("cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); + //printf("cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); } retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); From cd22f237f096885e7709794eac91f1fd8c8cd0eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:30:22 +0300 Subject: [PATCH 1322/2705] Test --- iguana/exchanges/LP_prices.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 4b3bc523b..82f511a70 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -18,7 +18,7 @@ // marketmaker // -struct LP_orderbookentry { bits256 txid; double price; uint64_t basesatoshis; int32_t vout; }; +struct LP_orderbookentry { bits256 txid,txid2; double price; uint64_t basesatoshis; int32_t vout,vout2; }; #define LP_MAXPRICEINFOS 64 struct LP_priceinfo @@ -343,17 +343,21 @@ cJSON *LP_orderbookjson(struct LP_orderbookentry *op) jaddnum(item,"volume",dstr(op->basesatoshis)); jaddbits256(item,"txid",op->txid); jaddnum(item,"vout",op->vout); + jaddbits256(item,"txid2",op->txid2); + jaddnum(item,"vout2",op->vout2); } return(item); } -struct LP_orderbookentry *LP_orderbookentry(char *base,char *rel,bits256 txid,int32_t vout,double price,uint64_t basesatoshis) +struct LP_orderbookentry *LP_orderbookentry(char *base,char *rel,bits256 txid,int32_t vout,bits256 txid2,int32_t vout2,double price,uint64_t basesatoshis) { struct LP_orderbookentry *op; if ( (op= calloc(1,sizeof(*op))) != 0 ) { op->txid = txid; op->vout = vout; + op->txid2 = txid2; + op->vout2 = vout2; op->price = price; op->basesatoshis = basesatoshis; } @@ -364,7 +368,7 @@ int32_t LP_orderbookfind(struct LP_orderbookentry **array,int32_t num,bits256 tx { int32_t i; for (i=0; ivout == vout && bits256_cmp(array[i]->txid,txid) == 0 ) + if ( (array[i]->vout == vout && bits256_cmp(array[i]->txid,txid) == 0) || (array[i]->vout2 == vout && bits256_cmp(array[i]->txid2,txid) == 0) ) return(i); return(-1); } @@ -383,7 +387,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol, if ( strcmp(base,symbol) == 0 ) basesatoshis = utxo->payment.value; else basesatoshis = utxo->payment.value * price; - if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,price,basesatoshis)) != 0 ) + if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,price,basesatoshis)) != 0 ) (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) { @@ -424,13 +428,13 @@ char *LP_orderbook(char *base,char *rel) if ( strcmp(ptr->Q.srccoin,base) == 0 && strcmp(ptr->Q.destcoin,rel) == 0 ) { asks = realloc(asks,sizeof(*asks) * (numasks+1)); - if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->price,ptr->Q.satoshis)) != 0 ) + if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,ptr->price,ptr->Q.satoshis)) != 0 ) asks[numasks++] = op; } else if ( strcmp(ptr->Q.srccoin,rel) == 0 && strcmp(ptr->Q.destcoin,base) == 0 ) { bids = realloc(bids,sizeof(*bids) * (numbids+1)); - if ( (op= LP_orderbookentry(base,rel,ptr->Q.desttxid,ptr->Q.destvout,1./ptr->price,ptr->Q.satoshis)) != 0 ) + if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,1./ptr->price,ptr->Q.satoshis)) != 0 ) bids[numbids++] = op; } } From 119e944462678289ad439eb52ac00f1e1a6c49c0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:33:21 +0300 Subject: [PATCH 1323/2705] Test --- iguana/exchanges/LP_prices.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 82f511a70..77376e4cd 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -439,13 +439,14 @@ char *LP_orderbook(char *base,char *rel) } } cachenumbids = numbids, cachenumasks = numasks; + printf("start cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); HASH_ITER(hh,LP_pubkeyinfos,pubp,ptmp) { if ( pubp->matrix[baseid][relid] > SMALLVAL ) numasks = LP_orderbook_utxoentries(now,base,rel,base,pubp->matrix[baseid][relid],&asks,numasks,cachenumasks,pubp->pubkey); if ( pubp->matrix[relid][baseid] > SMALLVAL ) numbids = LP_orderbook_utxoentries(now,base,rel,rel,pubp->matrix[relid][baseid],&bids,numbids,cachenumbids,pubp->pubkey); - //printf("cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); + printf("cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); } retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); From 961c15f2470ba4bd45b7d4dfb6b66a73509cf632 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:36:02 +0300 Subject: [PATCH 1324/2705] Test --- iguana/exchanges/LP_prices.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 77376e4cd..47353a84b 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -96,7 +96,7 @@ struct LP_pubkeyinfo *LP_pubkeyadd(bits256 pubkey) portable_mutex_lock(&LP_pubkeymutex); pubp = calloc(1,sizeof(*pubp)); pubp->pubkey = pubkey; - HASH_ADD(hh,LP_pubkeyinfos,pubkey,sizeof(pubkey),pubp); + HASH_ADD_KEYPTR(hh,LP_pubkeyinfos,&pubp->pubkey,sizeof(pubp->pubkey),pubp); portable_mutex_unlock(&LP_pubkeymutex); if ( (pubp= LP_pubkeyfind(pubkey)) == 0 ) printf("pubkeyadd find error after add\n"); @@ -442,6 +442,7 @@ char *LP_orderbook(char *base,char *rel) printf("start cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); HASH_ITER(hh,LP_pubkeyinfos,pubp,ptmp) { + char str[65]; printf("pubkey.(%s)\n",bits256_str(str,pubp->pubkey)); if ( pubp->matrix[baseid][relid] > SMALLVAL ) numasks = LP_orderbook_utxoentries(now,base,rel,base,pubp->matrix[baseid][relid],&asks,numasks,cachenumasks,pubp->pubkey); if ( pubp->matrix[relid][baseid] > SMALLVAL ) From 92db3e415fb2ba81685496589b7fede739d2a1c5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:40:41 +0300 Subject: [PATCH 1325/2705] Test --- iguana/exchanges/LP_prices.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 47353a84b..c31beb6f7 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -18,7 +18,7 @@ // marketmaker // -struct LP_orderbookentry { bits256 txid,txid2; double price; uint64_t basesatoshis; int32_t vout,vout2; }; +struct LP_orderbookentry { bits256 txid,txid2,pubkey; double price; uint64_t basesatoshis; int32_t vout,vout2; }; #define LP_MAXPRICEINFOS 64 struct LP_priceinfo @@ -343,13 +343,12 @@ cJSON *LP_orderbookjson(struct LP_orderbookentry *op) jaddnum(item,"volume",dstr(op->basesatoshis)); jaddbits256(item,"txid",op->txid); jaddnum(item,"vout",op->vout); - jaddbits256(item,"txid2",op->txid2); - jaddnum(item,"vout2",op->vout2); + jaddbits256(item,"pubkey",op->pubkey); } return(item); } -struct LP_orderbookentry *LP_orderbookentry(char *base,char *rel,bits256 txid,int32_t vout,bits256 txid2,int32_t vout2,double price,uint64_t basesatoshis) +struct LP_orderbookentry *LP_orderbookentry(char *base,char *rel,bits256 txid,int32_t vout,bits256 txid2,int32_t vout2,double price,uint64_t basesatoshis,bits256 pubkey) { struct LP_orderbookentry *op; if ( (op= calloc(1,sizeof(*op))) != 0 ) @@ -360,6 +359,7 @@ struct LP_orderbookentry *LP_orderbookentry(char *base,char *rel,bits256 txid,in op->vout2 = vout2; op->price = price; op->basesatoshis = basesatoshis; + op->pubkey = pubkey; } return(op); } @@ -387,7 +387,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol, if ( strcmp(base,symbol) == 0 ) basesatoshis = utxo->payment.value; else basesatoshis = utxo->payment.value * price; - if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,price,basesatoshis)) != 0 ) + if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,price,basesatoshis,pubkey)) != 0 ) (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) { @@ -428,13 +428,13 @@ char *LP_orderbook(char *base,char *rel) if ( strcmp(ptr->Q.srccoin,base) == 0 && strcmp(ptr->Q.destcoin,rel) == 0 ) { asks = realloc(asks,sizeof(*asks) * (numasks+1)); - if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,ptr->price,ptr->Q.satoshis)) != 0 ) + if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,ptr->price,ptr->Q.satoshis,ptr->Q.srchash)) != 0 ) asks[numasks++] = op; } else if ( strcmp(ptr->Q.srccoin,rel) == 0 && strcmp(ptr->Q.destcoin,base) == 0 ) { bids = realloc(bids,sizeof(*bids) * (numbids+1)); - if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,1./ptr->price,ptr->Q.satoshis)) != 0 ) + if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,1./ptr->price,ptr->Q.satoshis,ptr->Q.srchash)) != 0 ) bids[numbids++] = op; } } From 9a5b805efedaecf6e38a1ad64e1f90cfda161a0f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 14:51:52 +0300 Subject: [PATCH 1326/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_prices.c | 2 +- iguana/exchanges/LP_utxos.c | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c1ece23e6..1e354bfb5 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -30,7 +30,7 @@ char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; -char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196" , "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // +char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196" , };//'"5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex; int32_t LP_mypubsock = -1; diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index c31beb6f7..d95a63590 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -378,7 +378,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol, struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_orderbookentry *op; uint64_t basesatoshis; HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { - if ( LP_ismine(utxo) > 0 && strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) + if ( strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index dfe649e21..ffca36a6e 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -594,14 +594,12 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr { if ( (utxo= LP_utxoadd(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_mypeer != 0 ? LP_mypeer->profitmargin : 0.01)) != 0 ) { - //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); } } else { if ( (utxo= LP_utxoadd(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0.)) != 0 ) { - //utxo->S.mypub = curve25519(privkey,curve25519_basepoint9()); } } total += value; From b4e2153ff2ad162d58d7c98deb9c6d3b429f666b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 15:00:53 +0300 Subject: [PATCH 1327/2705] Test --- iguana/exchanges/LP_rpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index a80197ccd..d6472186a 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -51,8 +51,8 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { - char url[4096],str[65],str2[65]; - sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str2,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); + char url[4096],str[65],str2[65],str3[65]; + sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curl(url)); From cf8d5858c26fe6b7d5e11937dd39a70b6db48a4d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 15:06:31 +0300 Subject: [PATCH 1328/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index ffca36a6e..fa88c1972 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -442,7 +442,7 @@ int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - //printf("parse.(%s)\n",jprint(item,0)); + printf("parse.(%s)\n",jprint(item,0)); if ( (utxo= LP_utxoaddjson(1,mypubsock,item)) != 0 ) utxo->T.lasttime = now; } From 69e4262a75f08435a261441b6c3d5f454611a91e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 15:10:20 +0300 Subject: [PATCH 1329/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index fa88c1972..11b0175e7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -401,7 +401,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit } LP_utxosetkey(utxo->key,txid,vout); LP_utxosetkey(utxo->key2,txid2,vout2); - char str[65],str2[65],str3[65]; printf("iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); + char str[65],str2[65],str3[65]; printf("%s iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",utxo->coinaddr,iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) From 4bc4220d77fcf52b61ea5d3903cdbfbbb07ffde5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 15:33:02 +0300 Subject: [PATCH 1330/2705] Test --- iguana/exchanges/LP_commands.c | 6 +++--- iguana/exchanges/LP_nativeDEX.c | 6 +++--- iguana/exchanges/LP_transaction.c | 15 +++++++++------ iguana/exchanges/LP_utxos.c | 24 +++++++++++++++--------- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a4a964ee1..c0197a77b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -60,7 +60,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits25 int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) { - char *retstr,pairstr[512]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; + char *retstr,pairstr[512],destaddr[64]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; if ( (price= LP_price(base,rel)) > SMALLVAL ) { price *= (1. + profitmargin); @@ -78,7 +78,7 @@ int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson, printf("not eligible\n"); return(-1); } - if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 10000)); if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) @@ -107,7 +107,7 @@ int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson, } else { - printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); + printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); } } else printf("no price for %s/%s\n",base,rel); if ( retval < 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1e354bfb5..9dc4042df 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -156,18 +156,18 @@ int32_t LP_subsock_check(struct LP_peerinfo *peer) void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitmargin) { - struct _LP_utxoinfo u; char str[65]; uint32_t now = (uint32_t)time(NULL); + struct _LP_utxoinfo u; char str[65],destaddr[64]; uint32_t now = (uint32_t)time(NULL); //printf("%s lag.%d\n",bits256_str(str,utxo->txid),now-utxo->lastspentcheck); if ( utxo->T.spentflag == 0 && now > utxo->T.lastspentcheck+60 ) { u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; utxo->T.lastspentcheck = now; - if ( LP_txvalue(utxo->coin,utxo->payment.txid,utxo->payment.vout) == 0 ) + if ( LP_txvalue(destaddr,utxo->coin,utxo->payment.txid,utxo->payment.vout) == 0 ) { printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,dstr(utxo->payment.value)); LP_spentnotify(utxo,0); } - else if ( LP_txvalue(utxo->coin,u.txid,u.vout) == 0 ) + else if ( LP_txvalue(destaddr,utxo->coin,u.txid,u.vout) == 0 ) { printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,u.txid),u.vout,dstr(u.value)); LP_spentnotify(utxo,1); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index a5aed366b..5c07e0539 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -103,9 +103,10 @@ uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) return(value); } -uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) +uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) { - uint64_t value = 0; double interest; cJSON *txobj; + uint64_t value = 0; double interest; cJSON *txobj,*sobj,*array; int32_t n; + coinaddr = 0; if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) { if ( (value= jdouble(txobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(txobj,"value")*SATOSHIDEN) == 0 ) @@ -120,6 +121,8 @@ uint64_t LP_txvalue(char *symbol,bits256 txid,int32_t vout) value += SATOSHIDEN * interest; } } + if ( (sobj= jobj(txobj,"scriptPubKey")) != 0 && (array= jarray(&n,sobj,"addresses")) != 0 ) + strcpy(coinaddr,jstri(array,0)); //char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); free_json(txobj); } @@ -164,10 +167,10 @@ int32_t LP_vinscan(bits256 *spendtxidp,int32_t *spendvinip,char *symbol,bits256 int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 searchtxid,int32_t searchvout) { - cJSON *blockjson,*txids,*txobj; bits256 hash,txid; int32_t h,i,j,numtxids,loadheight,errs = 0; + char destaddr[64]; cJSON *blockjson,*txids,*txobj; bits256 hash,txid; int32_t h,i,j,numtxids,loadheight,errs = 0; *indp = -1; memset(spendtxidp,0,sizeof(*spendtxidp)); - if ( LP_txvalue(symbol,searchtxid,searchvout) > 0 ) + if ( LP_txvalue(destaddr,symbol,searchtxid,searchvout) > 0 ) return(0); if ( (txobj= LP_gettx(symbol,searchtxid)) == 0 ) return(0); @@ -725,7 +728,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr,int32_t suppress_pubkeys) { - char *rawtxbytes=0,*signedtx=0,tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1; struct vin_info V[16]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; + char *rawtxbytes=0,*signedtx=0,tmpaddr[64],hexstr[999],wifstr[128],txdestaddr[64],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1; struct vin_info V[16]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) @@ -734,7 +737,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch if ( redeemlen < 0 ) return(0); #ifndef BASILISK_DISABLESENDTX - if ( (value= LP_txvalue(symbol,utxotxid,vout)) == 0 ) + if ( (value= LP_txvalue(txdestaddr,symbol,utxotxid,vout)) == 0 ) { char str[65]; printf("basilisk_swap_bobtxspend.%s %s utxo.(%s) already spent or doesnt exist\n",name,symbol,bits256_str(str,utxotxid)); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 11b0175e7..a2720c1a1 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -294,7 +294,7 @@ void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) char *LP_spentcheck(cJSON *argjson) { - bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; int32_t iambob,retval = 0; + char destaddr[64]; bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; int32_t iambob,retval = 0; txid = jbits256(argjson,"txid"); vout = jint(argjson,"vout"); for (iambob=0; iambob<=1; iambob++) @@ -308,7 +308,7 @@ char *LP_spentcheck(cJSON *argjson) checktxid = jbits256(argjson,"checktxid"); checkvout = jint(argjson,"checkvout"); } - if ( LP_txvalue(utxo->coin,checktxid,checkvout) == 0 ) + if ( LP_txvalue(destaddr,utxo->coin,checktxid,checkvout) == 0 ) { if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) LP_mypeer->numutxos--; @@ -323,29 +323,35 @@ char *LP_spentcheck(cJSON *argjson) return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); } -int32_t LP_iseligible(int32_t iambob,char *coin,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) +int32_t LP_iseligible(int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) { - uint64_t val,val2,threshold; - if ( (val= LP_txvalue(coin,txid,vout)) >= satoshis ) + uint64_t val,val2,threshold; char destaddr[64]; + if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) >= satoshis ) { threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); - if ( (val2= LP_txvalue(coin,txid2,vout2)) >= threshold ) + if ( (val2= LP_txvalue(destaddr,symbol,txid2,vout2)) >= threshold ) { //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); return(1); - } else printf("mismatched %s txid value2 %.8f < %.8f\n",coin,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); - } else printf("mismatched %s txid value %.8f < %.8f\n",coin,dstr(val),dstr(satoshis)); + } else printf("mismatched %s txid value2 %.8f < %.8f\n",symbol,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); + } else printf("mismatched %s txid value %.8f < %.8f\n",symbol,dstr(val),dstr(satoshis)); return(0); } struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - char str[65]; uint64_t tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + char str[65],destaddr[64],destaddr2[64]; uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } + destaddr2[0] = 0; + if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) != value || (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) != value2 || strcmp(destaddr,destaddr2) != 0 || strcmp(coinaddr,destaddr) != 0 ) + { + printf("utxoadd mismatch (%s %.8f) + (%s %.8f) != %s %.8f %.8f\n",destaddr,dstr(val),destaddr2,dstr(val2),coinaddr,dstr(value),dstr(value2)); + return(0); + } if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; From c091ca8214dbfea672be5e9a30c9c935dac0b2fd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 15:45:45 +0300 Subject: [PATCH 1331/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 5c07e0539..9f1f0025a 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -106,7 +106,7 @@ uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) { uint64_t value = 0; double interest; cJSON *txobj,*sobj,*array; int32_t n; - coinaddr = 0; + coinaddr[0] = 0; if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) { if ( (value= jdouble(txobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(txobj,"value")*SATOSHIDEN) == 0 ) From 6811d3a7d7c87ff84e3ab8377646dd91d86d28ce Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 15:51:03 +0300 Subject: [PATCH 1332/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a2720c1a1..e5ccd7f15 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -340,7 +340,7 @@ int32_t LP_iseligible(int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - char str[65],destaddr[64],destaddr2[64]; uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + char str[65],str2[65],destaddr[64],destaddr2[64]; uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); @@ -349,7 +349,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit destaddr2[0] = 0; if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) != value || (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) != value2 || strcmp(destaddr,destaddr2) != 0 || strcmp(coinaddr,destaddr) != 0 ) { - printf("utxoadd mismatch (%s %.8f) + (%s %.8f) != %s %.8f %.8f\n",destaddr,dstr(val),destaddr2,dstr(val2),coinaddr,dstr(value),dstr(value2)); + printf("utxoadd mismatch %s/v%d (%s %.8f) + %s/v%d (%s %.8f) != %s %.8f %.8f\n",bits256_str(str,txid),vout,destaddr,dstr(val),bits256_str(str2,txid2),vout2,destaddr2,dstr(val2),coinaddr,dstr(value),dstr(value2)); return(0); } if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding From e554fdb6aa3a4dff695651a36faeee20cb46ba55 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 15:54:04 +0300 Subject: [PATCH 1333/2705] Test --- iguana/exchanges/LP_prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index d95a63590..ef4dfe43d 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -378,7 +378,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol, struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_orderbookentry *op; uint64_t basesatoshis; HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { - if ( strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) + if ( bits256_cmp(pubkey,utxo->pubkey) == 0 && strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { From 4a37c8b024ee9933b3d35e97296b8abeb7c5d7fc Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 15:56:50 +0300 Subject: [PATCH 1334/2705] Test --- iguana/exchanges/LP_prices.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index ef4dfe43d..2a3064c0c 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -378,6 +378,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol, struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_orderbookentry *op; uint64_t basesatoshis; HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { + char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); if ( bits256_cmp(pubkey,utxo->pubkey) == 0 && strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) From 7a0b26dbb5394377d429388ee47724f03fdef3fa Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:00:46 +0300 Subject: [PATCH 1335/2705] Test --- iguana/exchanges/getutxos | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 iguana/exchanges/getutxos diff --git a/iguana/exchanges/getutxos b/iguana/exchanges/getutxos new file mode 100755 index 000000000..a84c72fb0 --- /dev/null +++ b/iguana/exchanges/getutxos @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"getutxos\",\"coin\":\"REVS\"}" From 543b6ebb33f3e64f0be1fa4e541e4dfcd16459a8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:01:44 +0300 Subject: [PATCH 1336/2705] Test --- iguana/exchanges/LP_commands.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c0197a77b..15e429644 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -425,14 +425,11 @@ forwardhex(pubkey,hex)\n\ } else if ( strcmp(method,"getpeers") == 0 ) retstr = LP_peers(); + else if ( strcmp(method,"getutxos") == 0 ) + retstr = LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn")); else if ( IAMLP != 0 ) { - if ( strcmp(method,"getutxos") == 0 ) - { - retstr = LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn")); - //printf("RETURN. %d utxos\n",cJSON_GetArraySize(cJSON_Parse(retstr))); - } - else if ( strcmp(method,"register") == 0 ) + if ( strcmp(method,"register") == 0 ) retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr")); else if ( strcmp(method,"lookup") == 0 ) retstr = LP_lookup(jbits256(argjson,"client")); From 9ecbecc926f2bdaa25ea3aaf11cc707f5ecdfff6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:04:06 +0300 Subject: [PATCH 1337/2705] Test --- iguana/exchanges/LP_utxos.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e5ccd7f15..91027f338 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -252,17 +252,22 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t lastn) { int32_t i,firsti; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); - i = 0; - if ( lastn >= mypeer->numutxos ) - firsti = -1; - else firsti = (mypeer->numutxos - lastn); - HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) + if ( symbol != 0 && symbol[0] != 0 ) { - if ( i++ < firsti ) - continue; - if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) > 0 ) + i = 0; + if ( lastn <= 0 ) + lastn = LP_PROPAGATION_SLACK * 2; + if ( lastn >= mypeer->numutxos ) + firsti = -1; + else firsti = (mypeer->numutxos - lastn); + HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { - jaddi(utxosjson,LP_utxojson(utxo)); + if ( i++ < firsti ) + continue; + if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) > 0 ) + { + jaddi(utxosjson,LP_utxojson(utxo)); + } } } return(jprint(utxosjson,1)); From 14333e00e40cd02e26501933f28682d6b5615e99 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:05:34 +0300 Subject: [PATCH 1338/2705] Test --- iguana/exchanges/LP_utxos.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 91027f338..bf159a018 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -251,15 +251,16 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t lastn) { - int32_t i,firsti; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); + int32_t i,firsti,n; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); if ( symbol != 0 && symbol[0] != 0 ) { i = 0; + n = mypeer != 0 ? mypeer->numutxos : 0; if ( lastn <= 0 ) lastn = LP_PROPAGATION_SLACK * 2; - if ( lastn >= mypeer->numutxos ) + if ( lastn >= n ) firsti = -1; - else firsti = (mypeer->numutxos - lastn); + else firsti = (n - lastn); HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { if ( i++ < firsti ) From b1e71e6af88e4e9b61fb7107d91cacb8cde05960 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:20:08 +0300 Subject: [PATCH 1339/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +++- iguana/exchanges/LP_utxos.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9dc4042df..aa74ebaab 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -194,12 +194,14 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso int32_t lastn; if ( now > peer->lastutxos+interval ) { - peer->lastutxos = now; //lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; //if ( lastn < LP_PROPAGATION_SLACK * 2 ) lastn = LP_PROPAGATION_SLACK * 2; if ( mypeer == 0 || strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) + { + peer->lastutxos = now; LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); + } } } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index bf159a018..e03857022 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -476,10 +476,12 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( coin == 0 ) coin = ""; + printf("utxo query\n"); if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer != 0 ? mypeer->numpeers : 0,mypeer != 0 ? mypeer->numutxos : 0)) != 0 ) { now = (uint32_t)time(NULL); LP_utxosparse(mypubsock,destipaddr,destport,retstr,now); + printf("got.(%s)\n",retstr); free(retstr); /*i = 0; if ( lastn >= mypeer->numutxos ) From dc21f1e7e4d2c01a99e0cb398e946885e6ad2dea Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:21:30 +0300 Subject: [PATCH 1340/2705] Test --- iguana/exchanges/LP_peers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 145bcfde3..16aa291ea 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -160,7 +160,7 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr return; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer!=0?mypeer->numpeers:0,mypeer!=0?mypeer->numutxos:0)) != 0 ) { - printf("got.(%s)\n",retstr); + //printf("got.(%s)\n",retstr); now = (uint32_t)time(NULL); LP_peersparse(mypeer,mypubsock,destipaddr,destport,retstr,now); free(retstr); From 682241bf79986569deb7036a7709180bea5d302a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:24:15 +0300 Subject: [PATCH 1341/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index aa74ebaab..cf63dc765 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -192,7 +192,7 @@ void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubsock,struct LP_peerinfo *peer,uint32_t now,double profitmargin,int32_t interval) { int32_t lastn; - if ( now > peer->lastutxos+interval ) + if ( peer->lastutxos < now-interval ) { //lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; //if ( lastn < LP_PROPAGATION_SLACK * 2 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e03857022..5216006b2 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -476,7 +476,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( coin == 0 ) coin = ""; - printf("utxo query\n"); + printf("utxo query.(%s)\n",destipaddr); if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer != 0 ? mypeer->numpeers : 0,mypeer != 0 ? mypeer->numutxos : 0)) != 0 ) { now = (uint32_t)time(NULL); From 063268894c624704fd4f1f7259cee1ee9deba873 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:25:23 +0300 Subject: [PATCH 1342/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index cf63dc765..43f1fe8b8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -202,7 +202,7 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso peer->lastutxos = now; LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } - } + } else printf("skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); } void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) From 0be1f84aa147b88afe6ac99874ece3bf97ee9f01 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:26:27 +0300 Subject: [PATCH 1343/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 43f1fe8b8..fa1c30eee 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -202,7 +202,7 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso peer->lastutxos = now; LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } - } else printf("skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); + } else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); } void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) @@ -271,6 +271,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in nonz = n = 0; if ( (counter % 6000) == 0 ) LP_utxo_updates(pubsock,passphrase,profitmargin); + printf("checkpeers\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { nonz += LP_subsock_check(peer); From c53ab38e76fca54a9e4a1f497d9821c8d307595f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:29:10 +0300 Subject: [PATCH 1344/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fa1c30eee..da8baa6ef 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -265,12 +265,16 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in now = (uint32_t)time(NULL); if ( lastforward < now-3600 ) { + printf("LP_forwarding_register\n"); LP_forwarding_register(LP_mypubkey,pushaddr,10); lastforward = now; } nonz = n = 0; if ( (counter % 6000) == 0 ) + { + printf("LP_utxo_updates\n"); LP_utxo_updates(pubsock,passphrase,profitmargin); + } printf("checkpeers\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { From febc6be3b0b8f836743297a020a90c3ff39603d4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:31:50 +0300 Subject: [PATCH 1345/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index da8baa6ef..2ba4cfd0c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -267,6 +267,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in { printf("LP_forwarding_register\n"); LP_forwarding_register(LP_mypubkey,pushaddr,10); + printf("done LP_forwarding_register\n"); lastforward = now; } nonz = n = 0; From b55d93ddb390f046b9229e10cd9fe8f46828ece5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:33:22 +0300 Subject: [PATCH 1346/2705] Test --- iguana/exchanges/LP_forwarding.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 7b6d866b9..0a04d2bf7 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -96,7 +96,7 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) { if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) { - //printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); + printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( jint(retjson,"registered") != 0 && ++n >= max ) @@ -104,7 +104,7 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) free_json(retjson); } free(retstr); - } + } else printf("error registering with %s\n",peer->ipaddr); if ( retval == 0 ) break; } From a36936bce9cbe3f3298089bb0f6b9bc4c8d1eb7e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:35:31 +0300 Subject: [PATCH 1347/2705] Test --- iguana/exchanges/LP_forwarding.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 0a04d2bf7..1a14965cd 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -94,6 +94,7 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) } HASH_ITER(hh,LP_peerinfos,peer,tmp) { + printf("register with (%s)\n",peer->ipaddr); if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) { printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); From d4701c8f157b37ef8d114605eaaa9ce247ed4ec0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:43:29 +0300 Subject: [PATCH 1348/2705] Test --- crypto777/OS_portable.h | 3 ++- crypto777/bitcoind_RPC.c | 5 +++-- iguana/dpow/dpow_rpc.c | 4 ++-- iguana/exchanges/LP_bitcoin.c | 2 +- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_rpc.c | 14 +++++++------- iguana/exchanges/bitcoin.c | 2 +- iguana/exchanges/mm.c | 36 +++++++++++++++++------------------ iguana/exchanges/nxtae.c | 2 +- includes/cJSON.h | 2 +- 10 files changed, 37 insertions(+), 34 deletions(-) diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index 23a051b01..5229414a6 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -129,7 +129,8 @@ int32_t hseek(HUFF *hp,int32_t offset,int32_t mode); #define portable_mutex_unlock pthread_mutex_unlock #define OS_thread_create pthread_create -#define issue_curl(cmdstr) bitcoind_RPC(0,"curl",cmdstr,0,0,0) +#define issue_curl(cmdstr) bitcoind_RPC(0,"curl",cmdstr,0,0,0,0) +#define issue_curlt(cmdstr,timeout) bitcoind_RPC(0,"curl",cmdstr,0,0,0,timeout) struct allocitem { uint32_t allocsize,type; } PACKED; struct queueitem { struct queueitem *next,*prev; uint32_t allocsize,type; } PACKED; diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index 975208ddd..cfa5f5501 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -115,7 +115,7 @@ char *Jay_NXTrequest(char *command,char *params) return(retstr); } -char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params) +char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params,int32_t timeout) { static int didinit,count,count2; static double elapsedsum,elapsedsum2; extern int32_t USE_JAY; struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle; @@ -153,7 +153,8 @@ try_again: curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback - //curl_easy_setopt(curl_handle,CURLOPT_TIMEOUT, 60L); // causes problems with iguana timeouts + if ( timeout > 0 ) + curl_easy_setopt(curl_handle,CURLOPT_TIMEOUT, timeout); // causes problems with iguana timeouts if ( strncmp(url,"https",5) == 0 ) { curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); diff --git a/iguana/dpow/dpow_rpc.c b/iguana/dpow/dpow_rpc.c index 3a7c83aea..0e294f4d9 100755 --- a/iguana/dpow/dpow_rpc.c +++ b/iguana/dpow/dpow_rpc.c @@ -13,7 +13,7 @@ * * ******************************************************************************/ -#define issue_curl(cmdstr) bitcoind_RPC(0,"curl",cmdstr,0,0,0) +#define issue_curl(cmdstr) bitcoind_RPC(0,"curl",cmdstr,0,0,0,0) cJSON *dpow_getinfo(struct supernet_info *myinfo,struct iguana_info *coin) { @@ -839,7 +839,7 @@ char *dpow_issuemethod(char *userpass,char *method,char *params,uint16_t port) sprintf(url,(char *)"http://127.0.0.1:%u",port); sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); //printf("postdata.(%s) USERPASS.(%s)\n",postdata,KMDUSERPASS); - retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); + retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params,0); } return(retstr2); } diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index c7ee8b218..12b975c02 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2025,7 +2025,7 @@ int32_t bitcoin_p2shscript(uint8_t *script,int32_t n,const uint8_t *p2shscript,c char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params) { - return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params)); + return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params,0)); } int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 93642f146..d99b519bf 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -21,6 +21,7 @@ #ifndef LP_INCLUDE_H #define LP_INCLUDE_H +#define LP_HTTP_TIMEOUT 1 #define LP_DEXFEE(destsatoshis) ((destsatoshis) / INSTANTDEX_INSURANCEDIV) #define LP_DEPOSITSATOSHIS(satoshis) ((satoshis) + (satoshis >> 3)) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index d6472186a..5cf3dbe01 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -22,7 +22,7 @@ char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t por char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); //printf("send.(%s)\n",url); - retstr = issue_curl(url); + retstr = issue_curlt(url,LP_HTTP_TIMEOUT); //printf("GETPEERS.(%s)\n",retstr); return(retstr); } @@ -31,7 +31,7 @@ char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn, { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curl(url)); + return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t lastn) @@ -39,14 +39,14 @@ char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); //printf("getutxo.(%s)\n",url); - return(issue_curl(url)); + return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { char url[512]; sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curl(url)); + return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) @@ -55,7 +55,7 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); - return(issue_curl(url)); + return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *pushaddr) @@ -65,7 +65,7 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *push return(clonestr("{\"error\":\"illegal pushaddr\"}")); sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr+strlen("tcp://")); //printf("getutxo.(%s)\n",url); - return(issue_curl(url)); + return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) @@ -73,7 +73,7 @@ char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) char url[512],str[65]; sprintf(url,"http://%s:%u/api/stats/lookup?client=%s",destip,destport,bits256_str(str,pubkey)); //printf("getutxo.(%s)\n",url); - return(issue_curl(url)); + return(issue_curlt(url,LP_HTTP_TIMEOUT)); } cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index 452c8c075..62c0ed592 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -19,7 +19,7 @@ cJSON *instantdex_statemachinejson(struct bitcoin_swapinfo *swap); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params) { - return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params)); + return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params,0)); } int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index e98927ef8..6fcfda6ca 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -70,7 +70,7 @@ char *DEX_swapstatus() char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"getswaplist\"}"); - return(bitcoind_RPC(0,"InstantDEX",url,0,"getswaplist",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"getswaplist",postdata,0)); } char *DEX_amlp(char *blocktrail) @@ -78,7 +78,7 @@ char *DEX_amlp(char *blocktrail) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"tradebot\",\"method\":\"amlp\",\"blocktrail\":\"%s\"}",blocktrail); - return(bitcoind_RPC(0,"tradebot",url,0,"amlp",postdata)); + return(bitcoind_RPC(0,"tradebot",url,0,"amlp",postdata,0)); } char *DEX_openorders(char *exchange) @@ -86,7 +86,7 @@ char *DEX_openorders(char *exchange) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"openorders\",\"exchange\":\"%s\"}",exchange); - return(bitcoind_RPC(0,"InstantDEX",url,0,"openorders",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"openorders",postdata,0)); } char *DEX_tradehistory(char *exchange) @@ -94,7 +94,7 @@ char *DEX_tradehistory(char *exchange) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"tradehistory\",\"exchange\":\"%s\"}",exchange); - return(bitcoind_RPC(0,"InstantDEX",url,0,"tradehistory",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"tradehistory",postdata,0)); } char *DEX_orderstatus(char *exchange,char *orderid) @@ -102,7 +102,7 @@ char *DEX_orderstatus(char *exchange,char *orderid) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"orderstatus\",\"exchange\":\"%s\",\"orderid\":\"%s\"}",exchange,orderid); - return(bitcoind_RPC(0,"InstantDEX",url,0,"orderstatus",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"orderstatus",postdata,0)); } char *DEX_cancelorder(char *exchange,char *orderid) @@ -110,7 +110,7 @@ char *DEX_cancelorder(char *exchange,char *orderid) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"cancelorder\",\"exchange\":\"%s\",\"orderid\":\"%s\"}",exchange,orderid); - return(bitcoind_RPC(0,"InstantDEX",url,0,"cancelorder",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"cancelorder",postdata,0)); } char *DEX_balance(char *exchange,char *base,char *coinaddr) @@ -120,12 +120,12 @@ char *DEX_balance(char *exchange,char *base,char *coinaddr) if ( strcmp(exchange,"DEX") == 0 ) { sprintf(postdata,"{\"agent\":\"dex\",\"method\":\"getbalance\",\"address\":\"%s\",\"symbol\":\"%s\"}",coinaddr,base); - return(bitcoind_RPC(0,"dex",url,0,"getbalance",postdata)); + return(bitcoind_RPC(0,"dex",url,0,"getbalance",postdata,0)); } else { sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"balance\",\"exchange\":\"%s\",\"base\":\"%s\"}",exchange,base); - return(bitcoind_RPC(0,"InstantDEX",url,0,"balance",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"balance",postdata,0)); } } @@ -134,7 +134,7 @@ char *DEX_apikeypair(char *exchange,char *apikey,char *apisecret) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"apikeypair\",\"exchange\":\"%s\",\"apikey\":\"%s\",\"apisecret\":\"%s\"}",exchange,apikey,apisecret); - return(bitcoind_RPC(0,"InstantDEX",url,0,"apikeypair",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"apikeypair",postdata,0)); } char *DEX_setuserid(char *exchange,char *userid,char *tradepassword) @@ -142,7 +142,7 @@ char *DEX_setuserid(char *exchange,char *userid,char *tradepassword) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"setuserid\",\"exchange\":\"%s\",\"userid\":\"%s\",\"tradepassword\":\"%s\"}",exchange,userid,tradepassword); - return(bitcoind_RPC(0,"InstantDEX",url,0,"setuserid",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"setuserid",postdata,0)); } char *DEX_trade(char *exchange,char *base,char *rel,int32_t dir,double price,double volume) @@ -151,7 +151,7 @@ char *DEX_trade(char *exchange,char *base,char *rel,int32_t dir,double price,dou sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"%s\",\"exchange\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\",\"price\":%.8f,\"volume\":%.8f,\"dotrade\":1}",dir>0?"buy":"sell",exchange,base,rel,price,volume); //printf("DEX_trade.(%s)\n",postdata); - return(bitcoind_RPC(0,"InstantDEX",url,0,dir>0?"buy":"sell",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,dir>0?"buy":"sell",postdata,0)); } char *DEX_withdraw(char *exchange,char *base,char *destaddr,double amount) @@ -159,7 +159,7 @@ char *DEX_withdraw(char *exchange,char *base,char *destaddr,double amount) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"InstantDEX\",\"method\":\"withdraw\",\"exchange\":\"%s\",\"destaddr\":\"%s\",\"amount\":%.8f}",exchange,destaddr,amount); - return(bitcoind_RPC(0,"InstantDEX",url,0,"withdraw",postdata)); + return(bitcoind_RPC(0,"InstantDEX",url,0,"withdraw",postdata,0)); } char *iguana_walletpassphrase(char *passphrase,int32_t timeout) @@ -167,7 +167,7 @@ char *iguana_walletpassphrase(char *passphrase,int32_t timeout) char url[512],postdata[1024]; sprintf(url,"%s/coin=KMD&agent=bitcoinrpc&method=walletpassphrase?",IGUANA_URL); sprintf(postdata,"[\"%s\", %d]",passphrase,timeout); - return(bitcoind_RPC(0,"",url,0,"walletpassphrase",postdata)); + return(bitcoind_RPC(0,"",url,0,"walletpassphrase",postdata,0)); } /*char *iguana_listunspent(char *coin,char *coinaddr) @@ -194,7 +194,7 @@ char *DEX_listunspent(char *coin,char *coinaddr) char url[512],postdata[1024]; sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"dex\",\"method\":\"listunspent\",\"address\":\"%s\",\"symbol\":\"%s\",\"timeout\":60000}",coinaddr,coin); - return(bitcoind_RPC(0,"dex",url,0,"listunspent",postdata)); + return(bitcoind_RPC(0,"dex",url,0,"listunspent",postdata,0)); } bits256 iguana_wif2privkey(char *wifstr) @@ -203,7 +203,7 @@ bits256 iguana_wif2privkey(char *wifstr) memset(privkey.bytes,0,sizeof(privkey)); sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"SuperNET\",\"method\":\"wif2priv\",\"wif\":\"%s\"}",wifstr); - if ( (retstr= bitcoind_RPC(0,"SuperNET",url,0,"wif2priv",postdata)) != 0 ) + if ( (retstr= bitcoind_RPC(0,"SuperNET",url,0,"wif2priv",postdata,0)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { @@ -227,7 +227,7 @@ void iguana_priv2pub(uint8_t *pubkey33,char *coinaddr,bits256 privkey,uint8_t ad bits256_str(privstr,privkey); sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"SuperNET\",\"method\":\"priv2pub\",\"privkey\":\"%s\",\"addrtype\":%u}",privstr,addrtype); - if ( (retstr= bitcoind_RPC(0,"SuperNET",url,0,"priv2pub",postdata)) != 0 ) + if ( (retstr= bitcoind_RPC(0,"SuperNET",url,0,"priv2pub",postdata,0)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { @@ -623,7 +623,7 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"tradebot\",\"method\":\"liquidity\",\"targetcoin\":\"%s\",\"vals\":%s}",base,jprint(vals,1)); //printf("(%s)\n",postdata); - if ( (retstr= bitcoind_RPC(0,"tradebot",url,0,"liqudity",postdata)) != 0 ) + if ( (retstr= bitcoind_RPC(0,"tradebot",url,0,"liqudity",postdata,0)) != 0 ) { //printf("(%s) -> (%s)\n",postdata,retstr); free(retstr); @@ -643,7 +643,7 @@ int32_t marketmaker_spread(char *exchange,char *base,char *rel,double bid,double jaddnum(vals,"minvol",MAX(1,(int32_t)(vol * 0.01 * PAXPRICES[i]))); sprintf(url,"%s/?",IGUANA_URL); sprintf(postdata,"{\"agent\":\"tradebot\",\"method\":\"liquidity\",\"targetcoin\":\"%s\",\"vals\":%s}","KMD",jprint(vals,1)); - if ( (retstr= bitcoind_RPC(0,"tradebot",url,0,"liqudity",postdata)) != 0 ) + if ( (retstr= bitcoind_RPC(0,"tradebot",url,0,"liqudity",postdata,0)) != 0 ) { //printf("(%s) -> (%s)\n",postdata,retstr); free(retstr); diff --git a/iguana/exchanges/nxtae.c b/iguana/exchanges/nxtae.c index 03e2c1eee..d6fe1080c 100755 --- a/iguana/exchanges/nxtae.c +++ b/iguana/exchanges/nxtae.c @@ -14,7 +14,7 @@ ******************************************************************************/ #define DEFAULT_NXT_DEADLINE 720 -#define issue_NXTPOST(cmdstr) bitcoind_RPC(0,"curl",myinfo->NXTAPIURL,0,0,cmdstr) +#define issue_NXTPOST(cmdstr) bitcoind_RPC(0,"curl",myinfo->NXTAPIURL,0,0,cmdstr,0) #define NXT_MSTYPE 5 #define NXT_ASSETTYPE 2 #define NXT_GENESISTIME 1385294400 diff --git a/includes/cJSON.h b/includes/cJSON.h index b75e73bf1..77e0752e6 100755 --- a/includes/cJSON.h +++ b/includes/cJSON.h @@ -211,7 +211,7 @@ extern "C" char *get_cJSON_fieldname(cJSON *obj); void ensure_jsonitem(cJSON *json,char *field,char *value); int32_t in_jsonarray(cJSON *array,char *value); - char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params); + char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params,int32_t timeout); uint64_t calc_nxt64bits(const char *str); int32_t expand_nxt64bits(char *str,uint64_t nxt64bits); char *nxt64str(uint64_t nxt64bits); From ad2cda6aaac4d163cda5257dc6abad0568955883 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:55:10 +0300 Subject: [PATCH 1349/2705] Test --- crypto777/bitcoind_RPC.c | 2 +- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_peers.c | 5 +---- iguana/exchanges/LP_rpc.c | 24 +++++++++++++++++++----- iguana/exchanges/LP_utxos.c | 3 +-- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index cfa5f5501..8d864e38d 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -202,7 +202,7 @@ try_again: if ( res != CURLE_OK ) { numretries++; - if ( specialcase != 0 ) + if ( specialcase != 0 || timeout != 0 ) { printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); free(s.ptr); diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index d99b519bf..b8b7fe199 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -222,6 +222,7 @@ void LP_quotesinit(char *base,char *rel); int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag); int32_t LP_ismine(struct LP_utxoinfo *utxo); int32_t LP_isavailable(struct LP_utxoinfo *utxo); +struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port); #endif diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 16aa291ea..c129ba52d 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -156,8 +156,6 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr { char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); - if ( peer != 0 && peer->errors > 0 ) - return; if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,myprofit,mypeer!=0?mypeer->numpeers:0,mypeer!=0?mypeer->numutxos:0)) != 0 ) { //printf("got.(%s)\n",retstr); @@ -179,6 +177,5 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr if ( flag != 0 ) printf(" <- missing peers\n"); } - } else if ( peer != 0 ) - peer->errors++; + } } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 5cf3dbe01..5447f454e 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -17,14 +17,28 @@ // LP_rpc.c // marketmaker // + +char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) +{ + char *retstr = 0; struct LP_peerinfo *peer = 0; + peer = LP_peerfind((uint32_t)calc_ipbits(destip),port); + if ( peer == 0 || peer->errors < 3 ) + { + if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 ) + { + if ( peer != 0 ) + peer->errors++; + else printf("%s error on (%s:%u) without peer\n",debugstr,destip,port); + } + } + return(retstr); +} + char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { - char url[512],*retstr; + char url[512]; sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - //printf("send.(%s)\n",url); - retstr = issue_curlt(url,LP_HTTP_TIMEOUT); - //printf("GETPEERS.(%s)\n",retstr); - return(retstr); + return(LP_issue_curl("getpeers",destip,port,url)); } char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 5216006b2..f9fc0bca4 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -501,8 +501,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr } if ( flag != 0 ) printf(" <- missing utxos\n");*/ - } else if ( peer != 0 ) - peer->errors++; + } } cJSON *LP_inventory(char *symbol,int32_t iambob) From 28bb4b08d57ce7279d9b25f732e0c407511286db Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 16:59:00 +0300 Subject: [PATCH 1350/2705] Test --- iguana/exchanges/LP_include.h | 2 ++ iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_peers.c | 3 ++- iguana/exchanges/LP_rpc.c | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index b8b7fe199..5c037b4f4 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -22,6 +22,8 @@ #define LP_INCLUDE_H #define LP_HTTP_TIMEOUT 1 +#define LP_MAXPEER_ERRORS 3 + #define LP_DEXFEE(destsatoshis) ((destsatoshis) / INSTANTDEX_INSURANCEDIV) #define LP_DEPOSITSATOSHIS(satoshis) ((satoshis) + (satoshis >> 3)) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 2ba4cfd0c..fa072465c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -202,7 +202,7 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso peer->lastutxos = now; LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } - } else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); + } //else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); } void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index c129ba52d..2ef5511c8 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -42,7 +42,8 @@ char *LP_peers() struct LP_peerinfo *peer,*tmp; cJSON *peersjson = cJSON_CreateArray(); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - jaddi(peersjson,LP_peerjson(peer)); + if ( peer->errors < LP_MAXPEER_ERRORS ) + jaddi(peersjson,LP_peerjson(peer)); } return(jprint(peersjson,1)); } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 5447f454e..fb4b4d501 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -22,7 +22,7 @@ char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) { char *retstr = 0; struct LP_peerinfo *peer = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destip),port); - if ( peer == 0 || peer->errors < 3 ) + if ( peer == 0 || peer->errors < LP_MAXPEER_ERRORS ) { if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 ) { From 1fdfcea0e192286d720b4af23b0bfcacc86c8f95 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:02:04 +0300 Subject: [PATCH 1351/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fa072465c..e02039483 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -265,18 +265,17 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in now = (uint32_t)time(NULL); if ( lastforward < now-3600 ) { - printf("LP_forwarding_register\n"); + //printf("LP_forwarding_register\n"); LP_forwarding_register(LP_mypubkey,pushaddr,10); - printf("done LP_forwarding_register\n"); + //printf("done LP_forwarding_register\n"); lastforward = now; } nonz = n = 0; if ( (counter % 6000) == 0 ) { - printf("LP_utxo_updates\n"); + //printf("LP_utxo_updates\n"); LP_utxo_updates(pubsock,passphrase,profitmargin); } - printf("checkpeers\n"); HASH_ITER(hh,LP_peerinfos,peer,tmp) { nonz += LP_subsock_check(peer); From 2f49790046596c6e248ec329d4ef8ccef0089bd8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:08:22 +0300 Subject: [PATCH 1352/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_utxos.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index fb4b4d501..fd853d569 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,7 @@ char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); - //printf("getutxo.(%s)\n",url); + printf("getutxo.(%s)\n",url); return(issue_curlt(url,LP_HTTP_TIMEOUT)); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index f9fc0bca4..b160d2c64 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -476,12 +476,15 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( coin == 0 ) coin = ""; - printf("utxo query.(%s)\n",destipaddr); - if ( (retstr= issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer != 0 ? mypeer->numpeers : 0,mypeer != 0 ? mypeer->numutxos : 0)) != 0 ) + //printf("utxo query.(%s)\n",destipaddr); + if ( IAMLP != 0 ) + retstr = issue_LP_getutxos(destipaddr,destport,coin,lastn,myipaddr,myport,myprofit,mypeer != 0 ? mypeer->numpeers : 0,mypeer != 0 ? mypeer->numutxos : 0); + else retstr = issue_LP_clientgetutxos(destipaddr,destport,coin,100); + if ( retstr != 0 ) { now = (uint32_t)time(NULL); LP_utxosparse(mypubsock,destipaddr,destport,retstr,now); - printf("got.(%s)\n",retstr); + //printf("got.(%s)\n",retstr); free(retstr); /*i = 0; if ( lastn >= mypeer->numutxos ) From 0916bf42cf12c03d22a71b15ed3334db39e316b0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:12:41 +0300 Subject: [PATCH 1353/2705] Test --- iguana/exchanges/LP_utxos.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b160d2c64..d62f8aa0f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -252,23 +252,20 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t lastn) { int32_t i,firsti,n; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); - if ( symbol != 0 && symbol[0] != 0 ) + i = 0; + n = mypeer != 0 ? mypeer->numutxos : 0; + if ( lastn <= 0 ) + lastn = LP_PROPAGATION_SLACK * 2; + if ( lastn >= n ) + firsti = -1; + else firsti = (n - lastn); + HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { - i = 0; - n = mypeer != 0 ? mypeer->numutxos : 0; - if ( lastn <= 0 ) - lastn = LP_PROPAGATION_SLACK * 2; - if ( lastn >= n ) - firsti = -1; - else firsti = (n - lastn); - HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) + if ( i++ < firsti ) + continue; + if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) > 0 ) { - if ( i++ < firsti ) - continue; - if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) > 0 ) - { - jaddi(utxosjson,LP_utxojson(utxo)); - } + jaddi(utxosjson,LP_utxojson(utxo)); } } return(jprint(utxosjson,1)); From b83ad9b4448544e617226fa380c709a5487be220 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:14:29 +0300 Subject: [PATCH 1354/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index d62f8aa0f..774d780f2 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -259,6 +259,7 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la if ( lastn >= n ) firsti = -1; else firsti = (n - lastn); + printf("LP_utxos iambob.%d symbol.%p lastn.%d\n",iambob,symbol,lastn); HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { if ( i++ < firsti ) From f44f92f1e52617cbca2d481cbe9188599871de65 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:15:38 +0300 Subject: [PATCH 1355/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 774d780f2..17caf0ad0 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -259,7 +259,7 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la if ( lastn >= n ) firsti = -1; else firsti = (n - lastn); - printf("LP_utxos iambob.%d symbol.%p lastn.%d\n",iambob,symbol,lastn); + printf("LP_utxos iambob.%d symbol.%s lastn.%d\n",iambob,symbol==0?"":symbol,lastn); HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { if ( i++ < firsti ) From d55d3a80075a4e8a556bd84727b8bce3fd91de2d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:17:31 +0300 Subject: [PATCH 1356/2705] Test --- iguana/exchanges/LP_utxos.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 17caf0ad0..fff8afc7d 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -258,13 +258,13 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la lastn = LP_PROPAGATION_SLACK * 2; if ( lastn >= n ) firsti = -1; - else firsti = (n - lastn); - printf("LP_utxos iambob.%d symbol.%s lastn.%d\n",iambob,symbol==0?"":symbol,lastn); + else firsti = (lastn - n); + printf("LP_utxos iambob.%d symbol.%s firsti.%d lastn.%d\n",iambob,symbol==0?"":symbol,firsti,lastn); HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { if ( i++ < firsti ) continue; - if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 )//&& LP_ismine(utxo) > 0 ) + if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 ) { jaddi(utxosjson,LP_utxojson(utxo)); } From aab87b6c446b1732c95edefaff86bf8ac3be36ab Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:19:56 +0300 Subject: [PATCH 1357/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index fff8afc7d..a95cb65f7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -262,6 +262,7 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la printf("LP_utxos iambob.%d symbol.%s firsti.%d lastn.%d\n",iambob,symbol==0?"":symbol,firsti,lastn); HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { + char str[65]; printf("check %s.%s\n",utxo->coin,bits256_str(str,utxo->payment.txid)); if ( i++ < firsti ) continue; if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 ) From e8a9c21e2d74ce3e397b4efca3bd0d9fa0f739fb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:20:57 +0300 Subject: [PATCH 1358/2705] Test --- iguana/exchanges/LP_rpc.c | 1 - iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index fd853d569..11f1b7041 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -52,7 +52,6 @@ char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); - printf("getutxo.(%s)\n",url); return(issue_curlt(url,LP_HTTP_TIMEOUT)); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a95cb65f7..7e09d6833 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -483,7 +483,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr { now = (uint32_t)time(NULL); LP_utxosparse(mypubsock,destipaddr,destport,retstr,now); - //printf("got.(%s)\n",retstr); + printf("got.(%s)\n",retstr); free(retstr); /*i = 0; if ( lastn >= mypeer->numutxos ) From 0611da63ed37ef2e0453f5138a8293a4c4ddd017 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:21:27 +0300 Subject: [PATCH 1359/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7e09d6833..a95cb65f7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -483,7 +483,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr { now = (uint32_t)time(NULL); LP_utxosparse(mypubsock,destipaddr,destport,retstr,now); - printf("got.(%s)\n",retstr); + //printf("got.(%s)\n",retstr); free(retstr); /*i = 0; if ( lastn >= mypeer->numutxos ) From f04a1e107120863d8824208317110a1549ff37d6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:24:32 +0300 Subject: [PATCH 1360/2705] Test --- iguana/exchanges/LP_forwarding.c | 4 ++-- iguana/exchanges/LP_utxos.c | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 1a14965cd..5f935ba83 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -94,10 +94,10 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) } HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("register with (%s)\n",peer->ipaddr); + //printf("register with (%s)\n",peer->ipaddr); if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) { - printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); + //printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( jint(retjson,"registered") != 0 && ++n >= max ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a95cb65f7..0b06803db 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -433,7 +433,8 @@ struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { - struct LP_peerinfo *destpeer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + struct LP_peerinfo *destpeer,*peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; + printf("parse.(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -448,16 +449,16 @@ int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char if ( (subport= juint(item,"sub")) == 0 ) subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); - //if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - // peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); - if ( jobj(item,"txid") != 0 ) - { - txid = jbits256(item,"txid"); - printf("parse.(%s)\n",jprint(item,0)); - if ( (utxo= LP_utxoaddjson(1,mypubsock,item)) != 0 ) - utxo->T.lasttime = now; - } - } // else printf("skip.(%s)\n",jprint(item,0)); + if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) + peer = LP_addpeer(LP_mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + } + if ( jobj(item,"txid") != 0 ) + { + txid = jbits256(item,"txid"); + printf("parse.(%s)\n",jprint(item,0)); + if ( (utxo= LP_utxoaddjson(1,mypubsock,item)) != 0 ) + utxo->T.lasttime = now; + } } if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) { From 7ddcf384bcc4ce582f7720edc069317e1225427a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:33:05 +0300 Subject: [PATCH 1361/2705] test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0b06803db..6e685b80b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -428,7 +428,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson) { - return(LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid2"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit"))); + return(LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit"))); } int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) From 3cedddcd7809c8dc792aba8078aed7ff2ef61c8a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:34:24 +0300 Subject: [PATCH 1362/2705] Test --- iguana/exchanges/LP_utxos.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6e685b80b..f2b0c933e 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -259,10 +259,10 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la if ( lastn >= n ) firsti = -1; else firsti = (lastn - n); - printf("LP_utxos iambob.%d symbol.%s firsti.%d lastn.%d\n",iambob,symbol==0?"":symbol,firsti,lastn); + //printf("LP_utxos iambob.%d symbol.%s firsti.%d lastn.%d\n",iambob,symbol==0?"":symbol,firsti,lastn); HASH_ITER(hh,LP_utxoinfos[iambob],utxo,tmp) { - char str[65]; printf("check %s.%s\n",utxo->coin,bits256_str(str,utxo->payment.txid)); + //char str[65]; printf("check %s.%s\n",utxo->coin,bits256_str(str,utxo->payment.txid)); if ( i++ < firsti ) continue; if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 ) @@ -434,7 +434,7 @@ struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *destpeer,*peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; - printf("parse.(%s)\n",retstr); + //printf("parse.(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) @@ -455,7 +455,7 @@ int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - printf("parse.(%s)\n",jprint(item,0)); + //printf("parse.(%s)\n",jprint(item,0)); if ( (utxo= LP_utxoaddjson(1,mypubsock,item)) != 0 ) utxo->T.lasttime = now; } From cf18fac7520731bb50b005567705b7cfd14fad48 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:37:03 +0300 Subject: [PATCH 1363/2705] Test --- iguana/exchanges/LP_prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 2a3064c0c..52791da03 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -378,7 +378,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol, struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_orderbookentry *op; uint64_t basesatoshis; HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { - char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); + //char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); if ( bits256_cmp(pubkey,utxo->pubkey) == 0 && strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) From 67b51ac7016597f4a9097196b1e76d20c49d8d74 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 17:52:06 +0300 Subject: [PATCH 1364/2705] Test --- iguana/exchanges/LP_prices.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 52791da03..69918026e 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -373,21 +373,19 @@ int32_t LP_orderbookfind(struct LP_orderbookentry **array,int32_t num,bits256 tx return(-1); } -int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol,double price,struct LP_orderbookentry *(**arrayp),int32_t num,int32_t cachednum,bits256 pubkey) +int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,double price,struct LP_orderbookentry *(**arrayp),int32_t num,int32_t cachednum,bits256 pubkey) { struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_orderbookentry *op; uint64_t basesatoshis; HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { //char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); - if ( bits256_cmp(pubkey,utxo->pubkey) == 0 && strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) + if ( bits256_cmp(pubkey,utxo->pubkey) == 0 && strcmp(base,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { //char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); - if ( strcmp(base,symbol) == 0 ) - basesatoshis = utxo->payment.value; - else basesatoshis = utxo->payment.value * price; + basesatoshis = utxo->payment.value; if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,price,basesatoshis,pubkey)) != 0 ) (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) @@ -416,7 +414,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,char *symbol, char *LP_orderbook(char *base,char *rel) { - uint32_t now,i; struct LP_priceinfo *basepp=0,*relpp=0; struct LP_pubkeyinfo *pubp,*ptmp; struct LP_cacheinfo *ptr,*tmp; struct LP_orderbookentry *op,**bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0,cachenumbids,cachenumasks,baseid,relid; + uint32_t now,i; double price; struct LP_priceinfo *basepp=0,*relpp=0; struct LP_pubkeyinfo *pubp,*ptmp; struct LP_cacheinfo *ptr,*tmp; struct LP_orderbookentry *op,**bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0,cachenumbids,cachenumasks,baseid,relid; if ( (basepp= LP_priceinfofind(base)) == 0 || (relpp= LP_priceinfofind(rel)) == 0 ) return(clonestr("{\"error\":\"base or rel not added\"}")); baseid = basepp->ind; @@ -440,15 +438,15 @@ char *LP_orderbook(char *base,char *rel) } } cachenumbids = numbids, cachenumasks = numasks; - printf("start cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); + //printf("start cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); HASH_ITER(hh,LP_pubkeyinfos,pubp,ptmp) { - char str[65]; printf("pubkey.(%s)\n",bits256_str(str,pubp->pubkey)); - if ( pubp->matrix[baseid][relid] > SMALLVAL ) - numasks = LP_orderbook_utxoentries(now,base,rel,base,pubp->matrix[baseid][relid],&asks,numasks,cachenumasks,pubp->pubkey); - if ( pubp->matrix[relid][baseid] > SMALLVAL ) - numbids = LP_orderbook_utxoentries(now,base,rel,rel,pubp->matrix[relid][baseid],&bids,numbids,cachenumbids,pubp->pubkey); - printf("cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); + //char str[65]; printf("pubkey.(%s)\n",bits256_str(str,pubp->pubkey)); + if ( (price= pubp->matrix[baseid][relid]) > SMALLVAL ) + numasks = LP_orderbook_utxoentries(now,base,rel,price,&asks,numasks,cachenumasks,pubp->pubkey); + if ( (price= pubp->matrix[relid][baseid]) > SMALLVAL ) + numbids = LP_orderbook_utxoentries(now,base,rel,1./price,&bids,numbids,cachenumbids,pubp->pubkey); + //printf("cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); } retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); From 7819837ab953ed95a323d020fad5865c84f3079c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:08:10 +0300 Subject: [PATCH 1365/2705] Test --- iguana/exchanges/LP_prices.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 69918026e..aebff6fb8 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -373,20 +373,25 @@ int32_t LP_orderbookfind(struct LP_orderbookentry **array,int32_t num,bits256 tx return(-1); } -int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,double price,struct LP_orderbookentry *(**arrayp),int32_t num,int32_t cachednum,bits256 pubkey) +int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char *rel,struct LP_orderbookentry *(**arrayp),int32_t num,int32_t cachednum) { - struct LP_utxoinfo *utxo,*tmp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_orderbookentry *op; uint64_t basesatoshis; + struct LP_utxoinfo *utxo,*tmp; struct LP_pubkeyinfo *pubp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_priceinfo *basepp; struct LP_orderbookentry *op; double price; int32_t baseid,relid; uint64_t basesatoshis; + if ( (basepp= LP_priceinfoptr(&relid,base,rel)) != 0 ) + baseid = basepp->ind; + else return(num); HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { //char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); - if ( bits256_cmp(pubkey,utxo->pubkey) == 0 && strcmp(base,utxo->coin) == 0 && LP_isavailable(utxo) > 0 ) + if ( strcmp(base,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && (pubp= LP_pubkeyfind(utxo->pubkey)) != 0 && (price= pubp->matrix[baseid][relid]) > SMALLVAL ) { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { //char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); - basesatoshis = utxo->payment.value; - if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,price,basesatoshis,pubkey)) != 0 ) + if ( polarity > 0 ) + basesatoshis = utxo->payment.value; + else basesatoshis = utxo->payment.value * price; + if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey)) != 0 ) (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) { @@ -414,7 +419,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,char *base,char *rel,double price, char *LP_orderbook(char *base,char *rel) { - uint32_t now,i; double price; struct LP_priceinfo *basepp=0,*relpp=0; struct LP_pubkeyinfo *pubp,*ptmp; struct LP_cacheinfo *ptr,*tmp; struct LP_orderbookentry *op,**bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0,cachenumbids,cachenumasks,baseid,relid; + uint32_t now,i; struct LP_priceinfo *basepp=0,*relpp=0; struct LP_cacheinfo *ptr,*tmp; struct LP_orderbookentry *op,**bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0,cachenumbids,cachenumasks,baseid,relid; if ( (basepp= LP_priceinfofind(base)) == 0 || (relpp= LP_priceinfofind(rel)) == 0 ) return(clonestr("{\"error\":\"base or rel not added\"}")); baseid = basepp->ind; @@ -439,15 +444,8 @@ char *LP_orderbook(char *base,char *rel) } cachenumbids = numbids, cachenumasks = numasks; //printf("start cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); - HASH_ITER(hh,LP_pubkeyinfos,pubp,ptmp) - { - //char str[65]; printf("pubkey.(%s)\n",bits256_str(str,pubp->pubkey)); - if ( (price= pubp->matrix[baseid][relid]) > SMALLVAL ) - numasks = LP_orderbook_utxoentries(now,base,rel,price,&asks,numasks,cachenumasks,pubp->pubkey); - if ( (price= pubp->matrix[relid][baseid]) > SMALLVAL ) - numbids = LP_orderbook_utxoentries(now,base,rel,1./price,&bids,numbids,cachenumbids,pubp->pubkey); - //printf("cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); - } + numasks = LP_orderbook_utxoentries(now,1,base,rel,&asks,numasks,cachenumasks); + numbids = LP_orderbook_utxoentries(now,-1,rel,base,&bids,numbids,cachenumbids); retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); if ( numbids > 1 ) From 9d8799047d14b7203569da7e58ed38e700d479f5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:24:05 +0300 Subject: [PATCH 1366/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e02039483..5f0cc7a8c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -92,7 +92,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - //printf("PULLED %d, datalen.%d (%s)\n",recvsize,datalen,jsonstr); + printf("PULLED %d, datalen.%d (%s)\n",recvsize,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { len = (int32_t)strlen(jsonstr) + 1; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index f2b0c933e..dd03bef83 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -372,7 +372,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit } if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { - if ( LP_ismine(utxo) == 0 ) + if ( 0 && LP_ismine(utxo) == 0 ) { char str2[65],str3[65]; printf("iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis)); From eac7e9ea81f7cdeae7737076c59527f4060fcf45 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:39:24 +0300 Subject: [PATCH 1367/2705] Test --- iguana/exchanges/LP_forwarding.c | 16 ++++++++++++++-- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_nativeDEX.c | 27 +++++++++++++++++---------- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 5f935ba83..8bc32050c 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -113,10 +113,22 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) char *LP_forwardhex(bits256 pubkey,char *hexstr) { - struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; cJSON *retjson; + struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *retstr=0; cJSON *retjson,*argjson; if ( hexstr == 0 || hexstr[0] == 0 ) return(clonestr("{\"error\":\"nohex\"}")); - if ( (ptr= LP_forwardfind(pubkey)) != 0 ) + if ( bits256_nonz(pubkey) == 0 || bits256_cmp(pubkey,LP_mypubkey) == 0 ) + { + datalen = (int32_t)strlen(hexstr) >> 1; + data = malloc(datalen); + decode_hex(data,datalen,hexstr); + if ( (argjson= cJSON_Parse((char *)data)) != 0 ) + { + retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,argjson,0,0,LP_profitratio - 1.); + free_json(argjson); + } + return(retstr); + } + else if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { if ( ptr->pushsock >= 0 ) { diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 5c037b4f4..c50c03ecb 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -225,6 +225,7 @@ int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag); int32_t LP_ismine(struct LP_utxoinfo *utxo); int32_t LP_isavailable(struct LP_utxoinfo *utxo); struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port); +char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin); #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5f0cc7a8c..165ba1b48 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -79,6 +79,21 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_forwarding.c" #include "LP_commands.c" +char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) +{ + char *retstr=0; + if ( LP_tradecommand(myipaddr,pubsock,argjson,data,datalen,profitmargin) <= 0 ) + { + if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) + { + printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + } + } + return(retstr); +} + int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { int32_t recvsize,len,datalen=0,nonz = 0; void *ptr; char *retstr,*jsonstr=0; cJSON *argjson,*reqjson; @@ -110,16 +125,8 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) LP_send(pubsock,jprint(reqjson,1),1); } - else if ( LP_tradecommand(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin) <= 0 ) - { - if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) - { - printf("%s PULL.[%d] %s -> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",recvsize,jsonstr,retstr); - if ( pubsock >= 0 ) - LP_send(pubsock,retstr,1); - else free(retstr); - } - } + else if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin)) != 0 ) + free(retstr); portable_mutex_unlock(&LP_commandmutex); free_json(argjson); } else printf("error parsing(%s)\n",jsonstr); From e115266fd9e4d4d317fba66d3ec261ba019df4d4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:40:38 +0300 Subject: [PATCH 1368/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 165ba1b48..57cdaaf5c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -88,7 +88,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * { printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); if ( pubsock >= 0 ) - LP_send(pubsock,retstr,1); + LP_send(pubsock,retstr,0); } } return(retstr); From 45473ec1630b50bef85bb0646e16f02c0357db32 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:43:52 +0300 Subject: [PATCH 1369/2705] Test --- iguana/exchanges/LP_commands.c | 12 ------------ iguana/exchanges/LP_forwarding.c | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 15e429644..7b1e564c5 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -231,18 +231,6 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d return(retval); } -cJSON *LP_dereference(cJSON *argjson,char *excludemethod) -{ - cJSON *reqjson = 0; - if ( jstr(argjson,"method2") != 0 && strncmp(excludemethod,jstr(argjson,"method2"),strlen(excludemethod)) != 0 ) - { - reqjson = jduplicate(argjson); - jdelete(reqjson,"method"); - jaddstr(reqjson,"method",jstr(argjson,"method2")); - } - return(reqjson); -} - char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 8bc32050c..839756d4d 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -111,9 +111,21 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) } } +cJSON *LP_dereference(cJSON *argjson,char *excludemethod) +{ + cJSON *reqjson = 0; + if ( jstr(argjson,"method2") != 0 && strncmp(excludemethod,jstr(argjson,"method2"),strlen(excludemethod)) != 0 ) + { + reqjson = jduplicate(argjson); + jdelete(reqjson,"method"); + jaddstr(reqjson,"method",jstr(argjson,"method2")); + } + return(reqjson); +} + char *LP_forwardhex(bits256 pubkey,char *hexstr) { - struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *retstr=0; cJSON *retjson,*argjson; + struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *retstr=0; cJSON *retjson,*argjson,*reqjson; if ( hexstr == 0 || hexstr[0] == 0 ) return(clonestr("{\"error\":\"nohex\"}")); if ( bits256_nonz(pubkey) == 0 || bits256_cmp(pubkey,LP_mypubkey) == 0 ) @@ -123,7 +135,9 @@ char *LP_forwardhex(bits256 pubkey,char *hexstr) decode_hex(data,datalen,hexstr); if ( (argjson= cJSON_Parse((char *)data)) != 0 ) { - retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,argjson,0,0,LP_profitratio - 1.); + reqjson = LP_dereference(argjson,"forward"); + retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); + free_json(reqjson); free_json(argjson); } return(retstr); From 8b819f579007599a52d388cd11a5c629c018a43c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:48:38 +0300 Subject: [PATCH 1370/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/LP_forwarding.c | 6 ++++-- iguana/exchanges/LP_nativeDEX.c | 6 +++--- iguana/exchanges/mm.c | 2 +- iguana/exchanges/stats.c | 4 ++-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7b1e564c5..c489ac0ce 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -231,7 +231,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d return(retval); } -char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port +char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (method= jstr(argjson,"method")) == 0 ) @@ -422,7 +422,7 @@ forwardhex(pubkey,hex)\n\ else if ( strcmp(method,"lookup") == 0 ) retstr = LP_lookup(jbits256(argjson,"client")); else if ( strcmp(method,"forwardhex") == 0 ) - retstr = LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hex")); + retstr = LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); else if ( strcmp(method,"notified") == 0 ) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 839756d4d..11c64e84e 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -123,7 +123,7 @@ cJSON *LP_dereference(cJSON *argjson,char *excludemethod) return(reqjson); } -char *LP_forwardhex(bits256 pubkey,char *hexstr) +char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) { struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *retstr=0; cJSON *retjson,*argjson,*reqjson; if ( hexstr == 0 || hexstr[0] == 0 ) @@ -136,7 +136,9 @@ char *LP_forwardhex(bits256 pubkey,char *hexstr) if ( (argjson= cJSON_Parse((char *)data)) != 0 ) { reqjson = LP_dereference(argjson,"forward"); - retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); + if ( pubsock < 0 || bits256_cmp(pubkey,LP_mypubkey) == 0 ) + retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); + else LP_send(pubsock,jprint(reqjson,0),1); free_json(reqjson); free_json(argjson); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 57cdaaf5c..f857747e9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -84,7 +84,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * char *retstr=0; if ( LP_tradecommand(myipaddr,pubsock,argjson,data,datalen,profitmargin) <= 0 ) { - if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) + if ( (retstr= stats_JSON(pubsock,argjson,"127.0.0.1",0)) != 0 ) { printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); if ( pubsock >= 0 ) @@ -114,7 +114,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double portable_mutex_lock(&LP_commandmutex); if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) { - if ( (retstr= LP_forwardhex(jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) + if ( (retstr= LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) free(retstr); } else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) @@ -147,7 +147,7 @@ int32_t LP_subsock_check(struct LP_peerinfo *peer) if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { portable_mutex_lock(&LP_commandmutex); - if ( (retstr= stats_JSON(argjson,"127.0.0.1",0)) != 0 ) + if ( (retstr= stats_JSON(-1,argjson,"127.0.0.1",0)) != 0 ) { //printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 6fcfda6ca..41bbd2e2e 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -24,7 +24,7 @@ #include #include "OS_portable.h" #define MAX(a,b) ((a) > (b) ? (a) : (b)) -char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port); +char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port); #include "stats.c" void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]); diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 8af29db0e..06d1cfeb7 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -489,7 +489,7 @@ char *stats_rpcparse(char *retbuf,int32_t bufsize,int32_t *jsonflagp,int32_t *po if ( userpass != 0 && jstr(argjson,"userpass") == 0 ) jaddstr(argjson,"userpass",userpass); //printf("after urlconv.(%s) argjson.(%s)\n",jprint(json,0),jprint(argjson,0)); - if ( (retstr= stats_JSON(argjson,remoteaddr,port)) != 0 ) + if ( (retstr= stats_JSON(-1,argjson,remoteaddr,port)) != 0 ) { if ( (retitem= cJSON_Parse(retstr)) != 0 ) jaddi(retarray,retitem); @@ -512,7 +512,7 @@ char *stats_rpcparse(char *retbuf,int32_t bufsize,int32_t *jsonflagp,int32_t *po //printf("ARGJSON.(%s)\n",jprint(arg,0)); if ( userpass != 0 && jstr(arg,"userpass") == 0 ) jaddstr(arg,"userpass",userpass); - retstr = stats_JSON(arg,remoteaddr,port); + retstr = stats_JSON(-1,arg,remoteaddr,port); } free_json(argjson); free_json(json); From c2f4e555085d705a0d6f0e17857770ecfa42da5d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:53:23 +0300 Subject: [PATCH 1371/2705] Test --- iguana/exchanges/LP_forwarding.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 11c64e84e..7983f634a 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -136,9 +136,9 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) if ( (argjson= cJSON_Parse((char *)data)) != 0 ) { reqjson = LP_dereference(argjson,"forward"); - if ( pubsock < 0 || bits256_cmp(pubkey,LP_mypubkey) == 0 ) - retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); - else LP_send(pubsock,jprint(reqjson,0),1); + retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); + if ( pubsock >= 0 && bits256_cmp(pubkey,LP_mypubkey) != 0 ) + LP_send(pubsock,jprint(reqjson,0),1); free_json(reqjson); free_json(argjson); } From 8d98905938112dbca5332cc89c52dc326c78ee6e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:55:38 +0300 Subject: [PATCH 1372/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 7983f634a..e38b3175d 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -137,7 +137,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) { reqjson = LP_dereference(argjson,"forward"); retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); - if ( pubsock >= 0 && bits256_cmp(pubkey,LP_mypubkey) != 0 ) + if ( pubsock >= 0 ) LP_send(pubsock,jprint(reqjson,0),1); free_json(reqjson); free_json(argjson); From b254f769ba53dff3d2adbca29c3f274e7e72d69f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 18:58:42 +0300 Subject: [PATCH 1373/2705] Test --- iguana/exchanges/LP_peers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 2ef5511c8..af64c161e 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -42,7 +42,7 @@ char *LP_peers() struct LP_peerinfo *peer,*tmp; cJSON *peersjson = cJSON_CreateArray(); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( peer->errors < LP_MAXPEER_ERRORS ) + //if ( peer->errors < LP_MAXPEER_ERRORS ) jaddi(peersjson,LP_peerjson(peer)); } return(jprint(peersjson,1)); From cfe63f7543db590d2a460373e3db6f93fe6bf5c9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 19:00:26 +0300 Subject: [PATCH 1374/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f857747e9..748f33f50 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -30,7 +30,7 @@ char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; -char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196" , };//'"5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // +char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex; int32_t LP_mypubsock = -1; From c65a276338f013b9b0de4471d149f868d2b95a1d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 19:03:56 +0300 Subject: [PATCH 1375/2705] Test --- iguana/exchanges/LP_commands.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c489ac0ce..4510b05c4 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -235,7 +235,10 @@ char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) { char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (method= jstr(argjson,"method")) == 0 ) + { + printf("(%s)\n",jprint(argjson,0)); return(clonestr("{\"error\":\"need method in request\"}")); + } else if ( strcmp(method,"help") == 0 ) return(clonestr("{\"result\":\" \ available localhost RPC commands:\n \ From 69430c7cfecff269bb132fe4ab90069988586678 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 19:08:52 +0300 Subject: [PATCH 1376/2705] Test --- iguana/exchanges/LP_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 4510b05c4..eab3010e3 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -165,6 +165,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 || strcmp(method,"price") == 0 || strcmp(method,"connect") == 0) ) { + retval = 1; txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { From 19ff3b27d7bc5ae0ddbcbf56e7c410c46a31dd12 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 20:01:39 +0300 Subject: [PATCH 1377/2705] Test --- iguana/exchanges/LP_utxos.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index dd03bef83..cb99c9f40 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -352,24 +352,9 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit return(0); } destaddr2[0] = 0; - if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) != value || (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) != value2 || strcmp(destaddr,destaddr2) != 0 || strcmp(coinaddr,destaddr) != 0 ) - { - printf("utxoadd mismatch %s/v%d (%s %.8f) + %s/v%d (%s %.8f) != %s %.8f %.8f\n",bits256_str(str,txid),vout,destaddr,dstr(val),bits256_str(str2,txid2),vout2,destaddr2,dstr(val2),coinaddr,dstr(value),dstr(value2)); - return(0); - } if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; - if ( LP_iseligible(iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) - { - printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); - return(0); - } - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) - { - printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(0); - } if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { if ( 0 && LP_ismine(utxo) == 0 ) @@ -388,6 +373,21 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit } else { + if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) != value || (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) != value2 || strcmp(destaddr,destaddr2) != 0 || strcmp(coinaddr,destaddr) != 0 ) + { + printf("utxoadd mismatch %s/v%d (%s %.8f) + %s/v%d (%s %.8f) != %s %.8f %.8f\n",bits256_str(str,txid),vout,destaddr,dstr(val),bits256_str(str2,txid2),vout2,destaddr2,dstr(val2),coinaddr,dstr(value),dstr(value2)); + return(0); + } + if ( LP_iseligible(iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) + { + printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); + return(0); + } + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) + { + printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(0); + } utxo = calloc(1,sizeof(*utxo)); utxo->S.profitmargin = profitmargin; utxo->pubkey = pubkey; From b9f89cc176ce2840ba9031ac1e67adc529bf6474 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 20:05:27 +0300 Subject: [PATCH 1378/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 11f1b7041..0c5f29d45 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -65,7 +65,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65],str3[65]; - sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); + sprintf(url,"http://%s:%u/api/stats/notified?method=notified&pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curlt(url,LP_HTTP_TIMEOUT)); From 7fd70608ac643ccb0c43d62f9af198db07a3e4a3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 20:32:09 +0300 Subject: [PATCH 1379/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index cb99c9f40..f2cb877b6 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -203,6 +203,7 @@ int32_t LP_utxopurge(int32_t allutxos) cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { struct _LP_utxoinfo u; + jaddstr(item,"method","notified"); jaddstr(item,"coin",utxo->coin); jaddnum(item,"now",time(NULL)); jaddstr(item,"address",utxo->coinaddr); From 333d4c51d05d9129178f63d1f09fe280e5d43c0d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 20:34:14 +0300 Subject: [PATCH 1380/2705] Test --- iguana/exchanges/LP_commands.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index eab3010e3..1a4536fba 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -419,6 +419,15 @@ forwardhex(pubkey,hex)\n\ retstr = LP_peers(); else if ( strcmp(method,"getutxos") == 0 ) retstr = LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn")); + else if ( strcmp(method,"notified") == 0 ) + { + if ( juint(argjson,"timestamp") > time(NULL)-60 ) + { + printf("utxonotify.(%s)\n",jprint(argjson,0)); + LP_utxoaddjson(1,LP_mypubsock,argjson); + } + retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); + } else if ( IAMLP != 0 ) { if ( strcmp(method,"register") == 0 ) @@ -429,15 +438,6 @@ forwardhex(pubkey,hex)\n\ retstr = LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); - else if ( strcmp(method,"notified") == 0 ) - { - if ( juint(argjson,"timestamp") > time(NULL)-60 ) - { - printf("utxonotify.(%s)\n",jprint(argjson,0)); - LP_utxoaddjson(1,LP_mypubsock,argjson); - } - retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); - } } if ( retstr != 0 ) return(retstr); From 800e06a866d277814e1e39f26bc6aefb50ede402 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 20:37:30 +0300 Subject: [PATCH 1381/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index f2cb877b6..3d0833aa8 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -203,7 +203,7 @@ int32_t LP_utxopurge(int32_t allutxos) cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { struct _LP_utxoinfo u; - jaddstr(item,"method","notified"); + jaddstr(item,"method2","notified"); jaddstr(item,"coin",utxo->coin); jaddnum(item,"now",time(NULL)); jaddstr(item,"address",utxo->coinaddr); From ee35b352b5abd4d750d0850227324c128fb51a17 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 20:38:10 +0300 Subject: [PATCH 1382/2705] Test --- iguana/exchanges/LP_utxos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 3d0833aa8..6ee0ecfa7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -203,6 +203,7 @@ int32_t LP_utxopurge(int32_t allutxos) cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { struct _LP_utxoinfo u; + jaddstr(item,"method","notified"); jaddstr(item,"method2","notified"); jaddstr(item,"coin",utxo->coin); jaddnum(item,"now",time(NULL)); From 82d51540b9c5d6692d55298605af0c699b51074c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 14 Jun 2017 21:11:47 +0300 Subject: [PATCH 1383/2705] Test --- .gitignore | 2 ++ iguana/exchanges/LP_commands.c | 5 +++++ iguana/exchanges/LP_nativeDEX.c | 5 +++++ .../Contents/Resources/DWARF/marketmaker | Bin 0 -> 339918 bytes iguana/userpass | 1 + 5 files changed, 13 insertions(+) create mode 100644 iguana/marketmaker.dSYM/Contents/Resources/DWARF/marketmaker create mode 100644 iguana/userpass diff --git a/.gitignore b/.gitignore index c68d66ed4..f166a52e6 100755 --- a/.gitignore +++ b/.gitignore @@ -465,3 +465,5 @@ iguana/DB/SWAPS/3085356347-2346291696 iguana/DB/SWAPS/1819165332-1507632737 iguana/DB/SWAPS/283982730-556239841 + +iguana/marketmaker.dSYM/Contents/Info.plist diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 1a4536fba..550852f3e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -18,6 +18,11 @@ // marketmaker // +// price query is redundant as there is a pricefeed for all pubkeys now +// get orderbook, find pubkey of the one offering it and directly reserve it +// then it is the same as current logic, just skip the "price" step +// "notified" push is wrong + double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub) { cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 748f33f50..fbc4e3ccd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -366,7 +366,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit OS_randombytes((void *)&n,sizeof(n)); srand((int32_t)n); if ( userhome != 0 && userhome[0] != 0 ) + { safecopy(USERHOME,userhome,sizeof(USERHOME)); +#ifdef __APPLE__ + strcat(USERHOME,"/Library/Application Support"); +#endif + } portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); portable_mutex_init(&LP_commandmutex); diff --git a/iguana/marketmaker.dSYM/Contents/Resources/DWARF/marketmaker b/iguana/marketmaker.dSYM/Contents/Resources/DWARF/marketmaker new file mode 100644 index 0000000000000000000000000000000000000000..20c28fdf236fd57192d613a639e18656b299cb21 GIT binary patch literal 339918 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 Uw=OK@5b0b;*9k= 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 @dW@&@ZqN|^)*;6rg$gP_@g<2D_>WXQS zGDplOX2I5CM%8SPCRt^(WngNg{Cs^>oH(~k+L4Ix&2U6VQbxiKs}4w6xsET|CjO#X za|JIWENHW8=6L8bN@S$Ys*>un%I1^Kld9?~HDOLw zZN;o|dQ^~HSE=&`PwqpJLbKOoGHOyq!&lUn%_*zb?o6$$m^!nrYC5afc)B~10)Ew3 zWfrjs>2jDJGIUbDx@PK3+REu{MT~yJ=a`XS&)D&)uwJrgQF09M4Vj|)gpMxyKvTc=xWR^3V z4v1Kz82@74a+Ri6N=!-8YNTNwN$4zPMis4g)4=RP_ z7E2BtEim@!5QiO@;#w*@F03qU%b3(=m2XQnlVY0EVq&u+*2}>(S;{nljkBAIj5viH zSV$STXr9Iw!I4kD8uLAXOO|XY8sIboU5O=hQAIslQ>hn<(r#44NjRU|Bjk1wKboAPp{Yy5VvphIp(e+S-i~;4>uds3bS8PIDrPv1ow9 zn{Ei&-(4Y|DTGoTp(V}|M-E=hF$-KK(e`H0rdY6ZqBTa0PJ0nBb#z)sJIp0PTqKx_ zc(PFhyD*lbZIV8!;aQ5bMhmtLJB~z0xAxx4;SmS{J=Kxq#twJ@!;P^{a9}Zf2-qph z0S@~O-pZ~9J9K3^JC8|$yeQnYnA%B43hRNA%~8KTT)BGK6Otkt7q@x?niApB^BeF7 zCU3{0uxEvYmJib4zHQTRr&&0X9HC6j_{PV~`2>I6_DSztUi zXK=$nWEsa$V;h?}2e9p>=azmg&OiD9Ibvppb5{m0HIILU|1CKF5w9i8SMr}bSlM8j z9UCb`+t^UjJINnW8T?^Y^w0^_)YW09R7K~%gZ{!3EvJL+(Ufp69!|jhhHVh#7Od?A zJv~m?Y0zRgM1*6#l>*JVB))RMbo)t1*p$v?8CV>DDMC2xP~1C~!Xbe<$-;pW)l-rO zVp5SqYUALFq>-7nDR}8xI&i3wXvM_m5A&pXpaD}-+?DaE4pX2q{Faj`C?(nI8Z5|_ z4HNBmiC_yXPu--;E?T14PU*H;_QP^61dkGv(9~if(u`Si6gv+&$RjTz_#t)aObR#D z43E=rB7nmI`kBOE3XWm&kufqXOc!5GgE+ktbdN9%=cQPH#1BPK)F+$=@M|v7e92Q} zETFC^sbL&kq7@|`j>j<6vUSoZ{BJRJol8E>NVpba#+iq-Mo(-v5K0mCxw0Ya#Iv34 z4!6P?mf_T8A#TylO6ir0H5Fk_iWi#C41N(T!kCFH%hJpN1V2TOap^-ZmV{e6IzpgJCwwG^y)Ar9=_5rR51Mt!RQdnpicyi7r)+(|bS*Y?E`b9W2i(!tR*9JUkWMH)1Hkb~K(_Hv z`Y1=;pVexj6X*2tj#fBFp~jLp#xMsfnWfa#%ri5f*P~RR)(C$MHMUvOUWw$2)zQ&ElO4^9E;jHW?eh4&tW+GYx2L@3QnFj6OuV-H|PTN|5( z&x&WnUFMt`Nzwum<*8#Sy};RZdj|}}P%5J5^XMK@>lmkTrnkL3&gaZ)zk5 zM0beI0JBMzTe4Z)I&{=ZB!VL_JKGZ7&}B}d+aOECuzJBK?f^q9jPss2nWZP0n5v0R zEE|nH{*ig!(2Ng%xq&1u91z>4U(#wVW z1P=HEQj80Zr<^vfb|sJNqLDatLq>+2A*w2YecIROROP%>a5J&1#Y8ZUCtmEdzI9hRV8aBc7q43An71RTB4EY=&1d(XB}) zXHs$8k$WaylePv=k0uml*Q4gejN-!PmB%@>gCWJTB$f&0igAqMt_2VBR< z;Q@i@Ia3W+WUwC!H7tUK(y}lVli!8%i^F}SkS%cHn-cPrQrJ)8+=DqhnZUIZM%$y^ z-T{MwiP?^jN>D~G%t?ZtHiwgK?5B*oOcK*o3N39I`>e|t8R<1ONdziR{OP~|v$+Ht3 zy&6gNJigDYY4^>hrpc0RIz|9`9tw#OJ7};uaO0sBmNd74au_a#H6|?0YcKB1bHpK7 z$KG||rWj7JaDdd=2Eo=N5l(NwV0O}3Bp1{mG)+dbnq*tvg*o132U@(FmCDnU3A^4xEPKvA)H2~rKGGpVxUL8$AgECCi#2AHi zZVJaVIC{}c+qMYcFXY97URCa3n3!F4R!7rpNwKaH_*LwMBa1%6*J6?y;R#44aVXU( zCmo#BG;MIyXzS1m4cM%P%w$2UzMcy%veHVLUTotNzAKJsd+lV zJ>fCEga?8iBfV>A1WS{!w{>QTbYg4P6EnBYgn6nOz(z~Gt&#FvXRt=0IABn~=G5X6 zw+^+qcmGMIfYwJ1o$g}bTlt6E!Hi5}w4t+ETzaCm!?QlzLglUyH$&4|##LhP?&$KAhvu^A&lP-w+6A)>>H=Pg>=o?P(6ctvP@L%2QmkNXAH7j41_dSptUTO>#P&m`3YIRG zWS7~bS=fxI(H8?31G;Xi$h<`RvXHU7*Il^g>=iOAK;%sk#txOU#F8_nC@TepG=a_+ z?)S}}0IGx@9Nv+Xfq=)dy-A&HGHa-IIJK!~alMOCnMj_40JWKji(l{q8K(j2p!=z) z-oN9ru0E{{Ty&T=CE%Tvh@eC+4|IiW6W7UR05K*_9CF}9L@(Hq*hfZMNNp?$k06at z**X!U+^;p|%v_XmxR(@ymjE};seU*5V8Ssoa8;Y{X@vd8wS^-mNbfWt@f9NS7{2Q$niV(i8cS%M#S% z+#_SU^3b4Fo}fW8tyJm?BM_o0e6p@m#!(o&ibSP`vsiPPz`^w}*aZ5Q;YgPKeH6zx zXcE5`2dfx23X;sl4=6yChpR%$+1ntn^lU96;enThiN)NQz`VB=a6=1kW60G@E0RJt zOPhX37fjqcwX%i11luPsK`v@>Z%#*^=uQj=@1-EFBP{`8q@4;NTA;ltc2KQ#^qv` zEH83}i`t$(9xKgWS%|OG(b@>o<&7117G=)^Q5Qcn>t*C2%5?%>Nn=~dawJ9q*Drbv zsS~ALjmnCbPQ~$(lwdOASeJ1V2lkW1q%4{cd|FObfl4|VDXSXxYT-t6Jr%``rV*;r zU^bzkE)K7Ws3d6+1%Zw$LM#E>Ju{B1?l8`{i~?)yG>%KN6w5*!nnxRe7vABb7-#JY zZ@UQfsrRakodhAlxt6@8keN=KomqSu>=EaEBjQu&3pH6Ay`SxJ0zx zyLiGDGzHd)>`C#Y^kXZYZiQ0jJ2e%*IWYhfoHKgAVHSJ+TN6(z|3Ze_d)yyH^MmR3;!*=@+%K zs|e4{Do-s)%ScrLS5MYsiIk=(vpX8HnI21`6s0N6E}=P=gf^A;u(C5~Z|li>k_NyO zy-hGvA6e9)VH^;%JelQXskFp9G0y2kY4X<%+BeD4mA#kDFzz~A;q#9uO)4(-Xob$0>|FnI%qeg*M6jibtlrTb%R09nk* zE}z{{CMBX9Kn5)g%mWy(d`*w#nW7Vt`&bcKcA5(da+$*t635g{PivbZxyjaO6qk_U z6-ONmy1XVV8kh+pHj)G*0q)ck&$Myoj~7j$5~bf*lSm@Yxp?5OMg-nPjy9_Br+W|i z#tRkPZfFd4qlZ!lOU6i1)mHry3n*RmuJ8P^RBbRWM10BILXK4XY}5 zErn7}r?la1dAMpxqwQHqtpBT&UzGqp)eyKjAw9x@Nh1&3aK0f?o~{8EY(%ITTtu;> z!orzxBVG8605UxPjc7&V_VC`(13F2U@q?jvIck%N{J0>Cx%=zz?QZ#2BivX zK%@xBWx2yBgAn~iMWHvDrk)cR$%ZbA(Rj>|;d#^2h4{u_W-`=lv$TU&X_ z!#J?x1{4cVc5bL+-s3VwkU&0V&L*3bAtjV>)mAFrvOzW?%*~&yMG#4IKaM5}tuZ)S z_-+)v`gX)S>2;~DwK5C>MOlX1)Zr;!;+76w_lQ~cmc0HK;ZGMit1!}%zgQ|0iqdcvTc%rHs9QU5zmbm$BXo$!kj6#S!u8lS{{>uUpmR4 zT1bRNpcWYSF%V!_S$c0hi&?@+Xgo2tF`7y;BC1$CgF^%g%z++Is~Yc|%C%w{MU0wf zq~MUf)dSF1&k?1Jv2H2TTWTQL{97$c?qtLvV{lSYfk?45C{qh(cKm{Ym|^(AD=ECW zrQZs%QEMRE94r|)cQ(ZUV5t-<+lh4Y1%((6YVf)n(OL)@m;-QgksF$o2H|}v@(yX$ z4Ao(_JG6{6?i{m|?U?`1)L$1@xyddpX<0=*0rLvllwTJ6Rr4rl(tcf3BsCMI?(bMI zOQej^^$C<6cr5^nj4D{&Ug2v_ zm`A1tb}!AX*lM<#m-}%x(j3KoUA_^aapR*EO(hNCJcX~+sOd4{q1>eOLM@$qecR@Tf0ckst*}!gp=zuyCOX$dQFx}1LWeX~GyH0!SQ3Pb zRPkENya5dD0ILP0^W}eM>eQ+^lg5n?CBt~_p9%PSLK7zUl2BtuH*PYTRDGd@#)L<8 z3a)T59B3NyCaSmGrV~PVV<3s$Dtv398Plq!;UXJvjyn=>3oit->|&%zIB!oUVKne1 znI*99VfM|3EC}eF?8OvuSz|{-RBu4z+etX0CV%B~SDskGzQb0W-_;2Bgj%Gtwj)gG z%1(j6@FiB11rr5K zacm8*tQ@jQRb)vv<^{fvgO}>#PF>Qei#la3P8sg%%1W*4Grtso86mr8_(j@6D1~Dm zx_%+3Jl2cidtJO64#zXJKA4R!^VornI!%q7gZ5sic-oBgsvlATWq=5{9PfnMnsK*~ zUw?pW2}6SqCr}vVlBj))#e%S?U?6+B5Doa^(pYf3K}iJFh;V1_;BArwrYUY1;iN(& z8*jklR01ZsP+$;;^!p4{K=K-k*8=RG4t#S#sWGKQxA9Y8=^RmAzerlh!D>Sp9y6Nx zEU-~lru{Z-4uu6`D24F$dMj>w(`X9e{yBV5CSC7ADA1sQ*~j3t2=gWRKhnH%SXwbj zrJNMQ>0X3ZcvjWSBvX@jtg%bsE%Rt=6K0B`onj7wBI$U43rmJf1tl)h(%HVqnNf$& znv~7K%ibED!#B8@#uvZK@h<1=x+;7ZZN?P7+iA*4Tnb7IZ-LiTOmh}ybWeGinE)}w zJ!Hr+h>YTBPfIKL8Kq5vEiJsatAubr4dBBX{2~r-XJ7>N8)^bzMnF6{C*_MKa+eNU zE}gV20YDIo3#FX~J46SqU!B4)Y@QqX4L0}gnvI8;|#HnqYNJA99h)~?us?0^CJ{SOalheOTD)@Iq7 zEWPlwcQ{x-xWpiaHN(VYk)sMy?PI>elacUiJ;;=79hlZ9jb=U0OfidRnrt3p!knW5 z)HRkdQ;JbT3Zt_8*hOBZIu>$MOF+JmW~!RL%F#Hqnwj}C@Ur>r`cVCpYQE#vE^Z6h zJ2rbRzQ%)h$YxZ|oi3$J{nDw?s!Iy{^uXRbW;{ePvB~dbF_oh}KoD0SG)b zqRZ>PCYd_^B360%b|yFQ++#vma17NhH$wT;*PA6t_RLI^ zy(lB{4M04Z18iQF`AnmhlxFzuwAT*o*(`$4v?k%YJU;^2LW3T5EM9*WOybaOAxV5E zRnz2JkJHY!TU+tg3I59mlX!1MKfQ!r#&OuPXuQ39nofvD8k1ppi&?+T^UE958s_w6E=#VBiahTm&7;@<{c&IEm%+3?Mnvs&KVGNb_PU&*F!&+2k-RLhjhY? zX>N<-YpJj|DZgT4K=m~^NQMGR!9~NZCSHwk^h@QIDtQ`s6D!N4F!MMh+NFA64xXkp{kH*e+O&7c@| z44v%`U%P`55A!5VB)*8q>Uw#~Nx-232)9bPsv_PFwFNsu-ttjvqz6aQtU%L{-R#k& zj2N|Bcxw?KHDy&uUuZmD3KRfu4*8(o2+r7X4XF_>Uy40k zC9KZ97vvFdgX80jp;UKANQpEkWHj;ZFnlIQit`v#st5wGT2gIc*&jRIP6SSV!x=f} z%>;xnAsqfKT*YD@ZUN!u5N}B|$SHk$#m3l=nF zWR#!?7Ab8!W>zdRC?-n(mo%MC4cm=y@-5b>W23Z&v6JIR!5}m3&SFI3&SE&~7Q-}_ zhU7e3v8QY`U=yo^EejDM_{vyv6)~qv=M|$kan<2x36#fMyCle~j77h<#!H~Hu^HgU;5NWPoN$IE~|-MyiQO>r%YjuTK?p!z--utl5qu0U$Mr<8Aefw4(o!hNVZVH{$Iv zOtui_98C+n1e!)xWD6z6JBe`)SQ}c5kb>e$jms<;kBxWQK`-fvEYZnk2_oq!(*-=) z1v527Rx#1kLBlDdYRpa^5QJ4l%F6_k7Sn2}LFXq?8Cs6j=@G6DJ0H3?ELDhAt- z%DS>j7hehQhaW%wh86x6qWoi;>)?as`1dpZA8i#*c03RlobbJrq8H_Ll z0pB@yMj`|df(ZPR0<3!gp8RC_p$LZ|;4e@}I{t`(Q-m-9q1dFc{3OJWLO2G2f8wJQ zp#q@_VFtoXgjoo+2>jzytTPW!{5f3*e_Fvg9U+X+gwTwz2%#0B4WS(&h0ue*dQ0&< z6JZ&`*$C$$oR7df{<{G23lT0dX_uJiWq9%r<6MDo6~fgB*C1Sn@LPo6A+Y{Uc&p&VClQ`Tcn0BFgy#`nM0f?^H3YWv z2A*#syoK;K!n+9D5k5rt2;pA{pCNpX!17<=`5%OD5PoDD0tVd4LC8hugTQk6cv3bB z5C$Ol5c~*xBMd{}-$EIQurC73+kXcDJ`mwB1pblW@d*3_l@k#rA(SBSkLDhSP=+uS zp&Vfv!gK@*Wfg+OHxuz$2sI|{L_F&d>JjE6oQ`k?LI`020_#QaY&3EHHIRh}ix657 z+7b9Cf%wOAIuZDnrn(W%L|BHWz|Cr})JikNu z-oQWL`4fTzC6I^E2ca**K!iesiUng!_uT)Z3oicK4R^or)8Yp&T=kb1@4v9SlnW9)<+huV409QSBoQ4^RH?x6ilb zt@_WvWp|IC^xE(J?K3)JAO5^@?83sWZ=d_%l_>vxFm>?w`>Hx#_+!a_f7^ckwfk;r z{`R<6+yC04WVNbVcM-@f3@u^;UDY~#HR+rB+#QRTeqFB^v6 zwCS#o_CNdJcXw}H5;*AeWfxy|#pbgX-?k-o@*l^n_{VKW{uDpz^c~+G^w|f8eqX$J z#0TGh`r+WMFFftO^Vs`O?03(W=<@Jk2i?)|+~0D}{_OcfT3(8sv-_d9ZoIU#`Q@gr zkzak+GVF}&+b%u#+r0fxI)BH{cYJ+h)fZ=782e`4b0x1mHR7%r3-A1FZcbvy1rx`7 zzjLqO5Ah#*>pc?}z1Lm7@ya8Yyjwi`yI1Po*m~o>-yL_|8N;I!o;BrLJG+TlcqozJAA9 z)vIzp?V0_^vo8(b{?I+=ZO;ED^4`^ZTz2}`%QvpT})52v_YyY$UgZ<`x{8eNA%Lo6|u#&2hPcVdg#t)F1}*T4Y|*ad}Q<6T{V}?SpE3&o9>zM?0;Wt`Y6z6Q^A+l4IA{+ ztBHL_ca$$}+&#eA`O=PYeHY*R@4Y4rd}3VU#Um&G_3C%-?p?Ca19zX&dBl=2C%wL~ z@cV<0`=Z}LzxiP0Z|(|Lg>E|UnR$nt@So#9+VJPsC-w9@=*EqwU3-1lc`11D!^=M} zeEZ?+@4NWb5mm2OhT8tHD%$+qC%IRRykz<@eV&=SyM9Mx=cE6)s{hzaBAX`O`J22q z?wNVU8y8p2{vmkjUdx)F4;8&|#BqCF{CUfT8<#IQaP`+Wf3ohWS3bD)xxQ}?{`a@F zr`$aE##67Uo_EP7V}D-$-R1M{3jV!#%aXfy?q7G+q$`iPaO{hB?>u*2Uvx-4U&ddEr z)&7&u9rIG^=I53@`rOu*_s8U)`}z3~|9j@mPxbF}z<*2nUVA~uG5a6&=(FLoPTY3- z7h~NGPhNWZoJr01biJDDJMY{_`?)8b_4r#4uHSL?>nn24+jP^i>;CZbpLe(Y_Oq*N z-!Hw>9sY9LnsCF)Za(?Ni)OX_uzky2 z`+s)p=CMm|`?z7-UnX32%fDYfqx7}fJ?ds(bJh`mdj9rZ`}uc&{;!Xpdj9%b*8l6t zfB&sGam$-GKJ;Wo!Bg#rAM|3*S4rQW7GAmRsrkjvz5LmnFOR(VtDMMNp?80Ke#=Yk z_dj&Xmp}jchYR`-`>N)-18y7eN!hz!6m`FN(Z?UWyP^4$yx4&~ugrP)^^YF?d9T~g zzxni+ZqEDZl3V^b`VY~QdIqe1Y2B<1uif+5?@#S0+2`R~_v*TCG=An0eL6?lp66 z&F;6jNd@m4RkL>KmRt7yIBqw$AT#hki&dw8iDV}`ArZP4tDjPlOPIr=7b%=g`UqIwN4o=~QE-;!=l zyPn2$Eql`QQ>8(x?=Rn)VEZ~GrDUtVvp$Y;_%ktU3D$n;z**NyPmBJdw_HA)JGOm; zfe&o0Mh?hG>Q!Oi?2bMQ?GDy{w7J#5ntOe}U)dPw5bxb+!i$Xy&IKRMPpK4MIJIM1 zrEA`0eEx0ewpDNLp>Z`O4Ql%S>fNk9#SUFsty}B5e$SMmb&k$#l6bm&-9sH`HTL}3 z{jc=C^E119WL9?yyBB-rTUfL8*^7KedPF-qIre=w&eGIp)R#uP^`)OpJ6+*>XYYj{ zT7{+eJ=!n-&)j^EaR+tAU1jt4dtU2uD6+(+zS)-1lUG%0G&aoF1Pz zGtZr0@wQUmY=_p`{X0_4W8V(EzCU_#do4ZtQtJ8fAn8IT8_f=|F6FC6fX=c&AaKL`bpAO<9YnP4f%0Qvuz(z31vXF!)U{C_Xn_vsK?E=WBS-}%UKS24DoKzy!>|0&;*A*gzpr`=C6~0v*tU2w(t4kP1w|3@jiASb+@`0(D)K2U?&5 zdJq8&zz9--37CNe+fc~*f12BSAU;<`f0Xe`5Y@iUR>!Uo-0v*tU2w(tsMW{*zCSV2@kOQp11`2_? z0m=g{&;dP&0C@SS!fQrVDlh>vuz(z31vXF!)Oe|;0b0-kbO2ER-*ZQEl|fEJ(whyuewGDrg} zK_)m1a=~p-0KNf7Ka>YPpatjvqQG#F4AQ_#kO>ZhTyPr{fN$UnD5Ao9ro;FT(vV=* z&3>>B@69@@2YI0m(ZlIQ5|Wp**l~_iifhK&JCF5&7OaolXT1#jok}JTXT7!*>yx;T zQ0jy=LH70Oid20@K54rStpCOj(pHwL9XJC>myP9&Ev;B@q<;k#NrM>E)vIlaRNX?% zNc&~8{wnR&TE;rtp6#d0vUYH19nzI`t4P*M=*1h-gG#LN+jk|=-XKe{g{-TJf6+GV zf3_FfUFn4!(q0*#HH`fq>Dj*7mF=F=zfpg(J<^@+CBj*6QnTJvg7s9HpNBGEW$f6# zp*Y(|yRzPkvx8EnAl7m36{+&Ynx>YIZ)6>h`y1&r^qW#%57vLT;QqOx9=a+qSuv}& z$oO8-OGl*NTe98H#`ao)Qr}C~)tj=Oc8PV2jQ50z^*+RvYP$UoYd<_Mk)DNhMrpp- z7hYf;fir>Zc#?JfVAh?# zuy&R4zUV-;s#MFhZ1)<#_Kgz%6Th(@Df{8jJ=R-9_r1@05$>l{Q{5QW#bo{1(F=@5_zluD8>Et2;%zg7qY!P?s;UnGmSNUo*=y#^-@|P z{T*Rsy;s(Yc_Qo0h#UD=#Xh0*w7KXztY^ykGp-o7KcWHK^=sLlCF{W^>w%tU$g@u@ z+b=_qehoiLQ3wd>_(1xvN_AQ0dxXq)7y?C>{)viNm9A!;Cg*{(o^_eBT;3^&^*o8k z8aaRdX~*ULC4NWg7a2%S(!UoY+1|Jsmv`&P`m*e|d#hOQ7Q0Jl*5B~?f@*SW%X&~1 z)^{DC9q-KgB-)|$O!~J$;)n8edj`OTh6wL|v%=+j)jpTxsblH+j*KjOt>(UWSyIVJJ!y^`&NrM(Q9Z*Msd_cdkv8yQb+Igg@c zzkHv^_ALCMnq|AHPTRA-Blo-6a{jy>!v1e%epYN{9p%gZkJDLCko!UL=G@PA==)Qh%20pLVi7rpx-6Dd$^T%oC-2PcGlJA8VV8w;cU44rvhLPFH_l zR-|f_oUcVIvYykL?N^-G-%Zwsy{wPZSQlieg?XTKQQ~ikVVxrTe^?NgA1CYKz1-hI z`f&NQD7JS+yL5FGew5PW{PLFb>xaQ{kO<@(m#x~M%Huj?(FX@{c%cWd$zO8qURex2MeTxTfm zsu!~U7cFHyPv+y8>`xEb-vhDED3urgrhl?_Y{~6!lK5xH`Y12=tN%RMz8>SI)L+gA z{qL;p0@!}_DeFhISo@A-oh9|hJ!ZW*knK(1u#WO#-E1^#o6JvzUL23563>S6{G1WY z{-2dqg?~z2>aX&U%RdZa`?OE2?WMgkFIm59!uEz|SnrT{m0QKSzXRK^R$zTq;#FVb zyI9t1jr(k`ChIL=FY9DkZ$st&by3cf>jT){M%sUVg7r`t-y1cL_Xp;gu6Ax<`y#17 ze?RMOm`Ac#m-Eb5&a*pNY@dK1ML~Zsr9A$FG*#}oOUiK@_?N?!I@-&gT`Fhbw$1GS zS?1u1%)wacV=Z}xSR!lqY;*RXDQAqooH2GXhApev-donR_Y~H{M5l;8Eo&U#1yfS4 zoJq59vi>P+U ze31uD{FMHVk^Z*Ay@-0AD$iK{vIZZA@OW0q8qD0o{X2_nviysTxY3#uw<%y5@QIPm}$-doAlLh$Hz|*RcL3@sE~gx>+u4FOGWyrNJ_v zu{gUZg~@)mOlEB-@tnDhby^iJpAf`)v&_e&0j#r{u{|q~by;aYQ9gqSt*`F>=Sznd&XkB0Se<%0Q#F4DS>T-QcXRx+c<2@lR z*I{1%cEoq7Fs{1g*fvCBQ%#;%m!b)3C0_QTM#i!xf&E(svAy$q*168Cx4N@V2xdLy z2WvVrslHr^O?pe#yC1QAm&7)lz8HqIPtFpJoUNDT>}-X4C>6+B^;^w)w!~(#Jij}( z=K3GVS#(=sxlleY%@ch=_R?@vLoJ7Jb*jCUSUWf23~N)?Gp($9$=+OYk9Au)yM5&B zekJt>(3jPa=9b{{OUkqV51FehnX8X7m&^OHJxQKlAH}gghaXhabC#-}a+X}yaQ(Ao z?KGuB2q`y^{m;E&og)43c!hQQ%51;TjP-<4tdp<@D18$9%>dS;`mp_SG`FXb_-|dt z_V8bOTRwmOA!|KJ&I+sS-Ta;Gf5nySJA-~xdMtaP<`&jBWp5QpVSN^7G_^ec*8~Nz zb}MB2H}sS2i3P0dV;rR4$=M$$CeOEtb0iOOwU+%k^Zd-Wjz)3 zQ2*+5VqJiFBi(HwYj@dyFZ_ADjbwe=7l7`TV^` z#(P1=drSQP5`TwM?7sx_KxtA<)~AQCo+jtR%X_TdWIn?;vi>RkU+2Q{@{s*?yf^Ew zavlzB&3b{v@7!oEua*7=&=+Kp3WB-)hw}M%t<2A;1?;~|=6~5#)=@IQ>UON@8IEe& zxr=oRSr1{q)`P_3NJqA3da{3h6zdEbU&##CL6`@sZ+JTEwM|*?zry;W?7ulrSUXC6 z*Lt&dkol`C^Vd}3AB%oa(o4K|4rX0i#xqFvdmVpn?-(7NNIF>`9$5F3YDjyLh&v^{ ztk-ZkPmkJh`C|5LA0l=a`7D$Y$o7QSY`-J+2>E@7gY>td^mlD@_V0X~{iEc(*e;*n zM#}t78O`=Say|xN-YD&s`RM$Db$Au7Z!h{m>ACcGjP&=IoCl}YvE8l~`?nv;`X}N_ z^YZ|4qBLFFOTaS&r7W4RB67c*=+6F!!WFZsng?rB1nWaG-ziI2Pm*U3-~0S4Cj#khP^C)RIUv(6~Zw_UJqqiCk{4n_{ViKgk*cP$k7ti!9nzZZgB-{Uzn_--q?>%krtgB0MUV5EQVY@6 zt*ocXI#J6yagg}i{mJ$ZGQQZStPgr~eNT+6={o{ce{+dnW3ita!*-3VlhBu}oiJ|l zZzcDkNLeRCx3m4F%x87vQ}UDhjPG35BV=7pUcq{*?8`mg>M9RT_F`^{W^tWL2HzL1$FjdOmNnwd92}4zU?C@7&#qif*#l@eDc7W_u9!H4kH$WjF zO>H;F;Fh9&)#3PycV@#|}^LwQlMA`YAI@{^!tm`0!mxSKG%w`&x8ycbCYS$wRl~ z_m8Xgb=<+Fdq!U?o4ff|)xvE)em_TlEPkPt@y4|y=jgk~jhc5{<@@rj^SVW4swWP8 zy7^0q;Ai;{U89l?Puoi0l}>+qsq%!NA=7$S3P14lb-Oi@UwY?$T>s-isp2KoK1Uza zos?95TxgrT1AD)ul;3zS;CtTZ$mHpN>=^&5wI!|V(ck8ln&f|Q=u_jHB~GnM)pQT? z+*GR|E4X>j=22PUy^pN-_ufC?+RoSBWqjQ$7tCMR#%aXO^X8&IOUK#wecH`sQn!YU z2hMre?O&H;hqjNu_I2&%^Pg{DefV`p?eU{E^Is%pdB;1fALr%#@292B{~EWbZ|!HH zYtFUa7jg6CzSs-tEp~ryGW6zwMed!~5kIEi>S|+kwR2Jzn*w zS$)Ff+NG|&?p^vwvftN{Z%;P9`k%gFbTRBDuo`58T<{+#hRsq1Gy-8@07wM$K^8az z?tu@$37g6ngn+)l2o{6wAP3w6Z$Sxrd~O4+Krb*F&^yl6fW9Y`3m$?mzy+I>?rDKw z07wMOK^8az?tu@$$pPOr1Io=w+yq}iRUAk<&>jo~sbB>-0<7QzaK-uS3%Y_hFdJlo6X0L)2H4{auLgoaBp3yz zgA8yCTn8_Kx(v<;&=9l(!@v{}fVk25n^{3Q7oA=7qoGu1aYj=1OD_x`r{`E-I%HK3 zsE7(DsrTF}+bH{nWP2hT1^3v#Z>H=%IFyUxXBW&NveVx@tT@Y{c+e$zOl!l< zysoU&mtqJwPTA)=advziCA)>;br5Cyi1&<2O7?`-m%mc>d@N<^Ykf=?nyI$+<2=d^ z6mJW>F}OX+Pn6qyZJfm9y`rJglOxyXT_JDxuAKe6o|0WKCZIEA8)OK5Fa*S5Q_mt9 zCJaF?$z!YZ^*8htt*f5Y+fCV75|Vp7;4AetSn&8&bvQTEwt?b(r`)jw%69F-*-h#y z*`Kcz>rdHZF(L|J{mRP77F5W7-2#`0JYAB<>vml5b`2#Yky!zLl>HFhra|t+?7}I{_EgDh%mchHPJ4&vYn5u8OkX9QK7FwvLn-?k zdPJRCh{Fe+Dl#A^aRJ_C%O!d2$C#)-S8is|^A>w3yL1`O-dIC8~hzu=Le}69kpC)jd!uSprEt z3CE&Fc6x&?%E(H}-s*$phwP1RZuHck(n)wWald^BPyRsJl_fhB+3=oytp8Zb{!?Z+ zTdQQ3S?BnXvYk*THCfA>!;>&(0%fbQO(|+C5j8B*)N6g(uRzq~k~{_hDo9;Hwr0(C z1Flp9aDGw2wN;e*#=561Qhk zwu@ws<25zoYj0&uY1?uov)z@&v#{sn7v!BH%eV$wLb$y@IuE1l3*Fe;lPgL3_I@5^ z@56*rPh9ylKEFB8K-s@OJwD(Wep%I_5oK4AI6T04hj`ZNaCf5*4imW~j}lQ_-(4WA|^DI^tTeYoY6RV#(q8z>5@D? zA)7+t!n-fFU&;r{ek7~=IakI7JF*Js+{yTH_zwS!7D;^%dkh1e+?e^f|bntdu zLfJQ@-}U$?`x5d3#qs~BkWspDFn^C5qC6&ilzx|SQ$~4m#!FA~c90J4<_;D;L4S&a z2OFu|i5KaeyKnO-J70Q|$vv6Vb@w>Rc9ykfMqm-a<>ikm$It{B&b?~NaF$n_qtxvx z+oc0^5?2>_dcLX)r1N2xV80vn-3x2cLj4dc|AK zi=ZK&4~Bx-_6@nObV(k=_7POS17}F)>p4&`vaHopi3&Kk*cpF#_*Wg z)e!E%>yIwUP%iBG_~C$A2q>~nIIEU2yY zb@Eq-XNos^M9r+UQ<~{{V|=o%98{Qu={?6Il2|WtAPmFqME3T@$;x_hk)3~*cmBgpCl`_TK^ekv9>SaQPpKtU z|6<(a_L53p+f8@HjN@fKDx@Jecq`cr?mHa(2lI}g(It7DkiLF|C;B?jMeR@7Cdod) a*{A Date: Thu, 15 Jun 2017 09:47:49 +0300 Subject: [PATCH 1384/2705] Test --- iguana/userpass | 1 - 1 file changed, 1 deletion(-) delete mode 100644 iguana/userpass diff --git a/iguana/userpass b/iguana/userpass deleted file mode 100644 index 058af4d52..000000000 --- a/iguana/userpass +++ /dev/null @@ -1 +0,0 @@ -export userpass="c3d8c2a364b7d18c1f9d7321d017b92e9f9c791e4f5c741214fefdea8a071256" From 8a9897e608f0ca389c616fdc9401198d33032499 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 09:48:37 +0300 Subject: [PATCH 1385/2705] Test --- .../Contents/Resources/DWARF/marketmaker | Bin 339918 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 iguana/marketmaker.dSYM/Contents/Resources/DWARF/marketmaker diff --git a/iguana/marketmaker.dSYM/Contents/Resources/DWARF/marketmaker b/iguana/marketmaker.dSYM/Contents/Resources/DWARF/marketmaker deleted file mode 100644 index 20c28fdf236fd57192d613a639e18656b299cb21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339918 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 Uw=OK@5b0b;*9k= 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 @dW@&@ZqN|^)*;6rg$gP_@g<2D_>WXQS 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 a*{A Date: Thu, 15 Jun 2017 11:53:44 +0300 Subject: [PATCH 1386/2705] Test --- iguana/exchanges/LP_commands.c | 42 ++++----- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 153 ++++++++++++-------------------- iguana/exchanges/LP_peers.c | 2 +- iguana/exchanges/LP_prices.c | 146 +++++++++++++++++++++++------- iguana/exchanges/LP_rpc.c | 8 ++ iguana/exchanges/LP_utxos.c | 10 +-- 7 files changed, 207 insertions(+), 156 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 550852f3e..297ea0219 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -167,8 +167,8 @@ char *LP_connected(cJSON *argjson) // alice int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel,*retstr; cJSON *retjson; double price; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; - if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 || strcmp(method,"price") == 0 || strcmp(method,"connect") == 0) ) + char *method,*base,*rel,*retstr; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; + if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) { retval = 1; txid = jbits256(argjson,"txid"); @@ -183,12 +183,12 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d } if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) utxo->T.swappending = 0; - if ( strcmp(method,"price") == 0 || strcmp(method,"request") == 0 ) // bob + if ( strcmp(method,"request") == 0 ) // bob { retval = 1; if ( LP_isavailable(utxo) > 0 ) { - if ( (price= LP_price(base,rel)) > SMALLVAL ) + if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) { price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) @@ -198,20 +198,15 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d printf("not eligible\n"); return(-1); } - if ( strcmp(method,"price") == 0 ) - Q.timestamp = (uint32_t)time(NULL); + Q.timestamp = (uint32_t)time(NULL); retjson = LP_quotejson(&Q); utxo->S.otherpubkey = jbits256(argjson,"desthash"); - if ( strcmp(method,"request") == 0 ) - { - retval |= 2; - LP_unavailableset(utxo,jbits256(argjson,"desthash")); - jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); - jaddnum(retjson,"pending",utxo->T.swappending); - jaddbits256(retjson,"desthash",utxo->S.otherpubkey); - jaddstr(retjson,"method","reserved"); - } - else jaddstr(retjson,"method","quote"); + retval |= 2; + LP_unavailableset(utxo,jbits256(argjson,"desthash")); + jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); + jaddnum(retjson,"pending",utxo->T.swappending); + jaddbits256(retjson,"desthash",utxo->S.otherpubkey); + jaddstr(retjson,"method","reserved"); retstr = jprint(retjson,1); if ( pubsock >= 0 ) LP_send(pubsock,retstr,1); @@ -264,6 +259,7 @@ getutxos()\n\ getutxos(coin, lastn)\n\ orderbook(base, rel)\n\ getprice(base, rel)\n\ +getprices(base, rel)\n\ register(pubkey,pushaddr)\n\ lookup(pubkey)\n\ forward(pubkey,method2,)\n\ @@ -271,6 +267,8 @@ forward(pubkey,method2=publish,)\n\ forwardhex(pubkey,hex)\n\ \"}")); //printf("CMD.(%s)\n",jprint(argjson,0)); + base = jstr(argjson,"base"); + rel = jstr(argjson,"rel"); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) { if ( USERPASS_COUNTER == 0 ) @@ -284,7 +282,7 @@ forwardhex(pubkey,hex)\n\ } if ( (userpass= jstr(argjson,"userpass")) == 0 || strcmp(userpass,USERPASS) != 0 ) return(clonestr("{\"error\":\"authentication error\"}")); - if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) + if ( base != 0 && rel != 0 ) { double price; if ( LP_isdisabled(base,rel) != 0 ) @@ -367,7 +365,7 @@ forwardhex(pubkey,hex)\n\ else return(basilisk_swaplist()); } } - if ( LP_isdisabled(jstr(argjson,"base"),jstr(argjson,"base")) != 0 ) + if ( LP_isdisabled(base,rel) != 0 ) return(clonestr("{\"error\":\"at least one of coins disabled\"}")); if ( LP_isdisabled(jstr(argjson,"coin"),0) != 0 ) return(clonestr("{\"error\":\"coin is disabled\"}")); @@ -392,7 +390,7 @@ forwardhex(pubkey,hex)\n\ } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); } } - if ( strcmp(method,"quote") == 0 || strcmp(method,"reserved") == 0 ) + if ( strcmp(method,"reserved") == 0 ) retstr = LP_quotereceived(argjson); else if ( strcmp(method,"connected") == 0 ) retstr = LP_connected(argjson); @@ -405,9 +403,11 @@ forwardhex(pubkey,hex)\n\ else if ( strcmp(method,"broadcast") == 0 ) retstr = LP_broadcasted(argjson); else if ( strcmp(method,"getprice") == 0 ) - retstr = LP_pricestr(jstr(argjson,"base"),jstr(argjson,"rel"),0.); + retstr = LP_pricestr(base,rel,0.); + else if ( strcmp(method,"getprices") == 0 ) + retstr = LP_prices(); else if ( strcmp(method,"orderbook") == 0 ) - retstr = LP_orderbook(jstr(argjson,"base"),jstr(argjson,"rel")); + retstr = LP_orderbook(base,rel); else if ( strcmp(method,"forward") == 0 ) { cJSON *reqjson; diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index c50c03ecb..87fe57170 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -177,7 +177,7 @@ struct LP_peerinfo UT_hash_handle hh; uint64_t ip_port; double profitmargin; - uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected,lastutxos,lastpeers; + uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected,lastutxos,lastpeers,diduquery; int32_t pushsock,subsock; uint16_t port; char ipaddr[64]; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fbc4e3ccd..122f9512f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -190,9 +190,9 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma } } -void LP_utxo_updates(int32_t pubsock,char *passphrase,double profitmargin) +void LP_myutxo_updates(int32_t pubsock,char *passphrase,double profitmargin) { - //LP_utxopurge(0); + //LP_utxopurge(0); not good to disrupt existing pointers LP_privkey_updates(pubsock,passphrase); } @@ -212,9 +212,60 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso } //else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); } +int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) +{ + static uint32_t counter,lastforward,numpeers; + struct LP_utxoinfo *utxo,*utmp; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t n,nonz = 0; + now = (uint32_t)time(NULL); + //printf("start peers updates\n"); + n = 0; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + //printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); + if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) + { + peer->lastpeers = now; + if ( peer->numpeers != numpeers ) + printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,numpeers); + if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) + LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); + } + nonz += LP_subsock_check(peer); + if ( peer->diduquery == 0 ) + { + LP_peer_utxosquery(LP_mypeer,myport,pubsock,peer,now,profitmargin,60); + LP_peer_pricesquery(peer->ipaddr,peer->port); + peer->diduquery = now; + } + } + numpeers = n; + if ( lastforward < now-3600 ) + { + LP_forwarding_register(LP_mypubkey,pushaddr,10); + lastforward = now; + } + if ( (counter % 600) == 0 ) + LP_myutxo_updates(pubsock,passphrase,profitmargin); + if ( (counter % 600) == 0 ) + { + HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) + { + LP_utxo_spentcheck(pubsock,utxo,profitmargin); + } + HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp) + { + LP_utxo_spentcheck(pubsock,utxo,profitmargin); + } + } + if ( pullsock >= 0 ) + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); + counter++; + return(nonz); +} + void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) { - char *retstr; uint8_t r; int32_t i,n,j,counter=0,nonz; struct LP_peerinfo *peer,*tmp; uint32_t now,lastforward = 0; cJSON *item; struct LP_utxoinfo *utxo,*utmp; + char *retstr; uint8_t r; int32_t i,n,j; cJSON *item; if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); @@ -258,103 +309,13 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in LP_priceinfoadd(jstr(item,"coin")); } } - printf("update utxos\n"); LP_privkey_updates(pubsock,passphrase); - printf("update swaps\n"); if ( (retstr= basilisk_swaplist()) != 0 ) free(retstr); - printf("update peers\n"); - printf("mainloop pushaddr.(%s)\n",pushaddr); - if ( IAMLP == 0 ) + while ( 1 ) { - while ( 1 ) - { - now = (uint32_t)time(NULL); - if ( lastforward < now-3600 ) - { - //printf("LP_forwarding_register\n"); - LP_forwarding_register(LP_mypubkey,pushaddr,10); - //printf("done LP_forwarding_register\n"); - lastforward = now; - } - nonz = n = 0; - if ( (counter % 6000) == 0 ) - { - //printf("LP_utxo_updates\n"); - LP_utxo_updates(pubsock,passphrase,profitmargin); - } - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - nonz += LP_subsock_check(peer); - LP_peer_utxosquery(LP_mypeer,myport,pubsock,peer,now,profitmargin,600); - } - if ( pullsock >= 0 ) - { - if ( (n= LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin)) > 0 ) - { - nonz += n; - lastforward = now; - } - } - if ( nonz == 0 ) - usleep(200000); - counter++; - } - } - else - { - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - if ( strcmp(peer->ipaddr,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1") != 0 ) - { - //printf("query utxo from %s\n",peer->ipaddr); - LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",100,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); - } - } - while ( 1 ) - { - nonz = 0; - if ( (counter % 600) == 0 ) - LP_utxo_updates(pubsock,passphrase,profitmargin); - now = (uint32_t)time(NULL); - if ( lastforward < now-3600 ) - { - LP_forwarding_register(LP_mypubkey,pushaddr,10); - lastforward = now; - } - //printf("start peers updates\n"); - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - //printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); - if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != mypeer->numpeers || (rand() % 10000) == 0) ) - { - peer->lastpeers = now; - if ( peer->numpeers != mypeer->numpeers ) - printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,mypeer->numpeers); - if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) - LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,mypeer->ipaddr,myport,profitmargin); - } - nonz += LP_subsock_check(peer); - LP_peer_utxosquery(LP_mypeer,myport,pubsock,peer,now,profitmargin,60); - } - if ( (counter % 100) == 0 ) - { - HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) - { - LP_utxo_spentcheck(pubsock,utxo,profitmargin); - } - HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp) - { - LP_utxo_spentcheck(pubsock,utxo,profitmargin); - } - } - if ( pullsock >= 0 ) - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); - if ( nonz == 0 ) - usleep(100000); - counter++; - //printf("nonz.%d in mainloop\n",nonz); - } + if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,pullsock,myport,passphrase,profitmargin) == 0 ) + usleep(100000); } } diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index af64c161e..b6dc4b1db 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -57,7 +57,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char { if ( (peer= LP_peerfind(ipbits,port)) != 0 ) { - if ( peer->profitmargin == 0. ) + if ( profitmargin != 0. ) peer->profitmargin = profitmargin; if ( numpeers > peer->numpeers ) peer->numpeers = numpeers; diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index aebff6fb8..bd771857e 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -46,8 +46,38 @@ struct LP_pubkeyinfo UT_hash_handle hh; bits256 pubkey; double matrix[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS]; + uint32_t timestamp; } *LP_pubkeyinfos; +struct LP_priceinfo *LP_priceinfofind(char *symbol) +{ + int32_t i; struct LP_priceinfo *pp; uint64_t coinbits; + if ( LP_numpriceinfos > 0 ) + { + coinbits = stringbits(symbol); + pp = LP_priceinfos; + for (i=0; icoinbits == coinbits ) + return(pp); + } + return(0); +} + +struct LP_priceinfo *LP_priceinfoptr(int32_t *indp,char *base,char *rel) +{ + struct LP_priceinfo *basepp,*relpp; + if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + { + *indp = relpp->ind; + return(basepp); + } + else + { + *indp = -1; + return(0); + } +} + int32_t LP_cachekey(uint8_t *key,char *base,char *rel,bits256 txid,int32_t vout) { uint64_t basebits,relbits; int32_t offset = 0; @@ -104,52 +134,102 @@ struct LP_pubkeyinfo *LP_pubkeyadd(bits256 pubkey) return(pubp); } -double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,int32_t vout) +cJSON *LP_pubkeyjson(struct LP_pubkeyinfo *pubp) { - struct LP_cacheinfo *ptr; - if ( (ptr= LP_cachefind(base,rel,txid,vout)) != 0 ) + int32_t baseid,relid; char *base; double price; cJSON *item,*array,*obj; + obj = cJSON_CreateObject(); + array = cJSON_CreateArray(); + for (baseid=0; baseidQ; - if ( ptr->price == 0. && ptr->Q.satoshis != 0 ) + base = LP_priceinfos[baseid].symbol; + for (relid=0; relidprice? "); - ptr->price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; + if ( (price= pubp->matrix[baseid][relid]) > SMALLVAL ) + { + item = cJSON_CreateArray(); + jaddistr(item,base); + jaddistr(item,LP_priceinfos[relid].symbol); + jaddinum(item,price); + jaddi(array,item); + } } - //printf("found %s/%s %.8f\n",base,rel,ptr->price); - return(ptr->price); } - //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); - return(0.); + jaddbits256(obj,"pubkey",pubp->pubkey); + jaddnum(obj,"timestamp",pubp->timestamp); + jadd(obj,"asks",array); + return(obj); } -struct LP_priceinfo *LP_priceinfofind(char *symbol) +char *LP_prices() { - int32_t i; struct LP_priceinfo *pp; uint64_t coinbits; - if ( LP_numpriceinfos > 0 ) + struct LP_pubkeyinfo *pubp,*tmp; cJSON *array = cJSON_CreateArray(); + HASH_ITER(hh,LP_pubkeyinfos,pubp,tmp) { - coinbits = stringbits(symbol); - pp = LP_priceinfos; - for (i=0; icoinbits == coinbits ) - return(pp); + jaddi(array,LP_pubkeyjson(pubp)); } - return(0); + return(jprint(array,1)); } -struct LP_priceinfo *LP_priceinfoptr(int32_t *indp,char *base,char *rel) +void LP_prices_parse(cJSON *obj) { - struct LP_priceinfo *basepp,*relpp; - if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + struct LP_pubkeyinfo *pubp; struct LP_priceinfo *basepp; uint32_t timestamp; bits256 pubkey; cJSON *asks,*item; int32_t i,n,relid; char *base,*rel; double askprice; + pubkey = jbits256(obj,"pubkey"); + if ( bits256_nonz(pubkey) != 0 && (pubp= LP_pubkeyadd(pubkey)) != 0 ) { - *indp = relpp->ind; - return(basepp); + if ( (timestamp= juint(obj,"timestamp")) > pubp->timestamp && (asks= jarray(&n,obj,"asks")) != 0 ) + { + pubp->timestamp = timestamp; + for (i=0; iind,relid,askprice); + pubp->matrix[basepp->ind][relid] = askprice; + } + } + } } - else +} + +void LP_peer_pricesquery(char *destipaddr,uint16_t destport) +{ + char *retstr; cJSON *array; int32_t i,n; + if ( (retstr= issue_LP_getprices(destipaddr,destport)) != 0 ) { - *indp = -1; - return(0); + if ( (array= cJSON_Parse(retstr)) != 0 ) + { + if ( is_cJSON_Array(array) && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; iQ; + if ( ptr->price == 0. && ptr->Q.satoshis != 0 ) + { + printf("LP_pricecache: null ptr->price? "); + ptr->price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis; + } + //printf("found %s/%s %.8f\n",base,rel,ptr->price); + return(ptr->price); } + //char str[65]; printf("cachemiss %s/%s %s/v%d\n",base,rel,bits256_str(str,txid),vout); + return(0.); } void LP_priceinfoupdate(char *base,char *rel,double price) @@ -193,7 +273,7 @@ double LP_myprice(double *bidp,double *askp,char *base,char *rel) int32_t LP_mypriceset(char *base,char *rel,double price) { struct LP_priceinfo *basepp,*relpp; - if ( price > SMALLVAL && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + if ( base != 0 && rel != 0 && price > SMALLVAL && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { basepp->myprices[relpp->ind] = price; // ask relpp->myprices[basepp->ind] = (1. / price); // bid @@ -282,6 +362,8 @@ struct LP_priceinfo *LP_priceinfoadd(char *symbol) struct LP_cacheinfo *LP_cacheadd(char *base,char *rel,bits256 txid,int32_t vout,double price,struct LP_quoteinfo *qp) { char str[65]; struct LP_cacheinfo *ptr=0; + if ( base == 0 || rel == 0 ) + return(0); if ( (ptr= LP_cachefind(base,rel,txid,vout)) == 0 ) { ptr = calloc(1,sizeof(*ptr)); @@ -523,8 +605,10 @@ void LP_pricefeedupdate(bits256 pubkey,char *base,char *rel,double price) { printf("PRICEFEED UPDATE.(%s/%s) %.8f %s\n",base,rel,price,bits256_str(str,pubkey)); if ( (pubp= LP_pubkeyadd(pubkey)) != 0 ) + { pubp->matrix[basepp->ind][relpp->ind] = price; - else printf("error creating pubkey entry\n"); + pubp->timestamp = (uint32_t)time(NULL); + } else printf("error creating pubkey entry\n"); } else printf("error finding %s/%s %.8f\n",base,rel,price); } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 0c5f29d45..d7f4c79d1 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -89,6 +89,14 @@ char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) return(issue_curlt(url,LP_HTTP_TIMEOUT)); } +char *issue_LP_getprices(char *destip,uint16_t destport) +{ + char url[512]; + sprintf(url,"http://%s:%u/api/stats/getprices",destip,destport); + //printf("getutxo.(%s)\n",url); + return(issue_curlt(url,LP_HTTP_TIMEOUT)); +} + cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) { char *retstr; cJSON *retjson = 0; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6ee0ecfa7..36e9e0d34 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -203,8 +203,6 @@ int32_t LP_utxopurge(int32_t allutxos) cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { struct _LP_utxoinfo u; - jaddstr(item,"method","notified"); - jaddstr(item,"method2","notified"); jaddstr(item,"coin",utxo->coin); jaddnum(item,"now",time(NULL)); jaddstr(item,"address",utxo->coinaddr); @@ -433,7 +431,7 @@ struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson return(LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit"))); } -int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) +int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) { struct LP_peerinfo *destpeer,*peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; bits256 txid; struct LP_utxoinfo *utxo; //printf("parse.(%s)\n",retstr); @@ -452,13 +450,13 @@ int32_t LP_utxosparse(int32_t mypubsock,char *destipaddr,uint16_t destport,char subport = argport + 2; argipbits = (uint32_t)calc_ipbits(argipaddr); if ( (peer= LP_peerfind(argipbits,argport)) == 0 ) - peer = LP_addpeer(LP_mypeer,mypubsock,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); + peer = LP_addpeer(0,-1,argipaddr,argport,pushport,subport,jdouble(item,"profit"),jint(item,"numpeers"),jint(item,"numutxos")); } if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); //printf("parse.(%s)\n",jprint(item,0)); - if ( (utxo= LP_utxoaddjson(1,mypubsock,item)) != 0 ) + if ( (utxo= LP_utxoaddjson(1,-1,item)) != 0 ) utxo->T.lasttime = now; } } @@ -485,7 +483,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr if ( retstr != 0 ) { now = (uint32_t)time(NULL); - LP_utxosparse(mypubsock,destipaddr,destport,retstr,now); + LP_utxosparse(destipaddr,destport,retstr,now); //printf("got.(%s)\n",retstr); free(retstr); /*i = 0; From ee293e0b4594b1d41bb6b48aa7a8290ea0f9e9fc Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 11:58:02 +0300 Subject: [PATCH 1387/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 122f9512f..04878e772 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -217,6 +217,8 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso static uint32_t counter,lastforward,numpeers; struct LP_utxoinfo *utxo,*utmp; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t n,nonz = 0; now = (uint32_t)time(NULL); + if ( mypeer == 0 ) + myipaddr = "127.0.0.1"; //printf("start peers updates\n"); n = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) @@ -227,13 +229,13 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso peer->lastpeers = now; if ( peer->numpeers != numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,numpeers); - if ( strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) - LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); + if ( strcmp(peer->ipaddr,myipaddr) != 0 ) + LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } nonz += LP_subsock_check(peer); if ( peer->diduquery == 0 ) { - LP_peer_utxosquery(LP_mypeer,myport,pubsock,peer,now,profitmargin,60); + LP_peer_utxosquery(mypeer,myport,pubsock,peer,now,profitmargin,60); LP_peer_pricesquery(peer->ipaddr,peer->port); peer->diduquery = now; } From 785e6231f98c46b26f4865292fbd674dba653b35 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 11:59:59 +0300 Subject: [PATCH 1388/2705] Test --- iguana/exchanges/getprices | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 iguana/exchanges/getprices diff --git a/iguana/exchanges/getprices b/iguana/exchanges/getprices new file mode 100755 index 000000000..216b2b86c --- /dev/null +++ b/iguana/exchanges/getprices @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"getprices\",\"coin\":\"REVS\"}" From 2f2ceea2506d1193fb4de51f3483889f50d4cf7f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:04:00 +0300 Subject: [PATCH 1389/2705] Test --- iguana/exchanges/LP_prices.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index bd771857e..68e1de8bf 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -272,11 +272,17 @@ double LP_myprice(double *bidp,double *askp,char *base,char *rel) int32_t LP_mypriceset(char *base,char *rel,double price) { - struct LP_priceinfo *basepp,*relpp; + struct LP_priceinfo *basepp,*relpp; struct LP_pubkeyinfo *pubp; if ( base != 0 && rel != 0 && price > SMALLVAL && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) { basepp->myprices[relpp->ind] = price; // ask - relpp->myprices[basepp->ind] = (1. / price); // bid + //relpp->myprices[basepp->ind] = (1. / price); // bid + if ( (pubp= LP_pubkeyadd(LP_mypubkey)) != 0 ) + { + pubp->matrix[basepp->ind][relpp->ind] = price; + //pubp->matrix[relpp->ind][basepp->ind] = (1. / price); + pubp->timestamp = (uint32_t)time(NULL); + } return(0); } else return(-1); } From 47968e570dbfac2fc6be03f8f67a48131f501c4c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:09:27 +0300 Subject: [PATCH 1390/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 04878e772..3ffda9902 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -215,12 +215,16 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) { static uint32_t counter,lastforward,numpeers; - struct LP_utxoinfo *utxo,*utmp; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t n,nonz = 0; + struct LP_utxoinfo *utxo,*utmp; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0; now = (uint32_t)time(NULL); if ( mypeer == 0 ) myipaddr = "127.0.0.1"; //printf("start peers updates\n"); - n = 0; + numpeers = 0; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + numpeers++; + } HASH_ITER(hh,LP_peerinfos,peer,tmp) { //printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); @@ -240,7 +244,6 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso peer->diduquery = now; } } - numpeers = n; if ( lastforward < now-3600 ) { LP_forwarding_register(LP_mypubkey,pushaddr,10); From 229d4d931ec536cae7d801e4bb71a08915ae71ab Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:11:41 +0300 Subject: [PATCH 1391/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3ffda9902..cffd75b86 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -227,7 +227,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } HASH_ITER(hh,LP_peerinfos,peer,tmp) { - //printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); + printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) { peer->lastpeers = now; From 9142ca37359a9b0f08825d690f9093aa33229117 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:14:34 +0300 Subject: [PATCH 1392/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index cffd75b86..30ff70c8d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -227,9 +227,9 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) { + printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); peer->lastpeers = now; if ( peer->numpeers != numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,numpeers); From b2fbf61efdb1d8277f155c2a0c0c0e64686c7f76 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:14:50 +0300 Subject: [PATCH 1393/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 30ff70c8d..d314c9eb6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -229,7 +229,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) { - printf("updatepeer.%s lag.%d\n",peer->ipaddr,now-peer->lastpeers); + printf("numpeers.%d updatepeer.%s lag.%d\n",numpeers,peer->ipaddr,now-peer->lastpeers); peer->lastpeers = now; if ( peer->numpeers != numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,numpeers); From 208c3c4f6ba87458b6a2d3a851fd6a6c62065ccd Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:40:33 +0300 Subject: [PATCH 1394/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 ++ iguana/exchanges/LP_prices.c | 41 ++++++++++++++++++--------------- iguana/exchanges/LP_utxos.c | 1 + 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d314c9eb6..c368b6b7a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -260,6 +260,8 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp) { LP_utxo_spentcheck(pubsock,utxo,profitmargin); + if ( utxo->T.lasttime == 0 ) + LP_utxo_clientpublish(utxo); } } if ( pullsock >= 0 ) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 68e1de8bf..9c559ce73 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -461,9 +461,30 @@ int32_t LP_orderbookfind(struct LP_orderbookentry **array,int32_t num,bits256 tx return(-1); } +int32_t LP_utxo_clientpublish(struct LP_utxoinfo *utxo) +{ + struct LP_peerinfo *peer,*tmp; cJSON *retjson; char *retstr; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( (retstr= issue_LP_notifyutxo(peer->ipaddr,peer->port,utxo)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( jobj(retjson,"error") == 0 ) + utxo->T.lasttime = (uint32_t)time(NULL); + free_json(retjson); + } + free(retstr); + } + if ( utxo->T.lasttime != 0 ) + return(0); + } + return(-1); +} + int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char *rel,struct LP_orderbookentry *(**arrayp),int32_t num,int32_t cachednum) { - struct LP_utxoinfo *utxo,*tmp; struct LP_pubkeyinfo *pubp; struct LP_peerinfo *peer,*ptmp; char *retstr; cJSON *retjson; struct LP_priceinfo *basepp; struct LP_orderbookentry *op; double price; int32_t baseid,relid; uint64_t basesatoshis; + struct LP_utxoinfo *utxo,*tmp; struct LP_pubkeyinfo *pubp; struct LP_priceinfo *basepp; struct LP_orderbookentry *op; double price; int32_t baseid,relid; uint64_t basesatoshis; if ( (basepp= LP_priceinfoptr(&relid,base,rel)) != 0 ) baseid = basepp->ind; else return(num); @@ -482,23 +503,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey)) != 0 ) (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) - { - HASH_ITER(hh,LP_peerinfos,peer,ptmp) - { - if ( (retstr= issue_LP_notifyutxo(peer->ipaddr,peer->port,utxo)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( jobj(retjson,"error") == 0 ) - utxo->T.lasttime = (uint32_t)time(NULL); - free_json(retjson); - } - free(retstr); - } - if ( utxo->T.lasttime != 0 ) - break; - } - } + LP_utxo_clientpublish(utxo); } } } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 36e9e0d34..f450f2a48 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -420,6 +420,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); + else LP_utxo_clientpublish(utxo); if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) LP_mypeer->numutxos++; } From a92476a7f85e486e3b4f6643fa9a2ca058810f1a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:43:09 +0300 Subject: [PATCH 1395/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index d7f4c79d1..77f6a4b45 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -65,7 +65,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65],str3[65]; - sprintf(url,"http://%s:%u/api/stats/notified?method=notified&pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); + sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curlt(url,LP_HTTP_TIMEOUT)); From 907e5fcd87b0278e1e81ebe25ec7124e5b282826 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:44:13 +0300 Subject: [PATCH 1396/2705] Test --- iguana/exchanges/LP_commands.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 297ea0219..bef533d7c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -426,11 +426,9 @@ forwardhex(pubkey,hex)\n\ retstr = LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn")); else if ( strcmp(method,"notified") == 0 ) { + printf("utxonotify.(%s)\n",jprint(argjson,0)); if ( juint(argjson,"timestamp") > time(NULL)-60 ) - { - printf("utxonotify.(%s)\n",jprint(argjson,0)); LP_utxoaddjson(1,LP_mypubsock,argjson); - } retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } else if ( IAMLP != 0 ) From 3fb6ac1ef87cbafafbfa96f7b6db1491939933df Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:48:49 +0300 Subject: [PATCH 1397/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bef533d7c..76e5fc10a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -266,7 +266,7 @@ forward(pubkey,method2,)\n\ forward(pubkey,method2=publish,)\n\ forwardhex(pubkey,hex)\n\ \"}")); - //printf("CMD.(%s)\n",jprint(argjson,0)); + printf("CMD.(%s)\n",jprint(argjson,0)); base = jstr(argjson,"base"); rel = jstr(argjson,"rel"); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) From 3b11e8a10541886a137b7ea7b535d27a4ff7346f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:51:06 +0300 Subject: [PATCH 1398/2705] Test --- iguana/exchanges/LP_commands.c | 3 +-- iguana/exchanges/LP_utxos.c | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 76e5fc10a..d0278df45 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -237,7 +237,7 @@ char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (method= jstr(argjson,"method")) == 0 ) { - printf("(%s)\n",jprint(argjson,0)); + printf("stats_JSON no method: (%s)\n",jprint(argjson,0)); return(clonestr("{\"error\":\"need method in request\"}")); } else if ( strcmp(method,"help") == 0 ) @@ -266,7 +266,6 @@ forward(pubkey,method2,)\n\ forward(pubkey,method2=publish,)\n\ forwardhex(pubkey,hex)\n\ \"}")); - printf("CMD.(%s)\n",jprint(argjson,0)); base = jstr(argjson,"base"); rel = jstr(argjson,"rel"); if ( USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index f450f2a48..e6f29e506 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -203,6 +203,7 @@ int32_t LP_utxopurge(int32_t allutxos) cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { struct _LP_utxoinfo u; + jaddstr(item,"method","notified"); jaddstr(item,"coin",utxo->coin); jaddnum(item,"now",time(NULL)); jaddstr(item,"address",utxo->coinaddr); From 28eaf6155c0d72c04a2cf62918f72090bdb2aa79 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 12:55:39 +0300 Subject: [PATCH 1399/2705] Test --- iguana/exchanges/LP_commands.c | 50 ++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index d0278df45..d7d6302a6 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -234,13 +234,36 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; + char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos,flag = 0; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; + if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) + { + if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) + { + flag = 1; + if ( (pushport= juint(argjson,"push")) == 0 ) + pushport = argport + 1; + if ( (subport= juint(argjson,"sub")) == 0 ) + subport = argport + 2; + if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) + { + if ( 0 && (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) + peer->numpeers = otherpeers; + if ( 0 && (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) + { + printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer != 0 ? LP_mypeer->numutxos:0); + peer->numutxos = othernumutxos; + } + //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); + } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); + } + } if ( (method= jstr(argjson,"method")) == 0 ) { - printf("stats_JSON no method: (%s)\n",jprint(argjson,0)); + if ( flag == 0 ) + printf("stats_JSON no method: (%s)\n",jprint(argjson,0)); return(clonestr("{\"error\":\"need method in request\"}")); } - else if ( strcmp(method,"help") == 0 ) + if ( strcmp(method,"help") == 0 ) return(clonestr("{\"result\":\" \ available localhost RPC commands:\n \ setprice(base, rel, price)\n\ @@ -368,27 +391,6 @@ forwardhex(pubkey,hex)\n\ return(clonestr("{\"error\":\"at least one of coins disabled\"}")); if ( LP_isdisabled(jstr(argjson,"coin"),0) != 0 ) return(clonestr("{\"error\":\"coin is disabled\"}")); - if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) - { - if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) - { - if ( (pushport= juint(argjson,"push")) == 0 ) - pushport = argport + 1; - if ( (subport= juint(argjson,"sub")) == 0 ) - subport = argport + 2; - if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),argport)) != 0 ) - { - if ( 0 && (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) - peer->numpeers = otherpeers; - if ( 0 && (othernumutxos= jint(argjson,"numutxos")) > peer->numutxos ) - { - printf("change.(%s) numutxos.%d -> %d mynumutxos.%d\n",peer->ipaddr,peer->numutxos,othernumutxos,LP_mypeer != 0 ? LP_mypeer->numutxos:0); - peer->numutxos = othernumutxos; - } - //printf("peer.(%s) found (%d %d) (%d %d) (%s)\n",peer->ipaddr,peer->numpeers,peer->numutxos,otherpeers,othernumutxos,jprint(argjson,0)); - } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jdouble(argjson,"profit"),jint(argjson,"numpeers"),jint(argjson,"numutxos")); - } - } if ( strcmp(method,"reserved") == 0 ) retstr = LP_quotereceived(argjson); else if ( strcmp(method,"connected") == 0 ) From 212c3d8bed659a823411ee43ecd667f938effd88 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 13:22:31 +0300 Subject: [PATCH 1400/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++- iguana/exchanges/LP_prices.c | 62 ++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index d7d6302a6..946b428fd 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -259,7 +259,7 @@ char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) } if ( (method= jstr(argjson,"method")) == 0 ) { - if ( flag == 0 ) + if ( flag == 0 && jobj(argjson,"result") == 0 ) printf("stats_JSON no method: (%s)\n",jprint(argjson,0)); return(clonestr("{\"error\":\"need method in request\"}")); } @@ -386,6 +386,8 @@ forwardhex(pubkey,hex)\n\ return(basilisk_swapentry(requestid,quoteid)); else return(basilisk_swaplist()); } + else if ( strcmp(method,"myprices") == 0 ) + return(LP_myprices()); } if ( LP_isdisabled(base,rel) != 0 ) return(clonestr("{\"error\":\"at least one of coins disabled\"}")); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 9c559ce73..eb6138967 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -244,7 +244,7 @@ void LP_priceinfoupdate(char *base,char *rel,double price) } } -double LP_myprice(double *bidp,double *askp,char *base,char *rel) +/*double LP_myprice(double *bidp,double *askp,char *base,char *rel) { struct LP_priceinfo *basepp,*relpp; double val; *bidp = *askp = 0.; @@ -268,6 +268,62 @@ double LP_myprice(double *bidp,double *askp,char *base,char *rel) } } return(0.); +}*/ + +double LP_myprice(double *bidp,double *askp,char *base,char *rel) +{ + struct LP_priceinfo *basepp,*relpp; double val; + *bidp = *askp = 0.; + if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) + { + if ( (*askp= basepp->myprices[relpp->ind]) > SMALLVAL ) + { + if ( (val= relpp->myprices[basepp->ind]) > SMALLVAL ) + { + *bidp = 1. / val; + return((*askp + *bidp) * 0.5); + } + else + { + *bidp = 0.; + return(*askp); + } + } + else + { + if ( (val= relpp->myprices[basepp->ind]) > SMALLVAL ) + { + *bidp = 1. / val; + *askp = 0.; + return(*bidp); + } + } + } + return(0.); +} + +char *LP_myprices() +{ + int32_t baseid,relid; double bid,ask; char *base,*rel; cJSON *item,*array; + array = cJSON_CreateArray(); + for (baseid=0; baseid SMALLVAL ) + { + item = cJSON_CreateObject(); + jaddstr(item,"base",base); + jaddstr(item,"rel",rel); + jaddnum(item,"bid",bid); + jaddnum(item,"ask",ask); + jaddi(array,item); + } + } + } + return(jprint(array,1)); } int32_t LP_mypriceset(char *base,char *rel,double price) @@ -497,9 +553,9 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * { //char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); - if ( polarity > 0 ) + //if ( polarity > 0 ) basesatoshis = utxo->payment.value; - else basesatoshis = utxo->payment.value * price; + //else basesatoshis = utxo->payment.value * price; if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey)) != 0 ) (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) From 54752e688e15d7de6d5fbb5570a72f21994af482 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 13:23:01 +0300 Subject: [PATCH 1401/2705] Test --- iguana/exchanges/myprices | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 iguana/exchanges/myprices diff --git a/iguana/exchanges/myprices b/iguana/exchanges/myprices new file mode 100755 index 000000000..7333d682b --- /dev/null +++ b/iguana/exchanges/myprices @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"myprices\"}" From aba327b139d06cfdd130ffef7e70867e02417af9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 13:26:47 +0300 Subject: [PATCH 1402/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 946b428fd..d37be6f1a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -429,8 +429,8 @@ forwardhex(pubkey,hex)\n\ retstr = LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn")); else if ( strcmp(method,"notified") == 0 ) { - printf("utxonotify.(%s)\n",jprint(argjson,0)); - if ( juint(argjson,"timestamp") > time(NULL)-60 ) + //printf("utxonotify.(%s)\n",jprint(argjson,0)); + //if ( juint(argjson,"timestamp") > time(NULL)-60 ) LP_utxoaddjson(1,LP_mypubsock,argjson); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } From 114ec7872c51bbf70bdaa88fa1ef2f9fe66d758f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 13:46:12 +0300 Subject: [PATCH 1403/2705] Test --- iguana/exchanges/LP_commands.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index d37be6f1a..cb20e74fb 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -281,7 +281,6 @@ getpeers()\n\ getutxos()\n\ getutxos(coin, lastn)\n\ orderbook(base, rel)\n\ -getprice(base, rel)\n\ getprices(base, rel)\n\ register(pubkey,pushaddr)\n\ lookup(pubkey)\n\ @@ -405,8 +404,8 @@ forwardhex(pubkey,hex)\n\ retstr = LP_postedprice(argjson); else if ( strcmp(method,"broadcast") == 0 ) retstr = LP_broadcasted(argjson); - else if ( strcmp(method,"getprice") == 0 ) - retstr = LP_pricestr(base,rel,0.); + //else if ( strcmp(method,"getprice") == 0 ) + // retstr = LP_pricestr(base,rel,0.); else if ( strcmp(method,"getprices") == 0 ) retstr = LP_prices(); else if ( strcmp(method,"orderbook") == 0 ) From 8c36ea63bc289e90933dd1568bc822b00db36263 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 13:46:54 +0300 Subject: [PATCH 1404/2705] Test --- iguana/exchanges/getprice | 2 -- 1 file changed, 2 deletions(-) delete mode 100755 iguana/exchanges/getprice diff --git a/iguana/exchanges/getprice b/iguana/exchanges/getprice deleted file mode 100755 index 4b9614be7..000000000 --- a/iguana/exchanges/getprice +++ /dev/null @@ -1,2 +0,0 @@ -source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"getprice\",\"base\":\"REVS\",\"rel\":\"KMD\"}" From c9d1d7fd6ddc9cfdde98840546b05f9abad0133f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 13:57:45 +0300 Subject: [PATCH 1405/2705] Test --- iguana/exchanges/LP_commands.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index cb20e74fb..1d018dca9 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -271,8 +271,7 @@ myprice(base, rel)\n\ enable(coin)\n\ disable(coin)\n\ inventory(coin)\n\ -candidates(txid, vout)\n\ -autotrade(txid, vout, maxprice)\n\ +autotrade(base, rel, maxvolume, maxprice)\n\ swapstatus()\n\ swapstatus(requestid, quoteid)\n\ public API:\n \ From 76a2dae871712ad876ac88680f71041f057fbe62 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 15:47:35 +0300 Subject: [PATCH 1406/2705] Test --- iguana/exchanges/LP_commands.c | 232 +---------------- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_prices.c | 2 +- iguana/exchanges/LP_quotes.c | 400 ++++++++++++++++++----------- iguana/exchanges/LP_statemachine.c | 117 +++++++++ iguana/exchanges/LP_utxos.c | 17 ++ 6 files changed, 390 insertions(+), 380 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 1d018dca9..a3c70645a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -18,219 +18,6 @@ // marketmaker // -// price query is redundant as there is a pricefeed for all pubkeys now -// get orderbook, find pubkey of the one offering it and directly reserve it -// then it is the same as current logic, just skip the "price" step -// "notified" push is wrong - -double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub) -{ - cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; - qp->desthash = mypub; - strcpy(qp->srccoin,base); - strcpy(qp->destcoin,rel); - qp->desthash = LP_mypubkey; - if ( strcmp(method,"request") == 0 ) - { - qp->quotetime = (uint32_t)time(NULL); - if ( (utxo= LP_utxofind(0,qp->desttxid,qp->destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) - LP_unavailableset(utxo,qp->srchash); - else - { - printf("couldnt find my txid to make request\n"); - return(0.); - } - } - reqjson = LP_quotejson(qp); - if ( bits256_nonz(qp->desthash) != 0 ) - flag = 1; - jaddstr(reqjson,"method",method); - if ( strcmp(method,"price") != 0 ) - printf("QUERY.(%s)\n",jprint(reqjson,0)); - LP_forward(qp->srchash,jprint(reqjson,1),1); - for (i=0; i<30; i++) - { - if ( (price= LP_pricecache(qp,base,rel,qp->txid,qp->vout)) > SMALLVAL ) - { - if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) - { - //printf("break out of loop.%d price %.8f\n",i,price); - break; - } - } - usleep(100000); - } - return(price); -} - -int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) -{ - char *retstr,pairstr[512],destaddr[64]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; - if ( (price= LP_price(base,rel)) > SMALLVAL ) - { - price *= (1. + profitmargin); - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - if ( LP_quoteparse(&Q,argjson) < 0 ) - return(-2); - //printf("connect with.(%s)\n",jprint(argjson,0)); - Q.destsatoshis = Q.satoshis * price; - privkey = LP_privkey(utxo->coinaddr); - if ( bits256_nonz(utxo->S.mypub) == 0 ) - utxo->S.mypub = LP_pubkey(privkey); - if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) - { - printf("not eligible\n"); - return(-1); - } - if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) - { - nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 10000)); - if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) - printf("error creating utxo->pair\n"); - else if ( nn_bind(pair,pairstr) >= 0 ) - { - LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - swap = LP_swapinit(1,0,privkey,&Q.R,&Q); - swap->N.pair = pair; - utxo->S.swap = swap; - swap->utxo = utxo; - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)swap) == 0 ) - { - retjson = LP_quotejson(&Q); - jaddstr(retjson,"method","connected"); - jaddstr(retjson,"pair",pairstr); - jaddnum(retjson,"requestid",Q.R.requestid); - jaddnum(retjson,"quoteid",Q.R.quoteid); - retstr = jprint(retjson,1); - if ( pubsock >= 0 ) - LP_send(pubsock,retstr,1); - else LP_forward(utxo->S.otherpubkey,retstr,1); - retval = 0; - } else printf("error launching swaploop\n"); - } else printf("printf error nn_connect to %s\n",pairstr); - } - else - { - printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); - } - } else printf("no price for %s/%s\n",base,rel); - if ( retval < 0 ) - { - if ( pair >= 0 ) - nn_close(pair); - LP_availableset(utxo); - } - return(retval); -} - -char *LP_connected(cJSON *argjson) // alice -{ - cJSON *retjson; bits256 spendtxid; int32_t spendvini,selector,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; - LP_quoteparse(&Q,argjson); - if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) - { - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) - { - char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(clonestr("{\"error\",\"src txid in mempool\"}")); - } - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) - { - char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(clonestr("{\"error\",\"dest txid in mempool\"}")); - } - retjson = cJSON_CreateObject(); - if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) - jaddstr(retjson,"error","couldnt create pairsock"); - else if ( nn_connect(pairsock,pairstr) >= 0 ) - { - LP_unavailableset(utxo,Q.srchash); - Q.privkey = LP_privkey(Q.destaddr); - LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q); - swap->N.pair = pairsock; - utxo->S.swap = swap; - swap->utxo = utxo; - printf("alice pairstr.(%s)\n",pairstr); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 ) - { - jaddstr(retjson,"result","success"); - jadd(retjson,"trade",LP_quotejson(&Q)); - jaddnum(retjson,"requestid",Q.R.requestid); - jaddnum(retjson,"quoteid",Q.R.quoteid); - } else jaddstr(retjson,"error","couldnt aliceloop"); - } - return(jprint(retjson,1)); - } else return(clonestr("{\"result\",\"update stats\"}")); -} - -int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) -{ - char *method,*base,*rel,*retstr; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; - if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) - { - retval = 1; - txid = jbits256(argjson,"txid"); - if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) - { - printf("LP_tradecommand.(%s)\n",jprint(argjson,0)); - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) - { - char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - utxo->T.spentflag = (uint32_t)time(NULL); - return(0); - } - if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) - utxo->T.swappending = 0; - if ( strcmp(method,"request") == 0 ) // bob - { - retval = 1; - if ( LP_isavailable(utxo) > 0 ) - { - if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) - { - price *= (1. + profitmargin); - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) - { - printf("not eligible\n"); - return(-1); - } - Q.timestamp = (uint32_t)time(NULL); - retjson = LP_quotejson(&Q); - utxo->S.otherpubkey = jbits256(argjson,"desthash"); - retval |= 2; - LP_unavailableset(utxo,jbits256(argjson,"desthash")); - jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); - jaddnum(retjson,"pending",utxo->T.swappending); - jaddbits256(retjson,"desthash",utxo->S.otherpubkey); - jaddstr(retjson,"method","reserved"); - retstr = jprint(retjson,1); - if ( pubsock >= 0 ) - LP_send(pubsock,retstr,1); - else LP_forward(utxo->S.otherpubkey,retstr,1); - utxo->T.lasttime = (uint32_t)time(NULL); - } else printf("null price\n"); - } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); - } - else if ( strcmp(method,"connect") == 0 ) // bob - { - retval = 4; - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,jstr(argjson,"destcoin"),jbits256(argjson,"desttxid"),jint(argjson,"destvout"),jbits256(argjson,"feetxid"),jint(argjson,"feevout"))) >= 0 ) - { - char str[65]; printf("LP_tradecommand fee selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(0); - } - if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) - LP_connectstart(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); - else printf("swap %p when connect came in (%s)\n",utxo->S.swap,jprint(argjson,0)); - } - } - } - return(retval); -} char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { @@ -271,7 +58,7 @@ myprice(base, rel)\n\ enable(coin)\n\ disable(coin)\n\ inventory(coin)\n\ -autotrade(base, rel, maxvolume, maxprice)\n\ +autotrade(base, rel, price, volume)\n\ swapstatus()\n\ swapstatus(requestid, quoteid)\n\ public API:\n \ @@ -361,21 +148,8 @@ forwardhex(pubkey,hex)\n\ return(jprint(retjson,1)); } } - else if ( (strcmp(method,"candidates") == 0 || strcmp(method,"autotrade") == 0) ) - { - bits256 txid; int32_t vout; struct LP_utxoinfo *utxo; - txid = jbits256(argjson,"txid"); - if ( bits256_nonz(txid) == 0 ) - return(clonestr("{\"error\":\"invalid or missing txid\"}")); - if ( jobj(argjson,"vout") == 0 ) - return(clonestr("{\"error\":\"missing vout\"}")); - vout = jint(argjson,"vout"); - if ( (utxo= LP_utxofind(0,txid,vout)) == 0 ) - return(clonestr("{\"error\":\"txid/vout not found\"}")); - if ( strcmp(method,"candidates") == 0 ) - return(jprint(LP_tradecandidates(coin),1)); - else return(jprint(LP_autotrade(utxo,coin,jdouble(argjson,"maxprice")),1)); - } + else if ( strcmp(method,"autotrade") == 0 ) + return(LP_autotrade(base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"))); } else if ( strcmp(method,"swapstatus") == 0 ) { diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 87fe57170..7b4bd45aa 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -218,7 +218,7 @@ uint32_t basilisk_quoteid(struct basilisk_request *rp); struct basilisk_swap *LP_swapinit(int32_t iambob,int32_t optionduration,bits256 privkey,struct basilisk_request *rp,struct LP_quoteinfo *qp); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params); uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits,int32_t suppress_swapsend); -double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); +//double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); void LP_quotesinit(char *base,char *rel); int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index eb6138967..252a5ccd4 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -483,7 +483,7 @@ cJSON *LP_orderbookjson(struct LP_orderbookentry *op) cJSON *item = cJSON_CreateObject(); if ( op->price > SMALLVAL ) { - jaddnum(item,"price",op->price ); + jaddnum(item,"price",op->price); jaddnum(item,"volume",dstr(op->basesatoshis)); jaddbits256(item,"txid",op->txid); jaddnum(item,"vout",op->vout); diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index c1a104e3d..069d63575 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -145,22 +145,15 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * return(0); } -int32_t LP_quoteinfoset(struct LP_quoteinfo *qp,uint32_t timestamp,uint32_t quotetime,uint64_t value,uint64_t txfee,uint64_t destsatoshis,uint64_t desttxfee,bits256 desttxid,int32_t destvout,bits256 desthash,char *destaddr) +int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,uint32_t quotetime,uint64_t destsatoshis,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr) { - if ( txfee != qp->txfee ) - { - if ( txfee >= value ) - return(-1); - qp->txfee = txfee; - qp->satoshis = value - txfee; - } - qp->timestamp = timestamp; qp->quotetime = quotetime; qp->destsatoshis = destsatoshis; - qp->desttxfee = desttxfee; qp->desttxid = desttxid; qp->destvout = destvout; qp->desthash = desthash; + qp->feetxid = feetxid; + qp->feevout = feevout; safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr)); return(0); } @@ -236,182 +229,291 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) return(-1); } -cJSON *LP_tradecandidates(char *base) +double LP_query(char *method,struct LP_quoteinfo *qp) { - struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; - totaladded = 0; - HASH_ITER(hh,LP_peerinfos,peer,tmp) + cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; + if ( strcmp(method,"request") == 0 ) + { + qp->quotetime = (uint32_t)time(NULL); + if ( (utxo= LP_utxofind(0,qp->desttxid,qp->destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) + LP_unavailableset(utxo,qp->srchash); + else + { + printf("couldnt find my txid to make request\n"); + return(0.); + } + } + reqjson = LP_quotejson(qp); + if ( bits256_nonz(qp->desthash) != 0 ) + flag = 1; + jaddstr(reqjson,"method",method); + printf("QUERY.(%s)\n",jprint(reqjson,0)); + LP_forward(qp->srchash,jprint(reqjson,1),1); + for (i=0; i<30; i++) { - printf("%s:%u %s\n",peer->ipaddr,peer->port,base); - n = added = 0; - if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) + if ( (price= LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout)) > SMALLVAL ) { - printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); - if ( (array= cJSON_Parse(utxostr)) != 0 ) + if ( flag == 0 || bits256_nonz(qp->desthash) != 0 ) { - if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) - { - retarray = cJSON_CreateArray(); - for (i=0; i SMALLVAL ) + { + price *= (1. + profitmargin); + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + if ( LP_quoteparse(&Q,argjson) < 0 ) + return(-2); + printf("connect with.(%s)\n",jprint(argjson,0)); + Q.destsatoshis = Q.satoshis * price; + privkey = LP_privkey(utxo->coinaddr); + if ( bits256_nonz(utxo->S.mypub) == 0 ) + utxo->S.mypub = LP_pubkey(privkey); + if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) + { + printf("not eligible\n"); + return(-1); + } + if ( utxo->payment.value > (Q.satoshis << 1) ) + { + printf("utxo payment %.8f is less than half covered by Q %.8f\n",dstr(utxo->payment.value),dstr(Q.satoshis)); + return(-1); + } + if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + { + nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 10000)); + if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) + printf("error creating utxo->pair\n"); + else if ( nn_bind(pair,pairstr) >= 0 ) + { + LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); + swap = LP_swapinit(1,0,privkey,&Q.R,&Q); + swap->N.pair = pair; + utxo->S.swap = swap; + swap->utxo = utxo; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)swap) == 0 ) + { + retjson = LP_quotejson(&Q); + jaddstr(retjson,"method","connected"); + jaddstr(retjson,"pair",pairstr); + jaddnum(retjson,"requestid",Q.R.requestid); + jaddnum(retjson,"quoteid",Q.R.quoteid); + retstr = jprint(retjson,1); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + else LP_forward(utxo->S.otherpubkey,retstr,1); + retval = 0; + } else printf("error launching swaploop\n"); + } else printf("printf error nn_connect to %s\n",pairstr); + } + else { - printf("n.%d totaladded.%d vs added.%d\n",n,totaladded,added); - break; + printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); } + } else printf("no price for %s/%s\n",base,rel); + if ( retval < 0 ) + { + if ( pair >= 0 ) + nn_close(pair); + LP_availableset(utxo); } - return(retarray); + return(retval); } -void LP_quotesinit(char *base,char *rel) +char *LP_connected(cJSON *argjson) // alice { - cJSON *array,*item; struct LP_quoteinfo Q; bits256 zero; int32_t i,n,iter; - memset(&zero,0,sizeof(zero)); - for (iter=0; iter<2; iter++) - if ( (array= LP_tradecandidates(iter == 0 ? base : rel)) != 0 ) + cJSON *retjson; bits256 spendtxid; int32_t spendvini,selector,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; + LP_quoteparse(&Q,argjson); + if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) { - //printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); - if ( (n= cJSON_GetArraySize(array)) > 0 ) + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) + { + char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(clonestr("{\"error\",\"src txid in mempool\"}")); + } + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) + { + char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(clonestr("{\"error\",\"dest txid in mempool\"}")); + } + retjson = cJSON_CreateObject(); + if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) + jaddstr(retjson,"error","couldnt create pairsock"); + else if ( nn_connect(pairsock,pairstr) >= 0 ) { - memset(&Q,0,sizeof(Q)); - for (i=0; iN.pair = pairsock; + utxo->S.swap = swap; + swap->utxo = utxo; + printf("alice pairstr.(%s)\n",pairstr); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 ) { - item = jitem(array,i); - LP_quoteparse(&Q,item); - if ( iter == 0 ) - LP_query("price",&Q,base,rel,zero); - else LP_query("price",&Q,rel,base,zero); - } + jaddstr(retjson,"result","success"); + jadd(retjson,"trade",LP_quotejson(&Q)); + jaddnum(retjson,"requestid",Q.R.requestid); + jaddnum(retjson,"quoteid",Q.R.quoteid); + } else jaddstr(retjson,"error","couldnt aliceloop"); } - free_json(array); - } + return(jprint(retjson,1)); + } else return(clonestr("{\"result\",\"update stats\"}")); } -cJSON *LP_autotrade(struct LP_utxoinfo *myutxo,char *base,double maxprice) +int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - static bits256 zero; - int32_t i,n,besti,DEXselector=0; cJSON *array,*item,*bestitem=0; struct basilisk_request R; double bestmetric,metric,bestprice=0.,price,prices[100]; struct LP_quoteinfo Q[sizeof(prices)/sizeof(*prices)]; - bestprice = 0.; - if ( maxprice == 0. ) - maxprice = LP_price(base,myutxo->coin) / 0.975; - if ( (array= LP_tradecandidates(base)) != 0 ) + char *method,*base,*rel,*retstr; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; + if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) { - printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); - if ( (n= cJSON_GetArraySize(array)) > 0 ) + retval = 1; + txid = jbits256(argjson,"txid"); + if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { - memset(prices,0,sizeof(prices)); - memset(Q,0,sizeof(Q)); - for (i=0; icoin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) { - item = jitem(array,i); - LP_quoteparse(&Q[i],item); - if ( (price= jdouble(item,"price")) == 0. ) - { - price = LP_query("price",&Q[i],base,myutxo->coin,zero); - Q[i].destsatoshis = price * Q[i].satoshis; - } - if ( (prices[i]= price) > SMALLVAL && (bestprice == 0. || price < bestprice) ) - bestprice = price; - char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); + char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + utxo->T.spentflag = (uint32_t)time(NULL); + return(0); } - if ( bestprice > SMALLVAL ) + if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) + utxo->T.swappending = 0; + if ( strcmp(method,"request") == 0 ) // bob { - bestmetric = 0.; - besti = -1; - for (i=0; i 0 ) { - if ( (price= prices[i]) > SMALLVAL && myutxo->S.satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) + if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) { - metric = price / bestprice; - printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); - if ( metric < 1.1 ) + price *= (1. + profitmargin); + if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + return(-1); + if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { - metric = dstr(Q[i].destsatoshis) * metric * metric * metric; - printf("%f\n",metric); - if ( bestmetric == 0. || metric < bestmetric ) - { - besti = i; - bestmetric = metric; - } + printf("not eligible\n"); + return(-1); } - } else printf("(%f %f) ",dstr(myutxo->S.satoshis),dstr(Q[i].destsatoshis)); + Q.timestamp = (uint32_t)time(NULL); + retjson = LP_quotejson(&Q); + utxo->S.otherpubkey = jbits256(argjson,"desthash"); + retval |= 2; + LP_unavailableset(utxo,jbits256(argjson,"desthash")); + jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); + jaddnum(retjson,"pending",utxo->T.swappending); + jaddbits256(retjson,"desthash",utxo->S.otherpubkey); + jaddstr(retjson,"method","reserved"); + retstr = jprint(retjson,1); + if ( pubsock >= 0 ) + LP_send(pubsock,retstr,1); + else LP_forward(utxo->S.otherpubkey,retstr,1); + utxo->T.lasttime = (uint32_t)time(NULL); + } else printf("null price\n"); + } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); + } + else if ( strcmp(method,"connect") == 0 ) // bob + { + retval = 4; + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,jstr(argjson,"destcoin"),jbits256(argjson,"desttxid"),jint(argjson,"destvout"),jbits256(argjson,"feetxid"),jint(argjson,"feevout"))) >= 0 ) + { + char str[65]; printf("LP_tradecommand fee selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(0); } - printf("metrics, best %f\n",bestmetric); - if ( besti >= 0 )//&& bits256_cmp(myutxo->mypub,otherpubs[besti]) == 0 ) + if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) + LP_connectstart(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); + else printf("swap %p when connect came in (%s)\n",utxo->S.swap,jprint(argjson,0)); + } + } + } + return(retval); +} + +char *LP_autotrade(char *base,char *rel,double maxprice,double volume) +{ + uint64_t destsatoshis,asatoshis; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; + if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) + return(clonestr("{\"error\":\"invalid parameter\"}")); + destsatoshis = SATOSHIDEN * volume; + if ( (autxo= LP_utxo_bestfit(rel,destsatoshis)) == 0 ) + return(clonestr("{\"error\":\"cant find utxo that is big enough\"}")); + bestmetric = ordermatchprice = 0.; + if ( (obookstr= LP_orderbook(base,rel)) != 0 ) + { + if ( (orderbook= cJSON_Parse(obookstr)) != 0 ) + { + if ( (asks= jarray(&numasks,orderbook,"asks")) != 0 ) + { + for (i=0; i SMALLVAL && price <= maxprice ) { - Q[i].desttxid = myutxo->payment.txid; - Q[i].destvout = myutxo->payment.vout; - Q[i].feetxid = myutxo->fee.txid; - Q[i].feevout = myutxo->fee.vout; - strcpy(Q[i].destaddr,myutxo->coinaddr); - Q[i].desthash = LP_mypubkey; - strcpy(Q[i].srccoin,base); - strcpy(Q[i].destcoin,myutxo->coin); - price = LP_query("request",&Q[i],base,myutxo->coin,myutxo->S.mypub); - if ( jobj(bestitem,"price") != 0 ) - jdelete(bestitem,"price"); - jaddnum(bestitem,"price",prices[i]); - if ( price <= maxprice ) - { - Q[i].desttxid = myutxo->payment.txid; - Q[i].destvout = myutxo->payment.vout; - Q[i].feetxid = myutxo->fee.txid; - Q[i].feevout = myutxo->fee.vout; - strcpy(Q[i].destaddr,myutxo->coinaddr); - Q[i].desthash = LP_mypubkey; - strcpy(Q[i].srccoin,base); - strcpy(Q[i].destcoin,myutxo->coin); - price = LP_query("connect",&Q[i],base,myutxo->coin,myutxo->S.mypub); - LP_requestinit(&R,Q[i].srchash,Q[i].desthash,base,Q[i].satoshis,Q[i].destcoin,Q[i].destsatoshis,Q[i].timestamp,Q[i].quotetime,DEXselector); - jaddstr(bestitem,"status","connected"); - jaddnum(bestitem,"requestid",R.requestid); - jaddnum(bestitem,"quoteid",R.quoteid); - printf("Alice r.%u q.%u\n",R.requestid,R.quoteid); - } - else + pubkey = jbits256(item,"pubkey"); + if ( bits256_cmp(pubkey,LP_mypubkey) != 0 ) { - jaddstr(bestitem,"status","too expensive"); - jaddnum(bestitem,"price",price); - jaddnum(bestitem,"maxprice",maxprice); - jaddnum(bestitem,"bestprice",bestprice); + if ( bestprice == 0. ) // assumes price ordered asks + bestprice = price; + txid = jbits256(item,"txid"); + vout = jint(item,"vout"); + vol = jdouble(item,"volume"); + if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) + { + asatoshis = butxo->payment.value * price; + if ( asatoshis <= destsatoshis && destsatoshis > (asatoshis >> 1) ) + { + metric = price / bestprice; + printf("%f %f %f %f ",price,metric,dstr(asatoshis),metric * metric * metric); + if ( metric < 1.1 ) + { + metric = dstr(asatoshis) * metric * metric * metric; + printf("(%f) <- metric\n",metric); + if ( bestmetric == 0. || metric < bestmetric ) + { + bestutxo = butxo; + ordermatchprice = price; + bestmetric = metric; + } + } + } + } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); } - } + } else break; } } - free_json(array); + free_json(orderbook); } + free(obookstr); } - if ( bestitem == 0 ) - return(cJSON_Parse("{\"error\":\"no match found\"}")); - return(bestitem); + if ( bestutxo == 0 || ordermatchprice == 0. ) + return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); + asatoshis = bestutxo->payment.value * ordermatchprice; + if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice) < 0 ) + return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); + if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) + return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); + price = LP_query("request",&Q); + if ( price <= maxprice ) + { + bestitem = LP_quotejson(&Q); + price = LP_query("connect",&Q); + LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); + jaddstr(bestitem,"status","connected"); + jaddnum(bestitem,"maxprice",maxprice); + jaddnum(bestitem,"requestid",Q.R.requestid); + jaddnum(bestitem,"quoteid",Q.R.quoteid); + printf("Alice r.%u q.%u\n",Q.R.requestid,Q.R.quoteid); + } else jaddstr(bestitem,"status","too expensive"); + return(jprint(bestitem,0)); } diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index 2f2c39565..19e2adec8 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -1305,4 +1305,121 @@ int32_t bitcoin_coinptrs(bits256 pubkey,struct iguana_info **bobcoinp,struct igu if ( LP_ismine(utxo) > 0 && strcmp(utxo->coin,base) == 0 ) LP_priceping(LP_mypubsock,utxo,rel,price * LP_profitratio); }*/ +/* +bestprice = 0.; +if ( (array= LP_tradecandidates(base)) != 0 ) +{ + printf("candidates.(%s)\nn.%d\n",jprint(array,0),cJSON_GetArraySize(array)); + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + memset(prices,0,sizeof(prices)); + memset(Q,0,sizeof(Q)); + for (i=0; icoin,zero); + Q[i].destsatoshis = price * Q[i].satoshis; + } + if ( (prices[i]= price) > SMALLVAL && (bestprice == 0. || price < bestprice) ) + bestprice = price; + char str[65]; printf("i.%d of %d: (%s) -> txid.%s price %.8f best %.8f dest %.8f\n",i,n,jprint(item,0),bits256_str(str,Q[i].txid),price,bestprice,dstr(Q[i].destsatoshis)); + } + if ( bestprice > SMALLVAL ) + { + bestmetric = 0.; + besti = -1; + for (i=0; i SMALLVAL && myutxo->S.satoshis >= Q[i].destsatoshis+Q[i].desttxfee ) + { + metric = price / bestprice; + printf("%f %f %f %f ",price,metric,dstr(Q[i].destsatoshis),metric * metric * metric); + if ( metric < 1.1 ) + { + metric = dstr(Q[i].destsatoshis) * metric * metric * metric; + printf("%f\n",metric); + if ( bestmetric == 0. || metric < bestmetric ) + { + besti = i; + bestmetric = metric; + } + } + } else printf("(%f %f) ",dstr(myutxo->S.satoshis),dstr(Q[i].destsatoshis)); + } + printf("metrics, best %f\n",bestmetric); +*/ +/*cJSON *LP_tradecandidates(char *base) + { + struct LP_peerinfo *peer,*tmp; struct LP_quoteinfo Q; char *utxostr,coinstr[16]; cJSON *array,*retarray=0,*item; int32_t i,n,totaladded,added; + totaladded = 0; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + printf("%s:%u %s\n",peer->ipaddr,peer->port,base); + n = added = 0; + if ( (utxostr= issue_LP_clientgetutxos(peer->ipaddr,peer->port,base,100)) != 0 ) + { + printf("%s:%u %s %s\n",peer->ipaddr,peer->port,base,utxostr); + if ( (array= cJSON_Parse(utxostr)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + retarray = cJSON_CreateArray(); + for (i=0; i 0 ) + { + memset(&Q,0,sizeof(Q)); + for (i=0; icoin,bits256_str(str,utxo->payment.txid)); + if ( strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && LP_ismine(utxo) > 0 ) + { + if ( utxo->payment.value >= destsatoshis && (bestutxo == 0 || utxo->payment.value < bestutxo->payment.value) ) + bestutxo = utxo; + } + } + return(bestutxo); +} + void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) { cJSON *argjson; struct _LP_utxoinfo u; From 9193a26a1b04817a541cdf17e1c176f811d4901c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 16:05:33 +0300 Subject: [PATCH 1407/2705] Test --- iguana/exchanges/autotrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/autotrade b/iguana/exchanges/autotrade index c24a0a89a..3f0ef6783 100755 --- a/iguana/exchanges/autotrade +++ b/iguana/exchanges/autotrade @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"autotrade\",\"txid\":\"$1\",\"vout\":$2,\"coin\":\"REVS\",\"maxprice\":$3}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"autotrade\",\"base\":\"REVS\",\"rel":\"KMD\",\"volume\":1,\"maxprice\":2.0}" From a5e36a4c7cf08bf7404cf67e47f68404b87d72f3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 16:11:00 +0300 Subject: [PATCH 1408/2705] Test --- iguana/exchanges/autotrade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/autotrade b/iguana/exchanges/autotrade index 3f0ef6783..026a46b56 100755 --- a/iguana/exchanges/autotrade +++ b/iguana/exchanges/autotrade @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"autotrade\",\"base\":\"REVS\",\"rel":\"KMD\",\"volume\":1,\"maxprice\":2.0}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"autotrade\",\"base\":\"REVS\",\"rel\":\"KMD\",\"volume\":1.01,\"maxprice\":1.234}" From 496614940f4b9b920f24b353fa9c630249ac054a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 16:12:55 +0300 Subject: [PATCH 1409/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/autotrade | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a3c70645a..c779e8ae0 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -116,6 +116,8 @@ forwardhex(pubkey,hex)\n\ return(jprint(retjson,1)); } else return(clonestr("{\"error\":\"no price set\"}")); } + else if ( strcmp(method,"autotrade") == 0 ) + return(LP_autotrade(base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"))); } else if ( (coin= jstr(argjson,"coin")) != 0 ) { @@ -148,8 +150,6 @@ forwardhex(pubkey,hex)\n\ return(jprint(retjson,1)); } } - else if ( strcmp(method,"autotrade") == 0 ) - return(LP_autotrade(base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"))); } else if ( strcmp(method,"swapstatus") == 0 ) { diff --git a/iguana/exchanges/autotrade b/iguana/exchanges/autotrade index 026a46b56..371532304 100755 --- a/iguana/exchanges/autotrade +++ b/iguana/exchanges/autotrade @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"autotrade\",\"base\":\"REVS\",\"rel\":\"KMD\",\"volume\":1.01,\"maxprice\":1.234}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"autotrade\",\"base\":\"REVS\",\"rel\":\"KMD\",\"volume\":1.01,\"price\":1.234}" From d1e9e4ccc571a35faf0c32a2dbc06c82b3714407 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 16:31:38 +0300 Subject: [PATCH 1410/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_quotes.c | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c779e8ae0..335cd1bf6 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -168,7 +168,7 @@ forwardhex(pubkey,hex)\n\ if ( strcmp(method,"reserved") == 0 ) retstr = LP_quotereceived(argjson); else if ( strcmp(method,"connected") == 0 ) - retstr = LP_connected(argjson); + retstr = LP_connectedalice(argjson); else if ( strcmp(method,"checktxid") == 0 ) retstr = LP_spentcheck(argjson); else if ( strcmp(method,"getcoins") == 0 ) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 069d63575..b7540b15d 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -264,7 +264,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp) return(price); } -int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) +int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) { char *retstr,pairstr[512],destaddr[64]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; if ( (price= LP_price(base,rel)) > SMALLVAL ) @@ -326,14 +326,15 @@ int32_t LP_connectstart(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson, if ( pair >= 0 ) nn_close(pair); LP_availableset(utxo); - } + } else LP_unavailableset(utxo,utxo->S.otherpubkey); return(retval); } -char *LP_connected(cJSON *argjson) // alice +char *LP_connectedalice(cJSON *argjson) // alice { cJSON *retjson; bits256 spendtxid; int32_t spendvini,selector,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; LP_quoteparse(&Q,argjson); + printf("CONNECTED.(%s)\n",jprint(argjson,0)); if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) { if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) @@ -408,7 +409,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d retjson = LP_quotejson(&Q); utxo->S.otherpubkey = jbits256(argjson,"desthash"); retval |= 2; - LP_unavailableset(utxo,jbits256(argjson,"desthash")); + LP_unavailableset(utxo,utxo->S.otherpubkey); jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); jaddnum(retjson,"pending",utxo->T.swappending); jaddbits256(retjson,"desthash",utxo->S.otherpubkey); @@ -430,7 +431,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d return(0); } if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) - LP_connectstart(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); + LP_connectstartbob(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); else printf("swap %p when connect came in (%s)\n",utxo->S.swap,jprint(argjson,0)); } } @@ -440,7 +441,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d char *LP_autotrade(char *base,char *rel,double maxprice,double volume) { - uint64_t destsatoshis,asatoshis; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; + uint64_t destsatoshis,asatoshis; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) return(clonestr("{\"error\":\"invalid parameter\"}")); destsatoshis = SATOSHIDEN * volume; @@ -507,7 +508,19 @@ char *LP_autotrade(char *base,char *rel,double maxprice,double volume) bestitem = LP_quotejson(&Q); price = LP_query("connect",&Q); LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - jaddstr(bestitem,"status","connected"); + expiration = (uint32_t)time(NULL) + 10; + while ( time(NULL) < expiration ) + { + if ( autxo->S.swap != 0 ) + break; + sleep(1); + } + if ( autxo->S.swap == 0 ) + { + jaddstr(bestitem,"status","couldnt establish connection"); + LP_availableset(autxo); + } + else jaddstr(bestitem,"status","connected"); jaddnum(bestitem,"maxprice",maxprice); jaddnum(bestitem,"requestid",Q.R.requestid); jaddnum(bestitem,"quoteid",Q.R.quoteid); From 83d983914f5b5863257c3774a1f5016517a46b8b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 16:37:19 +0300 Subject: [PATCH 1411/2705] Test --- iguana/exchanges/LP_forwarding.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index e38b3175d..58c8c6932 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -133,6 +133,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) datalen = (int32_t)strlen(hexstr) >> 1; data = malloc(datalen); decode_hex(data,datalen,hexstr); + printf("LP_forwardhex.(%s)\n",(char *)data); if ( (argjson= cJSON_Parse((char *)data)) != 0 ) { reqjson = LP_dereference(argjson,"forward"); @@ -141,7 +142,8 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) LP_send(pubsock,jprint(reqjson,0),1); free_json(reqjson); free_json(argjson); - } + } else printf("LP_forwardhex couldnt parse (%s)\n",(char *)data); + free(data); return(retstr); } else if ( (ptr= LP_forwardfind(pubkey)) != 0 ) @@ -151,7 +153,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) datalen = (int32_t)strlen(hexstr) >> 1; data = malloc(datalen); decode_hex(data,datalen,hexstr); - //printf("forwardhex.(%s)\n",(char *)data); + printf("forwardhex.(%s)\n",(char *)data); sentbytes = LP_send(ptr->pushsock,(char *)data,1); } retjson = cJSON_CreateObject(); From c022f46ca1311f0d3ffd139e68bf2660504c923a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 16:42:05 +0300 Subject: [PATCH 1412/2705] Test --- iguana/exchanges/LP_quotes.c | 1 + iguana/exchanges/run | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index b7540b15d..7f799b6ce 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -377,6 +377,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d char *method,*base,*rel,*retstr; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) { + printf("TRADECOMMAND.(%s)\n",jprint(argjson,0)); retval = 1; txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) diff --git a/iguana/exchanges/run b/iguana/exchanges/run index 40df6ca42..ff014cfd2 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -1,5 +1,5 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; nohup ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, +pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, From f83744e517a15847c54d9664c33432e4f947eb75 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 16:49:30 +0300 Subject: [PATCH 1413/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_quotes.c | 13 +++++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 335cd1bf6..6ddf84009 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -46,7 +46,7 @@ char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) } if ( (method= jstr(argjson,"method")) == 0 ) { - if ( flag == 0 && jobj(argjson,"result") == 0 ) + if ( flag == 0 || jobj(argjson,"result") == 0 ) printf("stats_JSON no method: (%s)\n",jprint(argjson,0)); return(clonestr("{\"error\":\"need method in request\"}")); } diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 58c8c6932..bedf01474 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -133,11 +133,11 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) datalen = (int32_t)strlen(hexstr) >> 1; data = malloc(datalen); decode_hex(data,datalen,hexstr); - printf("LP_forwardhex.(%s)\n",(char *)data); if ( (argjson= cJSON_Parse((char *)data)) != 0 ) { reqjson = LP_dereference(argjson,"forward"); retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); + printf("LP_forwardhex.(%s) -> (%s)\n",jprint(reqjson,0),retstr!=0?retstr:""); if ( pubsock >= 0 ) LP_send(pubsock,jprint(reqjson,0),1); free_json(reqjson); diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 7f799b6ce..c07c8fe93 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -246,9 +246,18 @@ double LP_query(char *method,struct LP_quoteinfo *qp) reqjson = LP_quotejson(qp); if ( bits256_nonz(qp->desthash) != 0 ) flag = 1; - jaddstr(reqjson,"method",method); printf("QUERY.(%s)\n",jprint(reqjson,0)); - LP_forward(qp->srchash,jprint(reqjson,1),1); + if ( IAMLP != 0 ) + { + jaddstr(reqjson,"method",method); + LP_send(LP_mypubsock,jprint(reqjson,1),1); + } + else + { + jaddstr(reqjson,"method2",method); + jaddstr(reqjson,"method","forward"); + LP_forward(qp->srchash,jprint(reqjson,1),1); + } for (i=0; i<30; i++) { if ( (price= LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout)) > SMALLVAL ) From 9c2633ca63aea50364c80a7e54ded041c4fbd6eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 17:02:44 +0300 Subject: [PATCH 1414/2705] Test --- iguana/exchanges/LP_prices.c | 4 ++-- iguana/exchanges/LP_quotes.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 252a5ccd4..8028cb5df 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -553,9 +553,9 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * { //char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); - //if ( polarity > 0 ) + if ( polarity > 0 ) basesatoshis = utxo->payment.value; - //else basesatoshis = utxo->payment.value * price; + else basesatoshis = utxo->payment.value * price; if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey)) != 0 ) (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index c07c8fe93..fb1c431e0 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -166,7 +166,7 @@ char *LP_quotereceived(cJSON *argjson) if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) { ptr->Q = Q; - char str[65]; printf("received.(%s) quote %.8f\n",bits256_str(str,Q.txid),price); + printf("\n>>>>>>>>>> received.(%s) quote %.8f\n\n",jprint(argjson,0),price); return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); } @@ -276,6 +276,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp) int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) { char *retstr,pairstr[512],destaddr[64]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; + printf("LP_connectstartbob with.(%s)\n",jprint(argjson,0)); if ( (price= LP_price(base,rel)) > SMALLVAL ) { price *= (1. + profitmargin); @@ -283,7 +284,6 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs return(-1); if ( LP_quoteparse(&Q,argjson) < 0 ) return(-2); - printf("connect with.(%s)\n",jprint(argjson,0)); Q.destsatoshis = Q.satoshis * price; privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->S.mypub) == 0 ) From 2036c3af32584b334e91eb61a5156efb060809f5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 17:17:14 +0300 Subject: [PATCH 1415/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6ddf84009..f56fd27fe 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -46,7 +46,7 @@ char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) } if ( (method= jstr(argjson,"method")) == 0 ) { - if ( flag == 0 || jobj(argjson,"result") == 0 ) + if ( flag == 0 || jobj(argjson,"result") != 0 ) printf("stats_JSON no method: (%s)\n",jprint(argjson,0)); return(clonestr("{\"error\":\"need method in request\"}")); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c368b6b7a..ce5d8a2a6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -114,11 +114,13 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double portable_mutex_lock(&LP_commandmutex); if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) { + printf("got forwardhex\n"); if ( (retstr= LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) free(retstr); } else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) { + printf("got publish\n"); if ( jobj(argjson,"method2") != 0 ) jdelete(argjson,"method2"); jaddstr(argjson,"method2","broadcast"); @@ -138,16 +140,16 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double return(nonz); } -int32_t LP_subsock_check(struct LP_peerinfo *peer) +int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double profitmargin) { int32_t recvsize,nonz = 0; char *retstr; void *ptr; cJSON *argjson; - while ( peer->subsock >= 0 && (recvsize= nn_recv(peer->subsock,&ptr,NN_MSG,0)) >= 0 ) + while ( sock >= 0 && (recvsize= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { portable_mutex_lock(&LP_commandmutex); - if ( (retstr= stats_JSON(-1,argjson,"127.0.0.1",0)) != 0 ) + if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,0,0,profitmargin)) != 0 ) { //printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); @@ -236,7 +238,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - nonz += LP_subsock_check(peer); + nonz += LP_subsock_check(myipaddr,pubsock,peer->pushsock,profitmargin); if ( peer->diduquery == 0 ) { LP_peer_utxosquery(mypeer,myport,pubsock,peer,now,profitmargin,60); From 4796029a6b0b0065b2ca9acbd1715403a2e25b5b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 17:23:02 +0300 Subject: [PATCH 1416/2705] Test --- iguana/exchanges/LP_forwarding.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index bedf01474..d5351f267 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -170,7 +170,12 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) jaddnum(retjson,"datalen",datalen); return(jprint(retjson,1)); } - } else return(clonestr("{\"error\":\"notfound\"}")); + } + else + { + char str[65]; printf("couldnt find %s to forward to\n",bits256_str(str,pubkey)); + return(clonestr("{\"error\":\"notfound\"}")); + } printf("couldnt find pubkey\n"); } From 1d25085708a68358e4ed88425faaecb991c853fe Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 17:29:23 +0300 Subject: [PATCH 1417/2705] Test --- iguana/exchanges/LP_forwarding.c | 39 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index d5351f267..2e93f9126 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -125,58 +125,59 @@ cJSON *LP_dereference(cJSON *argjson,char *excludemethod) char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) { - struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *retstr=0; cJSON *retjson,*argjson,*reqjson; + struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *retstr=0; cJSON *retjson=0,*argjson=0,*reqjson=0; if ( hexstr == 0 || hexstr[0] == 0 ) return(clonestr("{\"error\":\"nohex\"}")); + datalen = (int32_t)strlen(hexstr) >> 1; + data = malloc(datalen); + decode_hex(data,datalen,hexstr); + if ( (argjson= cJSON_Parse((char *)data)) != 0 ) + reqjson = LP_dereference(argjson,"forward"); if ( bits256_nonz(pubkey) == 0 || bits256_cmp(pubkey,LP_mypubkey) == 0 ) { - datalen = (int32_t)strlen(hexstr) >> 1; - data = malloc(datalen); - decode_hex(data,datalen,hexstr); - if ( (argjson= cJSON_Parse((char *)data)) != 0 ) + if ( reqjson != 0 ) { - reqjson = LP_dereference(argjson,"forward"); retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); printf("LP_forwardhex.(%s) -> (%s)\n",jprint(reqjson,0),retstr!=0?retstr:""); if ( pubsock >= 0 ) - LP_send(pubsock,jprint(reqjson,0),1); - free_json(reqjson); - free_json(argjson); + LP_send(pubsock,jprint(reqjson,0),0); } else printf("LP_forwardhex couldnt parse (%s)\n",(char *)data); - free(data); - return(retstr); } else if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { if ( ptr->pushsock >= 0 ) { - datalen = (int32_t)strlen(hexstr) >> 1; - data = malloc(datalen); - decode_hex(data,datalen,hexstr); printf("forwardhex.(%s)\n",(char *)data); - sentbytes = LP_send(ptr->pushsock,(char *)data,1); + sentbytes = LP_send(ptr->pushsock,(char *)data,0); } retjson = cJSON_CreateObject(); if ( sentbytes == datalen ) { jaddstr(retjson,"result","success"); jaddnum(retjson,"forwarded",sentbytes); - return(jprint(retjson,1)); + retstr = jprint(retjson,1); } else { jaddstr(retjson,"error","send error"); jaddnum(retjson,"sentbytes",sentbytes); jaddnum(retjson,"datalen",datalen); - return(jprint(retjson,1)); + retstr = jprint(retjson,1); } } else { char str[65]; printf("couldnt find %s to forward to\n",bits256_str(str,pubkey)); - return(clonestr("{\"error\":\"notfound\"}")); + if ( pubsock >= 0 ) + LP_send(pubsock,jprint(reqjson,0),0); + retstr = clonestr("{\"error\":\"notfound\"}"); } - printf("couldnt find pubkey\n"); + free(data); + if ( reqjson != 0 ) + free_json(reqjson); + if ( argjson != 0 ) + free_json(argjson); + return(retstr); } int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) From 4b96701acad4572d1c25abf059fd5830d55ba3ad Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 17:37:18 +0300 Subject: [PATCH 1418/2705] Test --- iguana/exchanges/LP_forwarding.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 2e93f9126..e8a033252 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -147,7 +147,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) { if ( ptr->pushsock >= 0 ) { - printf("forwardhex.(%s)\n",(char *)data); + printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data); sentbytes = LP_send(ptr->pushsock,(char *)data,0); } retjson = cJSON_CreateObject(); @@ -209,7 +209,7 @@ int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) } else retval = 0; if ( retval == 0 && peer->pushsock >= 0 ) { - printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); + //printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); len = (int32_t)strlen(jsonstr) + 1; hexstr = malloc(len*2 + 1); init_hexbytes_noT(hexstr,(uint8_t *)jsonstr,len); From 18b5c793b013837f7fc56d3ac527a0593a85009e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 20:06:51 +0300 Subject: [PATCH 1419/2705] Test --- iguana/exchanges/DEXstats.h | 2 +- iguana/exchanges/LP_commands.c | 8 ++++---- iguana/exchanges/LP_forwarding.c | 19 +++++++++++++++---- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_quotes.c | 18 +++++++++--------- iguana/exchanges/mm.c | 2 +- iguana/exchanges/stats.c | 7 +++---- 8 files changed, 35 insertions(+), 25 deletions(-) diff --git a/iguana/exchanges/DEXstats.h b/iguana/exchanges/DEXstats.h index 6982cb64d..dec43b0cc 100644 --- a/iguana/exchanges/DEXstats.h +++ b/iguana/exchanges/DEXstats.h @@ -927,7 +927,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t } #ifndef FROM_MARKETMAKER -char *stats_JSON(cJSON *argjson,char *remoteaddr,uint16_t port) +char *stats_JSON(char *myipaddr,int32_t mypubsock,double profitmargin,cJSON *argjson,char *remoteaddr,uint16_t port) { char *method,*agent,*retstr,*source,*dest; struct tai T; uint32_t endtimestamp; struct DEXstats_disp prices[365]; int32_t leftdatenum,seconds,numdates; if ( (method= jstr(argjson,"method")) == 0 ) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index f56fd27fe..9a1275fbc 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -19,7 +19,7 @@ // -char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port +char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos,flag = 0; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) @@ -100,7 +100,7 @@ forwardhex(pubkey,hex)\n\ { if ( LP_mypriceset(base,rel,price) < 0 ) return(clonestr("{\"error\":\"couldnt set price\"}")); - else return(LP_pricepings(LP_mypubsock,base,rel,price * LP_profitratio)); + else return(LP_pricepings(myipaddr,LP_mypubsock,profitmargin,base,rel,price * LP_profitratio)); } else return(clonestr("{\"error\":\"no price\"}")); } else if ( strcmp(method,"myprice") == 0 ) @@ -117,7 +117,7 @@ forwardhex(pubkey,hex)\n\ } else return(clonestr("{\"error\":\"no price set\"}")); } else if ( strcmp(method,"autotrade") == 0 ) - return(LP_autotrade(base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"))); + return(LP_autotrade(myipaddr,pubsock,profitmargin,base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"))); } else if ( (coin= jstr(argjson,"coin")) != 0 ) { @@ -189,7 +189,7 @@ forwardhex(pubkey,hex)\n\ printf("FORWARDED.(%s)\n",jprint(argjson,0)); if ( (reqjson= LP_dereference(argjson,"forward")) != 0 ) { - if ( LP_forward(jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) + if ( LP_forward(myipaddr,pubsock,profitmargin,jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) retstr = clonestr("{\"result\":\"success\"}"); else retstr = clonestr("{\"error\":\"error forwarding\"}"); } else retstr = clonestr("{\"error\":\"cant recurse forwards\"}"); diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index e8a033252..0009e2b8a 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -180,14 +180,25 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) return(retstr); } -int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) +int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pubkey,char *jsonstr,int32_t freeflag) { - struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson,*reqjson; + struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson,*reqjson,*argjson; if ( jsonstr == 0 || jsonstr[0] == 0 ) return(-1); if ( bits256_nonz(pubkey) != 0 ) { - if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) + if ( bits256_cmp(pubkey,LP_mypubkey) == 0 ) + { + printf("GOT FORWARDED.(%s)\n",jsonstr); + if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) + { + if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,0,0,profitmargin)) != 0 ) + free(retstr); + free_json(argjson); + } + return(1); + } + else if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) { return(LP_send(ptr->pushsock,jsonstr,1)); } @@ -207,7 +218,7 @@ int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag) free(retstr); } } else retval = 0; - if ( retval == 0 && peer->pushsock >= 0 ) + if ( retval >= 0 && peer->pushsock >= 0 ) { //printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); len = (int32_t)strlen(jsonstr) + 1; diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 7b4bd45aa..86ef0c345 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -221,7 +221,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 //double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); void LP_quotesinit(char *base,char *rel); -int32_t LP_forward(bits256 pubkey,char *jsonstr,int32_t freeflag); +int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pubkey,char *jsonstr,int32_t freeflag); int32_t LP_ismine(struct LP_utxoinfo *utxo); int32_t LP_isavailable(struct LP_utxoinfo *utxo); struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ce5d8a2a6..8ffea2f99 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -84,7 +84,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * char *retstr=0; if ( LP_tradecommand(myipaddr,pubsock,argjson,data,datalen,profitmargin) <= 0 ) { - if ( (retstr= stats_JSON(pubsock,argjson,"127.0.0.1",0)) != 0 ) + if ( (retstr= stats_JSON(myipaddr,pubsock,profitmargin,argjson,"127.0.0.1",0)) != 0 ) { printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); if ( pubsock >= 0 ) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index fb1c431e0..758a83a07 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -171,7 +171,7 @@ char *LP_quotereceived(cJSON *argjson) } else return(clonestr("{\"error\":\"nullptr\"}")); } -char *LP_pricepings(int32_t pubsock,char *base,char *rel,double price) +char *LP_pricepings(char *myipaddr,int32_t pubsock,double profitmargin,char *base,char *rel,double price) { bits256 zero; cJSON *reqjson = cJSON_CreateObject(); jaddbits256(reqjson,"pubkey",LP_mypubkey); @@ -189,7 +189,7 @@ char *LP_pricepings(int32_t pubsock,char *base,char *rel,double price) jaddstr(reqjson,"method","forward"); jaddstr(reqjson,"method2","postprice"); memset(zero.bytes,0,sizeof(zero)); - LP_forward(zero,jprint(reqjson,1),1); + LP_forward(myipaddr,pubsock,profitmargin,zero,jprint(reqjson,1),1); } return(clonestr("{\"result\":\"success\"}")); } @@ -229,7 +229,7 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) return(-1); } -double LP_query(char *method,struct LP_quoteinfo *qp) +double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *method,struct LP_quoteinfo *qp) { cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; if ( strcmp(method,"request") == 0 ) @@ -256,7 +256,7 @@ double LP_query(char *method,struct LP_quoteinfo *qp) { jaddstr(reqjson,"method2",method); jaddstr(reqjson,"method","forward"); - LP_forward(qp->srchash,jprint(reqjson,1),1); + LP_forward(myipaddr,mypubsock,profitmargin,qp->srchash,jprint(reqjson,1),1); } for (i=0; i<30; i++) { @@ -320,7 +320,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs retstr = jprint(retjson,1); if ( pubsock >= 0 ) LP_send(pubsock,retstr,1); - else LP_forward(utxo->S.otherpubkey,retstr,1); + else LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); retval = 0; } else printf("error launching swaploop\n"); } else printf("printf error nn_connect to %s\n",pairstr); @@ -427,7 +427,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d retstr = jprint(retjson,1); if ( pubsock >= 0 ) LP_send(pubsock,retstr,1); - else LP_forward(utxo->S.otherpubkey,retstr,1); + else LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); utxo->T.lasttime = (uint32_t)time(NULL); } else printf("null price\n"); } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); @@ -449,7 +449,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d return(retval); } -char *LP_autotrade(char *base,char *rel,double maxprice,double volume) +char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume) { uint64_t destsatoshis,asatoshis; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) @@ -512,11 +512,11 @@ char *LP_autotrade(char *base,char *rel,double maxprice,double volume) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); - price = LP_query("request",&Q); + price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); if ( price <= maxprice ) { bestitem = LP_quotejson(&Q); - price = LP_query("connect",&Q); + price = LP_query(myipaddr,mypubsock,profitmargin,"connect",&Q); LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); expiration = (uint32_t)time(NULL) + 10; while ( time(NULL) < expiration ) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 41bbd2e2e..05b95a9a8 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -24,7 +24,7 @@ #include #include "OS_portable.h" #define MAX(a,b) ((a) > (b) ? (a) : (b)) -char *stats_JSON(int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port); +char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjson,char *remoteaddr,uint16_t port); #include "stats.c" void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]); diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index 06d1cfeb7..b0b4b11d8 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -304,8 +304,7 @@ cJSON *SuperNET_urlconv(char *value,int32_t bufsize,char *urlstr) char *stats_rpcparse(char *retbuf,int32_t bufsize,int32_t *jsonflagp,int32_t *postflagp,char *urlstr,char *remoteaddr,char *filetype,uint16_t port) { - cJSON *tokens,*argjson,*origargjson,*tmpjson=0,*json = 0; long filesize; - char symbol[64],buf[4096],*userpass=0,urlmethod[16],*data,url[8192],furl[8192],*retstr,*filestr,*token = 0; int32_t i,j,n,num=0; + cJSON *tokens,*argjson,*origargjson,*tmpjson=0,*json = 0; long filesize; double profitmargin = 0.; char *myipaddr="127.0.0.1",symbol[64],buf[4096],*userpass=0,urlmethod[16],*data,url[8192],furl[8192],*retstr,*filestr,*token = 0; int32_t i,j,n,num=0; //printf("rpcparse.(%s)\n",urlstr); for (i=0; i Date: Thu, 15 Jun 2017 20:14:00 +0300 Subject: [PATCH 1420/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_quotes.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9a1275fbc..b0c387750 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -186,9 +186,9 @@ forwardhex(pubkey,hex)\n\ else if ( strcmp(method,"forward") == 0 ) { cJSON *reqjson; - printf("FORWARDED.(%s)\n",jprint(argjson,0)); if ( (reqjson= LP_dereference(argjson,"forward")) != 0 ) { + printf("FORWARDED.(%s)\n",jprint(argjson,0)); if ( LP_forward(myipaddr,pubsock,profitmargin,jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) retstr = clonestr("{\"result\":\"success\"}"); else retstr = clonestr("{\"error\":\"error forwarding\"}"); diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 758a83a07..288d11741 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -256,6 +256,7 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho { jaddstr(reqjson,"method2",method); jaddstr(reqjson,"method","forward"); + jaddbits256(reqjson,"pubkey",qp->srchash); LP_forward(myipaddr,mypubsock,profitmargin,qp->srchash,jprint(reqjson,1),1); } for (i=0; i<30; i++) From 85acaa8dbac25edc943bb777d4c79c1bfee16cd0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 20:21:00 +0300 Subject: [PATCH 1421/2705] Test --- iguana/exchanges/LP_quotes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 288d11741..0e72ff9ec 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -417,6 +417,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d return(-1); } Q.timestamp = (uint32_t)time(NULL); + utxo->T.swappending = Q.timestamp + LP_RESERVETIME; retjson = LP_quotejson(&Q); utxo->S.otherpubkey = jbits256(argjson,"desthash"); retval |= 2; @@ -443,7 +444,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d } if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) LP_connectstartbob(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); - else printf("swap %p when connect came in (%s)\n",utxo->S.swap,jprint(argjson,0)); + else printf("pend.%u swap %p when connect came in (%s)\n",utxo->T.swappending,utxo->S.swap,jprint(argjson,0)); } } } From fe6eca375d2b261fbd70c714d0bc39c5259aab5b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 20:22:41 +0300 Subject: [PATCH 1422/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_forwarding.c | 6 +++--- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_quotes.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index b0c387750..88317a3c7 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -188,7 +188,7 @@ forwardhex(pubkey,hex)\n\ cJSON *reqjson; if ( (reqjson= LP_dereference(argjson,"forward")) != 0 ) { - printf("FORWARDED.(%s)\n",jprint(argjson,0)); + //printf("FORWARDED.(%s)\n",jprint(argjson,0)); if ( LP_forward(myipaddr,pubsock,profitmargin,jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) retstr = clonestr("{\"result\":\"success\"}"); else retstr = clonestr("{\"error\":\"error forwarding\"}"); diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 0009e2b8a..f29af26f5 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -138,7 +138,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) if ( reqjson != 0 ) { retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); - printf("LP_forwardhex.(%s) -> (%s)\n",jprint(reqjson,0),retstr!=0?retstr:""); + //printf("LP_forwardhex.(%s) -> (%s)\n",jprint(reqjson,0),retstr!=0?retstr:""); if ( pubsock >= 0 ) LP_send(pubsock,jprint(reqjson,0),0); } else printf("LP_forwardhex couldnt parse (%s)\n",(char *)data); @@ -147,7 +147,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) { if ( ptr->pushsock >= 0 ) { - printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data); + //printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data); sentbytes = LP_send(ptr->pushsock,(char *)data,0); } retjson = cJSON_CreateObject(); @@ -189,7 +189,7 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu { if ( bits256_cmp(pubkey,LP_mypubkey) == 0 ) { - printf("GOT FORWARDED.(%s)\n",jsonstr); + //printf("GOT FORWARDED.(%s)\n",jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,0,0,profitmargin)) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 8ffea2f99..c202dcae8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -86,7 +86,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * { if ( (retstr= stats_JSON(myipaddr,pubsock,profitmargin,argjson,"127.0.0.1",0)) != 0 ) { - printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); + //printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); if ( pubsock >= 0 ) LP_send(pubsock,retstr,0); } @@ -114,7 +114,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double portable_mutex_lock(&LP_commandmutex); if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) { - printf("got forwardhex\n"); + //printf("got forwardhex\n"); if ( (retstr= LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) free(retstr); } diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 0e72ff9ec..eb8830ef1 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -387,7 +387,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d char *method,*base,*rel,*retstr; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) { - printf("TRADECOMMAND.(%s)\n",jprint(argjson,0)); + //printf("TRADECOMMAND.(%s)\n",jprint(argjson,0)); retval = 1; txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) From 42cd2b60ea45553b0e04b1b07a9f7b2f9e77006e Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 20:26:48 +0300 Subject: [PATCH 1423/2705] Test --- iguana/exchanges/LP_quotes.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index eb8830ef1..02d2e54a9 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -392,7 +392,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d txid = jbits256(argjson,"txid"); if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { - printf("LP_tradecommand.(%s)\n",jprint(argjson,0)); + printf("pend.%u LP_tradecommand.(%s)\n",utxo->T.swappending,jprint(argjson,0)); if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) { char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); @@ -425,12 +425,14 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); jaddnum(retjson,"pending",utxo->T.swappending); jaddbits256(retjson,"desthash",utxo->S.otherpubkey); + jaddbits256(retjson,"pubkey",utxo->S.otherpubkey); jaddstr(retjson,"method","reserved"); retstr = jprint(retjson,1); if ( pubsock >= 0 ) LP_send(pubsock,retstr,1); else LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); utxo->T.lasttime = (uint32_t)time(NULL); + printf("set swappending.%u\n",utxo->T.swappending); } else printf("null price\n"); } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); } From 5fed6f8081489a5d58bfad9fc7ea3642b048e278 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 20:36:56 +0300 Subject: [PATCH 1424/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_quotes.c | 15 +++++++++------ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 88317a3c7..55f4ef46f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -58,7 +58,7 @@ myprice(base, rel)\n\ enable(coin)\n\ disable(coin)\n\ inventory(coin)\n\ -autotrade(base, rel, price, volume)\n\ +autotrade(base, rel, price, volume, timeout)\n\ swapstatus()\n\ swapstatus(requestid, quoteid)\n\ public API:\n \ @@ -117,7 +117,7 @@ forwardhex(pubkey,hex)\n\ } else return(clonestr("{\"error\":\"no price set\"}")); } else if ( strcmp(method,"autotrade") == 0 ) - return(LP_autotrade(myipaddr,pubsock,profitmargin,base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"))); + return(LP_autotrade(myipaddr,pubsock,profitmargin,base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"),jint(argjson,"timeout"))); } else if ( (coin= jstr(argjson,"coin")) != 0 ) { diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 86ef0c345..0a491d82e 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -23,6 +23,7 @@ #define LP_HTTP_TIMEOUT 1 #define LP_MAXPEER_ERRORS 3 +#define LP_AUTOTRADE_TIMEOUT 3 #define LP_DEXFEE(destsatoshis) ((destsatoshis) / INSTANTDEX_INSURANCEDIV) #define LP_DEPOSITSATOSHIS(satoshis) ((satoshis) + (satoshis >> 3)) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 02d2e54a9..c4c3826ff 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -319,9 +319,10 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs jaddnum(retjson,"requestid",Q.R.requestid); jaddnum(retjson,"quoteid",Q.R.quoteid); retstr = jprint(retjson,1); + printf("BOB sends back.(%s)\n",retstr); if ( pubsock >= 0 ) - LP_send(pubsock,retstr,1); - else LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); + LP_send(pubsock,retstr,0); + LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); retval = 0; } else printf("error launching swaploop\n"); } else printf("printf error nn_connect to %s\n",pairstr); @@ -429,8 +430,8 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d jaddstr(retjson,"method","reserved"); retstr = jprint(retjson,1); if ( pubsock >= 0 ) - LP_send(pubsock,retstr,1); - else LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); + LP_send(pubsock,retstr,0); + LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); utxo->T.lasttime = (uint32_t)time(NULL); printf("set swappending.%u\n",utxo->T.swappending); } else printf("null price\n"); @@ -453,7 +454,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d return(retval); } -char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume) +char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume,int32_t timeout) { uint64_t destsatoshis,asatoshis; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) @@ -462,6 +463,8 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba if ( (autxo= LP_utxo_bestfit(rel,destsatoshis)) == 0 ) return(clonestr("{\"error\":\"cant find utxo that is big enough\"}")); bestmetric = ordermatchprice = 0.; + if ( timeout == 0 ) + timeout = LP_AUTOTRADE_TIMEOUT; if ( (obookstr= LP_orderbook(base,rel)) != 0 ) { if ( (orderbook= cJSON_Parse(obookstr)) != 0 ) @@ -522,7 +525,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba bestitem = LP_quotejson(&Q); price = LP_query(myipaddr,mypubsock,profitmargin,"connect",&Q); LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - expiration = (uint32_t)time(NULL) + 10; + expiration = (uint32_t)time(NULL) + timeout; while ( time(NULL) < expiration ) { if ( autxo->S.swap != 0 ) From c6a48858249122602e7701cc966bcc7cb22b6ab9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 20:45:07 +0300 Subject: [PATCH 1425/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- iguana/exchanges/LP_utxos.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index c4c3826ff..502e0cd8f 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -319,7 +319,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs jaddnum(retjson,"requestid",Q.R.requestid); jaddnum(retjson,"quoteid",Q.R.quoteid); retstr = jprint(retjson,1); - printf("BOB sends back.(%s)\n",retstr); + char str[65]; printf("BOB pubsock.%d sends back.(%s) to (%s)\n",pubsock,retstr,bits256_str(str,utxo->S.otherpubkey)); if ( pubsock >= 0 ) LP_send(pubsock,retstr,0); LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 9e5be5bc5..1febfa78b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -140,27 +140,28 @@ void _LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) void LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) { - struct LP_utxoinfo *ptrs[8]; int32_t i,n; + struct LP_utxoinfo *ptrs[8]; int32_t i,n; struct _LP_utxoinfo u; memset(ptrs,0,sizeof(ptrs)); if ( (n= LP_utxocollisions(ptrs,utxo)) > 0 ) { for (i=0; ipayment.txid),utxo->payment.vout,n); + char str[65],str2[65]; printf("UTXO.[%d] RESERVED %s/v%d %s/v%d collisions.%d\n",utxo->iambob,bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,u.txid),u.vout,n); _LP_unavailableset(utxo,otherpubkey); } void LP_availableset(struct LP_utxoinfo *utxo) { - struct LP_utxoinfo *ptrs[8]; int32_t i,n; + struct LP_utxoinfo *ptrs[8]; int32_t i,n; struct _LP_utxoinfo u; memset(ptrs,0,sizeof(ptrs)); if ( (n= LP_utxocollisions(ptrs,utxo)) > 0 ) { for (i=0; ipayment.txid),utxo->payment.vout,n); + u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; + char str[65],str2[65]; printf("UTXO.[%d] AVAIL %s/v%d %s/v%d collisions.%d\n",utxo->iambob,bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,u.txid),u.vout,n); _LP_availableset(utxo); } From 59a85be27b820204f0d9ef0948d5611350d5fc02 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 20:52:18 +0300 Subject: [PATCH 1426/2705] Test --- iguana/exchanges/LP_forwarding.c | 3 ++- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index f29af26f5..fb49bf4be 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -200,6 +200,7 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu } else if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) { + printf("GOT FORWARDED.(%s)\n",jsonstr); return(LP_send(ptr->pushsock,jsonstr,1)); } } @@ -220,7 +221,7 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu } else retval = 0; if ( retval >= 0 && peer->pushsock >= 0 ) { - //printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); + printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); len = (int32_t)strlen(jsonstr) + 1; hexstr = malloc(len*2 + 1); init_hexbytes_noT(hexstr,(uint8_t *)jsonstr,len); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c202dcae8..646ee24a1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -148,10 +148,10 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { + printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); portable_mutex_lock(&LP_commandmutex); if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,0,0,profitmargin)) != 0 ) { - //printf("%s SUB.[%d] %s\n",peer->ipaddr,recvsize,(char *)ptr); free(retstr); } portable_mutex_unlock(&LP_commandmutex); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 1febfa78b..579be508a 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -147,6 +147,7 @@ void LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) for (i=0; iiambob != 0) ? utxo->deposit : utxo->fee; char str[65],str2[65]; printf("UTXO.[%d] RESERVED %s/v%d %s/v%d collisions.%d\n",utxo->iambob,bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,u.txid),u.vout,n); _LP_unavailableset(utxo,otherpubkey); } From 1c4f79980d1071127ba5efc01df0213937204186 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 21:01:52 +0300 Subject: [PATCH 1427/2705] Test --- iguana/exchanges/LP_quotes.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 502e0cd8f..1e06a4935 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -318,11 +318,13 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs jaddstr(retjson,"pair",pairstr); jaddnum(retjson,"requestid",Q.R.requestid); jaddnum(retjson,"quoteid",Q.R.quoteid); - retstr = jprint(retjson,1); - char str[65]; printf("BOB pubsock.%d sends back.(%s) to (%s)\n",pubsock,retstr,bits256_str(str,utxo->S.otherpubkey)); + char str[65]; printf("BOB pubsock.%d sends to (%s)\n",pubsock,bits256_str(str,utxo->S.otherpubkey)); if ( pubsock >= 0 ) - LP_send(pubsock,retstr,0); - LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); + LP_send(pubsock,jprint(retjson,0),1); + jdelete(retjson,"method"); + jaddstr(retjson,"method2","connected"); + jaddstr(retjson,"method","forward"); + LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,jprint(retjson,1),1); retval = 0; } else printf("error launching swaploop\n"); } else printf("printf error nn_connect to %s\n",pairstr); @@ -428,10 +430,12 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d jaddbits256(retjson,"desthash",utxo->S.otherpubkey); jaddbits256(retjson,"pubkey",utxo->S.otherpubkey); jaddstr(retjson,"method","reserved"); - retstr = jprint(retjson,1); if ( pubsock >= 0 ) - LP_send(pubsock,retstr,0); - LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,retstr,1); + LP_send(pubsock,jprint(retjson,0),1); + jdelete(retjson,"method"); + jaddstr(retjson,"method2","reserved"); + jaddstr(retjson,"method","forward"); + LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,jprint(retjson,1),1); utxo->T.lasttime = (uint32_t)time(NULL); printf("set swappending.%u\n",utxo->T.swappending); } else printf("null price\n"); From b7a478c0180b8c2b9955b823a03621d7d8039227 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 21:18:02 +0300 Subject: [PATCH 1428/2705] Test --- iguana/exchanges/LP_include.h | 4 ++-- iguana/exchanges/LP_quotes.c | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 0a491d82e..f13975b53 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -38,8 +38,8 @@ #define INSTANTDEX_BTC "1KRhTPvoxyJmVALwHFXZdeeWFbcJSbkFPu" #define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" -//#define BASILISK_DISABLEWAITTX -//#define BASILISK_DISABLESENDTX +#define BASILISK_DISABLEWAITTX +#define BASILISK_DISABLESENDTX #define LP_PROPAGATION_SLACK 100 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 1e06a4935..27973be58 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -276,8 +276,8 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) { - char *retstr,pairstr[512],destaddr[64]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; - printf("LP_connectstartbob with.(%s)\n",jprint(argjson,0)); + char pairstr[512],destaddr[64]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; + //printf("LP_connectstartbob with.(%s)\n",jprint(argjson,0)); if ( (price= LP_price(base,rel)) > SMALLVAL ) { price *= (1. + profitmargin); @@ -387,7 +387,7 @@ char *LP_connectedalice(cJSON *argjson) // alice int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel,*retstr; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; + char *method,*base,*rel; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) { //printf("TRADECOMMAND.(%s)\n",jprint(argjson,0)); @@ -437,7 +437,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d jaddstr(retjson,"method","forward"); LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,jprint(retjson,1),1); utxo->T.lasttime = (uint32_t)time(NULL); - printf("set swappending.%u\n",utxo->T.swappending); + //printf("set swappending.%u\n",utxo->T.swappending); } else printf("null price\n"); } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); } @@ -523,6 +523,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); + LP_unavailableset(autxo,bestutxo->pubkey); price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); if ( price <= maxprice ) { From 5e48b0bce77bc04db6d1daddf1b338ae77ec7bd0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 21:31:30 +0300 Subject: [PATCH 1429/2705] Test --- iguana/exchanges/LP_quotes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 27973be58..f52b7faf7 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -181,7 +181,7 @@ char *LP_pricepings(char *myipaddr,int32_t pubsock,double profitmargin,char *bas if ( pubsock >= 0 ) { jaddstr(reqjson,"method","postprice"); - printf("pricepings.(%s)\n",jprint(reqjson,0)); + printf("%d pricepings.(%s)\n",pubsock,jprint(reqjson,0)); LP_send(pubsock,jprint(reqjson,1),1); } else @@ -197,7 +197,7 @@ char *LP_pricepings(char *myipaddr,int32_t pubsock,double profitmargin,char *bas char *LP_postedprice(cJSON *argjson) { bits256 pubkey; double price; char *base,*rel; - //printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); + printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && (price= jdouble(argjson,"price")) > SMALLVAL ) { pubkey = jbits256(argjson,"pubkey"); From 18848a17ff27064b258422410fa6b8b37f842f80 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 21:34:22 +0300 Subject: [PATCH 1430/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 646ee24a1..c04ff7d9e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -238,7 +238,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - nonz += LP_subsock_check(myipaddr,pubsock,peer->pushsock,profitmargin); + nonz += LP_subsock_check(myipaddr,pubsock,peer->subsock,profitmargin); if ( peer->diduquery == 0 ) { LP_peer_utxosquery(mypeer,myport,pubsock,peer,now,profitmargin,60); From 2fd602efa58169185c112cde0bc5e974e937ccc5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 21:36:51 +0300 Subject: [PATCH 1431/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c04ff7d9e..8ffae6f3f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -82,6 +82,8 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *retstr=0; + if ( jobj(argjson,"result") != 0 || jobj(argjson,"error") != 0 ) + return(0); if ( LP_tradecommand(myipaddr,pubsock,argjson,data,datalen,profitmargin) <= 0 ) { if ( (retstr= stats_JSON(myipaddr,pubsock,profitmargin,argjson,"127.0.0.1",0)) != 0 ) From bd991ac1dcd6986fef9740a28a25253b7c158ef0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 21:43:57 +0300 Subject: [PATCH 1432/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 8ffae6f3f..334d0c0a4 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -89,7 +89,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * if ( (retstr= stats_JSON(myipaddr,pubsock,profitmargin,argjson,"127.0.0.1",0)) != 0 ) { //printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); - if ( pubsock >= 0 ) + if ( pubsock >= 0 ) //strncmp("{\"error\":",retstr,strlen("{\"error\":")) != 0 && LP_send(pubsock,retstr,0); } } @@ -152,7 +152,7 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof { printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); portable_mutex_lock(&LP_commandmutex); - if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,0,0,profitmargin)) != 0 ) + if ( (retstr= LP_command_process(myipaddr,-1,argjson,0,0,profitmargin)) != 0 ) { free(retstr); } From 00b8a949f832a076f17eabbf3ee2addaa57acedc Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 21:48:54 +0300 Subject: [PATCH 1433/2705] Test --- iguana/exchanges/LP_quotes.c | 1 - 1 file changed, 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index f52b7faf7..02b0ae7f8 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -523,7 +523,6 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); - LP_unavailableset(autxo,bestutxo->pubkey); price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); if ( price <= maxprice ) { From fb75b100e0829bbab482a6879fd2a96cb5d52fbb Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:02:41 +0300 Subject: [PATCH 1434/2705] Test --- iguana/exchanges/LP_forwarding.c | 6 ++++-- iguana/exchanges/LP_network.c | 10 ++++++---- iguana/exchanges/LP_quotes.c | 21 +++++++++++++++------ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index fb49bf4be..6842f2dd8 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -200,8 +200,10 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu } else if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 && ptr->lasttime > time(NULL)-LP_KEEPALIVE ) { - printf("GOT FORWARDED.(%s)\n",jsonstr); - return(LP_send(ptr->pushsock,jsonstr,1)); + printf("GOT FORWARDED.(%s) -> pushsock.%d\n",jsonstr,ptr->pushsock); + len = (int32_t)strlen(jsonstr); + if ( LP_send(ptr->pushsock,jsonstr,1) == len+1 ) + return(1); } } HASH_ITER(hh,LP_peerinfos,peer,tmp) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index f014e3095..4632f4f04 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -34,13 +34,13 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) free(msg); return(-1); } - for (i=0; i<100; i++) + len = (int32_t)strlen(msg) + 1; + for (i=0; i<1000; i++) { pfd.fd = sock; pfd.events = NN_POLLOUT; if ( nn_poll(&pfd,1,100) > 0 ) { - len = (int32_t)strlen(msg) + 1; if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); //else printf("SENT.(%s)\n",msg); @@ -50,10 +50,12 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) } usleep(1000); } - printf("error LP_send\n"); + printf("error LP_send, pipeline timeout\n"); + if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) + printf("LP_send sent %d instead of %d\n",sentbytes,len); if ( freeflag != 0 ) free(msg); - return(-1); + return(sentbytes); } uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits,uint32_t crcs[2]) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 02b0ae7f8..4918dff3b 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -276,11 +276,12 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) { - char pairstr[512],destaddr[64]; cJSON *retjson; double price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; + char pairstr[512],destaddr[64]; cJSON *retjson; double bid,ask,price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; //printf("LP_connectstartbob with.(%s)\n",jprint(argjson,0)); - if ( (price= LP_price(base,rel)) > SMALLVAL ) + if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) { - price *= (1. + profitmargin); + price = ask; + //price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); if ( LP_quoteparse(&Q,argjson) < 0 ) @@ -411,7 +412,8 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d { if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) { - price *= (1. + profitmargin); + price = ask; + //price *= (1. + profitmargin); if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) return(-1); if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) @@ -524,9 +526,9 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); + bestitem = LP_quotejson(&Q); if ( price <= maxprice ) { - bestitem = LP_quotejson(&Q); price = LP_query(myipaddr,mypubsock,profitmargin,"connect",&Q); LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); expiration = (uint32_t)time(NULL) + timeout; @@ -542,11 +544,18 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba LP_availableset(autxo); } else jaddstr(bestitem,"status","connected"); + jaddnum(bestitem,"quotedprice",price); jaddnum(bestitem,"maxprice",maxprice); jaddnum(bestitem,"requestid",Q.R.requestid); jaddnum(bestitem,"quoteid",Q.R.quoteid); printf("Alice r.%u q.%u\n",Q.R.requestid,Q.R.quoteid); - } else jaddstr(bestitem,"status","too expensive"); + } + else + { + jaddnum(bestitem,"quotedprice",price); + jaddnum(bestitem,"maxprice",maxprice); + jaddstr(bestitem,"status","too expensive"); + } return(jprint(bestitem,0)); } From b7c57d31940f13286a6614aaf1bbc559dd793032 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:12:21 +0300 Subject: [PATCH 1435/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 10 +++++----- iguana/exchanges/LP_peers.c | 8 +++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 334d0c0a4..18a010a31 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -373,7 +373,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); timeout = 1; - maxsize = 1024 * 1024; + maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 4632f4f04..60cfed5f1 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -35,7 +35,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) return(-1); } len = (int32_t)strlen(msg) + 1; - for (i=0; i<1000; i++) + for (i=0; i<100; i++) { pfd.fd = sock; pfd.events = NN_POLLOUT; @@ -43,7 +43,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) { if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); - //else printf("SENT.(%s)\n",msg); + else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); return(sentbytes); @@ -51,11 +51,11 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) usleep(1000); } printf("error LP_send, pipeline timeout\n"); - if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) - printf("LP_send sent %d instead of %d\n",sentbytes,len); + //if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) + // printf("LP_send sent %d instead of %d\n",sentbytes,len); if ( freeflag != 0 ) free(msg); - return(sentbytes); + return(-1); } uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits,uint32_t crcs[2]) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index b6dc4b1db..89fac7909 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -50,7 +50,7 @@ char *LP_peers() struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,double profitmargin,int32_t numpeers,int32_t numutxos) { - uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; + uint32_t ipbits; int32_t maxsize,pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; ipbits = (uint32_t)calc_ipbits(ipaddr); expand_ipbits(checkip,ipbits); if ( strcmp(checkip,ipaddr) == 0 ) @@ -72,11 +72,13 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char strcpy(peer->ipaddr,ipaddr); if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { - timeout = 1000; - nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); if ( nn_connect(pushsock,pushaddr) >= 0 ) { + timeout = 100; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + maxsize = 2 * 1024 * 1024; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDBUF,&maxsize,sizeof(maxsize)); printf("connected to push.(%s) %d\n",pushaddr,pushsock); peer->connected = (uint32_t)time(NULL); peer->pushsock = pushsock; From 649052cbbf398cfbb0e6c903115faa529dd151e0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:13:09 +0300 Subject: [PATCH 1436/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 60cfed5f1..e71afef66 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -39,7 +39,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) { pfd.fd = sock; pfd.events = NN_POLLOUT; - if ( nn_poll(&pfd,1,100) > 0 ) + if ( nn_poll(&pfd,1,1) > 0 ) { if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); From dd44d68cd01b34dc30a9cbc1344244734ae64d81 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:16:23 +0300 Subject: [PATCH 1437/2705] Test --- iguana/exchanges/LP_forwarding.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 6842f2dd8..6b2263712 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -202,7 +202,7 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu { printf("GOT FORWARDED.(%s) -> pushsock.%d\n",jsonstr,ptr->pushsock); len = (int32_t)strlen(jsonstr); - if ( LP_send(ptr->pushsock,jsonstr,1) == len+1 ) + if ( LP_send(ptr->pushsock,jsonstr,0) == len+1 ) return(1); } } @@ -237,6 +237,8 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu return(LP_send(peer->pushsock,jprint(reqjson,1),1)); } else retval = -1; } + if ( freeflag != 0 ) + free(jsonstr); return(-1); } From 4631609048e07cace4822b964d770e53e128d72a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:23:18 +0300 Subject: [PATCH 1438/2705] Test --- iguana/exchanges/LP_quotes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 4918dff3b..283b69dfe 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -523,6 +523,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba asatoshis = bestutxo->payment.value * ordermatchprice; if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); + printf("asatoshis %.8f = bvalue %.8f * ordermatch %.8f\n",dstr(asatoshis),dstr(bestutxo->payment.value),ordermatchprice); if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); From dbf22aebf8d698e2072a058bb382c7b57031a437 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:31:33 +0300 Subject: [PATCH 1439/2705] Test --- iguana/exchanges/LP_quotes.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 283b69dfe..b31662b7c 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -332,7 +332,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs } else { - printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.satoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); + printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.destsatoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); } } else printf("no price for %s/%s\n",base,rel); if ( retval < 0 ) @@ -405,7 +405,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d } if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) utxo->T.swappending = 0; - if ( strcmp(method,"request") == 0 ) // bob + if ( strcmp(method,"request") == 0 ) // bob needs apayment + fee tx's { retval = 1; if ( LP_isavailable(utxo) > 0 ) @@ -520,10 +520,10 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba } if ( bestutxo == 0 || ordermatchprice == 0. ) return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); - asatoshis = bestutxo->payment.value * ordermatchprice; if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); - printf("asatoshis %.8f = bvalue %.8f * ordermatch %.8f\n",dstr(asatoshis),dstr(bestutxo->payment.value),ordermatchprice); + asatoshis = Q.satoshis * ordermatchprice + Q.desttxfee; + printf("asatoshis %.8f = bvalue %.8f * ordermatch %.8f\n",dstr(asatoshis),dstr(Q.satoshis),ordermatchprice); if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); From 392474faf6c3e811cda66e50187c04941e988739 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:36:23 +0300 Subject: [PATCH 1440/2705] Test --- iguana/exchanges/LP_quotes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index b31662b7c..f6f3da0d8 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -332,7 +332,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs } else { - printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.destsatoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending ,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 , LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout) >= price*Q.satoshis+Q.desttxfee,dstr(LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)),dstr(price*Q.satoshis+Q.desttxfee)); + printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.destsatoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 ,destvalue >= price*Q.satoshis+Q.desttxfee,dstr(destvalue),dstr(price*Q.satoshis+Q.desttxfee)); } } else printf("no price for %s/%s\n",base,rel); if ( retval < 0 ) @@ -522,7 +522,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); - asatoshis = Q.satoshis * ordermatchprice + Q.desttxfee; + asatoshis = Q.satoshis * ordermatchprice + Q.desttxfee + 1; printf("asatoshis %.8f = bvalue %.8f * ordermatch %.8f\n",dstr(asatoshis),dstr(Q.satoshis),ordermatchprice); if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); From 3d8987b2ec6b4cfad17b7a2d54d79845cd7b761d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:41:26 +0300 Subject: [PATCH 1441/2705] Test --- iguana/exchanges/LP_quotes.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index f6f3da0d8..fe037b4b4 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -300,7 +300,8 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs printf("utxo payment %.8f is less than half covered by Q %.8f\n",dstr(utxo->payment.value),dstr(Q.satoshis)); return(-1); } - if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime < utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && (destvalue= LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout)) >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + destvalue = LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout); + if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime <= utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && destvalue >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) { nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 10000)); if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) @@ -332,7 +333,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs } else { - printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.destsatoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME ,Q.quotetime >= Q.timestamp ,Q.quotetime < utxo->T.swappending,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 ,destvalue >= price*Q.satoshis+Q.desttxfee,dstr(destvalue),dstr(price*Q.satoshis+Q.desttxfee)); + printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.destsatoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME,Q.quotetime >= Q.timestamp-3,Q.quotetime < utxo->T.swappending,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 ,destvalue >= price*Q.satoshis+Q.desttxfee,dstr(destvalue),dstr(price*Q.satoshis+Q.desttxfee)); } } else printf("no price for %s/%s\n",base,rel); if ( retval < 0 ) @@ -522,7 +523,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); - asatoshis = Q.satoshis * ordermatchprice + Q.desttxfee + 1; + asatoshis = 1.001 * (Q.satoshis * ordermatchprice + Q.desttxfee + 1); printf("asatoshis %.8f = bvalue %.8f * ordermatch %.8f\n",dstr(asatoshis),dstr(Q.satoshis),ordermatchprice); if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); From f0cbe33d0586ba79bb35818e5da898ed4fea0a2f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:45:24 +0300 Subject: [PATCH 1442/2705] Test --- iguana/exchanges/LP_quotes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index fe037b4b4..b04f7bc2b 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -286,7 +286,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs return(-1); if ( LP_quoteparse(&Q,argjson) < 0 ) return(-2); - Q.destsatoshis = Q.satoshis * price; + Q.destsatoshis = Q.satoshis * price + Q.desttxfee + 1; privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(utxo->S.mypub) == 0 ) utxo->S.mypub = LP_pubkey(privkey); @@ -523,7 +523,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); - asatoshis = 1.001 * (Q.satoshis * ordermatchprice + Q.desttxfee + 1); + asatoshis = (Q.satoshis * ordermatchprice + Q.desttxfee + 1); printf("asatoshis %.8f = bvalue %.8f * ordermatch %.8f\n",dstr(asatoshis),dstr(Q.satoshis),ordermatchprice); if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); From 4c5f4616789a9eb8bb73258bce29a44b3c8c5a17 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 22:55:20 +0300 Subject: [PATCH 1443/2705] Test --- iguana/exchanges/LP_quotes.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index b04f7bc2b..4c53039b1 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -68,7 +68,7 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) jaddbits256(retjson,"txid2",qp->txid2); jaddnum(retjson,"vout2",qp->vout2); } - if ( bits256_nonz(qp->desttxid) != 0 ) + //if ( bits256_nonz(qp->desttxid) != 0 ) { if ( qp->destaddr[0] != 0 ) jaddstr(retjson,"destaddr",qp->destaddr); @@ -277,7 +277,7 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) { char pairstr[512],destaddr[64]; cJSON *retjson; double bid,ask,price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; - //printf("LP_connectstartbob with.(%s)\n",jprint(argjson,0)); + printf("LP_connectstartbob with.(%s)\n",jprint(argjson,0)); if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) { price = ask; @@ -333,7 +333,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs } else { - printf("dest %.8f < required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.destsatoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME,Q.quotetime >= Q.timestamp-3,Q.quotetime < utxo->T.swappending,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 ,destvalue >= price*Q.satoshis+Q.desttxfee,dstr(destvalue),dstr(price*Q.satoshis+Q.desttxfee)); + printf("dest %.8f vs required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.destsatoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME,Q.quotetime >= Q.timestamp-3,Q.quotetime < utxo->T.swappending,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 ,destvalue >= price*Q.satoshis+Q.desttxfee,dstr(destvalue),dstr(price*Q.satoshis+Q.desttxfee)); } } else printf("no price for %s/%s\n",base,rel); if ( retval < 0 ) @@ -398,12 +398,19 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) { printf("pend.%u LP_tradecommand.(%s)\n",utxo->T.swappending,jprint(argjson,0)); + if ( LP_quoteparse(&Q,argjson) < 0 ) + return(-2); if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) { char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); utxo->T.spentflag = (uint32_t)time(NULL); return(0); } + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.destcoin,Q.desttxid,Q.destvout,Q.feetxid,Q.feevout)) >= 0 ) + { + char str[65]; printf("LP_tradecommand dest selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(0); + } if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) utxo->T.swappending = 0; if ( strcmp(method,"request") == 0 ) // bob needs apayment + fee tx's @@ -415,8 +422,8 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d { price = ask; //price *= (1. + profitmargin); - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); + //if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) + // return(-1); if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) { printf("not eligible\n"); From 04b12eda4533d3f305c822300a848b165e483056 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 23:01:11 +0300 Subject: [PATCH 1444/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/LP_quotes.c | 14 ++++++++++---- iguana/exchanges/LP_utxos.c | 6 +++--- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 18a010a31..fbc22e7c1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -150,7 +150,7 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { - printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); + //printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); portable_mutex_lock(&LP_commandmutex); if ( (retstr= LP_command_process(myipaddr,-1,argjson,0,0,profitmargin)) != 0 ) { diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index e71afef66..4faf2e2a5 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -43,7 +43,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) { if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); - else printf("SENT.(%s)\n",msg); + //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); return(sentbytes); diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index 4c53039b1..fd3b8af26 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -181,7 +181,7 @@ char *LP_pricepings(char *myipaddr,int32_t pubsock,double profitmargin,char *bas if ( pubsock >= 0 ) { jaddstr(reqjson,"method","postprice"); - printf("%d pricepings.(%s)\n",pubsock,jprint(reqjson,0)); + //printf("%d pricepings.(%s)\n",pubsock,jprint(reqjson,0)); LP_send(pubsock,jprint(reqjson,1),1); } else @@ -197,7 +197,7 @@ char *LP_pricepings(char *myipaddr,int32_t pubsock,double profitmargin,char *bas char *LP_postedprice(cJSON *argjson) { bits256 pubkey; double price; char *base,*rel; - printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); + //printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && (price= jdouble(argjson,"price")) > SMALLVAL ) { pubkey = jbits256(argjson,"pubkey"); @@ -246,7 +246,7 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho reqjson = LP_quotejson(qp); if ( bits256_nonz(qp->desthash) != 0 ) flag = 1; - printf("QUERY.(%s)\n",jprint(reqjson,0)); + //printf("QUERY.(%s)\n",jprint(reqjson,0)); if ( IAMLP != 0 ) { jaddstr(reqjson,"method",method); @@ -384,7 +384,13 @@ char *LP_connectedalice(cJSON *argjson) // alice } else jaddstr(retjson,"error","couldnt aliceloop"); } return(jprint(retjson,1)); - } else return(clonestr("{\"result\",\"update stats\"}")); + } + else + { + utxo = LP_utxofind(0,Q.desttxid,Q.destvout); + printf("alice fails %d %d %d %d %d\n",IAMLP == 0,bits256_cmp(Q.desthash,LP_mypubkey) == 0, utxo != 0,LP_ismine(utxo) > 0,LP_isavailable(utxo) > 0); + return(clonestr("{\"result\",\"update stats\"}")); + } } int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 579be508a..b83c019e6 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -20,21 +20,21 @@ int32_t LP_ismine(struct LP_utxoinfo *utxo) { - if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 ) + if ( utxo != 0 && bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 ) return(1); else return(0); } int32_t LP_isavailable(struct LP_utxoinfo *utxo) { - if ( utxo->T.swappending == 0 && utxo->S.swap == 0 ) + if ( utxo != 0 && utxo->T.swappending == 0 && utxo->S.swap == 0 ) return(1); else return(0); } int32_t LP_isunspent(struct LP_utxoinfo *utxo) { - if ( utxo->T.spentflag == 0 && LP_isavailable(utxo) > 0 ) + if ( utxo != 0 && utxo->T.spentflag == 0 && LP_isavailable(utxo) > 0 ) return(1); else return(0); } From bccf0c639e7beda8e4aa66b79b8e2f3b5ae2ec92 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 15 Jun 2017 23:03:41 +0300 Subject: [PATCH 1445/2705] Test --- iguana/exchanges/LP_quotes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_quotes.c index fd3b8af26..e87212958 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_quotes.c @@ -350,7 +350,7 @@ char *LP_connectedalice(cJSON *argjson) // alice cJSON *retjson; bits256 spendtxid; int32_t spendvini,selector,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; LP_quoteparse(&Q,argjson); printf("CONNECTED.(%s)\n",jprint(argjson,0)); - if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) + if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 )//&& LP_isavailable(utxo) > 0 ) { if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) { From 3f0a715b8f22b9be0de3c97999fade397a963801 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 12:45:02 +0300 Subject: [PATCH 1446/2705] Test --- iguana/exchanges/LP_commands.c | 11 +- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 14 +- .../{LP_quotes.c => LP_ordermatch.c} | 331 ++++++++++-------- iguana/exchanges/LP_statemachine.c | 10 + iguana/exchanges/LP_transaction.c | 1 + iguana/exchanges/LP_utxos.c | 25 +- iguana/exchanges/help | 2 + 8 files changed, 225 insertions(+), 171 deletions(-) rename iguana/exchanges/{LP_quotes.c => LP_ordermatch.c} (65%) create mode 100755 iguana/exchanges/help diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 55f4ef46f..6d6b61abe 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -94,9 +94,10 @@ forwardhex(pubkey,hex)\n\ double price; if ( LP_isdisabled(base,rel) != 0 ) return(clonestr("{\"error\":\"at least one of coins disabled\"}")); + price = jdouble(argjson,"price"); if ( strcmp(method,"setprice") == 0 ) { - if ( (price= jdouble(argjson,"price")) > SMALLVAL ) + if ( price > SMALLVAL ) { if ( LP_mypriceset(base,rel,price) < 0 ) return(clonestr("{\"error\":\"couldnt set price\"}")); @@ -117,7 +118,13 @@ forwardhex(pubkey,hex)\n\ } else return(clonestr("{\"error\":\"no price set\"}")); } else if ( strcmp(method,"autotrade") == 0 ) - return(LP_autotrade(myipaddr,pubsock,profitmargin,base,rel,jdouble(argjson,"price"),jdouble(argjson,"volume"),jint(argjson,"timeout"))); + { + if ( price > SMALLVAL ) + { + LP_mypriceset(base,rel,price); + return(LP_autotrade(myipaddr,pubsock,profitmargin,base,rel,price,jdouble(argjson,"volume"),jint(argjson,"timeout"))); + } else return(clonestr("{\"error\":\"no price set\"}")); + } } else if ( (coin= jstr(argjson,"coin")) != 0 ) { diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index f13975b53..26520dd47 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -157,7 +157,7 @@ struct LP_utxobob { struct _LP_utxoinfo utxo,deposit; }; struct LP_utxoalice { struct _LP_utxoinfo utxo,fee; }; -struct LP_utxoswap { bits256 otherpubkey,mypub; void *swap; uint64_t satoshis; double profitmargin; }; +struct LP_utxoswap { bits256 otherpubkey; void *swap; uint64_t satoshis; double profitmargin; }; struct LP_utxoinfo { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fbc22e7c1..f8426ead9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -17,7 +17,6 @@ // LP_nativeDEX.c // marketmaker // -// jl777: profitmargin per coin, ignore peers with errors #include #include "LP_include.h" @@ -75,7 +74,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_swap.c" #include "LP_peers.c" #include "LP_utxos.c" -#include "LP_quotes.c" +#include "LP_ordermatch.c" #include "LP_forwarding.c" #include "LP_commands.c" @@ -183,14 +182,6 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,u.txid),u.vout,dstr(u.value)); LP_spentnotify(utxo,1); } - /*else if ( LP_ismine(utxo) > 0 ) - { - printf("iterate through all locally generated quotes and update, or change to price feed\n"); - // jl777: iterated Q's - if ( strcmp(utxo->coin,"KMD") == 0 ) - LP_priceping(pubsock,utxo,"BTC",profitmargin); - else LP_priceping(pubsock,utxo,"KMD",profitmargin); - }*/ } } @@ -416,7 +407,4 @@ LP_mainloop(myipaddr,mypeer,mypubport,pubsock,pushaddr,pullsock,myport,passphras } -// splitfunds cant trade? -// timeout on bad peers - diff --git a/iguana/exchanges/LP_quotes.c b/iguana/exchanges/LP_ordermatch.c similarity index 65% rename from iguana/exchanges/LP_quotes.c rename to iguana/exchanges/LP_ordermatch.c index e87212958..498f33a6c 100644 --- a/iguana/exchanges/LP_quotes.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -15,7 +15,7 @@ ******************************************************************************/ // -// LP_quotes.c +// LP_ordermatch.c // marketmaker // @@ -68,7 +68,7 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) jaddbits256(retjson,"txid2",qp->txid2); jaddnum(retjson,"vout2",qp->vout2); } - //if ( bits256_nonz(qp->desttxid) != 0 ) + if ( bits256_nonz(qp->desttxid) != 0 ) { if ( qp->destaddr[0] != 0 ) jaddstr(retjson,"destaddr",qp->destaddr); @@ -122,7 +122,8 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price) { memset(qp,0,sizeof(*qp)); - qp->timestamp = (uint32_t)time(NULL); + if ( qp->timestamp == 0 ) + qp->timestamp = (uint32_t)time(NULL); safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) qp->txfee = 10000; @@ -145,9 +146,8 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * return(0); } -int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,uint32_t quotetime,uint64_t destsatoshis,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr) +int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,uint64_t destsatoshis,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr) { - qp->quotetime = quotetime; qp->destsatoshis = destsatoshis; qp->desttxid = desttxid; qp->destvout = destvout; @@ -210,11 +210,70 @@ char *LP_postedprice(cJSON *argjson) return(clonestr("{\"error\":\"missing fields in posted price\"}")); } -int32_t LP_sizematch(uint64_t mysatoshis,uint64_t othersatoshis) +int32_t LP_quote_checkmempool(struct LP_quoteinfo *qp) { - if ( mysatoshis >= othersatoshis ) - return(0); - else return(-1); + int32_t selector,spendvini; bits256 spendtxid; + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,qp->srccoin,qp->txid,qp->vout,qp->txid2,qp->vout2)) >= 0 ) + { + char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(-1); + } + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,qp->destcoin,qp->desttxid,qp->destvout,qp->feetxid,qp->feevout)) >= 0 ) + { + char str[65]; printf("LP_tradecommand dest selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(-1); + } + return(0); +} + +int32_t LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxop,struct LP_quoteinfo *qp,int32_t iambob) +{ + double qprice; uint64_t srcvalue,srcvalue2,destvalue,destvalue2; + *autxop = *butxop = 0; + if ( LP_iseligible(&srcvalue,&srcvalue2,1,qp->srccoin,qp->txid,qp->vout,qp->satoshis,qp->txid2,qp->vout2) == 0 ) + { + printf("bob not eligible\n"); + return(-2); + } + if ( LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout) == 0 ) + { + printf("alice not eligible\n"); + return(-3); + } + if ( LP_quote_checkmempool(qp) < 0 ) + return(-4); + if ( (*butxop= LP_utxofind(1,qp->txid,qp->vout)) == 0 ) + return(-5); + if ( bits256_cmp((*butxop)->deposit.txid,qp->txid2) != 0 || (*butxop)->deposit.vout != qp->vout2 ) + return(-6); + if ( strcmp((*butxop)->coinaddr,qp->coinaddr) != 0 ) + return(-7); + if ( iambob == 0 ) + { + if ( (*autxop= LP_utxofind(0,qp->desttxid,qp->destvout)) == 0 ) + return(-8); + if ( bits256_cmp((*autxop)->fee.txid,qp->feetxid) != 0 || (*autxop)->fee.vout != qp->feevout ) + return(-9); + if ( strcmp((*autxop)->coinaddr,qp->destaddr) != 0 ) + return(-10); + } + if ( destvalue <= qp->desttxfee || srcvalue <= qp->txfee ) + { + printf("destsatoshis %.8f or satoshis %.8f is too small txfees %.8f %.8f?\n",dstr(qp->destsatoshis),dstr(qp->satoshis),dstr(qp->desttxfee),dstr(qp->txfee)); + return(-11); + } + qprice = ((double)(qp->destsatoshis - qp->desttxfee) / (qp->satoshis - qp->txfee)); + if ( qp->satoshis < (srcvalue >> 1) ) + { + printf("utxo payment %.8f is less than half covered by Q %.8f\n",dstr(srcvalue),dstr(qp->satoshis)); + return(-12); + } + if ( qp->destsatoshis < (destvalue >> 1) ) + { + printf("destsatoshis %.8f is less than half of value %.8f\n",dstr(qp->destsatoshis),dstr(destvalue)); + return(-13); + } + return(qprice); } int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) @@ -234,7 +293,6 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; if ( strcmp(method,"request") == 0 ) { - qp->quotetime = (uint32_t)time(NULL); if ( (utxo= LP_utxofind(0,qp->desttxid,qp->destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) LP_unavailableset(utxo,qp->srchash); else @@ -274,68 +332,57 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho return(price); } -int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin) +int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) +{ + int32_t i; + for (i=0; i<10; i++) + { + nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 50000)); + if ( nn_bind(pair,pairstr) >= 0 ) + return(0); + } + return(-1); +} + +int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin,double price,struct LP_quoteinfo *qp) { - char pairstr[512],destaddr[64]; cJSON *retjson; double bid,ask,price; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; uint64_t destvalue; struct LP_quoteinfo Q; struct basilisk_swap *swap; + char pairstr[512]; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; printf("LP_connectstartbob with.(%s)\n",jprint(argjson,0)); - if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) - { - price = ask; - //price *= (1. + profitmargin); - if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - return(-1); - if ( LP_quoteparse(&Q,argjson) < 0 ) - return(-2); - Q.destsatoshis = Q.satoshis * price + Q.desttxfee + 1; - privkey = LP_privkey(utxo->coinaddr); - if ( bits256_nonz(utxo->S.mypub) == 0 ) - utxo->S.mypub = LP_pubkey(privkey); - if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) - { - printf("not eligible\n"); - return(-1); - } - if ( utxo->payment.value > (Q.satoshis << 1) ) - { - printf("utxo payment %.8f is less than half covered by Q %.8f\n",dstr(utxo->payment.value),dstr(Q.satoshis)); - return(-1); - } - destvalue = LP_txvalue(destaddr,rel,Q.desttxid,Q.destvout); - if ( bits256_nonz(privkey) != 0 && Q.quotetime >= Q.timestamp-3 && Q.quotetime <= utxo->T.swappending && bits256_cmp(utxo->S.mypub,Q.srchash) == 0 && destvalue >= price*Q.satoshis+Q.desttxfee && destvalue >= Q.destsatoshis+Q.desttxfee ) + qp->quotetime = (uint32_t)time(NULL); + privkey = LP_privkey(utxo->coinaddr); + if ( bits256_nonz(privkey) != 0 && qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending && bits256_cmp(LP_mypubkey,qp->srchash) == 0 ) + { + if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) + printf("error creating utxo->pair\n"); + else if ( LP_nanobind(pair,pairstr,myipaddr) >= 0 ) { - nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 10000)); - if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) - printf("error creating utxo->pair\n"); - else if ( nn_bind(pair,pairstr) >= 0 ) + LP_requestinit(&qp->R,qp->srchash,qp->desthash,base,qp->satoshis,rel,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); + swap = LP_swapinit(1,0,privkey,&qp->R,qp); + swap->N.pair = pair; + utxo->S.swap = swap; + swap->utxo = utxo; + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)swap) == 0 ) { - LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,rel,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - swap = LP_swapinit(1,0,privkey,&Q.R,&Q); - swap->N.pair = pair; - utxo->S.swap = swap; - swap->utxo = utxo; - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_bobloop,(void *)swap) == 0 ) - { - retjson = LP_quotejson(&Q); - jaddstr(retjson,"method","connected"); - jaddstr(retjson,"pair",pairstr); - jaddnum(retjson,"requestid",Q.R.requestid); - jaddnum(retjson,"quoteid",Q.R.quoteid); - char str[65]; printf("BOB pubsock.%d sends to (%s)\n",pubsock,bits256_str(str,utxo->S.otherpubkey)); - if ( pubsock >= 0 ) - LP_send(pubsock,jprint(retjson,0),1); - jdelete(retjson,"method"); - jaddstr(retjson,"method2","connected"); - jaddstr(retjson,"method","forward"); - LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,jprint(retjson,1),1); - retval = 0; - } else printf("error launching swaploop\n"); - } else printf("printf error nn_connect to %s\n",pairstr); - } - else - { - printf("dest %.8f vs required %.8f (%d %d %d %d %d %d) %.8f %.8f\n",dstr(Q.destsatoshis),dstr(price*(utxo->S.satoshis-Q.txfee)),bits256_nonz(privkey) != 0 ,Q.timestamp == utxo->T.swappending-LP_RESERVETIME,Q.quotetime >= Q.timestamp-3,Q.quotetime < utxo->T.swappending,bits256_cmp(utxo->S.mypub,Q.srchash) == 0 ,destvalue >= price*Q.satoshis+Q.desttxfee,dstr(destvalue),dstr(price*Q.satoshis+Q.desttxfee)); - } - } else printf("no price for %s/%s\n",base,rel); + retjson = LP_quotejson(qp); + jaddstr(retjson,"method","connected"); + jaddstr(retjson,"pair",pairstr); + jaddnum(retjson,"requestid",qp->R.requestid); + jaddnum(retjson,"quoteid",qp->R.quoteid); + char str[65]; printf("BOB pubsock.%d sends to (%s)\n",pubsock,bits256_str(str,utxo->S.otherpubkey)); + if ( pubsock >= 0 ) + LP_send(pubsock,jprint(retjson,0),1); + jdelete(retjson,"method"); + jaddstr(retjson,"method2","connected"); + jaddstr(retjson,"method","forward"); + LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,jprint(retjson,1),1); + retval = 0; + } else printf("error launching swaploop\n"); + } else printf("couldnt bind to any port %s\n",pairstr); + } + else + { + printf("dest %.8f vs required %.8f (%d %d %d %d %d)\n",dstr(qp->destsatoshis),dstr(price*(utxo->S.satoshis-qp->txfee)),bits256_nonz(privkey) != 0 ,qp->timestamp == utxo->T.swappending-LP_RESERVETIME,qp->quotetime >= qp->timestamp-3,qp->quotetime < utxo->T.swappending,bits256_cmp(LP_mypubkey,qp->srchash) == 0); + } if ( retval < 0 ) { if ( pair >= 0 ) @@ -347,33 +394,43 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs char *LP_connectedalice(cJSON *argjson) // alice { - cJSON *retjson; bits256 spendtxid; int32_t spendvini,selector,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *utxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; - LP_quoteparse(&Q,argjson); + cJSON *retjson; double bid,ask,price,qprice; int32_t pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *autxo,*butxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; + if ( LP_quoteparse(&Q,argjson) < 0 ) + clonestr("{\"error\":\"cant parse quote\"}"); + if ( bits256_cmp(Q.desthash,LP_mypubkey) != 0 ) + return(clonestr("{\"result\",\"update stats\"}")); printf("CONNECTED.(%s)\n",jprint(argjson,0)); - if ( IAMLP == 0 && bits256_cmp(Q.desthash,LP_mypubkey) == 0 && (utxo= LP_utxofind(0,Q.desttxid,Q.destvout)) != 0 && LP_ismine(utxo) > 0 )//&& LP_isavailable(utxo) > 0 ) + if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,0)) <= SMALLVAL ) + { + LP_availableset(autxo); + printf("quote validate error %.0f\n",qprice); + return(clonestr("{\"error\":\"quote validation error\"}")); + } + if ( (price= LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin)) <= SMALLVAL || bid <= SMALLVAL ) + { + printf("this node has no price for %s/%s\n",Q.srccoin,Q.destcoin); + LP_availableset(autxo); + return(clonestr("{\"error\":\"no price set\"}")); + } + price = bid; + if ( qprice > price ) + { + LP_availableset(autxo); + return(clonestr("{\"error\":\"quote price too expensive\"}")); + } + Q.privkey = LP_privkey(Q.destaddr); + if ( bits256_nonz(Q.privkey) != 0 && Q.quotetime >= Q.timestamp-3 ) { - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) - { - char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(clonestr("{\"error\",\"src txid in mempool\"}")); - } - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.srccoin,Q.txid,Q.vout,Q.txid2,Q.vout2)) >= 0 ) - { - char str[65]; printf("LP_connected src selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(clonestr("{\"error\",\"dest txid in mempool\"}")); - } retjson = cJSON_CreateObject(); if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) jaddstr(retjson,"error","couldnt create pairsock"); else if ( nn_connect(pairsock,pairstr) >= 0 ) { - LP_unavailableset(utxo,Q.srchash); - Q.privkey = LP_privkey(Q.destaddr); LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q); swap->N.pair = pairsock; - utxo->S.swap = swap; - swap->utxo = utxo; + autxo->S.swap = swap; + swap->utxo = autxo; printf("alice pairstr.(%s)\n",pairstr); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 ) { @@ -383,91 +440,73 @@ char *LP_connectedalice(cJSON *argjson) // alice jaddnum(retjson,"quoteid",Q.R.quoteid); } else jaddstr(retjson,"error","couldnt aliceloop"); } + if ( jobj(retjson,"error") != 0 ) + LP_availableset(autxo); return(jprint(retjson,1)); } else { - utxo = LP_utxofind(0,Q.desttxid,Q.destvout); - printf("alice fails %d %d %d %d %d\n",IAMLP == 0,bits256_cmp(Q.desthash,LP_mypubkey) == 0, utxo != 0,LP_ismine(utxo) > 0,LP_isavailable(utxo) > 0); - return(clonestr("{\"result\",\"update stats\"}")); + LP_availableset(autxo); + return(clonestr("{\"error\",\"no privkey\"}")); } } int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method,*base,*rel; cJSON *retjson; double price,bid,ask; bits256 txid,spendtxid; struct LP_utxoinfo *utxo; int32_t selector,spendvini,retval = -1; struct LP_quoteinfo Q; + char *method; cJSON *retjson; double qprice,price,bid,ask; struct LP_utxoinfo *autxo,*butxo; int32_t retval = -1; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) { //printf("TRADECOMMAND.(%s)\n",jprint(argjson,0)); retval = 1; - txid = jbits256(argjson,"txid"); - if ( (utxo= LP_utxofind(1,txid,jint(argjson,"vout"))) != 0 && LP_ismine(utxo) > 0 && (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && strcmp(base,utxo->coin) == 0 ) + if ( LP_quoteparse(&Q,argjson) == 0 ) { - printf("pend.%u LP_tradecommand.(%s)\n",utxo->T.swappending,jprint(argjson,0)); - if ( LP_quoteparse(&Q,argjson) < 0 ) - return(-2); - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout)) >= 0 ) + if ( (price= LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin)) <= SMALLVAL || ask <= SMALLVAL ) { - char str[65]; printf("LP_tradecommand selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - utxo->T.spentflag = (uint32_t)time(NULL); - return(0); + printf("this node has no price for %s/%s\n",Q.srccoin,Q.destcoin); + return(-3); } - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,Q.destcoin,Q.desttxid,Q.destvout,Q.feetxid,Q.feevout)) >= 0 ) + price = ask; + if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,1)) <= SMALLVAL ) { - char str[65]; printf("LP_tradecommand dest selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(0); + printf("quote validate error %.0f\n",qprice); + return(-4); } - if ( utxo->S.swap == 0 && time(NULL) > utxo->T.swappending ) - utxo->T.swappending = 0; + if ( qprice < price ) + { + printf("quote price %.8f too low vs %.8f for %s/%s\n",qprice,price,Q.srccoin,Q.destcoin); + return(-5); + } + if ( butxo->S.swap == 0 && time(NULL) > butxo->T.swappending ) + butxo->T.swappending = 0; if ( strcmp(method,"request") == 0 ) // bob needs apayment + fee tx's { - retval = 1; - if ( LP_isavailable(utxo) > 0 ) + if ( LP_isavailable(butxo) > 0 ) { - if ( (price= LP_myprice(&bid,&ask,base,rel)) > SMALLVAL ) - { - price = ask; - //price *= (1. + profitmargin); - //if ( LP_quoteinfoinit(&Q,utxo,rel,price) < 0 ) - // return(-1); - if ( LP_iseligible(1,Q.srccoin,Q.txid,Q.vout,Q.satoshis,Q.txid2,Q.vout2) == 0 ) - { - printf("not eligible\n"); - return(-1); - } - Q.timestamp = (uint32_t)time(NULL); - utxo->T.swappending = Q.timestamp + LP_RESERVETIME; - retjson = LP_quotejson(&Q); - utxo->S.otherpubkey = jbits256(argjson,"desthash"); - retval |= 2; - LP_unavailableset(utxo,utxo->S.otherpubkey); - jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); - jaddnum(retjson,"pending",utxo->T.swappending); - jaddbits256(retjson,"desthash",utxo->S.otherpubkey); - jaddbits256(retjson,"pubkey",utxo->S.otherpubkey); - jaddstr(retjson,"method","reserved"); - if ( pubsock >= 0 ) - LP_send(pubsock,jprint(retjson,0),1); - jdelete(retjson,"method"); - jaddstr(retjson,"method2","reserved"); - jaddstr(retjson,"method","forward"); - LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,jprint(retjson,1),1); - utxo->T.lasttime = (uint32_t)time(NULL); - //printf("set swappending.%u\n",utxo->T.swappending); - } else printf("null price\n"); - } else printf("swappending.%u swap.%p\n",utxo->T.swappending,utxo->S.swap); + butxo->T.swappending = Q.timestamp + LP_RESERVETIME; + retjson = LP_quotejson(&Q); + butxo->S.otherpubkey = jbits256(argjson,"desthash"); + LP_unavailableset(butxo,butxo->S.otherpubkey); + jaddnum(retjson,"quotetime",juint(argjson,"quotetime")); + jaddnum(retjson,"pending",butxo->T.swappending); + jaddbits256(retjson,"desthash",butxo->S.otherpubkey); + jaddbits256(retjson,"pubkey",butxo->S.otherpubkey); + jaddstr(retjson,"method","reserved"); + if ( pubsock >= 0 ) + LP_send(pubsock,jprint(retjson,0),1); + jdelete(retjson,"method"); + jaddstr(retjson,"method2","reserved"); + jaddstr(retjson,"method","forward"); + LP_forward(myipaddr,pubsock,profitmargin,butxo->S.otherpubkey,jprint(retjson,1),1); + butxo->T.lasttime = (uint32_t)time(NULL); + printf("set swappending.%u accept qprice %.8f, min %.8f\n",butxo->T.swappending,qprice,price); + } else printf("warning swappending.%u swap.%p\n",butxo->T.swappending,butxo->S.swap); } else if ( strcmp(method,"connect") == 0 ) // bob { retval = 4; - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,jstr(argjson,"destcoin"),jbits256(argjson,"desttxid"),jint(argjson,"destvout"),jbits256(argjson,"feetxid"),jint(argjson,"feevout"))) >= 0 ) - { - char str[65]; printf("LP_tradecommand fee selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(0); - } - if ( utxo->T.swappending != 0 && utxo->S.swap == 0 ) - LP_connectstartbob(pubsock,utxo,argjson,myipaddr,base,rel,profitmargin); - else printf("pend.%u swap %p when connect came in (%s)\n",utxo->T.swappending,utxo->S.swap,jprint(argjson,0)); + if ( butxo->T.swappending != 0 && butxo->S.swap == 0 ) + LP_connectstartbob(pubsock,butxo,argjson,myipaddr,Q.srccoin,Q.destcoin,profitmargin,qprice,&Q); + else printf("pend.%u swap %p when connect came in (%s)\n",butxo->T.swappending,butxo->S.swap,jprint(argjson,0)); } } } @@ -538,7 +577,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); asatoshis = (Q.satoshis * ordermatchprice + Q.desttxfee + 1); printf("asatoshis %.8f = bvalue %.8f * ordermatch %.8f\n",dstr(asatoshis),dstr(Q.satoshis),ordermatchprice); - if ( LP_quotedestinfo(&Q,Q.timestamp+1,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) + if ( LP_quotedestinfo(&Q,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); bestitem = LP_quotejson(&Q); diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index 19e2adec8..f42043ab3 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -1423,3 +1423,13 @@ if ( (array= LP_tradecandidates(base)) != 0 ) free_json(array); } }*/ + +/*else if ( LP_ismine(utxo) > 0 ) + { + printf("iterate through all locally generated quotes and update, or change to price feed\n"); + // jl777: iterated Q's + if ( strcmp(utxo->coin,"KMD") == 0 ) + LP_priceping(pubsock,utxo,"BTC",profitmargin); + else LP_priceping(pubsock,utxo,"KMD",profitmargin); + }*/ + diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 9f1f0025a..c37c100a9 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -271,6 +271,7 @@ int32_t LP_waitmempool(char *symbol,bits256 txid,int32_t duration) { if ( LP_mempoolscan(symbol,txid) >= 0 ) return(0); + usleep(250000); } return(-1); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b83c019e6..9c0de17c9 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -348,30 +348,37 @@ char *LP_spentcheck(cJSON *argjson) return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); } -int32_t LP_iseligible(int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) +int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) { - uint64_t val,val2,threshold; char destaddr[64]; + uint64_t val,val2=0,threshold; char destaddr[64],destaddr2[64]; + destaddr[0] = destaddr2[0] = 0; if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) >= satoshis ) { threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); - if ( (val2= LP_txvalue(destaddr,symbol,txid2,vout2)) >= threshold ) + if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) { //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); - return(1); + if ( strcmp(destaddr,destaddr2) == 0 ) + { + *valp = val; + *val2p = val2; + return(1); + } else printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); } else printf("mismatched %s txid value2 %.8f < %.8f\n",symbol,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); } else printf("mismatched %s txid value %.8f < %.8f\n",symbol,dstr(val),dstr(satoshis)); + *valp = val; + *val2p = val2; return(0); } struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - char str[65],str2[65],destaddr[64],destaddr2[64]; uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + char str[65]; uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } - destaddr2[0] = 0; if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; @@ -393,12 +400,12 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit } else { - if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) != value || (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) != value2 || strcmp(destaddr,destaddr2) != 0 || strcmp(coinaddr,destaddr) != 0 ) + /*if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) != value || (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) != value2 || strcmp(destaddr,destaddr2) != 0 || strcmp(coinaddr,destaddr) != 0 ) { printf("utxoadd mismatch %s/v%d (%s %.8f) + %s/v%d (%s %.8f) != %s %.8f %.8f\n",bits256_str(str,txid),vout,destaddr,dstr(val),bits256_str(str2,txid2),vout2,destaddr2,dstr(val2),coinaddr,dstr(value),dstr(value2)); return(0); - } - if ( LP_iseligible(iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) + }*/ + if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); diff --git a/iguana/exchanges/help b/iguana/exchanges/help new file mode 100755 index 000000000..a5f08aa50 --- /dev/null +++ b/iguana/exchanges/help @@ -0,0 +1,2 @@ +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"help\"}" From f586d3948d9c2907e3f765c8700198e8b7f7d801 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 12:49:17 +0300 Subject: [PATCH 1447/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6d6b61abe..db9d0eaee 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -21,7 +21,7 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { - char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport,pushport,subport; int32_t otherpeers,othernumutxos,flag = 0; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; + char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport=0,pushport,subport; int32_t otherpeers,othernumutxos,flag = 0; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) @@ -47,7 +47,7 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs if ( (method= jstr(argjson,"method")) == 0 ) { if ( flag == 0 || jobj(argjson,"result") != 0 ) - printf("stats_JSON no method: (%s)\n",jprint(argjson,0)); + printf("stats_JSON no method: (%s) (%s:%u)\n",jprint(argjson,0),ipaddr,argport); return(clonestr("{\"error\":\"need method in request\"}")); } if ( strcmp(method,"help") == 0 ) From c1ee2388fd0bb63afe78071b60c9d84a20527df2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 12:49:44 +0300 Subject: [PATCH 1448/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index db9d0eaee..40e8f7154 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -24,7 +24,7 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport=0,pushport,subport; int32_t otherpeers,othernumutxos,flag = 0; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { - if ( strcmp(ipaddr,"127.0.0.1") != 0 && port >= 1000 ) + if ( strcmp(ipaddr,"127.0.0.1") != 0 && argport >= 1000 ) { flag = 1; if ( (pushport= juint(argjson,"push")) == 0 ) From 7126c3d19be839334b2d7a1fa5eb95133bc135f2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 12:56:09 +0300 Subject: [PATCH 1449/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 498f33a6c..55eb9cc6d 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -546,7 +546,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { asatoshis = butxo->payment.value * price; - if ( asatoshis <= destsatoshis && destsatoshis > (asatoshis >> 1) ) + if ( asatoshis <= destsatoshis && destsatoshis > (asatoshis >> 1) && asatoshis > (autxo->payment.value >> 1) ) { metric = price / bestprice; printf("%f %f %f %f ",price,metric,dstr(asatoshis),metric * metric * metric); From 4adc1818d83a28bc0c2aa5b2977284deeafee612 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 12:57:48 +0300 Subject: [PATCH 1450/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 55eb9cc6d..00a6365ea 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -561,7 +561,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba bestmetric = metric; } } - } + } printf("skip %.8f < half of %.8f\n",dstr(asatoshis),dstr(autxo->payment.value)); } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); } } else break; From 348ea72061eb9507f9ef42d9d0dbfad802dd7470 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:00:30 +0300 Subject: [PATCH 1451/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 00a6365ea..59303e7a9 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -561,7 +561,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba bestmetric = metric; } } - } printf("skip %.8f < half of %.8f\n",dstr(asatoshis),dstr(autxo->payment.value)); + } printf("skip.(%d %d %d) destsatoshis %.8f asatoshis %.8f < half of %.8f\n",asatoshis <= destsatoshis,destsatoshis > (asatoshis >> 1),asatoshis > (autxo->payment.value >> 1),dstr(destsatoshis),dstr(asatoshis),dstr(autxo->payment.value)); } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); } } else break; From 023fb100575710277cb44ac8a2e23484b08719d6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:29:10 +0300 Subject: [PATCH 1452/2705] Test --- iguana/exchanges/LP_ordermatch.c | 55 +++++++++++++++----------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 59303e7a9..eb3c7b368 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -119,7 +119,7 @@ int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) return(0); } -int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price) +int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price,uint64_t destsatoshis) { memset(qp,0,sizeof(*qp)); if ( qp->timestamp == 0 ) @@ -127,14 +127,15 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) qp->txfee = 10000; - if ( utxo->iambob == 0 || qp->txfee >= utxo->S.satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(utxo->S.satoshis) ) + qp->satoshis = destsatoshis / price; + if ( utxo->iambob == 0 || qp->txfee >= qp->satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis) ) return(-1); + qp->satoshis -= qp->txfee; qp->txid = utxo->payment.txid; qp->vout = utxo->payment.vout; qp->txid2 = utxo->deposit.txid; qp->vout2 = utxo->deposit.vout; - qp->satoshis = utxo->S.satoshis - qp->txfee; - qp->destsatoshis = qp->satoshis * price; + qp->destsatoshis = destsatoshis; if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) qp->desttxfee = 10000; if ( qp->desttxfee >= qp->destsatoshis ) @@ -146,9 +147,8 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * return(0); } -int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,uint64_t destsatoshis,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr) +int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr) { - qp->destsatoshis = destsatoshis; qp->desttxid = desttxid; qp->destvout = destvout; qp->desthash = desthash; @@ -515,13 +515,14 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume,int32_t timeout) { - uint64_t destsatoshis,asatoshis; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; + uint64_t destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) return(clonestr("{\"error\":\"invalid parameter\"}")); - destsatoshis = SATOSHIDEN * volume; - if ( (autxo= LP_utxo_bestfit(rel,destsatoshis)) == 0 ) + if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * volume)) == 0 ) return(clonestr("{\"error\":\"cant find utxo that is big enough\"}")); bestmetric = ordermatchprice = 0.; + desttxfee = LP_getestimatedrate(rel) * LP_AVETXSIZE; + txfee = LP_getestimatedrate(base) * LP_AVETXSIZE; if ( timeout == 0 ) timeout = LP_AUTOTRADE_TIMEOUT; if ( (obookstr= LP_orderbook(base,rel)) != 0 ) @@ -543,25 +544,23 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba txid = jbits256(item,"txid"); vout = jint(item,"vout"); vol = jdouble(item,"volume"); - if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) + metric = price / bestprice; + if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.1 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { - asatoshis = butxo->payment.value * price; - if ( asatoshis <= destsatoshis && destsatoshis > (asatoshis >> 1) && asatoshis > (autxo->payment.value >> 1) ) + if ( (destsatoshis= (butxo->payment.value * price)) > autxo->payment.value-desttxfee ) + destsatoshis *= ((double)autxo->payment.value / destsatoshis - desttxfee*2); + if ( destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->payment.value >> 1) ) { - metric = price / bestprice; - printf("%f %f %f %f ",price,metric,dstr(asatoshis),metric * metric * metric); - if ( metric < 1.1 ) + metric = dstr(destsatoshis) * metric * metric * metric; + printf("(%f) <- metric\n",metric); + if ( bestmetric == 0. || metric < bestmetric ) { - metric = dstr(asatoshis) * metric * metric * metric; - printf("(%f) <- metric\n",metric); - if ( bestmetric == 0. || metric < bestmetric ) - { - bestutxo = butxo; - ordermatchprice = price; - bestmetric = metric; - } + bestutxo = butxo; + ordermatchprice = price; + bestdestsatoshis = destsatoshis; + bestmetric = metric; } - } printf("skip.(%d %d %d) destsatoshis %.8f asatoshis %.8f < half of %.8f\n",asatoshis <= destsatoshis,destsatoshis > (asatoshis >> 1),asatoshis > (autxo->payment.value >> 1),dstr(destsatoshis),dstr(asatoshis),dstr(autxo->payment.value)); + } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->payment.value >> 1),dstr(destsatoshis),dstr(butxo->payment.value),dstr(autxo->payment.value)); } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); } } else break; @@ -571,13 +570,11 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba } free(obookstr); } - if ( bestutxo == 0 || ordermatchprice == 0. ) + if ( bestutxo == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 ) return(clonestr("{\"error\":\"cant find ordermatch utxo\"}")); - if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice) < 0 ) + if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestdestsatoshis) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); - asatoshis = (Q.satoshis * ordermatchprice + Q.desttxfee + 1); - printf("asatoshis %.8f = bvalue %.8f * ordermatch %.8f\n",dstr(asatoshis),dstr(Q.satoshis),ordermatchprice); - if ( LP_quotedestinfo(&Q,asatoshis,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) + if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); bestitem = LP_quotejson(&Q); From 2d8fa6bef0276615a9c62331656783a1ee994503 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:34:34 +0300 Subject: [PATCH 1453/2705] Test --- iguana/exchanges/LP_ordermatch.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index eb3c7b368..da27b3d86 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -515,7 +515,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume,int32_t timeout) { - uint64_t destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; + int64_t destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) return(clonestr("{\"error\":\"invalid parameter\"}")); if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * volume)) == 0 ) @@ -547,20 +547,22 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba metric = price / bestprice; if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.1 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { - if ( (destsatoshis= (butxo->payment.value * price)) > autxo->payment.value-desttxfee ) - destsatoshis *= ((double)autxo->payment.value / destsatoshis - desttxfee*2); - if ( destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->payment.value >> 1) ) + if ( (destsatoshis= (butxo->payment.value * price)) > autxo->payment.value-desttxfee && destsatoshis > 2*desttxfee ) { - metric = dstr(destsatoshis) * metric * metric * metric; - printf("(%f) <- metric\n",metric); - if ( bestmetric == 0. || metric < bestmetric ) + destsatoshis *= ((double)autxo->payment.value / destsatoshis - desttxfee*2); + if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->payment.value >> 1) ) { - bestutxo = butxo; - ordermatchprice = price; - bestdestsatoshis = destsatoshis; - bestmetric = metric; - } - } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->payment.value >> 1),dstr(destsatoshis),dstr(butxo->payment.value),dstr(autxo->payment.value)); + printf("best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); + metric = dstr(destsatoshis) * metric * metric * metric; + if ( bestmetric == 0. || metric < bestmetric ) + { + bestutxo = butxo; + ordermatchprice = price; + bestdestsatoshis = destsatoshis; + bestmetric = metric; + } + } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->payment.value >> 1),dstr(destsatoshis),dstr(butxo->payment.value),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); + } } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); } } else break; From f1c7e0d3f809035b97721b18471425f0d64b8d27 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:36:00 +0300 Subject: [PATCH 1454/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index da27b3d86..0a61c77d8 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -549,7 +549,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba { if ( (destsatoshis= (butxo->payment.value * price)) > autxo->payment.value-desttxfee && destsatoshis > 2*desttxfee ) { - destsatoshis *= ((double)autxo->payment.value / destsatoshis - desttxfee*2); + destsatoshis *= ((double)autxo->payment.value / (destsatoshis - desttxfee*2)); if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->payment.value >> 1) ) { printf("best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); From f4a469b246e25f49edfc2beaf0f3b749df553fdf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:38:21 +0300 Subject: [PATCH 1455/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 0a61c77d8..c064bf0a0 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -552,7 +552,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba destsatoshis *= ((double)autxo->payment.value / (destsatoshis - desttxfee*2)); if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->payment.value >> 1) ) { - printf("best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); + printf("price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; if ( bestmetric == 0. || metric < bestmetric ) { From 643907500b10140d419deb504684c70a5084643d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:40:25 +0300 Subject: [PATCH 1456/2705] Test --- iguana/exchanges/LP_ordermatch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index c064bf0a0..c31e73254 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -545,7 +545,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba vout = jint(item,"vout"); vol = jdouble(item,"volume"); metric = price / bestprice; - if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.1 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) + if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.2 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { if ( (destsatoshis= (butxo->payment.value * price)) > autxo->payment.value-desttxfee && destsatoshis > 2*desttxfee ) { @@ -560,6 +560,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba ordermatchprice = price; bestdestsatoshis = destsatoshis; bestmetric = metric; + printf("set best!\n"); } } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->payment.value >> 1),dstr(destsatoshis),dstr(butxo->payment.value),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); } From b6060d5e09ae01e1b3af835aa4cbf2d7ae0393b4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:42:56 +0300 Subject: [PATCH 1457/2705] Test --- iguana/exchanges/LP_ordermatch.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index c31e73254..8294bed7b 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -129,7 +129,10 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * qp->txfee = 10000; qp->satoshis = destsatoshis / price; if ( utxo->iambob == 0 || qp->txfee >= qp->satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis) ) + { + printf("quoteinit error.(%d %d %d %d)\n",utxo->iambob == 0,qp->txfee >= qp->satoshis,qp->txfee >= utxo->deposit.value,utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis)); return(-1); + } qp->satoshis -= qp->txfee; qp->txid = utxo->payment.txid; qp->vout = utxo->payment.vout; @@ -139,7 +142,10 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) qp->desttxfee = 10000; if ( qp->desttxfee >= qp->destsatoshis ) + { + printf("quoteinit desttxfee %.8f < %.8f destsatoshis\n",dstr(qp->desttxfee),dstr(qp->destsatoshis)); return(-2); + } qp->destsatoshis -= qp->desttxfee; safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); From b777ae2b948112786ebb9f1f73ff5ca8ef771699 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:43:56 +0300 Subject: [PATCH 1458/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 8294bed7b..be4468b3e 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -130,7 +130,7 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * qp->satoshis = destsatoshis / price; if ( utxo->iambob == 0 || qp->txfee >= qp->satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis) ) { - printf("quoteinit error.(%d %d %d %d)\n",utxo->iambob == 0,qp->txfee >= qp->satoshis,qp->txfee >= utxo->deposit.value,utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis)); + printf("quoteinit error.(%d %d %d %d) %.8f vs %.8f\n",utxo->iambob == 0,qp->txfee >= qp->satoshis,qp->txfee >= utxo->deposit.value,utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis),dstr(utxo->deposit.value),dstr(LP_DEPOSITSATOSHIS(qp->satoshis))); return(-1); } qp->satoshis -= qp->txfee; From bed2887867fbdd0a53599043ec85b3ac515aed7b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:47:25 +0300 Subject: [PATCH 1459/2705] Test --- iguana/exchanges/LP_ordermatch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index be4468b3e..0a1b4d064 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -553,10 +553,10 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba metric = price / bestprice; if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.2 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { - if ( (destsatoshis= (butxo->payment.value * price)) > autxo->payment.value-desttxfee && destsatoshis > 2*desttxfee ) + if ( (destsatoshis= (butxo->S.satoshis * price)) > autxo->payment.value-desttxfee && destsatoshis > 2*desttxfee ) { destsatoshis *= ((double)autxo->payment.value / (destsatoshis - desttxfee*2)); - if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->payment.value >> 1) ) + if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->S.satoshis >> 1) ) { printf("price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; @@ -568,7 +568,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba bestmetric = metric; printf("set best!\n"); } - } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->payment.value >> 1),dstr(destsatoshis),dstr(butxo->payment.value),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); + } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->S.satoshis >> 1),dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); } } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); } From 37412af68a063f61a2c59d304d2f560b4f9d3a35 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 13:57:19 +0300 Subject: [PATCH 1460/2705] Test --- iguana/exchanges/LP_ordermatch.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 0a1b4d064..d5cd41c0f 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -87,7 +87,7 @@ cJSON *LP_quotejson(struct LP_quoteinfo *qp) jadd64bits(retjson,"destsatoshis",qp->destsatoshis); if ( qp->satoshis != 0 ) { - price = (double)(qp->destsatoshis + qp->desttxfee) / qp->satoshis; + price = (double)qp->destsatoshis / qp->satoshis; jaddnum(retjson,"price",price); } } @@ -127,13 +127,12 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) qp->txfee = 10000; - qp->satoshis = destsatoshis / price; + qp->satoshis = destsatoshis / price + 0.49; if ( utxo->iambob == 0 || qp->txfee >= qp->satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis) ) { printf("quoteinit error.(%d %d %d %d) %.8f vs %.8f\n",utxo->iambob == 0,qp->txfee >= qp->satoshis,qp->txfee >= utxo->deposit.value,utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis),dstr(utxo->deposit.value),dstr(LP_DEPOSITSATOSHIS(qp->satoshis))); return(-1); } - qp->satoshis -= qp->txfee; qp->txid = utxo->payment.txid; qp->vout = utxo->payment.vout; qp->txid2 = utxo->deposit.txid; @@ -146,7 +145,6 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * printf("quoteinit desttxfee %.8f < %.8f destsatoshis\n",dstr(qp->desttxfee),dstr(qp->destsatoshis)); return(-2); } - qp->destsatoshis -= qp->desttxfee; safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); qp->srchash = utxo->pubkey; @@ -263,12 +261,12 @@ int32_t LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxo if ( strcmp((*autxop)->coinaddr,qp->destaddr) != 0 ) return(-10); } - if ( destvalue <= qp->desttxfee || srcvalue <= qp->txfee ) + if ( destvalue < qp->desttxfee+qp->destsatoshis || srcvalue < qp->txfee+qp->satoshis ) { printf("destsatoshis %.8f or satoshis %.8f is too small txfees %.8f %.8f?\n",dstr(qp->destsatoshis),dstr(qp->satoshis),dstr(qp->desttxfee),dstr(qp->txfee)); return(-11); } - qprice = ((double)(qp->destsatoshis - qp->desttxfee) / (qp->satoshis - qp->txfee)); + qprice = ((double)qp->destsatoshis / qp->satoshis); if ( qp->satoshis < (srcvalue >> 1) ) { printf("utxo payment %.8f is less than half covered by Q %.8f\n",dstr(srcvalue),dstr(qp->satoshis)); @@ -279,6 +277,7 @@ int32_t LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxo printf("destsatoshis %.8f is less than half of value %.8f\n",dstr(qp->destsatoshis),dstr(destvalue)); return(-13); } + printf("qprice %.8f <- %.8f/%.8f txfees.(%.8f %.8f)\n",qprice,dstr(qp->destsatoshis),dstr(qp->satoshis),dstr(qp->txfee),dstr(qp->desttxfee)); return(qprice); } @@ -479,7 +478,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d } if ( qprice < price ) { - printf("quote price %.8f too low vs %.8f for %s/%s\n",qprice,price,Q.srccoin,Q.destcoin); + printf("(%.8f %.8f) quote price %.8f too low vs %.8f for %s/%s\n",bid,ask,qprice,price,Q.srccoin,Q.destcoin); return(-5); } if ( butxo->S.swap == 0 && time(NULL) > butxo->T.swappending ) From 381a036e04efee32d2096a5a2ab5bb3a601710c2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:04:55 +0300 Subject: [PATCH 1461/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index d5cd41c0f..f66946973 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -241,7 +241,7 @@ int32_t LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxo } if ( LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout) == 0 ) { - printf("alice not eligible\n"); + printf("alice not eligible (%.8f %.8f)\n",dstr(destvalue),dstr(destvalue2)); return(-3); } if ( LP_quote_checkmempool(qp) < 0 ) From 52c35c4cf07c2bbd1696a1a67e5973f37d95af04 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:06:45 +0300 Subject: [PATCH 1462/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index f66946973..0a97a8d08 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -241,7 +241,7 @@ int32_t LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxo } if ( LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout) == 0 ) { - printf("alice not eligible (%.8f %.8f)\n",dstr(destvalue),dstr(destvalue2)); + char str[65]; printf("alice not eligible (%.8f %.8f) %s/v%d\n",dstr(destvalue),dstr(destvalue2),bits256_str(str,qp->feetxid),qp->feevout); return(-3); } if ( LP_quote_checkmempool(qp) < 0 ) From 7f6454ca98c9214061fdf0798c2b0381bc616fe2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:14:44 +0300 Subject: [PATCH 1463/2705] Test --- iguana/exchanges/LP_ordermatch.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 0a97a8d08..8414b882f 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -552,23 +552,22 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba metric = price / bestprice; if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.2 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { - if ( (destsatoshis= (butxo->S.satoshis * price)) > autxo->payment.value-desttxfee && destsatoshis > 2*desttxfee ) - { + destsatoshis = (butxo->S.satoshis * price); + if ( destsatoshis > autxo->payment.value-desttxfee ) destsatoshis *= ((double)autxo->payment.value / (destsatoshis - desttxfee*2)); - if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->S.satoshis >> 1) ) + if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->S.satoshis >> 1) ) + { + printf("price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); + metric = dstr(destsatoshis) * metric * metric * metric; + if ( bestmetric == 0. || metric < bestmetric ) { - printf("price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); - metric = dstr(destsatoshis) * metric * metric * metric; - if ( bestmetric == 0. || metric < bestmetric ) - { - bestutxo = butxo; - ordermatchprice = price; - bestdestsatoshis = destsatoshis; - bestmetric = metric; - printf("set best!\n"); - } - } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->S.satoshis >> 1),dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); - } + bestutxo = butxo; + ordermatchprice = price; + bestdestsatoshis = destsatoshis; + bestmetric = metric; + printf("set best!\n"); + } + } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->S.satoshis >> 1),dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); } } else break; From 70d2b9d49f82f61873b665ef67206eb996fa05d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:17:59 +0300 Subject: [PATCH 1464/2705] Test --- iguana/exchanges/LP_ordermatch.c | 46 +++++++++++++++++++------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 8414b882f..90f5c24bc 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -585,34 +585,42 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); bestitem = LP_quotejson(&Q); - if ( price <= maxprice ) + if ( price > SMALLVAL ) { - price = LP_query(myipaddr,mypubsock,profitmargin,"connect",&Q); - LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); - expiration = (uint32_t)time(NULL) + timeout; - while ( time(NULL) < expiration ) + if ( price <= maxprice ) { - if ( autxo->S.swap != 0 ) - break; - sleep(1); + price = LP_query(myipaddr,mypubsock,profitmargin,"connect",&Q); + LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); + expiration = (uint32_t)time(NULL) + timeout; + while ( time(NULL) < expiration ) + { + if ( autxo->S.swap != 0 ) + break; + sleep(1); + } + if ( autxo->S.swap == 0 ) + { + jaddstr(bestitem,"status","couldnt establish connection"); + LP_availableset(autxo); + } + else jaddstr(bestitem,"status","connected"); + jaddnum(bestitem,"quotedprice",price); + jaddnum(bestitem,"maxprice",maxprice); + jaddnum(bestitem,"requestid",Q.R.requestid); + jaddnum(bestitem,"quoteid",Q.R.quoteid); + printf("Alice r.%u q.%u\n",Q.R.requestid,Q.R.quoteid); } - if ( autxo->S.swap == 0 ) + else { - jaddstr(bestitem,"status","couldnt establish connection"); - LP_availableset(autxo); + jaddnum(bestitem,"quotedprice",price); + jaddnum(bestitem,"maxprice",maxprice); + jaddstr(bestitem,"status","too expensive"); } - else jaddstr(bestitem,"status","connected"); - jaddnum(bestitem,"quotedprice",price); - jaddnum(bestitem,"maxprice",maxprice); - jaddnum(bestitem,"requestid",Q.R.requestid); - jaddnum(bestitem,"quoteid",Q.R.quoteid); - printf("Alice r.%u q.%u\n",Q.R.requestid,Q.R.quoteid); } else { - jaddnum(bestitem,"quotedprice",price); jaddnum(bestitem,"maxprice",maxprice); - jaddstr(bestitem,"status","too expensive"); + jaddstr(bestitem,"status","no response to request"); } return(jprint(bestitem,0)); } From 73640984301bc9441ac1789d09721b06639b0783 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:21:15 +0300 Subject: [PATCH 1465/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 90f5c24bc..e684733e4 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -230,7 +230,7 @@ int32_t LP_quote_checkmempool(struct LP_quoteinfo *qp) return(0); } -int32_t LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxop,struct LP_quoteinfo *qp,int32_t iambob) +double LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxop,struct LP_quoteinfo *qp,int32_t iambob) { double qprice; uint64_t srcvalue,srcvalue2,destvalue,destvalue2; *autxop = *butxop = 0; From bc5b54016296f371b77897b798fac51e7753c7cc Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:25:15 +0300 Subject: [PATCH 1466/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_ordermatch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 40e8f7154..eaffc014b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -121,7 +121,7 @@ forwardhex(pubkey,hex)\n\ { if ( price > SMALLVAL ) { - LP_mypriceset(base,rel,price); + LP_mypriceset(rel,base,1./price); return(LP_autotrade(myipaddr,pubsock,profitmargin,base,rel,price,jdouble(argjson,"volume"),jint(argjson,"timeout"))); } else return(clonestr("{\"error\":\"no price set\"}")); } diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index e684733e4..80c4c4068 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -413,7 +413,7 @@ char *LP_connectedalice(cJSON *argjson) // alice } if ( (price= LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin)) <= SMALLVAL || bid <= SMALLVAL ) { - printf("this node has no price for %s/%s\n",Q.srccoin,Q.destcoin); + printf("this node has no price for %s/%s (%.8f %.8f)\n",Q.srccoin,Q.destcoin,bid,ask); LP_availableset(autxo); return(clonestr("{\"error\":\"no price set\"}")); } From 5e7ff4fa3cf61c504b0c24e3bf6385be943178ae Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:27:02 +0300 Subject: [PATCH 1467/2705] Test --- iguana/exchanges/LP_commands.c | 1 + iguana/exchanges/LP_ordermatch.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index eaffc014b..f8ee69477 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -121,6 +121,7 @@ forwardhex(pubkey,hex)\n\ { if ( price > SMALLVAL ) { + printf("price set (%s/%s) <- %.8f\n",rel,base,1./price); LP_mypriceset(rel,base,1./price); return(LP_autotrade(myipaddr,pubsock,profitmargin,base,rel,price,jdouble(argjson,"volume"),jint(argjson,"timeout"))); } else return(clonestr("{\"error\":\"no price set\"}")); diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 80c4c4068..3b2293ef5 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -411,13 +411,13 @@ char *LP_connectedalice(cJSON *argjson) // alice printf("quote validate error %.0f\n",qprice); return(clonestr("{\"error\":\"quote validation error\"}")); } - if ( (price= LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin)) <= SMALLVAL || bid <= SMALLVAL ) + if ( (price= LP_myprice(&bid,&ask,Q.destcoin,Q.srccoin)) <= SMALLVAL || bid <= SMALLVAL ) { - printf("this node has no price for %s/%s (%.8f %.8f)\n",Q.srccoin,Q.destcoin,bid,ask); + printf("this node has no price for %s/%s (%.8f %.8f)\n",Q.destcoin,Q.srccoin,bid,ask); LP_availableset(autxo); return(clonestr("{\"error\":\"no price set\"}")); } - price = bid; + price = 1. / bid; if ( qprice > price ) { LP_availableset(autxo); From 714a45540e77b8ca446744e36e8de9918f2d95c0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:31:40 +0300 Subject: [PATCH 1468/2705] Test --- iguana/exchanges/LP_ordermatch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 3b2293ef5..08220a2a9 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -411,14 +411,14 @@ char *LP_connectedalice(cJSON *argjson) // alice printf("quote validate error %.0f\n",qprice); return(clonestr("{\"error\":\"quote validation error\"}")); } - if ( (price= LP_myprice(&bid,&ask,Q.destcoin,Q.srccoin)) <= SMALLVAL || bid <= SMALLVAL ) + if ( (price= LP_myprice(&bid,&ask,Q.destcoin,Q.srccoin)) <= SMALLVAL || ask <= SMALLVAL ) { printf("this node has no price for %s/%s (%.8f %.8f)\n",Q.destcoin,Q.srccoin,bid,ask); LP_availableset(autxo); return(clonestr("{\"error\":\"no price set\"}")); } - price = 1. / bid; - if ( qprice > price ) + price = 1. / ask; + if ( qprice > price+SMALLVAL ) { LP_availableset(autxo); return(clonestr("{\"error\":\"quote price too expensive\"}")); @@ -476,7 +476,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d printf("quote validate error %.0f\n",qprice); return(-4); } - if ( qprice < price ) + if ( qprice < price-SMALLVAL ) { printf("(%.8f %.8f) quote price %.8f too low vs %.8f for %s/%s\n",bid,ask,qprice,price,Q.srccoin,Q.destcoin); return(-5); From cf2035e002ef7df38abe79afc53197c21862a601 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:38:23 +0300 Subject: [PATCH 1469/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_swap.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 6b2263712..0fcd9876f 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -223,7 +223,7 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu } else retval = 0; if ( retval >= 0 && peer->pushsock >= 0 ) { - printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); + //printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); len = (int32_t)strlen(jsonstr) + 1; hexstr = malloc(len*2 + 1); init_hexbytes_noT(hexstr,(uint8_t *)jsonstr,len); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index fa674cf7a..b0facbf01 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -419,15 +419,15 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; - //printf("waitsend.%s\n",statename); + printf("waitsend.%s\n",statename); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { - //printf("waited for %s\n",statename); + printf("waited for %s\n",statename); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { - //printf("sent.%d after waitfor.%s\n",sendlen,statename); + printf("sent.%d after waitfor.%s\n",sendlen,statename); retval = 0; } else printf("send %s error\n",statename); } else printf("%s datagen no data\n",statename); From 3acf2894c5942643bb38f04bc20b817b16fdd90c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:41:57 +0300 Subject: [PATCH 1470/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- iguana/exchanges/LP_swap.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 08220a2a9..71edf0d29 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -418,7 +418,7 @@ char *LP_connectedalice(cJSON *argjson) // alice return(clonestr("{\"error\":\"no price set\"}")); } price = 1. / ask; - if ( qprice > price+SMALLVAL ) + //if ( qprice > price+SMALLVAL ) { LP_availableset(autxo); return(clonestr("{\"error\":\"quote price too expensive\"}")); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index b0facbf01..cf717ea35 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -403,12 +403,13 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i void *data; int32_t datalen,retval = -1; uint32_t expiration = (uint32_t)time(NULL) + timeout; while ( time(NULL) < expiration ) { - //printf("start wait\n"); + printf("start wait\n"); if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { - //printf("wait for got.%d\n",datalen); + printf("wait for got.%d\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); + printf("retval.%d\n",retval); return(retval); } else printf("error nn_recv\n"); } From 5c253c727eb69c450273762e8cc4a9031baffa2b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:46:07 +0300 Subject: [PATCH 1471/2705] Test --- iguana/exchanges/LP_ordermatch.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 71edf0d29..c19cb9086 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -339,12 +339,17 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) { - int32_t i; + int32_t i,timeout; for (i=0; i<10; i++) { nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 50000)); if ( nn_bind(pair,pairstr) >= 0 ) + { + timeout = 100; + nn_setsockopt(pair,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pair,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); return(0); + } } return(-1); } @@ -399,7 +404,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs char *LP_connectedalice(cJSON *argjson) // alice { - cJSON *retjson; double bid,ask,price,qprice; int32_t pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *autxo,*butxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; + cJSON *retjson; double bid,ask,price,qprice; int32_t timeout,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *autxo,*butxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; if ( LP_quoteparse(&Q,argjson) < 0 ) clonestr("{\"error\":\"cant parse quote\"}"); if ( bits256_cmp(Q.desthash,LP_mypubkey) != 0 ) @@ -431,6 +436,9 @@ char *LP_connectedalice(cJSON *argjson) // alice jaddstr(retjson,"error","couldnt create pairsock"); else if ( nn_connect(pairsock,pairstr) >= 0 ) { + timeout = 100; + nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q); swap->N.pair = pairsock; From 899c0ad3dad6a7db9e61e12ebed31fa7acc9a8a5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:51:08 +0300 Subject: [PATCH 1472/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_swap.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 26520dd47..b02350f2b 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -227,6 +227,7 @@ int32_t LP_ismine(struct LP_utxoinfo *utxo); int32_t LP_isavailable(struct LP_utxoinfo *utxo); struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port); char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin); +void LP_availableset(struct LP_utxoinfo *utxo); #endif diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index cf717ea35..cf8b9f847 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -141,7 +141,10 @@ void basilisk_swap_finished(struct basilisk_swap *swap) if ( swap->N.pair >= 0 ) nn_close(swap->N.pair); if ( swap->utxo != 0 ) - swap->utxo->S.swap = 0; + { + printf("make available\n"); + LP_availableset(swap->utxo); + } } uint32_t basilisk_quoteid(struct basilisk_request *rp) From cef7fa69946aa551ccbf20a5981e04191055fa24 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:52:53 +0300 Subject: [PATCH 1473/2705] Test --- iguana/exchanges/LP_swap.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index cf8b9f847..b488edefe 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -657,14 +657,14 @@ void LP_bobloop(void *_swap) fprintf(stderr,"start swap iambob\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); - expiration = (uint32_t)time(NULL) + 10; + expiration = (uint32_t)time(NULL) + 3; if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",10,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",3,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); - else if ( LP_waitsend("choosei",10,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + else if ( LP_waitsend("choosei",3,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); - else if ( LP_waitsend("mostprivs",10,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + else if ( LP_waitsend("mostprivs",3,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error waitsend mostprivs\n"); else if ( basilisk_bobscripts_set(swap,1,1) < 0 ) printf("error bobscripts deposit\n"); @@ -675,11 +675,11 @@ void LP_bobloop(void *_swap) basilisk_bobdeposit_refund(swap,swap->I.putduration); //printf("depositlen.%d\n",swap->bobdeposit.I.datalen); LP_swapsfp_update(&swap->I.req); - if ( LP_waitfor(swap->N.pair,swap,10,LP_verify_otherfee) < 0 ) + if ( LP_waitfor(swap->N.pair,swap,3,LP_verify_otherfee) < 0 ) printf("error waiting for alicefee\n"); else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0) == 0 ) printf("error sending bobdeposit\n"); - else if ( LP_waitfor(swap->N.pair,swap,10,LP_verify_alicepayment) < 0 ) + else if ( LP_waitfor(swap->N.pair,swap,3,LP_verify_alicepayment) < 0 ) printf("error waiting for alicepayment\n"); else { @@ -708,15 +708,15 @@ void LP_aliceloop(void *_swap) uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = _swap; maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); - expiration = (uint32_t)time(NULL) + 10; + expiration = (uint32_t)time(NULL) + 3; if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); - if ( LP_sendwait("pubkeys",10,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_sendwait("pubkeys",3,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); - else if ( LP_sendwait("choosei",10,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + else if ( LP_sendwait("choosei",3,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); - else if ( LP_sendwait("mostprivs",10,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + else if ( LP_sendwait("mostprivs",3,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error LP_sendwait mostprivs\n"); else if ( basilisk_alicetxs(swap->N.pair,swap,data,maxlen) != 0 ) printf("basilisk_alicetxs error\n"); @@ -725,7 +725,7 @@ void LP_aliceloop(void *_swap) LP_swapsfp_update(&swap->I.req); if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x80,data,maxlen,&swap->myfee,0x40,0) == 0 ) printf("error sending alicefee\n"); - else if ( LP_waitfor(swap->N.pair,swap,10,LP_verify_bobdeposit) < 0 ) + else if ( LP_waitfor(swap->N.pair,swap,3,LP_verify_bobdeposit) < 0 ) printf("error waiting for bobdeposit\n"); else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0) == 0 ) printf("error sending alicepayment\n"); From 8094a93566641835f19705984b31d68ac117a09c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:55:28 +0300 Subject: [PATCH 1474/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 4faf2e2a5..61e3ccb9a 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -50,7 +50,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) } usleep(1000); } - printf("error LP_send, pipeline timeout\n"); + printf("error LP_send, pipeline timeout.(%s)\n",msg); //if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) // printf("LP_send sent %d instead of %d\n",sentbytes,len); if ( freeflag != 0 ) From fdfef78938aa4fd68aa265f2186d664eb7ca5203 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 14:56:33 +0300 Subject: [PATCH 1475/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 61e3ccb9a..d75c68258 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -43,7 +43,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) { if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); - //else printf("SENT.(%s)\n",msg); + else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); return(sentbytes); From 14d1a1ddacd1688b05c6b1e001ba8f0fc2c569eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 15:07:29 +0300 Subject: [PATCH 1476/2705] Test --- iguana/exchanges/LP_forwarding.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 0fcd9876f..f5186648d 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -48,6 +48,21 @@ char *LP_lookup(bits256 pubkey) else return(clonestr("{\"error\":\"notfound\"}")); } +int32_t LP_pushsock_create(char *pushaddr) +{ + int32_t pushsock,timeout; + if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) + return(-1); + else if ( nn_connect(pushsock,pushaddr) < 0 ) + { + nn_close(pushsock); + return(-1); + } + timeout = 100; + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + return(pushsock); +} + char *LP_register(bits256 pubkey,char *ipaddr) { struct LP_forwardinfo *ptr=0; int32_t pushsock; char pushaddr[64]; @@ -60,15 +75,17 @@ char *LP_register(bits256 pubkey,char *ipaddr) if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { ptr->lasttime = (uint32_t)time(NULL); + if ( ptr->pushsock >= 0 ) + { + nn_close(ptr->pushsock); + printf("recreate pushsock for %s\n",pushaddr); + if ( (ptr->pushsock= LP_pushsock_create(pushaddr)) < 0 ) + return(clonestr("{\"error\":\"couldnt recreate pushsock\",\"registered\":0}")); + } return(clonestr("{\"error\":\"already registered\",\"registered\":1}")); } - else if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) - return(clonestr("{\"error\":\"out of sockets\"}")); - else if ( nn_connect(pushsock,pushaddr) < 0 ) - { - nn_close(pushsock); - return(clonestr("{\"error\":\"cant connect\"}")); - } + else if ( (pushsock= LP_pushsock_create(pushaddr)) < 0 ) + return(clonestr("{\"error\":\"couldnt create pushsock\"}")); else { char str[65]; printf("registered (%s) -> (%s)\n",bits256_str(str,pubkey),pushaddr); From 864663fb207c09e583b343c1331c734d64dd04d5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 15:19:26 +0300 Subject: [PATCH 1477/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f8426ead9..e21e43590 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -149,7 +149,7 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof nonz++; if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { - //printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); + printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); portable_mutex_lock(&LP_commandmutex); if ( (retstr= LP_command_process(myipaddr,-1,argjson,0,0,profitmargin)) != 0 ) { @@ -316,6 +316,8 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in free(retstr); while ( 1 ) { + if ( (rand() % 100) == 0 ) + printf("mainloop\n"); if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,pullsock,myport,passphrase,profitmargin) == 0 ) usleep(100000); } From ba3f984079ae92df6d89747fb17029f6a5441cbf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 15:30:38 +0300 Subject: [PATCH 1478/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 91 ++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e21e43590..60ccb8830 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -95,59 +95,66 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * return(retstr); } -int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) +void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen) { - int32_t recvsize,len,datalen=0,nonz = 0; void *ptr; char *retstr,*jsonstr=0; cJSON *argjson,*reqjson; - while ( (recvsize= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + int32_t len,datalen=0,nonz = 0; char *retstr,*jsonstr=0; cJSON *argjson,*reqjson; + if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) { - nonz++; - if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) - { - datalen >>= 1; - jsonstr = malloc(datalen + 1); - decode_hex((void *)jsonstr,datalen,(char *)ptr); - jsonstr[datalen] = 0; - } else jsonstr = (char *)ptr; - printf("PULLED %d, datalen.%d (%s)\n",recvsize,datalen,jsonstr); - if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) + datalen >>= 1; + jsonstr = malloc(datalen + 1); + decode_hex((void *)jsonstr,datalen,(char *)ptr); + jsonstr[datalen] = 0; + } else jsonstr = (char *)ptr; + printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); + if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) + { + len = (int32_t)strlen(jsonstr) + 1; + portable_mutex_lock(&LP_commandmutex); + if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) { - len = (int32_t)strlen(jsonstr) + 1; - portable_mutex_lock(&LP_commandmutex); - if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) - { - //printf("got forwardhex\n"); - if ( (retstr= LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) - free(retstr); - } - else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) - { - printf("got publish\n"); - if ( jobj(argjson,"method2") != 0 ) - jdelete(argjson,"method2"); - jaddstr(argjson,"method2","broadcast"); - if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) - LP_send(pubsock,jprint(reqjson,1),1); - } - else if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvsize - len,profitmargin)) != 0 ) + //printf("got forwardhex\n"); + if ( (retstr= LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) free(retstr); - portable_mutex_unlock(&LP_commandmutex); - free_json(argjson); - } else printf("error parsing(%s)\n",jsonstr); - if ( (void *)jsonstr != ptr ) - free(jsonstr); - if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0; + } + else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) + { + printf("got publish\n"); + if ( jobj(argjson,"method2") != 0 ) + jdelete(argjson,"method2"); + jaddstr(argjson,"method2","broadcast"); + if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) + LP_send(pubsock,jprint(reqjson,1),1); + } + else if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvlen - len,profitmargin)) != 0 ) + free(retstr); + portable_mutex_unlock(&LP_commandmutex); + free_json(argjson); + } else printf("error parsing(%s)\n",jsonstr); + if ( (void *)jsonstr != ptr ) + free(jsonstr); + if ( ptr != 0 ) + nn_freemsg(ptr), ptr = 0; +} + +int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) +{ + void *ptr; int32_t recvlen,nonz = 0; + while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + { + nonz++; + LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); } return(nonz); } int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double profitmargin) { - int32_t recvsize,nonz = 0; char *retstr; void *ptr; cJSON *argjson; - while ( sock >= 0 && (recvsize= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) + int32_t recvlen,nonz = 0; void *ptr; + while ( sock >= 0 && (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) + LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen); + /*if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); portable_mutex_lock(&LP_commandmutex); @@ -159,7 +166,7 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof free_json(argjson); } else printf("error parsing.(%s)\n",(char *)ptr); if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0; + nn_freemsg(ptr), ptr = 0;*/ } return(nonz); } From a6d32f1138b2213b60f62bc64a5dbef7128dc77d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 15:41:16 +0300 Subject: [PATCH 1479/2705] Test --- iguana/exchanges/LP_ordermatch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index c19cb9086..fec341f65 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -423,7 +423,7 @@ char *LP_connectedalice(cJSON *argjson) // alice return(clonestr("{\"error\":\"no price set\"}")); } price = 1. / ask; - //if ( qprice > price+SMALLVAL ) + //if ( qprice > price+0.00000001 ) { LP_availableset(autxo); return(clonestr("{\"error\":\"quote price too expensive\"}")); @@ -484,7 +484,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d printf("quote validate error %.0f\n",qprice); return(-4); } - if ( qprice < price-SMALLVAL ) + if ( qprice < price-0.00000001 ) { printf("(%.8f %.8f) quote price %.8f too low vs %.8f for %s/%s\n",bid,ask,qprice,price,Q.srccoin,Q.destcoin); return(-5); From 37c9e7fbfa4d4427a322ac1069af94e8230c1121 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 15:43:52 +0300 Subject: [PATCH 1480/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_ordermatch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index f8ee69477..6642ee06c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -48,7 +48,7 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs { if ( flag == 0 || jobj(argjson,"result") != 0 ) printf("stats_JSON no method: (%s) (%s:%u)\n",jprint(argjson,0),ipaddr,argport); - return(clonestr("{\"error\":\"need method in request\"}")); + return(0); } if ( strcmp(method,"help") == 0 ) return(clonestr("{\"result\":\" \ diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index fec341f65..1d07debe2 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -471,7 +471,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d { //printf("TRADECOMMAND.(%s)\n",jprint(argjson,0)); retval = 1; - if ( LP_quoteparse(&Q,argjson) == 0 ) + if ( LP_quoteparse(&Q,argjson) == 0 && bits256_cmp(LP_mypubkey,Q.srchash) == 0 ) { if ( (price= LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin)) <= SMALLVAL || ask <= SMALLVAL ) { From bfc179c4aa1a47975f65a5d638eeb7e6625bda94 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 15:49:30 +0300 Subject: [PATCH 1481/2705] Test --- iguana/exchanges/LP_commands.c | 35 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6642ee06c..6bd88ada0 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -170,27 +170,25 @@ forwardhex(pubkey,hex)\n\ return(LP_myprices()); } if ( LP_isdisabled(base,rel) != 0 ) - return(clonestr("{\"error\":\"at least one of coins disabled\"}")); - if ( LP_isdisabled(jstr(argjson,"coin"),0) != 0 ) - return(clonestr("{\"error\":\"coin is disabled\"}")); - if ( strcmp(method,"reserved") == 0 ) + retstr = clonestr("{\"error\":\"at least one of coins disabled\"}"); + else if ( LP_isdisabled(jstr(argjson,"coin"),0) != 0 ) + retstr = clonestr("{\"error\":\"coin is disabled\"}"); + else if ( strcmp(method,"reserved") == 0 ) retstr = LP_quotereceived(argjson); else if ( strcmp(method,"connected") == 0 ) retstr = LP_connectedalice(argjson); else if ( strcmp(method,"checktxid") == 0 ) retstr = LP_spentcheck(argjson); else if ( strcmp(method,"getcoins") == 0 ) - retstr = jprint(LP_coinsjson(),1); + return(jprint(LP_coinsjson(),1)); else if ( strcmp(method,"postprice") == 0 ) retstr = LP_postedprice(argjson); else if ( strcmp(method,"broadcast") == 0 ) retstr = LP_broadcasted(argjson); - //else if ( strcmp(method,"getprice") == 0 ) - // retstr = LP_pricestr(base,rel,0.); else if ( strcmp(method,"getprices") == 0 ) - retstr = LP_prices(); + return(LP_prices()); else if ( strcmp(method,"orderbook") == 0 ) - retstr = LP_orderbook(base,rel); + return(LP_orderbook(base,rel)); else if ( strcmp(method,"forward") == 0 ) { cJSON *reqjson; @@ -204,14 +202,12 @@ forwardhex(pubkey,hex)\n\ } else if ( strcmp(method,"getpeers") == 0 ) - retstr = LP_peers(); + return(LP_peers()); else if ( strcmp(method,"getutxos") == 0 ) - retstr = LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn")); + return(LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn"))); else if ( strcmp(method,"notified") == 0 ) { - //printf("utxonotify.(%s)\n",jprint(argjson,0)); - //if ( juint(argjson,"timestamp") > time(NULL)-60 ) - LP_utxoaddjson(1,LP_mypubsock,argjson); + LP_utxoaddjson(1,LP_mypubsock,argjson); retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); } else if ( IAMLP != 0 ) @@ -219,16 +215,17 @@ forwardhex(pubkey,hex)\n\ if ( strcmp(method,"register") == 0 ) retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr")); else if ( strcmp(method,"lookup") == 0 ) - retstr = LP_lookup(jbits256(argjson,"client")); + return(LP_lookup(jbits256(argjson,"client"))); else if ( strcmp(method,"forwardhex") == 0 ) retstr = LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex")); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); } if ( retstr != 0 ) - return(retstr); - retjson = cJSON_CreateObject(); - jaddstr(retjson,"error","unrecognized command"); + { + free(retstr); + return(0); + } printf("ERROR.(%s)\n",jprint(argjson,0)); - return(clonestr(jprint(retjson,1))); + return(0); } From a5bcbfdffef9ba48c62e0c835000ce07fbdc44ab Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 15:56:43 +0300 Subject: [PATCH 1482/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/LP_ordermatch.c | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index f5186648d..0b30713c8 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -88,7 +88,6 @@ char *LP_register(bits256 pubkey,char *ipaddr) return(clonestr("{\"error\":\"couldnt create pushsock\"}")); else { - char str[65]; printf("registered (%s) -> (%s)\n",bits256_str(str,pubkey),pushaddr); ptr = calloc(1,sizeof(*ptr)); ptr->pubkey = pubkey; strcpy(ptr->pushaddr,pushaddr); @@ -97,6 +96,7 @@ char *LP_register(bits256 pubkey,char *ipaddr) portable_mutex_lock(&LP_forwardmutex); HASH_ADD_KEYPTR(hh,LP_forwardinfos,&ptr->pubkey,sizeof(ptr->pubkey),ptr); portable_mutex_unlock(&LP_forwardmutex); + char str[65]; printf("registered (%s) -> (%s) pushsock.%d\n",bits256_str(str,pubkey),pushaddr,ptr->pushsock); return(LP_lookup(pubkey)); } } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 60ccb8830..95dd98e85 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -97,7 +97,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen) { - int32_t len,datalen=0,nonz = 0; char *retstr,*jsonstr=0; cJSON *argjson,*reqjson; + int32_t len,datalen=0; char *retstr,*jsonstr=0; cJSON *argjson,*reqjson; if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) { datalen >>= 1; @@ -383,7 +383,6 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { pubsock = -1; nanomsg_tcpname(subaddr,myipaddr,mypubport); - printf(">>>>>>>>> myipaddr.%s (%s %s)\n",myipaddr,pushaddr,subaddr); if ( (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) { if ( nn_bind(pubsock,subaddr) >= 0 ) @@ -398,6 +397,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_close(pubsock), pubsock = -1; } } else printf("error getting sockets %d %d\n",pullsock,pubsock); + printf(">>>>>>>>> myipaddr.%s (%s %s) pubsock.%d pullsock.%d\n",myipaddr,pushaddr,subaddr,pubsock,pullsock); LP_mypubsock = pubsock; LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index d75c68258..99884bcb4 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -50,7 +50,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) } usleep(1000); } - printf("error LP_send, pipeline timeout.(%s)\n",msg); + printf("error LP_send sock.%d, pipeline timeout.(%s)\n",sock,msg); //if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) // printf("LP_send sent %d instead of %d\n",sentbytes,len); if ( freeflag != 0 ) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 1d07debe2..1ba842b14 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -348,6 +348,7 @@ int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) timeout = 100; nn_setsockopt(pair,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(pair,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + printf("nanobind %s to %d\n",pairstr,pair); return(0); } } @@ -444,7 +445,7 @@ char *LP_connectedalice(cJSON *argjson) // alice swap->N.pair = pairsock; autxo->S.swap = swap; swap->utxo = autxo; - printf("alice pairstr.(%s)\n",pairstr); + printf("alice pairstr.(%s) pairsock.%d\n",pairstr,pairsock); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 ) { jaddstr(retjson,"result","success"); From 5db55485b5352732d23c42abc960c0e9db6bf4c8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:02:26 +0300 Subject: [PATCH 1483/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 1ba842b14..884bf34ca 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -563,7 +563,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba { destsatoshis = (butxo->S.satoshis * price); if ( destsatoshis > autxo->payment.value-desttxfee ) - destsatoshis *= ((double)autxo->payment.value / (destsatoshis - desttxfee*2)); + destsatoshis *= ((double)autxo->payment.value / (destsatoshis - desttxfee)); if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->S.satoshis >> 1) ) { printf("price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); From 76601ae7d13a7fd66d95a65ee0f68545b74af327 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:05:35 +0300 Subject: [PATCH 1484/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_ordermatch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6bd88ada0..1edcc4e4d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -208,7 +208,7 @@ forwardhex(pubkey,hex)\n\ else if ( strcmp(method,"notified") == 0 ) { LP_utxoaddjson(1,LP_mypubsock,argjson); - retstr = clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}"); + return(clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}")); } else if ( IAMLP != 0 ) { diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 884bf34ca..84d277f4e 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -563,7 +563,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba { destsatoshis = (butxo->S.satoshis * price); if ( destsatoshis > autxo->payment.value-desttxfee ) - destsatoshis *= ((double)autxo->payment.value / (destsatoshis - desttxfee)); + destsatoshis *= ((double)autxo->payment.value / (destsatoshis + desttxfee)); if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->S.satoshis >> 1) ) { printf("price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); From ef13f460b6857a98f1126fcd1c325efe335a09b9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:12:36 +0300 Subject: [PATCH 1485/2705] Test --- iguana/exchanges/LP_ordermatch.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 84d277f4e..0b475f1bb 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -529,7 +529,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume,int32_t timeout) { - int64_t destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; + int64_t satoshis,destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) return(clonestr("{\"error\":\"invalid parameter\"}")); if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * volume)) == 0 ) @@ -562,9 +562,10 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.2 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { destsatoshis = (butxo->S.satoshis * price); - if ( destsatoshis > autxo->payment.value-desttxfee ) - destsatoshis *= ((double)autxo->payment.value / (destsatoshis + desttxfee)); - if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && destsatoshis/price-txfee > (butxo->S.satoshis >> 1) ) + if ( destsatoshis > autxo->payment.value-2*desttxfee ) + destsatoshis *= ((double)autxo->payment.value / (destsatoshis + 2*desttxfee)); + satoshis = destsatoshis / price; + if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && satoshis-txfee > (butxo->S.satoshis >> 1) && satoshis < butxo->payment.value-txfee ) { printf("price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; From a7726b08eb742fdec36ccdb4f78346700ad63314 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:19:55 +0300 Subject: [PATCH 1486/2705] Test --- iguana/exchanges/LP_ordermatch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 0b475f1bb..64b477a95 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -263,7 +263,7 @@ double LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxop } if ( destvalue < qp->desttxfee+qp->destsatoshis || srcvalue < qp->txfee+qp->satoshis ) { - printf("destsatoshis %.8f or satoshis %.8f is too small txfees %.8f %.8f?\n",dstr(qp->destsatoshis),dstr(qp->satoshis),dstr(qp->desttxfee),dstr(qp->txfee)); + printf("destvalue %.8f srcvalue %.8f, destsatoshis %.8f or satoshis %.8f is too small txfees %.8f %.8f?\n",dstr(destvalue),dstr(srcvalue),dstr(qp->destsatoshis),dstr(qp->satoshis),dstr(qp->desttxfee),dstr(qp->txfee)); return(-11); } qprice = ((double)qp->destsatoshis / qp->satoshis); @@ -562,8 +562,8 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.2 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { destsatoshis = (butxo->S.satoshis * price); - if ( destsatoshis > autxo->payment.value-2*desttxfee ) - destsatoshis *= ((double)autxo->payment.value / (destsatoshis + 2*desttxfee)); + if ( destsatoshis > autxo->payment.value-desttxfee-1 ) + destsatoshis = autxo->payment.value-desttxfee-1; satoshis = destsatoshis / price; if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && satoshis-txfee > (butxo->S.satoshis >> 1) && satoshis < butxo->payment.value-txfee ) { From 1de8e0dc389c59fc99f753d9db47375c171c1084 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:20:50 +0300 Subject: [PATCH 1487/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 1edcc4e4d..05088c558 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -213,7 +213,7 @@ forwardhex(pubkey,hex)\n\ else if ( IAMLP != 0 ) { if ( strcmp(method,"register") == 0 ) - retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr")); + return(LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr"))); else if ( strcmp(method,"lookup") == 0 ) return(LP_lookup(jbits256(argjson,"client"))); else if ( strcmp(method,"forwardhex") == 0 ) From 4dcfe358b75e8ccc05a7b00e0c61343c26f9e81a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:28:29 +0300 Subject: [PATCH 1488/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_ordermatch.c | 16 +++++++++------- iguana/exchanges/LP_transaction.c | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index b02350f2b..9ddca6a0b 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -24,6 +24,7 @@ #define LP_HTTP_TIMEOUT 1 #define LP_MAXPEER_ERRORS 3 #define LP_AUTOTRADE_TIMEOUT 3 +#define LP_MIN_TXFEE 10000 #define LP_DEXFEE(destsatoshis) ((destsatoshis) / INSTANTDEX_INSURANCEDIV) #define LP_DEPOSITSATOSHIS(satoshis) ((satoshis) + (satoshis >> 3)) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 64b477a95..1263dc763 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -125,8 +125,8 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * if ( qp->timestamp == 0 ) qp->timestamp = (uint32_t)time(NULL); safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); - if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < 10000 ) - qp->txfee = 10000; + if ( (qp->txfee= LP_getestimatedrate(utxo->coin)*LP_AVETXSIZE) < LP_MIN_TXFEE ) + qp->txfee = LP_MIN_TXFEE; qp->satoshis = destsatoshis / price + 0.49; if ( utxo->iambob == 0 || qp->txfee >= qp->satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis) ) { @@ -138,8 +138,8 @@ int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char * qp->txid2 = utxo->deposit.txid; qp->vout2 = utxo->deposit.vout; qp->destsatoshis = destsatoshis; - if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < 10000 ) - qp->desttxfee = 10000; + if ( (qp->desttxfee= LP_getestimatedrate(qp->destcoin) * LP_AVETXSIZE) < LP_MIN_TXFEE ) + qp->desttxfee = LP_MIN_TXFEE; if ( qp->desttxfee >= qp->destsatoshis ) { printf("quoteinit desttxfee %.8f < %.8f destsatoshis\n",dstr(qp->desttxfee),dstr(qp->destsatoshis)); @@ -535,8 +535,10 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * volume)) == 0 ) return(clonestr("{\"error\":\"cant find utxo that is big enough\"}")); bestmetric = ordermatchprice = 0.; - desttxfee = LP_getestimatedrate(rel) * LP_AVETXSIZE; - txfee = LP_getestimatedrate(base) * LP_AVETXSIZE; + if ( (desttxfee= LP_getestimatedrate(rel) * LP_AVETXSIZE) < LP_MINTXFEE ) + desttxfee = LP_MIN_TXFEE; + if ( (txfee= LP_getestimatedrate(base) * LP_AVETXSIZE) < LP_MINTXFEE ) + txfee = LP_MIN_TXFEE; if ( timeout == 0 ) timeout = LP_AUTOTRADE_TIMEOUT; if ( (obookstr= LP_orderbook(base,rel)) != 0 ) @@ -567,7 +569,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba satoshis = destsatoshis / price; if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && satoshis-txfee > (butxo->S.satoshis >> 1) && satoshis < butxo->payment.value-txfee ) { - printf("price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); + printf("value %.8f price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",dstr(autxo->payment.value),price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; if ( bestmetric == 0. || metric < bestmetric ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index c37c100a9..1af4c0395 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -881,8 +881,8 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub if ( coin->estimatedrate == 0. ) coin->estimatedrate = LP_getestimatedrate(coin->symbol); newtxfee = coin->estimatedrate * len; - if ( newtxfee < 10000 ) - newtxfee = 10000; + if ( newtxfee < LP_MIN_TXFEE ) + newtxfee = LP_MIN_TXFEE; printf("txfee %.8f -> newtxfee %.8f\n",dstr(txfee),dstr(newtxfee)); } else break; } From afc3650929dcea34bff6e9ba923b6d123d86a215 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:38:03 +0300 Subject: [PATCH 1489/2705] Test --- iguana/exchanges/LP_ordermatch.c | 8 ++++---- iguana/exchanges/LP_prices.c | 4 ++-- iguana/exchanges/LP_utxos.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 1263dc763..1d642d285 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -535,9 +535,9 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * volume)) == 0 ) return(clonestr("{\"error\":\"cant find utxo that is big enough\"}")); bestmetric = ordermatchprice = 0.; - if ( (desttxfee= LP_getestimatedrate(rel) * LP_AVETXSIZE) < LP_MINTXFEE ) + if ( (desttxfee= LP_getestimatedrate(rel) * LP_AVETXSIZE) < LP_MIN_TXFEE ) desttxfee = LP_MIN_TXFEE; - if ( (txfee= LP_getestimatedrate(base) * LP_AVETXSIZE) < LP_MINTXFEE ) + if ( (txfee= LP_getestimatedrate(base) * LP_AVETXSIZE) < LP_MIN_TXFEE ) txfee = LP_MIN_TXFEE; if ( timeout == 0 ) timeout = LP_AUTOTRADE_TIMEOUT; @@ -561,7 +561,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba vout = jint(item,"vout"); vol = jdouble(item,"volume"); metric = price / bestprice; - if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.2 && vol*SATOSHIDEN == butxo->payment.value && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) + if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.2 && vol*SATOSHIDEN == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { destsatoshis = (butxo->S.satoshis * price); if ( destsatoshis > autxo->payment.value-desttxfee-1 ) @@ -580,7 +580,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba printf("set best!\n"); } } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->S.satoshis >> 1),dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); - } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->payment.value):0); + } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0); } } else break; } diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 8028cb5df..c1284fad3 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -554,8 +554,8 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * //char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); if ( polarity > 0 ) - basesatoshis = utxo->payment.value; - else basesatoshis = utxo->payment.value * price; + basesatoshis = utxo->S.satoshis; + else basesatoshis = utxo->S.satoshis * price; if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey)) != 0 ) (*arrayp)[num++] = op; if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 9c0de17c9..bd0d53970 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -286,7 +286,7 @@ struct LP_utxoinfo *LP_utxo_bestfit(char *symbol,uint64_t destsatoshis) //char str[65]; printf("check %s.%s\n",utxo->coin,bits256_str(str,utxo->payment.txid)); if ( strcmp(symbol,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && LP_ismine(utxo) > 0 ) { - if ( utxo->payment.value >= destsatoshis && (bestutxo == 0 || utxo->payment.value < bestutxo->payment.value) ) + if ( utxo->S.satoshis >= destsatoshis && (bestutxo == 0 || utxo->S.satoshis < bestutxo->S.satoshis) ) bestutxo = utxo; } } From befa5bdaca9e9fb7492c49e490d115e6b435d11c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:46:14 +0300 Subject: [PATCH 1490/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 95dd98e85..a189ca860 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -323,7 +323,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in free(retstr); while ( 1 ) { - if ( (rand() % 100) == 0 ) + if ( 0 && (rand() % 100) == 0 ) printf("mainloop\n"); if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,pullsock,myport,passphrase,profitmargin) == 0 ) usleep(100000); diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 99884bcb4..344f4c204 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -35,7 +35,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) return(-1); } len = (int32_t)strlen(msg) + 1; - for (i=0; i<100; i++) + for (i=0; i<1000; i++) { pfd.fd = sock; pfd.events = NN_POLLOUT; From 006f428636cf34739ab8c8af5c18d8b975aab03f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 16:59:27 +0300 Subject: [PATCH 1491/2705] Test --- iguana/exchanges/LP_ordermatch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 1d642d285..54384fc60 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -557,6 +557,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba { if ( bestprice == 0. ) // assumes price ordered asks bestprice = price; + printf("item.[%d] %s\n",i,jprint(item,0)); txid = jbits256(item,"txid"); vout = jint(item,"vout"); vol = jdouble(item,"volume"); From 39b2c584fc1f318a0bc268e450e1650810e5a6a1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:05:59 +0300 Subject: [PATCH 1492/2705] Test --- iguana/exchanges/LP_ordermatch.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 54384fc60..ff4ee3dd7 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -552,6 +552,9 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba item = jitem(asks,i); if ( (price= jdouble(item,"price")) > SMALLVAL && price <= maxprice ) { + price *= 1.0001; + if ( price > maxprice ) + price = maxprice; pubkey = jbits256(item,"pubkey"); if ( bits256_cmp(pubkey,LP_mypubkey) != 0 ) { From 3ec15809c85ed05fe068a6e73a6477ce1d3cab13 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:18:25 +0300 Subject: [PATCH 1493/2705] Test --- iguana/exchanges/LP_prices.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index c1284fad3..3d0e879c0 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -540,26 +540,30 @@ int32_t LP_utxo_clientpublish(struct LP_utxoinfo *utxo) int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char *rel,struct LP_orderbookentry *(**arrayp),int32_t num,int32_t cachednum) { - struct LP_utxoinfo *utxo,*tmp; struct LP_pubkeyinfo *pubp; struct LP_priceinfo *basepp; struct LP_orderbookentry *op; double price; int32_t baseid,relid; uint64_t basesatoshis; + struct LP_utxoinfo *utxo,*tmp; struct LP_pubkeyinfo *pubp=0; struct LP_priceinfo *basepp; struct LP_orderbookentry *op; double price; int32_t baseid,relid; uint64_t basesatoshis; if ( (basepp= LP_priceinfoptr(&relid,base,rel)) != 0 ) baseid = basepp->ind; else return(num); HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp) { + if ( pubp == 0 || bits256_cmp(pubp->pubkey,utxo->pubkey) != 0 ) + pubp = LP_pubkeyfind(utxo->pubkey); //char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); - if ( strcmp(base,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && (pubp= LP_pubkeyfind(utxo->pubkey)) != 0 && (price= pubp->matrix[baseid][relid]) > SMALLVAL ) + if ( strcmp(base,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && pubp != 0 && (price= pubp->matrix[baseid][relid]) > SMALLVAL ) { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { //char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); - *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); if ( polarity > 0 ) basesatoshis = utxo->S.satoshis; else basesatoshis = utxo->S.satoshis * price; if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey)) != 0 ) + { + *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); (*arrayp)[num++] = op; - if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) - LP_utxo_clientpublish(utxo); + if ( bits256_cmp(utxo->pubkey,LP_mypubkey) == 0 && utxo->T.lasttime == 0 ) + LP_utxo_clientpublish(utxo); + } } } } From b62a3869a90fd2328b59c816519fc79ec710fc28 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:23:09 +0300 Subject: [PATCH 1494/2705] Test --- iguana/exchanges/LP_prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 3d0e879c0..02adf85d3 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -553,10 +553,10 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * { if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 ) { - //char str[65]; printf("found utxo not in orderbook %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); if ( polarity > 0 ) basesatoshis = utxo->S.satoshis; else basesatoshis = utxo->S.satoshis * price; + char str[65]; printf("found utxo not in orderbook %s/v%d %.8f %.8f\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,dstr(basesatoshis),polarity > 0 ? price : 1./price); if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey)) != 0 ) { *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); From 8e04818a37b1b135c02e348eb8f51fd3bb278852 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:27:54 +0300 Subject: [PATCH 1495/2705] Test --- iguana/exchanges/LP_prices.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 02adf85d3..f9ed9828c 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -572,13 +572,14 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * char *LP_orderbook(char *base,char *rel) { - uint32_t now,i; struct LP_priceinfo *basepp=0,*relpp=0; struct LP_cacheinfo *ptr,*tmp; struct LP_orderbookentry *op,**bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0,cachenumbids,cachenumasks,baseid,relid; + uint32_t now,i; struct LP_priceinfo *basepp=0,*relpp=0; struct LP_orderbookentry **bids = 0,**asks = 0; cJSON *retjson,*array; int32_t numbids=0,numasks=0,cachenumbids,cachenumasks,baseid,relid; if ( (basepp= LP_priceinfofind(base)) == 0 || (relpp= LP_priceinfofind(rel)) == 0 ) return(clonestr("{\"error\":\"base or rel not added\"}")); baseid = basepp->ind; relid = relpp->ind; now = (uint32_t)time(NULL); - HASH_ITER(hh,LP_cacheinfos,ptr,tmp) + /*struct LP_cacheinfo *ptr,*tmp; + HASH_ITER(hh,LP_cacheinfos,ptr,tmp) { if ( ptr->timestamp < now-3600*2 || ptr->price == 0. ) continue; @@ -594,7 +595,7 @@ char *LP_orderbook(char *base,char *rel) if ( (op= LP_orderbookentry(base,rel,ptr->Q.txid,ptr->Q.vout,ptr->Q.txid2,ptr->Q.vout2,1./ptr->price,ptr->Q.satoshis,ptr->Q.srchash)) != 0 ) bids[numbids++] = op; } - } + }*/ cachenumbids = numbids, cachenumasks = numasks; //printf("start cache.(%d %d) numbids.%d numasks.%d\n",cachenumbids,cachenumasks,numbids,numasks); numasks = LP_orderbook_utxoentries(now,1,base,rel,&asks,numasks,cachenumasks); From e75f8eb260c2ff6c7ea23f1ccf86acb742cd034b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:30:55 +0300 Subject: [PATCH 1496/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- iguana/exchanges/LP_prices.c | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index ff4ee3dd7..fed378733 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -170,7 +170,7 @@ char *LP_quotereceived(cJSON *argjson) if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) { ptr->Q = Q; - printf("\n>>>>>>>>>> received.(%s) quote %.8f\n\n",jprint(argjson,0),price); + printf("\n>>>>>>>>>> received quote %.8f\n\n",price); return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); } diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index f9ed9828c..361553dbb 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -453,9 +453,9 @@ static int _cmp_orderbook(const void *a,const void *b) #define ptr_a (*(struct LP_orderbookentry **)a)->price #define ptr_b (*(struct LP_orderbookentry **)b)->price if ( ptr_b > ptr_a ) - retval = 1; - else if ( ptr_b < ptr_a ) retval = -1; + else if ( ptr_b < ptr_a ) + retval = 1; else { #undef ptr_a @@ -463,9 +463,9 @@ static int _cmp_orderbook(const void *a,const void *b) #define ptr_a ((struct LP_orderbookentry *)a)->basesatoshis #define ptr_b ((struct LP_orderbookentry *)b)->basesatoshis if ( ptr_b > ptr_a ) - return(1); - else if ( ptr_b < ptr_a ) return(-1); + else if ( ptr_b < ptr_a ) + return(1); } // printf("%.8f vs %.8f -> %d\n",ptr_a,ptr_b,retval); return(retval); @@ -473,11 +473,6 @@ static int _cmp_orderbook(const void *a,const void *b) #undef ptr_b } -static int _cmp_orderbookrev(const void *a,const void *b) -{ - return(-_cmp_orderbook(a,b)); -} - cJSON *LP_orderbookjson(struct LP_orderbookentry *op) { cJSON *item = cJSON_CreateObject(); @@ -603,13 +598,13 @@ char *LP_orderbook(char *base,char *rel) retjson = cJSON_CreateObject(); array = cJSON_CreateArray(); if ( numbids > 1 ) - qsort(bids,numbids,sizeof(*bids),_cmp_orderbookrev); + qsort(bids,numbids,sizeof(*bids),_cmp_orderbook); if ( numasks > 1 ) { for (i=0; iprice); printf(" -> "); - qsort(asks,numasks,sizeof(*asks),_cmp_orderbookrev); + qsort(asks,numasks,sizeof(*asks),_cmp_orderbook); for (i=0; iprice); printf("sorted asks.%d\n",numasks); From a0986c7353179b883fbe249ed1d3f1d0a8b896a0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:32:32 +0300 Subject: [PATCH 1497/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_prices.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a189ca860..9b7c42610 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -105,7 +105,7 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); + //printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { len = (int32_t)strlen(jsonstr) + 1; diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 361553dbb..8d55d3e02 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -551,7 +551,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * if ( polarity > 0 ) basesatoshis = utxo->S.satoshis; else basesatoshis = utxo->S.satoshis * price; - char str[65]; printf("found utxo not in orderbook %s/v%d %.8f %.8f\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,dstr(basesatoshis),polarity > 0 ? price : 1./price); + //char str[65]; printf("found utxo not in orderbook %s/v%d %.8f %.8f\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,dstr(basesatoshis),polarity > 0 ? price : 1./price); if ( (op= LP_orderbookentry(base,rel,utxo->payment.txid,utxo->payment.vout,utxo->deposit.txid,utxo->deposit.vout,polarity > 0 ? price : 1./price,basesatoshis,utxo->pubkey)) != 0 ) { *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1)); From 61703097afb3702a036db537a246aca99e295ba7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:38:14 +0300 Subject: [PATCH 1498/2705] Test --- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/LP_ordermatch.c | 2 +- iguana/exchanges/LP_utxos.c | 29 +++++++++++++++++++---------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 344f4c204..7fd4414b4 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -43,7 +43,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) { if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); - else printf("SENT.(%s)\n",msg); + //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); return(sentbytes); diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index fed378733..d65519218 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -560,7 +560,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba { if ( bestprice == 0. ) // assumes price ordered asks bestprice = price; - printf("item.[%d] %s\n",i,jprint(item,0)); + //printf("item.[%d] %s\n",i,jprint(item,0)); txid = jbits256(item,"txid"); vout = jint(item,"vout"); vol = jdouble(item,"volume"); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index bd0d53970..f1aa59266 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -114,19 +114,25 @@ int32_t LP_utxocollisions(struct LP_utxoinfo *ptrs[],struct LP_utxoinfo *refutxo n = LP_utxoaddptrs(ptrs,n,utxo); } portable_mutex_unlock(&LP_utxomutex); - if ( n > 0 ) + if ( 0 && n > 0 ) printf("LP_utxocollisions n.%d\n",n); return(n); } -void _LP_availableset(struct LP_utxoinfo *utxo) +int32_t _LP_availableset(struct LP_utxoinfo *utxo) { + int32_t flag = 0; if ( utxo != 0 ) { - memset(&utxo->S.otherpubkey,0,sizeof(utxo->S.otherpubkey)); - utxo->S.swap = 0; - utxo->T.swappending = 0; + if ( bits256_nonz(utxo->S.otherpubkey) != 0 ) + flag = 1, memset(&utxo->S.otherpubkey,0,sizeof(utxo->S.otherpubkey)); + if ( utxo->S.swap != 0 ) + flag = 1, utxo->S.swap = 0; + if ( utxo->T.swappending != 0 ) + flag = 1, utxo->T.swappending = 0; + return(flag); } + return(0); } void _LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) @@ -154,16 +160,19 @@ void LP_unavailableset(struct LP_utxoinfo *utxo,bits256 otherpubkey) void LP_availableset(struct LP_utxoinfo *utxo) { - struct LP_utxoinfo *ptrs[8]; int32_t i,n; struct _LP_utxoinfo u; + struct LP_utxoinfo *ptrs[8]; int32_t i,n,count = 0; struct _LP_utxoinfo u; memset(ptrs,0,sizeof(ptrs)); if ( (n= LP_utxocollisions(ptrs,utxo)) > 0 ) { for (i=0; i 0 ) + { + u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; + char str[65],str2[65]; printf("UTXO.[%d] AVAIL %s/v%d %s/v%d collisions.%d\n",utxo->iambob,bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,u.txid),u.vout,n); } - u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; - char str[65],str2[65]; printf("UTXO.[%d] AVAIL %s/v%d %s/v%d collisions.%d\n",utxo->iambob,bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,u.txid),u.vout,n); - _LP_availableset(utxo); } int32_t LP_utxopurge(int32_t allutxos) From 396df9bb81b2d81039f352d3c9d28b793d30ceef Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:41:37 +0300 Subject: [PATCH 1499/2705] Test --- iguana/exchanges/LP_ordermatch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index d65519218..a3f65d7cb 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -36,6 +36,7 @@ struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srch rp->desthash = desthash; rp->destamount = destsatoshis; rp->quoteid = basilisk_quoteid(rp); + printf("r.%u %u, q.%u %u: %s %.8f -> %s %.8f\n",rp->timestamp,rp->requestid,rp->quotetime,rp->quoteid,rp->src,dstr(rp->srcamount),rp->dest,dstr(rp->destamount)); return(rp); } @@ -424,8 +425,9 @@ char *LP_connectedalice(cJSON *argjson) // alice return(clonestr("{\"error\":\"no price set\"}")); } price = 1. / ask; - //if ( qprice > price+0.00000001 ) + if ( qprice > price+0.00000001 ) { + printf("qprice %.8f too big vs %.8f\n",qprice,price); LP_availableset(autxo); return(clonestr("{\"error\":\"quote price too expensive\"}")); } From e8d4b07426f00f2cfff1d2f1d5a04ff80e67efdf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:49:56 +0300 Subject: [PATCH 1500/2705] Test --- iguana/exchanges/LP_swap.c | 12 ++++++------ iguana/exchanges/LP_transaction.c | 3 +-- iguana/exchanges/LP_utxos.c | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index b488edefe..201ed38f0 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -406,13 +406,13 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i void *data; int32_t datalen,retval = -1; uint32_t expiration = (uint32_t)time(NULL) + timeout; while ( time(NULL) < expiration ) { - printf("start wait\n"); + //printf("start wait\n"); if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 ) { - printf("wait for got.%d\n",datalen); + //printf("wait for got.%d\n",datalen); retval = (*verify)(swap,data,datalen); nn_freemsg(data); - printf("retval.%d\n",retval); + //printf("retval.%d\n",retval); return(retval); } else printf("error nn_recv\n"); } @@ -423,15 +423,15 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; - printf("waitsend.%s\n",statename); + //printf("waitsend.%s\n",statename); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { - printf("waited for %s\n",statename); + //printf("waited for %s\n",statename); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { - printf("sent.%d after waitfor.%s\n",sendlen,statename); + //printf("sent.%d after waitfor.%s\n",sendlen,statename); retval = 0; } else printf("send %s error\n",statename); } else printf("%s datagen no data\n",statename); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 1af4c0395..2ba86473c 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1501,8 +1501,7 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d { bitcoin_address(swap->alicepayment.I.destaddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); //LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.I.destaddr); - if ( strcmp(swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr) != 0 ) - printf("alice addr mismatch %s vs %s\n",swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr); + strcpy(swap->alicepayment.p2shaddr,swap->alicepayment.I.destaddr); retval = 0; for (i=0; ialicepayment.I.datalen; i++) printf("%02x",swap->alicepayment.txbytes[i]); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index f1aa59266..ffb383b21 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -448,7 +448,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit } LP_utxosetkey(utxo->key,txid,vout); LP_utxosetkey(utxo->key2,txid2,vout2); - char str[65],str2[65],str3[65]; printf("%s iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",utxo->coinaddr,iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); + //char str[65],str2[65],str3[65]; printf("%s iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",utxo->coinaddr,iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) From 518b3c5f2e62b6dea62bb46e98cbd05d3b943e57 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 17:56:17 +0300 Subject: [PATCH 1501/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 ++ iguana/exchanges/LP_swap.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index a3f65d7cb..a23528166 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -456,6 +456,7 @@ char *LP_connectedalice(cJSON *argjson) // alice jaddnum(retjson,"quoteid",Q.R.quoteid); } else jaddstr(retjson,"error","couldnt aliceloop"); } + printf("connected result.(%s)\n",jprint(retjson,0)); if ( jobj(retjson,"error") != 0 ) LP_availableset(autxo); return(jprint(retjson,1)); @@ -463,6 +464,7 @@ char *LP_connectedalice(cJSON *argjson) // alice else { LP_availableset(autxo); + printf("no privkey found\n"); return(clonestr("{\"error\",\"no privkey\"}")); } } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 201ed38f0..688ec46d7 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -414,7 +414,7 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i nn_freemsg(data); //printf("retval.%d\n",retval); return(retval); - } else printf("error nn_recv\n"); + } // else printf("error nn_recv\n"); } printf("waitfor timedout\n"); return(retval); From 5612e89df69608a9ec5f0cf0b322315d65cdd078 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 18:03:19 +0300 Subject: [PATCH 1502/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_swap.c | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 9ddca6a0b..8a2636dd3 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -23,6 +23,7 @@ #define LP_HTTP_TIMEOUT 1 #define LP_MAXPEER_ERRORS 3 +#define LP_SWAPSTEP_TIMEOUT 3 #define LP_AUTOTRADE_TIMEOUT 3 #define LP_MIN_TXFEE 10000 diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 688ec46d7..ef8cc573f 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -603,7 +603,7 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 if ( suppress_swapsend == 0 ) { retval = LP_swapsend(pairsock,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs); - if ( LP_waitmempool(rawtx->coin->symbol,rawtx->I.signedtxid,10) < 0 ) + if ( LP_waitmempool(rawtx->coin->symbol,rawtx->I.signedtxid,LP_SWAPSTEP_TIMEOUT) < 0 ) { char str[65]; printf("failed to find %s %s in the mempool?\n",rawtx->name,bits256_str(str,rawtx->I.actualtxid)); retval = -1; @@ -657,14 +657,14 @@ void LP_bobloop(void *_swap) fprintf(stderr,"start swap iambob\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); - expiration = (uint32_t)time(NULL) + 3; + expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",3,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); - else if ( LP_waitsend("choosei",3,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + else if ( LP_waitsend("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); - else if ( LP_waitsend("mostprivs",3,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + else if ( LP_waitsend("mostprivs",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error waitsend mostprivs\n"); else if ( basilisk_bobscripts_set(swap,1,1) < 0 ) printf("error bobscripts deposit\n"); @@ -675,11 +675,11 @@ void LP_bobloop(void *_swap) basilisk_bobdeposit_refund(swap,swap->I.putduration); //printf("depositlen.%d\n",swap->bobdeposit.I.datalen); LP_swapsfp_update(&swap->I.req); - if ( LP_waitfor(swap->N.pair,swap,3,LP_verify_otherfee) < 0 ) + if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT,LP_verify_otherfee) < 0 ) printf("error waiting for alicefee\n"); else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0) == 0 ) printf("error sending bobdeposit\n"); - else if ( LP_waitfor(swap->N.pair,swap,3,LP_verify_alicepayment) < 0 ) + else if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT,LP_verify_alicepayment) < 0 ) printf("error waiting for alicepayment\n"); else { @@ -695,7 +695,7 @@ void LP_bobloop(void *_swap) printf("error bobscripts payment\n"); else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) printf("error sending bobpayment\n"); - LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); + LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); } } basilisk_swap_finished(swap); @@ -708,15 +708,15 @@ void LP_aliceloop(void *_swap) uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = _swap; maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); - expiration = (uint32_t)time(NULL) + 3; + expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); - if ( LP_sendwait("pubkeys",3,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_sendwait("pubkeys",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); - else if ( LP_sendwait("choosei",3,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) + else if ( LP_sendwait("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); - else if ( LP_sendwait("mostprivs",3,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) + else if ( LP_sendwait("mostprivs",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_mostprivs_verify,LP_mostprivs_data) < 0 ) printf("error LP_sendwait mostprivs\n"); else if ( basilisk_alicetxs(swap->N.pair,swap,data,maxlen) != 0 ) printf("basilisk_alicetxs error\n"); @@ -725,7 +725,7 @@ void LP_aliceloop(void *_swap) LP_swapsfp_update(&swap->I.req); if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x80,data,maxlen,&swap->myfee,0x40,0) == 0 ) printf("error sending alicefee\n"); - else if ( LP_waitfor(swap->N.pair,swap,3,LP_verify_bobdeposit) < 0 ) + else if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT,LP_verify_bobdeposit) < 0 ) printf("error waiting for bobdeposit\n"); else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0) == 0 ) printf("error sending alicepayment\n"); @@ -736,23 +736,23 @@ void LP_aliceloop(void *_swap) printf("waiting for alicepayment to confirm\n"); sleep(3); } - if ( LP_waitfor(swap->N.pair,swap,10,LP_verify_bobpayment) < 0 ) + if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT,LP_verify_bobpayment) < 0 ) printf("error waiting for bobpayment\n"); else { while ( LP_numconfirms(swap,&swap->bobpayment) < 1 ) { printf("waiting for bobpayment to confirm\n"); - sleep(3); + sleep(LP_SWAPSTEP_TIMEOUT); } if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) printf("error sending alicespend\n"); while ( LP_numconfirms(swap,&swap->alicespend) < 1 ) { printf("waiting for alicespend to confirm\n"); - sleep(3); + sleep(LP_SWAPSTEP_TIMEOUT); } - LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,600); + LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); } } } From 3c98281e3277be214dfb8b65dd1f0e05435a9a4a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 18:30:00 +0300 Subject: [PATCH 1503/2705] Test --- iguana/exchanges/LP_commands.c | 3 +++ iguana/exchanges/LP_include.h | 6 ++--- iguana/exchanges/LP_nativeDEX.c | 5 ----- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/LP_prices.c | 23 ++++++++++++++++++- iguana/exchanges/LP_swap.c | 37 ++++++++++++++++--------------- iguana/exchanges/LP_transaction.c | 7 +++--- 7 files changed, 52 insertions(+), 31 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 05088c558..bcbd2541b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -68,6 +68,7 @@ getutxos()\n\ getutxos(coin, lastn)\n\ orderbook(base, rel)\n\ getprices(base, rel)\n\ +trust(pubkey, trust)\n\ register(pubkey,pushaddr)\n\ lookup(pubkey)\n\ forward(pubkey,method2,)\n\ @@ -168,6 +169,8 @@ forwardhex(pubkey,hex)\n\ } else if ( strcmp(method,"myprices") == 0 ) return(LP_myprices()); + else if ( strcmp(method,"trust") == 0 ) + return(LP_pubkey_trustset(jbits256(argjson,"pubkey"),jint(argjson,"trust"))); } if ( LP_isdisabled(base,rel) != 0 ) retstr = clonestr("{\"error\":\"at least one of coins disabled\"}"); diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 8a2636dd3..34a4bd009 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -40,14 +40,14 @@ #define INSTANTDEX_BTC "1KRhTPvoxyJmVALwHFXZdeeWFbcJSbkFPu" #define INSTANTDEX_BTCD "RThtXup6Zo7LZAi8kRWgjAyi1s4u6U9Cpf" -#define BASILISK_DISABLEWAITTX -#define BASILISK_DISABLESENDTX +//#define BASILISK_DISABLEWAITTX +//#define BASILISK_DISABLESENDTX #define LP_PROPAGATION_SLACK 100 // txid ordering is not enforced, so getting extra recent txid #define LP_RESERVETIME 60 #define LP_AVETXSIZE 200 #define LP_CACHEDURATION 60 -#define BASILISK_DEFAULT_NUMCONFIRMS 5 +#define BASILISK_DEFAULT_NUMCONFIRMS 2 #define DEX_SLEEP 3 #define BASILISK_KEYSIZE ((int32_t)(2*sizeof(bits256)+sizeof(uint32_t)*2)) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9b7c42610..4678cbce7 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -38,11 +38,6 @@ double LP_profitratio = 1.; bits256 LP_mypubkey; // stubs -int32_t basilisk_istrustedbob(struct basilisk_swap *swap) -{ - // for BTC and if trusted LP - return(0); -} void tradebot_swap_balancingtrade(struct basilisk_swap *swap,int32_t iambob) { diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 7fd4414b4..58783ad03 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -77,7 +77,7 @@ uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbit { } } - printf("sent %d bytes\n",sentbytes); + //printf("sent %d bytes\n",sentbytes); //else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data); free(buf); return(nextbits); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 8d55d3e02..3bbdfe01c 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -46,7 +46,7 @@ struct LP_pubkeyinfo UT_hash_handle hh; bits256 pubkey; double matrix[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS]; - uint32_t timestamp; + uint32_t timestamp,istrusted; } *LP_pubkeyinfos; struct LP_priceinfo *LP_priceinfofind(char *symbol) @@ -134,6 +134,25 @@ struct LP_pubkeyinfo *LP_pubkeyadd(bits256 pubkey) return(pubp); } +int32_t LP_pubkey_istrusted(bits256 pubkey) +{ + struct LP_pubkeyinfo *pubp; + if ( (pubp= LP_pubkeyfind(pubkey)) != 0 ) + return(pubp->istrusted != 0); + return(0); +} + +char *LP_pubkey_trustedset(bits256 pubkey,uint32_t trustval) +{ + struct LP_pubkeyinfo *pubp; + if ( (pubp= LP_pubkeyfind(pubkey)) != 0 ) + { + pubp->istrusted = trustval; + return(clonestr("{\"result\":\"success\"}")); + } + return(clonestr("{\"error\":\"pubkey not found\"}")); +} + cJSON *LP_pubkeyjson(struct LP_pubkeyinfo *pubp) { int32_t baseid,relid; char *base; double price; cJSON *item,*array,*obj; @@ -157,6 +176,8 @@ cJSON *LP_pubkeyjson(struct LP_pubkeyinfo *pubp) jaddbits256(obj,"pubkey",pubp->pubkey); jaddnum(obj,"timestamp",pubp->timestamp); jadd(obj,"asks",array); + if ( pubp->istrusted != 0 ) + jaddnum(obj,"istrusted",pubp->istrusted); return(obj); } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index ef8cc573f..f310e0fa2 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -139,12 +139,9 @@ void basilisk_swap_finished(struct basilisk_swap *swap) free(swap->messages), swap->messages = 0; swap->nummessages = 0; if ( swap->N.pair >= 0 ) - nn_close(swap->N.pair); + nn_close(swap->N.pair), swap->N.pair = -1; if ( swap->utxo != 0 ) - { - printf("make available\n"); LP_availableset(swap->utxo); - } } uint32_t basilisk_quoteid(struct basilisk_request *rp) @@ -686,7 +683,7 @@ void LP_bobloop(void *_swap) swap->bobreclaim.utxovout = 0; swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); - while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + while ( LP_numconfirms(swap,&swap->alicepayment) < swap->I.aliceconfirms ) { printf("waiting for alicepayment to confirm\n"); sleep(3); @@ -731,7 +728,7 @@ void LP_aliceloop(void *_swap) printf("error sending alicepayment\n"); else { - while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + while ( LP_numconfirms(swap,&swap->alicepayment) < swap->I.aliceconfirms ) { printf("waiting for alicepayment to confirm\n"); sleep(3); @@ -740,14 +737,14 @@ void LP_aliceloop(void *_swap) printf("error waiting for bobpayment\n"); else { - while ( LP_numconfirms(swap,&swap->bobpayment) < 1 ) + while ( LP_numconfirms(swap,&swap->bobpayment) < swap->I.bobconfirms ) { printf("waiting for bobpayment to confirm\n"); sleep(LP_SWAPSTEP_TIMEOUT); } if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) printf("error sending alicespend\n"); - while ( LP_numconfirms(swap,&swap->alicespend) < 1 ) + while ( LP_numconfirms(swap,&swap->alicespend) < swap->I.aliceconfirms ) { printf("waiting for alicespend to confirm\n"); sleep(LP_SWAPSTEP_TIMEOUT); @@ -843,6 +840,9 @@ int32_t instantdex_pubkeyargs(struct basilisk_swap *swap,int32_t numpubs,bits256 void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx *rawtx,struct iguana_info *coin,int32_t numconfirms,int32_t vintype,uint64_t satoshis,int32_t vouttype,uint8_t *pubkey33,int32_t jumblrflag) { +#ifdef BASILISK_DISABLEWAITTX + numconfirms = 0; +#endif strcpy(rawtx->name,name); rawtx->coin = coin; strcpy(rawtx->I.coinstr,coin->symbol); @@ -874,7 +874,7 @@ void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx * struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 pubkey25519,struct basilisk_swap *swap,int32_t optionduration,uint32_t statebits,struct LP_quoteinfo *qp) { //FILE *fp; char fname[512]; - uint8_t *alicepub33=0,*bobpub33=0; int32_t jumblrflag=-2,x = -1; struct iguana_info *coin; + uint8_t *alicepub33=0,*bobpub33=0; int32_t bobistrusted,aliceistrusted,jumblrflag=-2,x = -1; struct iguana_info *coin; swap->I.putduration = swap->I.callduration = INSTANTDEX_LOCKTIME; if ( optionduration < 0 ) swap->I.putduration -= optionduration; @@ -900,11 +900,15 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 { swap->I.iambob = 0; swap->I.otherhash = swap->I.req.desthash; + aliceistrusted = 1; + bobistrusted = LP_pubkey_istrusted(swap->I.req.desthash); } else { swap->I.iambob = 1; swap->I.otherhash = swap->I.req.srchash; + bobistrusted = 1; + aliceistrusted = LP_pubkey_istrusted(swap->I.req.desthash); } if ( bits256_nonz(privkey) == 0 || (x= instantdex_pubkeyargs(swap,2 + INSTANTDEX_DECKSIZE,privkey,swap->I.orderhash,0x02+swap->I.iambob)) != 2 + INSTANTDEX_DECKSIZE ) { @@ -929,24 +933,21 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 } if ( strcmp("BTC",swap->bobcoin.symbol) == 0 ) { - swap->I.bobconfirms = (1*0 + sqrt(dstr(swap->I.bobsatoshis) * .1)); - swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); + swap->I.bobconfirms = (1 + sqrt(dstr(swap->I.bobsatoshis) * .1)); + swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms + 1); } else if ( strcmp("BTC",swap->alicecoin.symbol) == 0 ) { - swap->I.aliceconfirms = (1*0 + sqrt(dstr(swap->I.alicesatoshis) * .1)); - swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms * 3); + swap->I.aliceconfirms = (1 + sqrt(dstr(swap->I.alicesatoshis) * .1)); + swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.aliceconfirms + 1); } else { swap->I.bobconfirms = BASILISK_DEFAULT_NUMCONFIRMS; swap->I.aliceconfirms = BASILISK_DEFAULT_NUMCONFIRMS; } - /*if ( swap->I.bobconfirms == 0 ) - swap->I.bobconfirms = swap->bobcoin->chain->minconfirms; - if ( swap->I.aliceconfirms == 0 ) - swap->I.aliceconfirms = swap->alicecoin->chain->minconfirms;*/ - //jumblrflag = (bits256_cmp(pubkey25519,myinfo->jumblr_pubkey) == 0 || bits256_cmp(pubkey25519,myinfo->jumblr_depositkey) == 0); + swap->I.bobconfirms *= !bobistrusted; + swap->I.aliceconfirms *= !aliceistrusted; printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); if ( swap->I.iambob != 0 ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 2ba86473c..54fd5da35 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -251,16 +251,17 @@ int32_t LP_mempool_vinscan(bits256 *spendtxidp,int32_t *spendvinp,char *symbol,b int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) { int32_t numconfirms = 100; -#ifndef BASILISK_DISABLEWAITTX +//#ifndef BASILISK_DISABLEWAITTX cJSON *txobj; numconfirms = -1; if ( (txobj= LP_gettx(rawtx->coin->symbol,rawtx->I.signedtxid)) != 0 ) { numconfirms = jint(txobj,"confirmations"); free_json(txobj); - } else if ( LP_mempoolscan(rawtx->coin->symbol,rawtx->I.signedtxid) >= 0 ) + } + else if ( LP_mempoolscan(rawtx->coin->symbol,rawtx->I.signedtxid) >= 0 ) numconfirms = 0; -#endif +//#endif return(numconfirms); } From 09d00d70460b81778dc0dc241482dec0ad814289 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 18:30:49 +0300 Subject: [PATCH 1504/2705] test --- iguana/exchanges/LP_prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 3bbdfe01c..598d0d3ad 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -142,7 +142,7 @@ int32_t LP_pubkey_istrusted(bits256 pubkey) return(0); } -char *LP_pubkey_trustedset(bits256 pubkey,uint32_t trustval) +char *LP_pubkey_trustset(bits256 pubkey,uint32_t trustval) { struct LP_pubkeyinfo *pubp; if ( (pubp= LP_pubkeyfind(pubkey)) != 0 ) From cfb6801fb90ac9df286c40bcbff5a02784ff8663 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 18:50:59 +0300 Subject: [PATCH 1505/2705] Test --- iguana/exchanges/LP_network.c | 1 + iguana/exchanges/LP_utxos.c | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 58783ad03..535f027fd 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -17,6 +17,7 @@ // LP_network.c // marketmaker // +// jl777: might need to queue outbound packets and send via separate thread char *nanomsg_tcpname(char *str,char *ipaddr,uint16_t port) { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index ffb383b21..9a1d9ddda 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -17,6 +17,7 @@ // LP_utxos.c // marketmaker // +// jl777: invalidate utxo when either part is spent. if not expected spend, mark as bad and generate new utxopair using other half int32_t LP_ismine(struct LP_utxoinfo *utxo) { @@ -285,6 +286,20 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la return(jprint(utxosjson,1)); } +int32_t LP_inventory_prevent(int32_t iambob,bits256 txid,int32_t vout) +{ + struct LP_utxoinfo *utxo; + if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 || (utxo= LP_utxo2find(iambob,txid,vout)) != 0 ) + { + if ( utxo->T.spentflag != 0 ) + { + char str[65]; printf("prevent adding %s/v%d to inventory\n",bits256_str(str,txid),vout); + return(1); + } + } + return(0); +} + struct LP_utxoinfo *LP_utxo_bestfit(char *symbol,uint64_t destsatoshis) { struct LP_utxoinfo *utxo,*tmp,*bestutxo = 0; @@ -608,17 +623,19 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr if ( iambob == 0 ) values = calloc(n,sizeof(*values)); else memset(values,0,n * sizeof(*values)); - if ( iambob == 0 && IAMLP != 0 ) - continue; + //if ( iambob == 0 && IAMLP != 0 ) + // continue; + used = 0; for (i=0; i Date: Sat, 17 Jun 2017 18:59:26 +0300 Subject: [PATCH 1506/2705] Test --- iguana/exchanges/LP_utxos.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 9a1d9ddda..ddd96fd02 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -406,6 +406,16 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; + if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) + { + printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); + return(0); + } + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) + { + printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); + return(0); + } if ( (utxo= LP_utxofinds(iambob,txid,vout,txid2,vout2)) != 0 ) { if ( 0 && LP_ismine(utxo) == 0 ) @@ -417,7 +427,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { utxo->T.errors++; - char str[65],str2[65],str3[65],str4[65]; printf("error on subsequent utxo add.(%s v %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,txid),bits256_str(str2,utxo->payment.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); + char str[65],str2[65],str3[65],str4[65]; printf("error on subsequent utxo add.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,utxo->payment.txid),bits256_str(str2,u.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); } else if ( profitmargin > SMALLVAL ) utxo->S.profitmargin = profitmargin; @@ -429,16 +439,6 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit printf("utxoadd mismatch %s/v%d (%s %.8f) + %s/v%d (%s %.8f) != %s %.8f %.8f\n",bits256_str(str,txid),vout,destaddr,dstr(val),bits256_str(str2,txid2),vout2,destaddr2,dstr(val2),coinaddr,dstr(value),dstr(value2)); return(0); }*/ - if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) - { - printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); - return(0); - } - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) - { - printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); - return(0); - } utxo = calloc(1,sizeof(*utxo)); utxo->S.profitmargin = profitmargin; utxo->pubkey = pubkey; From d1451ee19b0dca670ad0eecd4812cce0f2782935 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 19:02:41 +0300 Subject: [PATCH 1507/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index ddd96fd02..13e72aedf 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -406,6 +406,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; + char str2[65],str3[65]; printf("%s iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",utxo->coinaddr,iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); @@ -463,7 +464,6 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit } LP_utxosetkey(utxo->key,txid,vout); LP_utxosetkey(utxo->key2,txid2,vout2); - //char str[65],str2[65],str3[65]; printf("%s iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",utxo->coinaddr,iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); portable_mutex_lock(&LP_utxomutex); HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) From 646a4f979ab8e5eea22406baa9834a3a97bf5ad2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 19:04:03 +0300 Subject: [PATCH 1508/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 13e72aedf..8a27f7b87 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -406,7 +406,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; - char str2[65],str3[65]; printf("%s iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",utxo->coinaddr,iambob,bits256_str(str3,utxo->pubkey),utxo->coin,dstr(value),dstr(value2),bits256_str(str,utxo->payment.txid),bits256_str(str2,txid2)); + char str2[65]; printf("%s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); From 96b64d1b775ed7c5ffc926378749c0404f299a2c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 19:19:27 +0300 Subject: [PATCH 1509/2705] Test --- iguana/exchanges/LP_swap.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index f310e0fa2..af26c15fc 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -680,19 +680,22 @@ void LP_bobloop(void *_swap) printf("error waiting for alicepayment\n"); else { - swap->bobreclaim.utxovout = 0; - swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; - basilisk_bobpayment_reclaim(swap,swap->I.callduration); - while ( LP_numconfirms(swap,&swap->alicepayment) < swap->I.aliceconfirms ) - { - printf("waiting for alicepayment to confirm\n"); - sleep(3); - } if ( basilisk_bobscripts_set(swap,0,1) < 0 ) printf("error bobscripts payment\n"); - else if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) - printf("error sending bobpayment\n"); - LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); + else + { + swap->bobreclaim.utxovout = 0; + swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; + basilisk_bobpayment_reclaim(swap,swap->I.callduration); + while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + { + char str[65];printf("waiting for alicepayment to be confirmed %s %s\n",swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); + sleep(3); + } + if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) + printf("error sending bobpayment\n"); + LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); + } } } basilisk_swap_finished(swap); @@ -728,10 +731,10 @@ void LP_aliceloop(void *_swap) printf("error sending alicepayment\n"); else { - while ( LP_numconfirms(swap,&swap->alicepayment) < swap->I.aliceconfirms ) + while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) { - printf("waiting for alicepayment to confirm\n"); - sleep(3); + char str[65];printf("waiting for alicepayment to be confirmed %s %s\n",swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); + sleep(LP_SWAPSTEP_TIMEOUT); } if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT,LP_verify_bobpayment) < 0 ) printf("error waiting for bobpayment\n"); From 28b1a35cf7ee2722eedd7d3f7b72ea593cc1dc80 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 19:43:20 +0300 Subject: [PATCH 1510/2705] Test --- iguana/exchanges/LP_remember.c | 18 ++++++++++++++++++ iguana/exchanges/LP_swap.c | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index dc02a419b..f5d083594 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -867,6 +867,24 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( finishedflag != 0 ) jaddstr(item,"status","finished"); else jaddstr(item,"status","pending"); + if ( bits256_nonz(paymentspent) == 0 ) + { + if ( bits256_nonz(txids[BASILISK_ALICESPEND]) != 0 ) + paymentspent = txids[BASILISK_ALICESPEND]; + else paymentspent = txids[BASILISK_BOBRECLAIM]; + } + if ( bits256_nonz(depositspent) == 0 ) + { + if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) + depositspent = txids[BASILISK_BOBREFUND]; + else depositspent = txids[BASILISK_ALICECLAIM]; + } + if ( bits256_nonz(Apaymentspent) == 0 ) + { + if ( bits256_nonz(txids[BASILISK_BOBSPEND]) != 0 ) + Apaymentspent = txids[BASILISK_BOBSPEND]; + else Apaymentspent = txids[BASILISK_ALICERECLAIM]; + } bits256_str(str,paymentspent), jaddbits256(item,"paymentspent",paymentspent); bits256_str(str,Apaymentspent), jaddbits256(item,"Apaymentspent",Apaymentspent); bits256_str(str,depositspent), jaddbits256(item,"depositspent",depositspent); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index af26c15fc..44275bbc7 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -644,6 +644,11 @@ int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t { printf("SWAP completed! %u-%u %s\n",requestid,quoteid,jprint(retjson,0)); free_json(retjson); + if ( (retstr= basilisk_swapentry(requestid,quoteid)) != 0 ) + { + printf("second call.(%s)\n",retstr); + free(retstr); + } return(0); } else return(-1); } From e0b1efd47cdf2d92f655a98697fa167983b99013 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 19:53:48 +0300 Subject: [PATCH 1511/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4678cbce7..83b703df3 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -270,6 +270,11 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) { char *retstr; uint8_t r; int32_t i,n,j; cJSON *item; + if ( (retstr= basilisk_swapentry(0,0)) != 0 ) + { + //printf("SWAPS.(%s)\n",retstr); + free(retstr); + } if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); From abbad6221d38b129be840c7a17ef5feef297d9b6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 19:55:30 +0300 Subject: [PATCH 1512/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 8a27f7b87..30523f7d7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -406,7 +406,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; - char str2[65]; printf("%s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); + //char str2[65]; printf("%s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); From 51b3a0ac73e3bae248f0fd52b3fa3af54f513dd6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 20:03:08 +0300 Subject: [PATCH 1513/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_swap.c | 14 +++++------ iguana/exchanges/LP_transaction.c | 40 +++++++++++++++---------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 77f6a4b45..5c6621641 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -212,7 +212,7 @@ int32_t LP_importaddress(char *symbol,char *address) sprintf(buf,"[\"%s\", \"%s\", false]",address,address); if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"importaddress",buf)) != 0 ) { - printf("importaddress.(%s %s) -> (%s)\n",symbol,address,retstr); + //printf("importaddress.(%s %s) -> (%s)\n",symbol,address,retstr); free(retstr); } else printf("importaddress.(%s %s)\n",symbol,address); return(1); diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 44275bbc7..a723a775c 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -508,10 +508,10 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) { memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); - for (i=0; iI.redeemlen; i++) - printf("%02x",rawtx->redeemscript[i]); + //for (i=0; iI.redeemlen; i++) + // printf("%02x",rawtx->redeemscript[i]); bitcoin_address(redeemaddr,rawtx->coin->p2shtype,rawtx->redeemscript,rawtx->I.redeemlen); - printf(" received redeemscript.(%s)\n",redeemaddr); + //printf(" received redeemscript.(%s)\n",redeemaddr); LP_swap_coinaddr(swap,rawtx->coin,checkaddr,data,datalen); if ( strcmp(redeemaddr,checkaddr) != 0 ) { @@ -522,9 +522,9 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba //printf("recvlen.%d datalen.%d redeemlen.%d\n",recvlen,datalen,rawtx->redeemlen); if ( rawtx->I.datalen == 0 ) { - for (i=0; itxbytes,data,datalen); rawtx->I.datalen = datalen; } @@ -545,7 +545,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { rawtx->I.actualtxid = rawtx->I.signedtxid; - char str[65]; printf("got %s txid.%s (%s)\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),jprint(txobj,0)); + //char str[65]; printf("got %s txid.%s (%s)\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),jprint(txobj,0)); rawtx->I.locktime = rawtx->msgtx.lock_time; if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 54fd5da35..76b158391 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -218,7 +218,7 @@ int32_t LP_mempoolscan(char *symbol,bits256 txid) for (i=0; i satoshis+txfee ) change = value - (satoshis + txfee); - printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(change),dstr(txfee)); + //printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(change),dstr(txfee)); } else if ( value > txfee ) satoshis = value - txfee; else printf("unexpected small value %.8f vs txfee %.8f\n",dstr(value),dstr(txfee)); @@ -854,7 +854,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160,char *vinaddr) { int32_t retval=-1,len,iter; char *signedtx,*changeaddr = 0,_changeaddr[64]; struct iguana_info *coin; int64_t newtxfee=0,destamount; - char str2[65]; printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str2,rawtx->utxotxid),rawtx->utxovout); + //char str2[65]; printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str2,rawtx->utxotxid),rawtx->utxovout); if ( (coin= rawtx->coin) == 0 ) return(-1); //return(_basilisk_rawtx_gen(str,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay,privkey)); @@ -904,7 +904,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ { changeaddr = _changeaddr; bitcoin_address(changeaddr,pubtype,changermd160,20); - printf("changeaddr.(%s)\n",changeaddr); + //printf("changeaddr.(%s)\n",changeaddr); } for (iter=0; iter<2; iter++) { @@ -1480,14 +1480,14 @@ void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,s { int32_t i; char coinaddr[64]; alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); - for (i=0; i<33; i++) + /*for (i=0; i<33; i++) printf("%02x",swap->persistent_pubkey33[i]); printf(" pubkey33, "); for (i=0; i<20; i++) printf("%02x",swap->changermd160[i]); - printf(" rmd160, "); + printf(" rmd160, ");*/ bitcoin_address(coinaddr,coin->pubtype,swap->changermd160,20); - printf("%s suppress.%d fee.%d\n",coinaddr,alicepayment->I.suppress_pubkeys,swap->myfee.I.suppress_pubkeys); + //printf("%s suppress.%d fee.%d\n",coinaddr,alicepayment->I.suppress_pubkeys,swap->myfee.I.suppress_pubkeys); basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); } @@ -1520,9 +1520,9 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d swap->I.statebits |= LP_swapdata_rawtxsend(pairsock,swap,0x80,data,maxlen,&swap->myfee,0x40,0); LP_unspents_mark(swap->I.iambob!=0?swap->bobcoin.symbol:swap->alicecoin.symbol,swap->myfee.vins); //basilisk_txlog(swap,&swap->myfee,-1); - for (i=0; imyfee.I.datalen; i++) - printf("%02x",swap->myfee.txbytes[i]); - printf(" <- fee state.%x\n",swap->I.statebits); + //for (i=0; imyfee.I.datalen; i++) + // printf("%02x",swap->myfee.txbytes[i]); + //printf(" <- fee state.%x\n",swap->I.statebits); swap->I.statebits |= 0x40; } else @@ -1568,12 +1568,12 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); //LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); - for (i=0; ibobdeposit.I.datalen; i++) + /*for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); printf(" <- bobdeposit.%d %s\n",swap->bobdeposit.I.datalen,bits256_str(str,swap->bobdeposit.I.signedtxid)); for (i=0; ibobdeposit.I.redeemlen; i++) printf("%02x",swap->bobdeposit.redeemscript[i]); - printf(" <- bobdeposit redeem %d %s suppress.%d\n",i,swap->bobdeposit.I.destaddr,swap->aliceclaim.I.suppress_pubkeys); + printf(" <- bobdeposit redeem %d %s suppress.%d\n",i,swap->bobdeposit.I.destaddr,swap->aliceclaim.I.suppress_pubkeys);*/ memcpy(swap->aliceclaim.redeemscript,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); swap->aliceclaim.I.redeemlen = swap->bobdeposit.I.redeemlen; memcpy(swap->aliceclaim.I.pubkey33,swap->persistent_pubkey33,33); @@ -1581,12 +1581,12 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da retval = 0; if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) { - for (i=0; ibobdeposit.I.datalen; i++) + /*for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); printf(" <- bobdeposit\n"); for (i=0; ialiceclaim.I.datalen; i++) printf("%02x",swap->aliceclaim.txbytes[i]); - printf(" <- aliceclaim\n"); + printf(" <- aliceclaim\n");*/ //basilisk_txlog(swap,&swap->aliceclaim,swap->I.putduration+swap->I.callduration); return(LP_waitmempool(swap->bobcoin.symbol,swap->bobdeposit.I.signedtxid,10)); } else printf("error signing aliceclaim suppress.%d vin.(%s)\n",swap->aliceclaim.I.suppress_pubkeys,swap->bobdeposit.I.destaddr); @@ -1632,26 +1632,26 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); //LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); - for (i=0; ibobpayment.I.datalen; i++) + /*for (i=0; ibobpayment.I.datalen; i++) printf("%02x",swap->bobpayment.txbytes[i]); printf(" <- bobpayment.%d\n",swap->bobpayment.I.datalen); for (i=0; ibobpayment.I.redeemlen; i++) printf("%02x",swap->bobpayment.redeemscript[i]); - printf(" <- bobpayment redeem %d %s %s\n",i,swap->bobpayment.I.destaddr,bits256_str(str,swap->bobpayment.I.signedtxid)); + printf(" <- bobpayment redeem %d %s %s\n",i,swap->bobpayment.I.destaddr,bits256_str(str,swap->bobpayment.I.signedtxid));*/ memcpy(swap->I.userdata_alicespend,userdata,len); swap->I.userdata_alicespendlen = len; retval = 0; memcpy(swap->alicespend.I.pubkey33,swap->persistent_pubkey33,33); bitcoin_address(swap->alicespend.I.destaddr,swap->bobcoin.pubtype,swap->persistent_pubkey33,33); - char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); + //char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->alicepayment.I.destaddr)) == 0 ) { - for (i=0; ibobpayment.I.datalen; i++) + /*for (i=0; ibobpayment.I.datalen; i++) printf("%02x",swap->bobpayment.txbytes[i]); printf(" <- bobpayment\n"); for (i=0; ialicespend.I.datalen; i++) printf("%02x",swap->alicespend.txbytes[i]); - printf(" <- alicespend\n\n"); + printf(" <- alicespend\n\n");*/ swap->I.alicespent = 1; return(LP_waitmempool(swap->bobcoin.symbol,swap->bobpayment.I.signedtxid,10)); } else printf("error signing aliceclaim suppress.%d vin.(%s)\n",swap->alicespend.I.suppress_pubkeys,swap->bobpayment.I.destaddr); From d92ea815b16c9e4d9ba16a5c691d1a87c137dfc1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 20:12:08 +0300 Subject: [PATCH 1514/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_swap.c | 6 +++--- iguana/exchanges/LP_transaction.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 5c6621641..8d6219288 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -214,7 +214,7 @@ int32_t LP_importaddress(char *symbol,char *address) { //printf("importaddress.(%s %s) -> (%s)\n",symbol,address,retstr); free(retstr); - } else printf("importaddress.(%s %s)\n",symbol,address); + } //else printf("importaddress.(%s %s)\n",symbol,address); return(1); } diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index a723a775c..d0c47063a 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -689,9 +689,6 @@ void LP_bobloop(void *_swap) printf("error bobscripts payment\n"); else { - swap->bobreclaim.utxovout = 0; - swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; - basilisk_bobpayment_reclaim(swap,swap->I.callduration); while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) { char str[65];printf("waiting for alicepayment to be confirmed %s %s\n",swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); @@ -699,6 +696,9 @@ void LP_bobloop(void *_swap) } if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) printf("error sending bobpayment\n"); + swap->bobreclaim.utxovout = 0; + swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; + basilisk_bobpayment_reclaim(swap,swap->I.callduration); LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); } } diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 76b158391..c07863ba5 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1316,16 +1316,16 @@ int32_t basilisk_swapuserdata(uint8_t *userdata,bits256 privkey,int32_t ifpath,b int32_t basilisk_bobpayment_reclaim(struct basilisk_swap *swap,int32_t delay) { - uint8_t userdata[512]; int32_t i,retval,len = 0; static bits256 zero; - printf("basilisk_bobpayment_reclaim\n"); + uint8_t userdata[512]; int32_t retval,len = 0; static bits256 zero; + //printf("basilisk_bobpayment_reclaim\n"); len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); memcpy(swap->I.userdata_bobreclaim,userdata,len); swap->I.userdata_bobreclaimlen = len; if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1,swap->changermd160,swap->bobpayment.I.destaddr)) == 0 ) { - for (i=0; ibobreclaim.I.datalen; i++) - printf("%02x",swap->bobreclaim.txbytes[i]); - printf(" <- bobreclaim\n"); + //for (i=0; ibobreclaim.I.datalen; i++) + // printf("%02x",swap->bobreclaim.txbytes[i]); + //printf(" <- bobreclaim\n"); //basilisk_txlog(swap,&swap->bobreclaim,delay); return(retval); } @@ -1478,7 +1478,7 @@ int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_r void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) { - int32_t i; char coinaddr[64]; + char coinaddr[64]; alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); /*for (i=0; i<33; i++) printf("%02x",swap->persistent_pubkey33[i]); @@ -1554,7 +1554,7 @@ int32_t LP_verify_otherfee(struct basilisk_swap *swap,uint8_t *data,int32_t data int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { - uint8_t userdata[512]; char str[65]; int32_t i,retval=-1,len = 0; static bits256 zero; + uint8_t userdata[512]; int32_t retval=-1,len = 0; static bits256 zero; if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobdeposit,0,data,datalen,0) == 0 ) { swap->aliceclaim.utxovout = 0; @@ -1617,7 +1617,7 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { - uint8_t userdata[512]; char str[65]; int32_t i,retval=-1,len = 0; bits256 revAm; + uint8_t userdata[512]; int32_t i,retval=-1,len = 0; bits256 revAm; memset(revAm.bytes,0,sizeof(revAm)); if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->bobpayment,0,data,datalen,0) == 0 ) { From adc6b3000916217dcc55ef47a6969e00be28743d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 20:18:35 +0300 Subject: [PATCH 1515/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 30523f7d7..846163b3a 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -291,7 +291,7 @@ int32_t LP_inventory_prevent(int32_t iambob,bits256 txid,int32_t vout) struct LP_utxoinfo *utxo; if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 || (utxo= LP_utxo2find(iambob,txid,vout)) != 0 ) { - if ( utxo->T.spentflag != 0 ) + //if ( utxo->T.spentflag != 0 ) { char str[65]; printf("prevent adding %s/v%d to inventory\n",bits256_str(str,txid),vout); return(1); From 16a71cec942b70b557548bce96916aa402b5b0b7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 20:26:15 +0300 Subject: [PATCH 1516/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- iguana/exchanges/LP_transaction.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index d0c47063a..b7bfa8256 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -747,14 +747,14 @@ void LP_aliceloop(void *_swap) { while ( LP_numconfirms(swap,&swap->bobpayment) < swap->I.bobconfirms ) { - printf("waiting for bobpayment to confirm\n"); + char str[65];printf("waiting for bobpayment to be confirmed %s %s\n",swap->bobcoin.symbol,bits256_str(str,swap->bobpayment.I.signedtxid)); sleep(LP_SWAPSTEP_TIMEOUT); } if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) printf("error sending alicespend\n"); while ( LP_numconfirms(swap,&swap->alicespend) < swap->I.aliceconfirms ) { - printf("waiting for alicespend to confirm\n"); + char str[65];printf("waiting for alicespend to be confirmed %s %s\n",swap->bobcoin.symbol,bits256_str(str,swap->alicespend.I.signedtxid)); sleep(LP_SWAPSTEP_TIMEOUT); } LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index c07863ba5..f3038a967 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -843,7 +843,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch printf("incomplete signing suppress.%d %s (%s)\n",suppress_pubkeys,name,jprint(vins,0)); if ( signedtx != 0 ) free(signedtx), signedtx = 0; - } else printf("%s -> %s\n",name,bits256_str(str,*signedtxidp)); + } else printf("basilisk_swap_bobtxspend %s -> %s\n",name,bits256_str(str,*signedtxidp)); free(rawtxbytes); } else printf("error making rawtx suppress.%d\n",suppress_pubkeys); free_json(privkeys); From 3c69590533d3ee465d0a0631b3f96cd770d45717 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 20:31:13 +0300 Subject: [PATCH 1517/2705] Test --- iguana/exchanges/LP_swap.c | 20 ++++++++++---------- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index b7bfa8256..deb8de656 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -655,7 +655,7 @@ int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t void LP_bobloop(void *_swap) { - uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = _swap; + uint8_t *data; int32_t maxlen,n; uint32_t expiration; struct basilisk_swap *swap = _swap; fprintf(stderr,"start swap iambob\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); @@ -689,9 +689,9 @@ void LP_bobloop(void *_swap) printf("error bobscripts payment\n"); else { - while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + while ( (n= LP_numconfirms(swap,&swap->alicepayment)) < 1 ) { - char str[65];printf("waiting for alicepayment to be confirmed %s %s\n",swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); + char str[65];printf("%d waiting for alicepayment to be confirmed.%d %s %s\n",n,swap->I.aliceconfirms,swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); sleep(3); } if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) @@ -710,7 +710,7 @@ void LP_bobloop(void *_swap) void LP_aliceloop(void *_swap) { - uint8_t *data; int32_t maxlen; uint32_t expiration; struct basilisk_swap *swap = _swap; + uint8_t *data; int32_t maxlen,n; uint32_t expiration; struct basilisk_swap *swap = _swap; maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; @@ -736,25 +736,25 @@ void LP_aliceloop(void *_swap) printf("error sending alicepayment\n"); else { - while ( LP_numconfirms(swap,&swap->alicepayment) < 1 ) + while ( (n= LP_numconfirms(swap,&swap->alicepayment)) < 1 ) { - char str[65];printf("waiting for alicepayment to be confirmed %s %s\n",swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); + char str[65];printf("%d waiting for alicepayment to be confirmed.%d %s %s\n",n,swap->I.aliceconfirms,swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); sleep(LP_SWAPSTEP_TIMEOUT); } if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT,LP_verify_bobpayment) < 0 ) printf("error waiting for bobpayment\n"); else { - while ( LP_numconfirms(swap,&swap->bobpayment) < swap->I.bobconfirms ) + while ( (n= LP_numconfirms(swap,&swap->bobpayment)) < swap->I.bobconfirms ) { - char str[65];printf("waiting for bobpayment to be confirmed %s %s\n",swap->bobcoin.symbol,bits256_str(str,swap->bobpayment.I.signedtxid)); + char str[65];printf("%d waiting for bobpayment to be confirmed.%d %s %s\n",n,swap->I.bobconfirms,swap->bobcoin.symbol,bits256_str(str,swap->bobpayment.I.signedtxid)); sleep(LP_SWAPSTEP_TIMEOUT); } if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x20000,data,maxlen,&swap->alicespend,0x40000,0) == 0 ) printf("error sending alicespend\n"); - while ( LP_numconfirms(swap,&swap->alicespend) < swap->I.aliceconfirms ) + while ( (n= LP_numconfirms(swap,&swap->alicespend)) < swap->I.aliceconfirms ) { - char str[65];printf("waiting for alicespend to be confirmed %s %s\n",swap->bobcoin.symbol,bits256_str(str,swap->alicespend.I.signedtxid)); + char str[65];printf("%d waiting for alicespend to be confirmed.%d %s %s\n",n,swap->I.aliceconfirms,swap->bobcoin.symbol,bits256_str(str,swap->alicespend.I.signedtxid)); sleep(LP_SWAPSTEP_TIMEOUT); } LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 846163b3a..f45d0665f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -293,7 +293,7 @@ int32_t LP_inventory_prevent(int32_t iambob,bits256 txid,int32_t vout) { //if ( utxo->T.spentflag != 0 ) { - char str[65]; printf("prevent adding %s/v%d to inventory\n",bits256_str(str,txid),vout); + //char str[65]; printf("prevent adding %s/v%d to inventory\n",bits256_str(str,txid),vout); return(1); } } From d3d65f86e0aa11220e3e0adc5245f7b18d77f9a9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 20:35:08 +0300 Subject: [PATCH 1518/2705] Test --- iguana/exchanges/LP_swap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index deb8de656..b3fd8fc71 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -689,9 +689,9 @@ void LP_bobloop(void *_swap) printf("error bobscripts payment\n"); else { - while ( (n= LP_numconfirms(swap,&swap->alicepayment)) < 1 ) + while ( (n= LP_numconfirms(swap,&swap->alicepayment)) < 1 ) // sync with alice { - char str[65];printf("%d waiting for alicepayment to be confirmed.%d %s %s\n",n,swap->I.aliceconfirms,swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); + char str[65];printf("%d waiting for alicepayment to be confirmed.%d %s %s\n",n,1,swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); sleep(3); } if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) @@ -738,7 +738,7 @@ void LP_aliceloop(void *_swap) { while ( (n= LP_numconfirms(swap,&swap->alicepayment)) < 1 ) { - char str[65];printf("%d waiting for alicepayment to be confirmed.%d %s %s\n",n,swap->I.aliceconfirms,swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); + char str[65];printf("%d waiting for alicepayment to be confirmed.%d %s %s\n",n,1,swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); sleep(LP_SWAPSTEP_TIMEOUT); } if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT,LP_verify_bobpayment) < 0 ) @@ -942,12 +942,12 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 if ( strcmp("BTC",swap->bobcoin.symbol) == 0 ) { swap->I.bobconfirms = (1 + sqrt(dstr(swap->I.bobsatoshis) * .1)); - swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms + 1); + swap->I.aliceconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.bobconfirms); } else if ( strcmp("BTC",swap->alicecoin.symbol) == 0 ) { swap->I.aliceconfirms = (1 + sqrt(dstr(swap->I.alicesatoshis) * .1)); - swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.aliceconfirms + 1); + swap->I.bobconfirms = MIN(BASILISK_DEFAULT_NUMCONFIRMS,swap->I.aliceconfirms); } else { From 5cf95595a46f2aa8875bcf06723371174d60bc7f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 17 Jun 2017 20:41:16 +0300 Subject: [PATCH 1519/2705] Test --- iguana/exchanges/LP_include.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 34a4bd009..ca4c784c3 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -47,7 +47,7 @@ #define LP_RESERVETIME 60 #define LP_AVETXSIZE 200 #define LP_CACHEDURATION 60 -#define BASILISK_DEFAULT_NUMCONFIRMS 2 +#define BASILISK_DEFAULT_NUMCONFIRMS 1 #define DEX_SLEEP 3 #define BASILISK_KEYSIZE ((int32_t)(2*sizeof(bits256)+sizeof(uint32_t)*2)) From 8904263427c3a70ba58e1b31a7ea8f225fdb7065 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:13:03 +0300 Subject: [PATCH 1520/2705] Test --- iguana/exchanges/LP_utxos.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index f45d0665f..223a6ab59 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -397,7 +397,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - char str[65]; uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); @@ -406,7 +406,14 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; - //char str2[65]; printf("%s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); + + char str[65],str2[65],dispflag = 0; + bits256_str(str,txid); + bits256_str(str2,txid2); + if ( strcmp(str,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 || strcmp(str2,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 ) + dispflag = 1; + if ( dispflag != 0 ) + printf("%s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); @@ -428,7 +435,9 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { utxo->T.errors++; - char str[65],str2[65],str3[65],str4[65]; printf("error on subsequent utxo add.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,utxo->payment.txid),bits256_str(str2,u.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); + char str[65],str2[65],str3[65],str4[65]; + if ( dispflag != 0 ) + printf("error on subsequent utxo add.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,utxo->payment.txid),bits256_str(str2,u.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); } else if ( profitmargin > SMALLVAL ) utxo->S.profitmargin = profitmargin; From 2929b269ad2b40e87f838e6465a2b28bd34c334a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:14:35 +0300 Subject: [PATCH 1521/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 223a6ab59..1baa8e44f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -437,7 +437,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit utxo->T.errors++; char str[65],str2[65],str3[65],str4[65]; if ( dispflag != 0 ) - printf("error on subsequent utxo add.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,utxo->payment.txid),bits256_str(str2,u.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); + printf("error on subsequent utxo add.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,txid),bits256_str(str2,txid2),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); } else if ( profitmargin > SMALLVAL ) utxo->S.profitmargin = profitmargin; From a9c9d3364d9d361c882e16397c74ecf10e6dbe34 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:23:11 +0300 Subject: [PATCH 1522/2705] Test --- iguana/exchanges/LP_remember.c | 6 +++--- iguana/exchanges/LP_utxos.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index f5d083594..d2a06d19f 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -427,13 +427,13 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( bits256_nonz(privkey) != 0 ) { privAm = privkey; - printf("set privAm <- %s\n",bits256_str(str,privAm)); + //printf("set privAm <- %s\n",bits256_str(str,privAm)); } privkey = jbits256(item,"privBn"); if ( bits256_nonz(privkey) != 0 ) { privBn = privkey; - printf("set privBn <- %s\n",bits256_str(str,privBn)); + //printf("set privBn <- %s\n",bits256_str(str,privBn)); } expiration = juint(item,"expiration"); state = jint(item,"state"); @@ -554,7 +554,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } else if ( finishedflag == 0 ) printf("%s not finished\n",fname); } - printf("alicepayment.%s bobpayment.%s bobdeposit.%s\n",alicepaymentaddr,bobpaymentaddr,bobdepositaddr); + //printf("alicepayment.%s bobpayment.%s bobdeposit.%s\n",alicepaymentaddr,bobpaymentaddr,bobdepositaddr); //printf("iambob.%d src.%s dest.%s bob.%s alice.%s pubA0.(%s)\n",iambob,src,dest,bobcoin,alicecoin,bits256_str(str,pubA0)); Adestaddr[0] = destaddr[0] = 0; Adest = Bdest = AAdest = ABdest = 0; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 1baa8e44f..838030769 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -412,13 +412,13 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit bits256_str(str2,txid2); if ( strcmp(str,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 || strcmp(str2,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 ) dispflag = 1; - if ( dispflag != 0 ) - printf("%s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); } + if ( dispflag != 0 ) + printf("%.8f %.8f %s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",dstr(val),dstr(val2),coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) { printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); From b715e748a8dc93fe5892dff8436f47780f83180f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:24:24 +0300 Subject: [PATCH 1523/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 838030769..9230fd53f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -381,7 +381,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) { - //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); if ( strcmp(destaddr,destaddr2) == 0 ) { *valp = val; From 673b20adbd00f40b7e8cfb94f82adc6a8134bbc4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:31:12 +0300 Subject: [PATCH 1524/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 9230fd53f..10ca1fb76 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -382,7 +382,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) { printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); - if ( strcmp(destaddr,destaddr2) == 0 ) + if ( strcmp(destaddr,destaddr2) == 0 && ((iambob == 0 && val2 <= val) || (iambob != 0 && val2 >= val)) ) { *valp = val; *val2p = val2; From a18d308d078f364650644e28387ca32bbfff2b5f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:31:30 +0300 Subject: [PATCH 1525/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 10ca1fb76..24e69be3c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -381,7 +381,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) { - printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); if ( strcmp(destaddr,destaddr2) == 0 && ((iambob == 0 && val2 <= val) || (iambob != 0 && val2 >= val)) ) { *valp = val; From b084e3aec48a040b5fe8a082e24f32d0a6c1f630 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:34:15 +0300 Subject: [PATCH 1526/2705] test --- iguana/exchanges/LP_utxos.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 24e69be3c..07a6f6f23 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -381,14 +381,17 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) { - //printf("val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); - if ( strcmp(destaddr,destaddr2) == 0 && ((iambob == 0 && val2 <= val) || (iambob != 0 && val2 >= val)) ) + if ( strcmp(destaddr,destaddr2) == 0 ) + printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); + else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 < val) ) + printf("ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + else { *valp = val; *val2p = val2; return(1); - } else printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - } else printf("mismatched %s txid value2 %.8f < %.8f\n",symbol,dstr(val2),dstr(LP_DEPOSITSATOSHIS(satoshis))); + } + } } else printf("mismatched %s txid value %.8f < %.8f\n",symbol,dstr(val),dstr(satoshis)); *valp = val; *val2p = val2; @@ -414,7 +417,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit dispflag = 1; if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { - printf("utxoadd got spent txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); + printf("utxoadd got ineligible txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); } if ( dispflag != 0 ) From 7db4b8489c8bd785d653fa3095fb8bed84ca9f88 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:36:40 +0300 Subject: [PATCH 1527/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 07a6f6f23..6a4d404e0 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -417,7 +417,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit dispflag = 1; if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { - printf("utxoadd got ineligible txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",dstr(value),dstr(value2),dstr(tmpsatoshis)); + printf("iambob.%d utxoadd got ineligible txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",iambob,dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); } if ( dispflag != 0 ) From feb5ee76fccb06eb28b0a820fd631040334da7e6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:37:28 +0300 Subject: [PATCH 1528/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 6a4d404e0..3d0c6320f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -381,7 +381,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) { - if ( strcmp(destaddr,destaddr2) == 0 ) + if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 < val) ) printf("ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); From de31bcdd7ce26292e85eaae707e1cc9a261a8d17 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:38:22 +0300 Subject: [PATCH 1529/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 3d0c6320f..2d73afe3c 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -410,7 +410,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; - char str[65],str2[65],dispflag = 0; + char str[65],str2[65],dispflag = 1; bits256_str(str,txid); bits256_str(str2,txid2); if ( strcmp(str,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 || strcmp(str2,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 ) From f054b47f8fc49c89f551984e3b87cc7d04fdcec0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:39:20 +0300 Subject: [PATCH 1530/2705] Test --- iguana/exchanges/LP_utxos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 2d73afe3c..53b5b95c7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -410,7 +410,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; - char str[65],str2[65],dispflag = 1; + char str[65],str2[65],dispflag = 0; bits256_str(str,txid); bits256_str(str2,txid2); if ( strcmp(str,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 || strcmp(str2,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 ) @@ -422,6 +422,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit } if ( dispflag != 0 ) printf("%.8f %.8f %s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",dstr(val),dstr(val2),coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); + dispflag = 1; if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) { printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); From 692a6a96a6a727c551077f8d3a8a6ffcef02a708 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:40:42 +0300 Subject: [PATCH 1531/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 53b5b95c7..b9f5675e3 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -441,7 +441,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit utxo->T.errors++; char str[65],str2[65],str3[65],str4[65]; if ( dispflag != 0 ) - printf("error on subsequent utxo add.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",bits256_str(str,txid),bits256_str(str2,txid2),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); + printf("error on subsequent utxo iambob.%d %.8f %.8f add.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",iambob,dstr(val),dstr(val2),bits256_str(str,txid),bits256_str(str2,txid2),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); } else if ( profitmargin > SMALLVAL ) utxo->S.profitmargin = profitmargin; From 251b1ae736f57e6551e8567d8501e00ff0fbc92a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:41:34 +0300 Subject: [PATCH 1532/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b9f5675e3..20fbd9b26 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -383,7 +383,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol { if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 < val) ) + else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < val) ) printf("ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); else { From f68b949e7bee3f2854e1f226fd89d216253cd547 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:44:41 +0300 Subject: [PATCH 1533/2705] Test --- iguana/exchanges/LP_utxos.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 20fbd9b26..7306919d7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -409,8 +409,13 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; - char str[65],str2[65],dispflag = 0; + if ( iambob == 0 && bits256_cmp(pubkey,LP_mypubkey) != 0 ) + { + printf("trying to add Alice utxo when not mine? %s/v%d\n",bits256_str(str,txid),vout); + return(0); + } + bits256_str(str,txid); bits256_str(str2,txid2); if ( strcmp(str,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 || strcmp(str2,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 ) From a395f83c6930e8ba27e9e58f332d812f20f9ab5c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 10:51:43 +0300 Subject: [PATCH 1534/2705] Test --- iguana/exchanges/LP_utxos.c | 61 ++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7306919d7..8a3bb15bb 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -262,9 +262,35 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) return(item); } +int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) +{ + uint64_t val,val2=0,threshold; char destaddr[64],destaddr2[64]; + destaddr[0] = destaddr2[0] = 0; + if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) >= satoshis ) + { + threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); + if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) + { + if ( strcmp(destaddr,destaddr2) != 0 ) + printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); + else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < val) ) + printf("ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + else + { + *valp = val; + *val2p = val2; + return(1); + } + } + } else printf("mismatched %s txid value %.8f < %.8f\n",symbol,dstr(val),dstr(satoshis)); + *valp = val; + *val2p = val2; + return(0); +} + char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t lastn) { - int32_t i,firsti,n; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); + int32_t i,firsti,n; uint64_t val,val2; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo,*tmp; cJSON *utxosjson = cJSON_CreateArray(); i = 0; n = mypeer != 0 ? mypeer->numutxos : 0; if ( lastn <= 0 ) @@ -280,7 +306,12 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la continue; if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 ) { - jaddi(utxosjson,LP_utxojson(utxo)); + u = (iambob != 0) ? utxo->deposit : utxo->fee; + if ( LP_iseligible(&val,&val2,0,symbol,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) == 0 ) + { + char str[65]; printf("iambob.%d not eligible (%.8f %.8f) %s/v%d\n",iambob,dstr(val),dstr(val2),bits256_str(str,utxo->payment.txid),utxo->payment.vout); + continue; + } else jaddi(utxosjson,LP_utxojson(utxo)); } } return(jprint(utxosjson,1)); @@ -372,32 +403,6 @@ char *LP_spentcheck(cJSON *argjson) return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); } -int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) -{ - uint64_t val,val2=0,threshold; char destaddr[64],destaddr2[64]; - destaddr[0] = destaddr2[0] = 0; - if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) >= satoshis ) - { - threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); - if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) - { - if ( strcmp(destaddr,destaddr2) != 0 ) - printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < val) ) - printf("ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); - else - { - *valp = val; - *val2p = val2; - return(1); - } - } - } else printf("mismatched %s txid value %.8f < %.8f\n",symbol,dstr(val),dstr(satoshis)); - *valp = val; - *val2p = val2; - return(0); -} - struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; From 69e3ce00855bd20e62949f7e1757d27ab4d5852b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:12:01 +0300 Subject: [PATCH 1535/2705] Test --- iguana/exchanges/LP_utxos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 8a3bb15bb..bef71b92a 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -494,7 +494,8 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit portable_mutex_unlock(&LP_utxomutex); if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - else LP_utxo_clientpublish(utxo); + else if ( iambob != 0 ) + LP_utxo_clientpublish(utxo); if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) LP_mypeer->numutxos++; } From 4d5070eabb65c8943e44f0bea682585b9233f8f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:13:44 +0300 Subject: [PATCH 1536/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index bef71b92a..4b601f8d2 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -307,9 +307,9 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 ) { u = (iambob != 0) ? utxo->deposit : utxo->fee; - if ( LP_iseligible(&val,&val2,0,symbol,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) == 0 ) + if ( LP_iseligible(&val,&val2,0,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) == 0 ) { - char str[65]; printf("iambob.%d not eligible (%.8f %.8f) %s/v%d\n",iambob,dstr(val),dstr(val2),bits256_str(str,utxo->payment.txid),utxo->payment.vout); + char str[65]; printf("iambob.%d not eligible (%.8f %.8f) %s %s/v%d\n",iambob,dstr(val),dstr(val2),utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout); continue; } else jaddi(utxosjson,LP_utxojson(utxo)); } From 74d48ad2209d381bc53bfd84c217fc31e585bd90 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:16:54 +0300 Subject: [PATCH 1537/2705] Test --- iguana/exchanges/LP_utxos.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 4b601f8d2..0c994b8a7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -273,15 +273,15 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol { if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < val) ) - printf("ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",dstr(val),dstr(val2),dstr(satoshis)); + //else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < satoshis) ) + // printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",iambob,dstr(val),dstr(val2),dstr(satoshis)); else { *valp = val; *val2p = val2; return(1); } - } + } else printf("no val2\n"); } else printf("mismatched %s txid value %.8f < %.8f\n",symbol,dstr(val),dstr(satoshis)); *valp = val; *val2p = val2; From 051ec447f0b694db025c241a7f378a6d91c86e26 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:18:20 +0300 Subject: [PATCH 1538/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0c994b8a7..610574e3d 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -273,8 +273,8 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol { if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - //else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < satoshis) ) - // printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",iambob,dstr(val),dstr(val2),dstr(satoshis)); + else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < satoshis) ) + printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",iambob,dstr(val),dstr(val2),dstr(satoshis)); else { *valp = val; From 9a91e2486d419acec1612b78491d0d7712517393 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:19:25 +0300 Subject: [PATCH 1539/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 610574e3d..e73a97cc7 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -274,7 +274,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < satoshis) ) - printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f\n",iambob,dstr(val),dstr(val2),dstr(satoshis)); + printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f diff %lld\n",iambob,dstr(val),dstr(val2),dstr(satoshis),(long long)(val2 - val)); else { *valp = val; From f2a90d91ba0a11d92179c035fd1d6eb85370c92c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:20:02 +0300 Subject: [PATCH 1540/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e73a97cc7..db6fce480 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -273,7 +273,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol { if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < satoshis) ) + else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 < satoshis) ) printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f diff %lld\n",iambob,dstr(val),dstr(val2),dstr(satoshis),(long long)(val2 - val)); else { From 234714ab04e218834f61f137d7bba0bd8bd25241 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:21:49 +0300 Subject: [PATCH 1541/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index db6fce480..74fbe5449 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -307,7 +307,7 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 ) { u = (iambob != 0) ? utxo->deposit : utxo->fee; - if ( LP_iseligible(&val,&val2,0,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) == 0 ) + if ( LP_iseligible(&val,&val2,iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) == 0 ) { char str[65]; printf("iambob.%d not eligible (%.8f %.8f) %s %s/v%d\n",iambob,dstr(val),dstr(val2),utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout); continue; From 1c0241e74def8f2322a48c70e3d38da73da8c806 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:25:57 +0300 Subject: [PATCH 1542/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 74fbe5449..9a686dd40 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -273,7 +273,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol { if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 < satoshis) ) + else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 < val) ) printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f diff %lld\n",iambob,dstr(val),dstr(val2),dstr(satoshis),(long long)(val2 - val)); else { From 7572cfb08534ec34f595c6feb38b6b1277da6a37 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:33:41 +0300 Subject: [PATCH 1543/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- iguana/exchanges/LP_utxos.c | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 83b703df3..4f194727e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -31,7 +31,7 @@ char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // -portable_mutex_t LP_peermutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex; +portable_mutex_t LP_peermutex,LP_UTXOmutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex; int32_t LP_mypubsock = -1; int32_t USERPASS_COUNTER,IAMLP = 0; double LP_profitratio = 1.; @@ -346,6 +346,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } portable_mutex_init(&LP_peermutex); portable_mutex_init(&LP_utxomutex); + portable_mutex_init(&LP_UTXOmutex); portable_mutex_init(&LP_commandmutex); portable_mutex_init(&LP_swaplistmutex); portable_mutex_init(&LP_cachemutex); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 9a686dd40..025c3bb21 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -420,11 +420,6 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit printf("trying to add Alice utxo when not mine? %s/v%d\n",bits256_str(str,txid),vout); return(0); } - - bits256_str(str,txid); - bits256_str(str2,txid2); - if ( strcmp(str,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 || strcmp(str2,"7ea7481baf03698cbeb7b9cd0ed3f86f3c40debab72626516dda7e8d155630eb") == 0 ) - dispflag = 1; if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) { printf("iambob.%d utxoadd got ineligible txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",iambob,dstr(value),dstr(value2),dstr(tmpsatoshis)); @@ -504,7 +499,11 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson) { - return(LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit"))); + struct LP_utxoinfo *utxo; + portable_mutex_lock(&LP_UTXOmutex); + utxo = LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit")); + portable_mutex_unlock(&LP_UTXOmutex); + return(utxo); } int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t now) @@ -684,6 +683,7 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr { value = values[i]; values[i] = 0, used++; + portable_mutex_lock(&LP_UTXOmutex); if ( iambob != 0 ) { if ( (utxo= LP_utxoadd(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_mypeer != 0 ? LP_mypeer->profitmargin : 0.01)) != 0 ) @@ -696,6 +696,7 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr { } } + portable_mutex_unlock(&LP_UTXOmutex); total += value; } } From c7a045dd50147fccbb3308b4f67e3391c51201f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:37:25 +0300 Subject: [PATCH 1544/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 025c3bb21..57eb3e191 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -444,9 +444,9 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(spendscript,utxo->spendscript) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) { utxo->T.errors++; - char str[65],str2[65],str3[65],str4[65]; + char str[65],str2[65],str3[65],str4[65],str5[65],str6[65]; if ( dispflag != 0 ) - printf("error on subsequent utxo iambob.%d %.8f %.8f add.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",iambob,dstr(val),dstr(val2),bits256_str(str,txid),bits256_str(str2,txid2),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str3,pubkey),bits256_str(str4,utxo->pubkey)); + printf("error on subsequent utxo iambob.%d %.8f %.8f add.(%s %s) when.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",iambob,dstr(val),dstr(val2),bits256_str(str,txid),bits256_str(str2,txid2),bits256_str(str3,utxo->payment.txid),bits256_str(str4,utxo->deposit.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str5,pubkey),bits256_str(str6,utxo->pubkey)); } else if ( profitmargin > SMALLVAL ) utxo->S.profitmargin = profitmargin; From fbc663c204c950915d34c1b9cc1bc52099de8a35 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:39:12 +0300 Subject: [PATCH 1545/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 57eb3e191..43f9b193b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -273,7 +273,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol { if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 < val) ) + else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < val) ) printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f diff %lld\n",iambob,dstr(val),dstr(val2),dstr(satoshis),(long long)(val2 - val)); else { From f576e4389e3812327da5833bb937f173bdbd89b7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:42:41 +0300 Subject: [PATCH 1546/2705] Test --- iguana/exchanges/LP_utxos.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 43f9b193b..36661a074 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -218,6 +218,7 @@ cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) jaddstr(item,"method","notified"); jaddstr(item,"coin",utxo->coin); jaddnum(item,"now",time(NULL)); + jaddnum(item,"iambob",utxo->iambob); jaddstr(item,"address",utxo->coinaddr); jaddbits256(item,"txid",utxo->payment.txid); jaddnum(item,"vout",utxo->payment.vout); @@ -500,6 +501,11 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson) { struct LP_utxoinfo *utxo; + if ( jobj(argjson,"iambob") == 0 || iambob != jint(argjson,"iambob") ) + { + printf("LP_utxoaddjson: iambob.%d != arg.%d obj.%p\n",iambob,jint(argjson,"iambob"),jobj(argjson,"iambob")); + return(0); + } portable_mutex_lock(&LP_UTXOmutex); utxo = LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit")); portable_mutex_unlock(&LP_UTXOmutex); From 48a1094355d3bb6dc7873ad521d06cd1c6f99d3f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:47:20 +0300 Subject: [PATCH 1547/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 36661a074..4006048b6 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -274,7 +274,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol { if ( strcmp(destaddr,destaddr2) != 0 ) printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); - else if ( (iambob == 0 && val2 >= val) || (iambob != 0 && val2 < val) ) + else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 <= satoshis) ) printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f diff %lld\n",iambob,dstr(val),dstr(val2),dstr(satoshis),(long long)(val2 - val)); else { From 7057701f2d3b5df3b9c047595f76544f7a841bce Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:50:16 +0300 Subject: [PATCH 1548/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4f194727e..780942e1d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -246,7 +246,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_forwarding_register(LP_mypubkey,pushaddr,10); lastforward = now; } - if ( (counter % 600) == 0 ) + if ( (counter % 600) == 300 ) LP_myutxo_updates(pubsock,passphrase,profitmargin); if ( (counter % 600) == 0 ) { @@ -318,7 +318,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in LP_priceinfoadd(jstr(item,"coin")); } } - LP_privkey_updates(pubsock,passphrase); + //LP_privkey_updates(pubsock,passphrase); if ( (retstr= basilisk_swaplist()) != 0 ) free(retstr); while ( 1 ) From 8554b2f600d5442aedd56922cf15d23582ecd003 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:51:00 +0300 Subject: [PATCH 1549/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 4006048b6..a9ac7a6a8 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -415,7 +415,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding tmpsatoshis = (((value2 - 100000) / 9) << 3); else tmpsatoshis = value; - char str[65],str2[65],dispflag = 0; + char str[65],str2[65],dispflag = (iambob == 0); if ( iambob == 0 && bits256_cmp(pubkey,LP_mypubkey) != 0 ) { printf("trying to add Alice utxo when not mine? %s/v%d\n",bits256_str(str,txid),vout); From f7aa7cf5aa38f48b3b4c5ab4bad08425b0c7d51d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:52:09 +0300 Subject: [PATCH 1550/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 780942e1d..c851d0bf0 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -241,13 +241,15 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso peer->diduquery = now; } } - if ( lastforward < now-3600 ) - { - LP_forwarding_register(LP_mypubkey,pushaddr,10); - lastforward = now; - } if ( (counter % 600) == 300 ) + { LP_myutxo_updates(pubsock,passphrase,profitmargin); + if ( lastforward < now-3600 ) + { + LP_forwarding_register(LP_mypubkey,pushaddr,10); + lastforward = now; + } + } if ( (counter % 600) == 0 ) { HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) From 36cead151c4709400bf1e02f4222dfa40d854f06 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:53:30 +0300 Subject: [PATCH 1551/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c851d0bf0..c55580ad1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -241,7 +241,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso peer->diduquery = now; } } - if ( (counter % 600) == 300 ) + if ( (counter % 600) == 100 ) { LP_myutxo_updates(pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) From d496ac598dd6ffde57c17b0e078b3562cf64deaa Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:54:22 +0300 Subject: [PATCH 1552/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c55580ad1..2ebdadbef 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -241,7 +241,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso peer->diduquery = now; } } - if ( (counter % 600) == 100 ) + if ( (counter % 600) == 60 ) { LP_myutxo_updates(pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) From 0fec1e979033ebbbe34bb4517d47d3aae69bc790 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:55:10 +0300 Subject: [PATCH 1553/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a9ac7a6a8..0e2585918 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -503,7 +503,7 @@ struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson struct LP_utxoinfo *utxo; if ( jobj(argjson,"iambob") == 0 || iambob != jint(argjson,"iambob") ) { - printf("LP_utxoaddjson: iambob.%d != arg.%d obj.%p\n",iambob,jint(argjson,"iambob"),jobj(argjson,"iambob")); + printf("LP_utxoaddjson: iambob.%d != arg.%d obj.%p (%s)\n",iambob,jint(argjson,"iambob"),jobj(argjson,"iambob"),jprint(argjson,0)); return(0); } portable_mutex_lock(&LP_UTXOmutex); From 3f4cc31861319506f211a2f8816cf1fa11651992 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 11:56:50 +0300 Subject: [PATCH 1554/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 8d6219288..5d3823b4b 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -65,7 +65,7 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65],str3[65]; - sprintf(url,"http://%s:%u/api/stats/notified?pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); + sprintf(url,"http://%s:%u/api/stats/notified?iambob=%d&pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,utxo->iambob,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(issue_curlt(url,LP_HTTP_TIMEOUT)); From 980fbf283f1ff59a20f0499bc6d790aa48439d56 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:02:51 +0300 Subject: [PATCH 1555/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_ordermatch.c | 4 ++-- iguana/exchanges/LP_rpc.c | 19 ++++++++++++++----- iguana/exchanges/LP_utxos.c | 11 ++++++++--- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index ca4c784c3..b66e2c47c 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -230,6 +230,7 @@ int32_t LP_isavailable(struct LP_utxoinfo *utxo); struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port); char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin); void LP_availableset(struct LP_utxoinfo *utxo); +int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2,bits256 pubkey); #endif diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index a23528166..af2d2599e 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -235,12 +235,12 @@ double LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxop { double qprice; uint64_t srcvalue,srcvalue2,destvalue,destvalue2; *autxop = *butxop = 0; - if ( LP_iseligible(&srcvalue,&srcvalue2,1,qp->srccoin,qp->txid,qp->vout,qp->satoshis,qp->txid2,qp->vout2) == 0 ) + if ( LP_iseligible(&srcvalue,&srcvalue2,1,qp->srccoin,qp->txid,qp->vout,qp->satoshis,qp->txid2,qp->vout2,qp->srchash) == 0 ) { printf("bob not eligible\n"); return(-2); } - if ( LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout) == 0 ) + if ( LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout,qp->desthash) == 0 ) { char str[65]; printf("alice not eligible (%.8f %.8f) %s/v%d\n",dstr(destvalue),dstr(destvalue2),bits256_str(str,qp->feetxid),qp->feevout); return(-3); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 5d3823b4b..5cc5c8098 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -64,11 +64,20 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { - char url[4096],str[65],str2[65],str3[65]; - sprintf(url,"http://%s:%u/api/stats/notified?iambob=%d&pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,utxo->iambob,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); - if ( strlen(url) > 1024 ) - printf("WARNING long url.(%s)\n",url); - return(issue_curlt(url,LP_HTTP_TIMEOUT)); + char url[4096],str[65],str2[65],str3[65]; struct _LP_utxoinfo u; uint64_t val,val2; + u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; + if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout,utxo->pubkey) > 0 ) + { + sprintf(url,"http://%s:%u/api/stats/notified?iambob=%d&pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,utxo->iambob,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); + if ( strlen(url) > 1024 ) + printf("WARNING long url.(%s)\n",url); + return(issue_curlt(url,LP_HTTP_TIMEOUT)); + } + else + { + printf("issue_LP_notifyutxo: ineligible utxo iambob.%d %.8f %.8f\n",utxo->iambob,dstr(val),dstr(val2)); + return(0); + } } char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *pushaddr) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0e2585918..8aeb74a50 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -263,10 +263,15 @@ cJSON *LP_utxojson(struct LP_utxoinfo *utxo) return(item); } -int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) +int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2,bits256 pubkey) { uint64_t val,val2=0,threshold; char destaddr[64],destaddr2[64]; destaddr[0] = destaddr2[0] = 0; + if ( iambob == 0 && bits256_cmp(pubkey,LP_mypubkey) != 0 ) + { + char str[65]; printf("external Alice utxo.(%s) rejected\n",bits256_str(str,txid)); + return(0); + } if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) >= satoshis ) { threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); @@ -308,7 +313,7 @@ char *LP_utxos(int32_t iambob,struct LP_peerinfo *mypeer,char *symbol,int32_t la if ( (symbol == 0 || symbol[0] == 0 || strcmp(symbol,utxo->coin) == 0) && utxo->T.spentflag == 0 ) { u = (iambob != 0) ? utxo->deposit : utxo->fee; - if ( LP_iseligible(&val,&val2,iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout) == 0 ) + if ( LP_iseligible(&val,&val2,iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout,utxo->pubkey) == 0 ) { char str[65]; printf("iambob.%d not eligible (%.8f %.8f) %s %s/v%d\n",iambob,dstr(val),dstr(val2),utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout); continue; @@ -421,7 +426,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit printf("trying to add Alice utxo when not mine? %s/v%d\n",bits256_str(str,txid),vout); return(0); } - if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) + if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2,pubkey) <= 0 ) { printf("iambob.%d utxoadd got ineligible txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",iambob,dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); From 2018f632ee0690bd52c3129bcfa6ee7531ef3ee3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:06:21 +0300 Subject: [PATCH 1556/2705] Test --- iguana/exchanges/LP_rpc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 5cc5c8098..3cf0959b4 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -65,6 +65,11 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { char url[4096],str[65],str2[65],str3[65]; struct _LP_utxoinfo u; uint64_t val,val2; + if ( LP_mypeer != 0 && strcmp(destip,LP_mypeer->ipaddr) == 0 && LP_mypeer->port == destport ) + { + printf("no need to notify ourselves\n"); + return(clonestr("{\"result\":\"success\"}")); + } u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout,utxo->pubkey) > 0 ) { From e1eb7ff78f9dc450b97c9dc79f4f9aa5c9e05035 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:08:08 +0300 Subject: [PATCH 1557/2705] Test --- iguana/exchanges/LP_rpc.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 3cf0959b4..cbd18ea10 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -34,6 +34,15 @@ char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) return(retstr); } +char *LP_isitme(char *destip,uint16_t destport) +{ + if ( LP_mypeer != 0 && strcmp(destip,LP_mypeer->ipaddr) == 0 && LP_mypeer->port == destport ) + { + printf("no need to notify ourselves\n"); + return(clonestr("{\"result\":\"success\"}")); + } else return(0); +} + char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { char url[512]; @@ -57,14 +66,18 @@ char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) { - char url[512]; + char url[512],*retstr; + if ( (retstr= LP_isitme(destip,destport)) != 0 ) + return(retstr); sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) { - char url[4096],str[65],str2[65],str3[65]; struct _LP_utxoinfo u; uint64_t val,val2; + char url[4096],str[65],str2[65],str3[65],*retstr; struct _LP_utxoinfo u; uint64_t val,val2; + if ( (retstr= LP_isitme(destip,destport)) != 0 ) + return(retstr); if ( LP_mypeer != 0 && strcmp(destip,LP_mypeer->ipaddr) == 0 && LP_mypeer->port == destport ) { printf("no need to notify ourselves\n"); From 59a69be762e1a7dd85d2978061dd5d9e5ddd8319 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:10:30 +0300 Subject: [PATCH 1558/2705] Test --- iguana/exchanges/LP_rpc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index cbd18ea10..c361dd528 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -80,8 +80,8 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx return(retstr); if ( LP_mypeer != 0 && strcmp(destip,LP_mypeer->ipaddr) == 0 && LP_mypeer->port == destport ) { - printf("no need to notify ourselves\n"); - return(clonestr("{\"result\":\"success\"}")); + //printf("no need to notify ourselves\n"); + return(0);//clonestr("{\"result\":\"success\"}")); } u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout,utxo->pubkey) > 0 ) From ec0c531f4918b8184a8bac2ee13206a736d126a9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:12:11 +0300 Subject: [PATCH 1559/2705] test --- iguana/exchanges/LP_rpc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index c361dd528..09534dc89 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -38,7 +38,7 @@ char *LP_isitme(char *destip,uint16_t destport) { if ( LP_mypeer != 0 && strcmp(destip,LP_mypeer->ipaddr) == 0 && LP_mypeer->port == destport ) { - printf("no need to notify ourselves\n"); + //printf("no need to notify ourselves\n"); return(clonestr("{\"result\":\"success\"}")); } else return(0); } @@ -68,7 +68,10 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, { char url[512],*retstr; if ( (retstr= LP_isitme(destip,destport)) != 0 ) - return(retstr); + { + free(retstr); + return(0); + } sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); return(issue_curlt(url,LP_HTTP_TIMEOUT)); } @@ -77,11 +80,9 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx { char url[4096],str[65],str2[65],str3[65],*retstr; struct _LP_utxoinfo u; uint64_t val,val2; if ( (retstr= LP_isitme(destip,destport)) != 0 ) - return(retstr); - if ( LP_mypeer != 0 && strcmp(destip,LP_mypeer->ipaddr) == 0 && LP_mypeer->port == destport ) { - //printf("no need to notify ourselves\n"); - return(0);//clonestr("{\"result\":\"success\"}")); + free(retstr); + return(0); } u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout,utxo->pubkey) > 0 ) From 367508925d3eaff042e022e19aec85637d552ba9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:14:23 +0300 Subject: [PATCH 1560/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 8aeb74a50..e8cbdd937 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -541,7 +541,7 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - //printf("parse.(%s)\n",jprint(item,0)); + printf("parse.(%s)\n",jprint(item,0)); if ( (utxo= LP_utxoaddjson(1,-1,item)) != 0 ) utxo->T.lasttime = now; } From c2e469876230b1b9fd2be46deb0bd8595fcd634f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:24:21 +0300 Subject: [PATCH 1561/2705] Test --- iguana/exchanges/LP_utxos.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e8cbdd937..aa191f2c9 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -493,12 +493,15 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) HASH_ADD_KEYPTR(hh2,LP_utxoinfos2[iambob],utxo->key2,sizeof(utxo->key2),utxo); portable_mutex_unlock(&LP_utxomutex); - if ( mypubsock >= 0 ) - LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - else if ( iambob != 0 ) - LP_utxo_clientpublish(utxo); - if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) - LP_mypeer->numutxos++; + if ( iambob != 0 ) + { + if ( mypubsock >= 0 ) + LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); + else + LP_utxo_clientpublish(utxo); + if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) + LP_mypeer->numutxos++; + } } return(utxo); } From 4eda8c2d2a77b8d203040cb9baeb4060dfad5969 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:27:20 +0300 Subject: [PATCH 1562/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index aa191f2c9..cc8e71922 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -544,7 +544,7 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n if ( jobj(item,"txid") != 0 ) { txid = jbits256(item,"txid"); - printf("parse.(%s)\n",jprint(item,0)); + //printf("parse.(%s)\n",jprint(item,0)); if ( (utxo= LP_utxoaddjson(1,-1,item)) != 0 ) utxo->T.lasttime = now; } From df63c672096f6d84d2c944ce842acf6d7fa56161 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:34:49 +0300 Subject: [PATCH 1563/2705] Test --- iguana/exchanges/LP_rpc.c | 5 +++++ iguana/exchanges/LP_utxos.c | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 09534dc89..cab431136 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -84,6 +84,11 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx free(retstr); return(0); } + if ( utxo->iambob == 0 ) + { + printf("issue_LP_notifyutxo trying to send Alice %s/v%d\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout); + return(0); + } u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout,utxo->pubkey) > 0 ) { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index cc8e71922..4339493a6 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -267,11 +267,6 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol { uint64_t val,val2=0,threshold; char destaddr[64],destaddr2[64]; destaddr[0] = destaddr2[0] = 0; - if ( iambob == 0 && bits256_cmp(pubkey,LP_mypubkey) != 0 ) - { - char str[65]; printf("external Alice utxo.(%s) rejected\n",bits256_str(str,txid)); - return(0); - } if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) >= satoshis ) { threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : LP_DEXFEE(satoshis); From 32664507b4c174200d79bc993da51aab9dd31908 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:38:55 +0300 Subject: [PATCH 1564/2705] Test --- iguana/exchanges/LP_ordermatch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index af2d2599e..65116d8c4 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -569,13 +569,13 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba vout = jint(item,"vout"); vol = jdouble(item,"volume"); metric = price / bestprice; - if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && metric < 1.2 && vol*SATOSHIDEN == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) + if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && vol*SATOSHIDEN == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { destsatoshis = (butxo->S.satoshis * price); if ( destsatoshis > autxo->payment.value-desttxfee-1 ) destsatoshis = autxo->payment.value-desttxfee-1; satoshis = destsatoshis / price; - if ( destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && satoshis-txfee > (butxo->S.satoshis >> 1) && satoshis < butxo->payment.value-txfee ) + if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && satoshis-txfee > (butxo->S.satoshis >> 1) && satoshis < butxo->payment.value-txfee ) { printf("value %.8f price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",dstr(autxo->payment.value),price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; @@ -587,7 +587,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba bestmetric = metric; printf("set best!\n"); } - } else printf("skip.(%d %d) destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1) ,destsatoshis/price > (butxo->S.satoshis >> 1),dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); + } else printf("skip.(%d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1),destsatoshis/price > (butxo->S.satoshis >> 1),metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0); } } else break; From a00e3d1ad7ec0aca1752a52be8b4dd60f764837f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:40:01 +0300 Subject: [PATCH 1565/2705] Test --- iguana/exchanges/LP_ordermatch.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 65116d8c4..72d72ff5c 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -619,10 +619,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba sleep(1); } if ( autxo->S.swap == 0 ) - { jaddstr(bestitem,"status","couldnt establish connection"); - LP_availableset(autxo); - } else jaddstr(bestitem,"status","connected"); jaddnum(bestitem,"quotedprice",price); jaddnum(bestitem,"maxprice",maxprice); @@ -642,6 +639,8 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba jaddnum(bestitem,"maxprice",maxprice); jaddstr(bestitem,"status","no response to request"); } + if ( autxo->S.swap == 0 ) + LP_availableset(autxo); return(jprint(bestitem,0)); } From 580c71cd06ea34aa4a6bc2a47dd3a15ce39678b6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:42:30 +0300 Subject: [PATCH 1566/2705] Test --- iguana/exchanges/LP_ordermatch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 72d72ff5c..0711cc871 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -588,7 +588,13 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba printf("set best!\n"); } } else printf("skip.(%d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1),destsatoshis/price > (butxo->S.satoshis >> 1),metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); - } else printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0); + } + else + { + if ( butxo != 0 ) + printf("%d %d %d: ",vol*SATOSHIDEN == butxo->S.satoshis,LP_isavailable(butxo) > 0,LP_ismine(butxo) == 0); + printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0); + } } } else break; } From 93e248c999e207771a085fa1afc4349e854a583a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:44:30 +0300 Subject: [PATCH 1567/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 0711cc871..31916e03a 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -592,7 +592,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba else { if ( butxo != 0 ) - printf("%d %d %d: ",vol*SATOSHIDEN == butxo->S.satoshis,LP_isavailable(butxo) > 0,LP_ismine(butxo) == 0); + printf("%llu %llu %d %d %d: ",(long long)vol*SATOSHIDEN,(long long)butxo->S.satoshis,vol*SATOSHIDEN == butxo->S.satoshis,LP_isavailable(butxo) > 0,LP_ismine(butxo) == 0); printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0); } } From bb89905db1160d4746146fa65327629cbd178146 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:45:32 +0300 Subject: [PATCH 1568/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 31916e03a..fb1e9d442 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -592,7 +592,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba else { if ( butxo != 0 ) - printf("%llu %llu %d %d %d: ",(long long)vol*SATOSHIDEN,(long long)butxo->S.satoshis,vol*SATOSHIDEN == butxo->S.satoshis,LP_isavailable(butxo) > 0,LP_ismine(butxo) == 0); + printf("%llu %llu %d %d %d: ",(long long)(vol*SATOSHIDEN),(long long)butxo->S.satoshis,vol*SATOSHIDEN == butxo->S.satoshis,LP_isavailable(butxo) > 0,LP_ismine(butxo) == 0); printf("cant find butxo.%p or value mismatch %.8f != %.8f\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0); } } From 8596b6e5c20b6fc572b457b6f66cc59b6981730e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:46:50 +0300 Subject: [PATCH 1569/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index fb1e9d442..48294f780 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -569,7 +569,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba vout = jint(item,"vout"); vol = jdouble(item,"volume"); metric = price / bestprice; - if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && vol*SATOSHIDEN == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) + if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && (long long)(vol*SATOSHIDEN) == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { destsatoshis = (butxo->S.satoshis * price); if ( destsatoshis > autxo->payment.value-desttxfee-1 ) From f2cfa71be3d68b3e79eceda75d868a0312a7def8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:49:34 +0300 Subject: [PATCH 1570/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 2ebdadbef..3f99137c6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -212,7 +212,7 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) { static uint32_t counter,lastforward,numpeers; - struct LP_utxoinfo *utxo,*utmp; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0; + struct LP_utxoinfo *utxo,*utmp; char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0; now = (uint32_t)time(NULL); if ( mypeer == 0 ) myipaddr = "127.0.0.1"; @@ -263,6 +263,14 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_utxo_clientpublish(utxo); } } + if ( (counter % 600) == 599 ) + { + if ( (retstr= basilisk_swapentry(0,0)) != 0 ) + { + //printf("SWAPS.(%s)\n",retstr); + free(retstr); + } + } if ( pullsock >= 0 ) nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); counter++; @@ -272,11 +280,6 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) { char *retstr; uint8_t r; int32_t i,n,j; cJSON *item; - if ( (retstr= basilisk_swapentry(0,0)) != 0 ) - { - //printf("SWAPS.(%s)\n",retstr); - free(retstr); - } if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) { printf("error launching stats rpcloop for port.%u\n",myport); From caa75b4da5b19b34636ff4d1fe701fe0b39f3727 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:50:44 +0300 Subject: [PATCH 1571/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3f99137c6..1e998c33c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -279,12 +279,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) { - char *retstr; uint8_t r; int32_t i,n,j; cJSON *item; - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) - { - printf("error launching stats rpcloop for port.%u\n",myport); - exit(-1); - } + uint8_t r; int32_t i,n,j; cJSON *item; if ( IAMLP != 0 ) { if ( seednode == 0 || seednode[0] == 0 ) @@ -324,8 +319,11 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } } //LP_privkey_updates(pubsock,passphrase); - if ( (retstr= basilisk_swaplist()) != 0 ) - free(retstr); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",myport); + exit(-1); + } while ( 1 ) { if ( 0 && (rand() % 100) == 0 ) From 54ef95a9f9c3e424f44760d066745fcbca516855 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:51:46 +0300 Subject: [PATCH 1572/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1e998c33c..18d50e2b5 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -319,11 +319,6 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } } //LP_privkey_updates(pubsock,passphrase); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) - { - printf("error launching stats rpcloop for port.%u\n",myport); - exit(-1); - } while ( 1 ) { if ( 0 && (rand() % 100) == 0 ) @@ -381,6 +376,11 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } } + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",myport); + exit(-1); + } if ( IAMLP != 0 ) { if ( myipaddr != 0 ) From 56345730b056f187cc3c1fb05ac0c1973ac07c68 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:53:54 +0300 Subject: [PATCH 1573/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 13 +++++++------ iguana/exchanges/LP_utxos.c | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 18d50e2b5..0b6c57171 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -190,7 +190,7 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma void LP_myutxo_updates(int32_t pubsock,char *passphrase,double profitmargin) { //LP_utxopurge(0); not good to disrupt existing pointers - LP_privkey_updates(pubsock,passphrase); + LP_privkey_updates(pubsock,passphrase,0); } void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubsock,struct LP_peerinfo *peer,uint32_t now,double profitmargin,int32_t interval) @@ -376,11 +376,6 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } } - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) - { - printf("error launching stats rpcloop for port.%u\n",myport); - exit(-1); - } if ( IAMLP != 0 ) { if ( myipaddr != 0 ) @@ -416,6 +411,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit printf("couldnt get myipaddr\n"); exit(-1); } + LP_privkey_updates(pubsock,passphrase,1); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",myport); + exit(-1); + } LP_mainloop(myipaddr,mypeer,mypubport,pubsock,pushaddr,pullsock,myport,passphrase,profitmargin,jobj(argjson,"coins"),jstr(argjson,"seednode")); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 4339493a6..7640f424b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -756,7 +756,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co return(privkey); } -void LP_privkey_updates(int32_t pubsock,char *passphrase) +void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t initonly) { int32_t i; struct iguana_info *coin; bits256 pubkey,privkey; uint8_t pubkey33[33]; memset(privkey.bytes,0,sizeof(privkey)); @@ -768,7 +768,7 @@ void LP_privkey_updates(int32_t pubsock,char *passphrase) { if ( bits256_nonz(privkey) == 0 || coin->smartaddr[0] == 0 ) privkey = LP_privkeycalc(pubkey33,&pubkey,coin,passphrase,""); - if ( coin->inactive == 0 ) + if ( coin->inactive == 0 && initonly == 0 ) LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33); } } From a31c92fc22e08a57004576dc5de3cee20fe1e7a6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 12:57:47 +0300 Subject: [PATCH 1574/2705] Test --- iguana/exchanges/LP_utxos.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7640f424b..bab077f1a 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -763,11 +763,14 @@ void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t initonly) pubkey = privkey; for (i=0; ismartaddr[0] == 0 ) + { + printf("LP_privkeycalc\n"); privkey = LP_privkeycalc(pubkey33,&pubkey,coin,passphrase,""); + } if ( coin->inactive == 0 && initonly == 0 ) LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33); } From 850596d6140bf355e49214cf5cc8ef2c6129d012 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:00:26 +0300 Subject: [PATCH 1575/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0b6c57171..0dc3ab6d1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -318,7 +318,12 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in LP_priceinfoadd(jstr(item,"coin")); } } - //LP_privkey_updates(pubsock,passphrase); + LP_privkey_updates(pubsock,passphrase,1); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",myport); + exit(-1); + } while ( 1 ) { if ( 0 && (rand() % 100) == 0 ) @@ -411,12 +416,6 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit printf("couldnt get myipaddr\n"); exit(-1); } - LP_privkey_updates(pubsock,passphrase,1); - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) - { - printf("error launching stats rpcloop for port.%u\n",myport); - exit(-1); - } LP_mainloop(myipaddr,mypeer,mypubport,pubsock,pushaddr,pullsock,myport,passphrase,profitmargin,jobj(argjson,"coins"),jstr(argjson,"seednode")); } From 7381e22678849a12bcd5bedbbe1d713cf2061034 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:04:15 +0300 Subject: [PATCH 1576/2705] Test --- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/LP_utxos.c | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 535f027fd..1cc3123da 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -51,7 +51,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) } usleep(1000); } - printf("error LP_send sock.%d, pipeline timeout.(%s)\n",sock,msg); + printf("error LP_send sock.%d, pipeline timeout.(%s) %s\n",sock,msg,nn_strerror(nn_errno())); //if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) // printf("LP_send sent %d instead of %d\n",sentbytes,len); if ( freeflag != 0 ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index bab077f1a..7640f424b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -763,14 +763,11 @@ void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t initonly) pubkey = privkey; for (i=0; ismartaddr[0] == 0 ) - { - printf("LP_privkeycalc\n"); privkey = LP_privkeycalc(pubkey33,&pubkey,coin,passphrase,""); - } if ( coin->inactive == 0 && initonly == 0 ) LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33); } From 63225c20e420d913d839b08fa1d3e26ab92e6de8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:11:26 +0300 Subject: [PATCH 1577/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +++- iguana/exchanges/LP_network.c | 3 +++ iguana/exchanges/LP_ordermatch.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0dc3ab6d1..4b4ba45d3 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -20,6 +20,8 @@ #include #include "LP_include.h" +portable_mutex_t LP_peermutex,LP_UTXOmutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex,LP_networkmutex; + #include "LP_network.c" struct LP_utxoinfo *LP_utxoinfos[2],*LP_utxoinfos2[2]; @@ -31,7 +33,6 @@ char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // -portable_mutex_t LP_peermutex,LP_UTXOmutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex; int32_t LP_mypubsock = -1; int32_t USERPASS_COUNTER,IAMLP = 0; double LP_profitratio = 1.; @@ -353,6 +354,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit portable_mutex_init(&LP_commandmutex); portable_mutex_init(&LP_swaplistmutex); portable_mutex_init(&LP_cachemutex); + portable_mutex_init(&LP_networkmutex); portable_mutex_init(&LP_forwardmutex); portable_mutex_init(&LP_pubkeymutex); if ( profitmargin == 0. || profitmargin == 0.01 ) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 1cc3123da..6b83a356f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -40,6 +40,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) { pfd.fd = sock; pfd.events = NN_POLLOUT; + portable_mutex_lock(&LP_networkmutex); if ( nn_poll(&pfd,1,1) > 0 ) { if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) @@ -47,8 +48,10 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); + portable_mutex_unlock(&LP_networkmutex); return(sentbytes); } + portable_mutex_unlock(&LP_networkmutex); usleep(1000); } printf("error LP_send sock.%d, pipeline timeout.(%s) %s\n",sock,msg,nn_strerror(nn_errno())); diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 48294f780..cdac078d2 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -171,7 +171,7 @@ char *LP_quotereceived(cJSON *argjson) if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) { ptr->Q = Q; - printf("\n>>>>>>>>>> received quote %.8f\n\n",price); + printf(">>>>>>>>>> received quote %s/%s %.8f\n",Q.srccoin,Q.destcoin,price); return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); } From 84dd15d45aea77b8f885f074369a6cbf0c05bbe1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:15:38 +0300 Subject: [PATCH 1578/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4b4ba45d3..111e40623 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -138,6 +138,8 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; + if ( IAMLP == 0 ) + printf("pulled.%d (%s)\n",recvlen,(char *)ptr); LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); } return(nonz); From 262d0a95f07ff59689fe94145b7e2ad20ce48329 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:18:05 +0300 Subject: [PATCH 1579/2705] Test --- iguana/exchanges/LP_forwarding.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 0b30713c8..b6d36145f 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -58,8 +58,9 @@ int32_t LP_pushsock_create(char *pushaddr) nn_close(pushsock); return(-1); } - timeout = 100; + timeout = 1; nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + LP_send(pushsock,"{\"method\":\"hello\"}",0); return(pushsock); } From a4adaa7030ef6e2d2c7a30a31f69eea077680e56 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:24:13 +0300 Subject: [PATCH 1580/2705] Test --- iguana/exchanges/LP_forwarding.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index b6d36145f..eff4f29b8 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -50,7 +50,7 @@ char *LP_lookup(bits256 pubkey) int32_t LP_pushsock_create(char *pushaddr) { - int32_t pushsock,timeout; + int32_t pushsock,timeout,i; struct nn_pollfd pfd; if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) return(-1); else if ( nn_connect(pushsock,pushaddr) < 0 ) @@ -60,7 +60,18 @@ int32_t LP_pushsock_create(char *pushaddr) } timeout = 1; nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - LP_send(pushsock,"{\"method\":\"hello\"}",0); + pfd.fd = pushsock; + pfd.events = NN_POLLOUT; + for (i=0; i<1000; i++) + { + if ( nn_poll(&pfd,1,1) > 0 ) + { + LP_send(pushsock,"{\"method\":\"hello\"}",0); + break; + } + } + if ( i == 100 ) + printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,pushaddr); return(pushsock); } From fdf10a96327ddba8304318141417c2ad86bfb10b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:26:10 +0300 Subject: [PATCH 1581/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index eff4f29b8..34da1ee06 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -66,7 +66,7 @@ int32_t LP_pushsock_create(char *pushaddr) { if ( nn_poll(&pfd,1,1) > 0 ) { - LP_send(pushsock,"{\"method\":\"hello\"}",0); + printf("HELLO sent.%d bytes\n",LP_send(pushsock,"{\"method\":\"hello\"}",0)); break; } } From acd4a7f32d55dda0edb4901b80ffd0cf6e6fa25f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:29:47 +0300 Subject: [PATCH 1582/2705] Test --- iguana/exchanges/LP_forwarding.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 34da1ee06..f486faf1b 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -50,27 +50,31 @@ char *LP_lookup(bits256 pubkey) int32_t LP_pushsock_create(char *pushaddr) { - int32_t pushsock,timeout,i; struct nn_pollfd pfd; + int32_t pushsock,timeout,i,n=1000; struct nn_pollfd pfd; if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) + { + printf("LP_pushsock_create couldnt allocate socket for %s\n",pushaddr); return(-1); + } else if ( nn_connect(pushsock,pushaddr) < 0 ) { nn_close(pushsock); + printf("LP_pushsock_create couldnt connect to %s\n",pushaddr); return(-1); } timeout = 1; nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); pfd.fd = pushsock; pfd.events = NN_POLLOUT; - for (i=0; i<1000; i++) + for (i=0; i 0 ) { - printf("HELLO sent.%d bytes\n",LP_send(pushsock,"{\"method\":\"hello\"}",0)); + printf("HELLO sent.%d bytes to %s\n",LP_send(pushsock,"{\"method\":\"hello\"}",0),pushaddr); break; } } - if ( i == 100 ) + if ( i == n ) printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,pushaddr); return(pushsock); } From 9a9a53a0b9667d89bd448002ebc671639a3d62dd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:31:29 +0300 Subject: [PATCH 1583/2705] Test --- iguana/exchanges/LP_forwarding.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index f486faf1b..c93cfbc8d 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -50,7 +50,7 @@ char *LP_lookup(bits256 pubkey) int32_t LP_pushsock_create(char *pushaddr) { - int32_t pushsock,timeout,i,n=1000; struct nn_pollfd pfd; + int32_t pushsock,timeout,i,n=1000; char msg[512]; struct nn_pollfd pfd; if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) { printf("LP_pushsock_create couldnt allocate socket for %s\n",pushaddr); @@ -70,7 +70,8 @@ int32_t LP_pushsock_create(char *pushaddr) { if ( nn_poll(&pfd,1,1) > 0 ) { - printf("HELLO sent.%d bytes to %s\n",LP_send(pushsock,"{\"method\":\"hello\"}",0),pushaddr); + sprintf(msg,"{\"method\":\"hello\",\"from\":\"%s\"}",LP_mypeer != 0 ? LP_mypeer->ipaddr : ""); + printf("HELLO sent.%d bytes to %s\n",LP_send(pushsock,msg,0),pushaddr); break; } } From 6b2c6863e1dafda7a198a521d193f60804dce84f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:33:52 +0300 Subject: [PATCH 1584/2705] Test --- iguana/exchanges/LP_commands.c | 6 +++++- iguana/exchanges/LP_rpc.c | 7 ++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bcbd2541b..9b1c9867e 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -216,7 +216,11 @@ forwardhex(pubkey,hex)\n\ else if ( IAMLP != 0 ) { if ( strcmp(method,"register") == 0 ) - return(LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr"))); + { + retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr")); + printf("got (%s) from register\n",retstr!=0?retstr:""); + return(retstr); + } else if ( strcmp(method,"lookup") == 0 ) return(LP_lookup(jbits256(argjson,"client"))); else if ( strcmp(method,"forwardhex") == 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index cab431136..c1cc0bb52 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -106,12 +106,13 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *pushaddr) { - char url[512],str[65]; + char url[512],str[65],*retstr; if ( strncmp("tcp://",pushaddr,strlen("tcp://")) != 0 || strlen(pushaddr) <= strlen("tcp://") ) return(clonestr("{\"error\":\"illegal pushaddr\"}")); sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr+strlen("tcp://")); - //printf("getutxo.(%s)\n",url); - return(issue_curlt(url,LP_HTTP_TIMEOUT)); + retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); + return(retstr); } char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) From c40593cea695ada0aa9d69680ffa32572f3ac0a7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:34:30 +0300 Subject: [PATCH 1585/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index c1cc0bb52..7de3a990c 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -110,7 +110,7 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *push if ( strncmp("tcp://",pushaddr,strlen("tcp://")) != 0 || strlen(pushaddr) <= strlen("tcp://") ) return(clonestr("{\"error\":\"illegal pushaddr\"}")); sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr+strlen("tcp://")); - retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + retstr = issue_curlt(url,5); printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); return(retstr); } From bad675684016a5707ad408e1eb1a21efe3555e10 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:39:37 +0300 Subject: [PATCH 1586/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index c93cfbc8d..b11cbb962 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -50,7 +50,7 @@ char *LP_lookup(bits256 pubkey) int32_t LP_pushsock_create(char *pushaddr) { - int32_t pushsock,timeout,i,n=1000; char msg[512]; struct nn_pollfd pfd; + int32_t pushsock,timeout,i,n=10; char msg[512]; struct nn_pollfd pfd; if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) { printf("LP_pushsock_create couldnt allocate socket for %s\n",pushaddr); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 111e40623..d2c8bc2f8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -227,6 +227,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } HASH_ITER(hh,LP_peerinfos,peer,tmp) { + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) { printf("numpeers.%d updatepeer.%s lag.%d\n",numpeers,peer->ipaddr,now-peer->lastpeers); @@ -246,10 +247,12 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } if ( (counter % 600) == 60 ) { + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); LP_myutxo_updates(pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) { LP_forwarding_register(LP_mypubkey,pushaddr,10); + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); lastforward = now; } } @@ -257,10 +260,12 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) { + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); LP_utxo_spentcheck(pubsock,utxo,profitmargin); } HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp) { + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); LP_utxo_spentcheck(pubsock,utxo,profitmargin); if ( utxo->T.lasttime == 0 ) LP_utxo_clientpublish(utxo); @@ -268,14 +273,14 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } if ( (counter % 600) == 599 ) { + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); if ( (retstr= basilisk_swapentry(0,0)) != 0 ) { //printf("SWAPS.(%s)\n",retstr); free(retstr); } } - if ( pullsock >= 0 ) - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); + nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); counter++; return(nonz); } @@ -380,7 +385,6 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - timeout = 1; maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } From d2fea638633dfed2153b7c92c50feea5b4ab49e5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:41:54 +0300 Subject: [PATCH 1587/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_rpc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 9b1c9867e..57454830f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -218,7 +218,7 @@ forwardhex(pubkey,hex)\n\ if ( strcmp(method,"register") == 0 ) { retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr")); - printf("got (%s) from register\n",retstr!=0?retstr:""); + //printf("got (%s) from register\n",retstr!=0?retstr:""); return(retstr); } else if ( strcmp(method,"lookup") == 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 7de3a990c..0003c99da 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -110,8 +110,8 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *push if ( strncmp("tcp://",pushaddr,strlen("tcp://")) != 0 || strlen(pushaddr) <= strlen("tcp://") ) return(clonestr("{\"error\":\"illegal pushaddr\"}")); sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr+strlen("tcp://")); - retstr = issue_curlt(url,5); - printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); + retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); return(retstr); } From 123b9538f6e2efb47a4e46d9661533fb60cd0ed6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:51:15 +0300 Subject: [PATCH 1588/2705] Test --- iguana/exchanges/LP_forwarding.c | 56 ++++++++++++++++++++++---------- iguana/exchanges/LP_nativeDEX.c | 2 ++ 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index b11cbb962..3ded921fd 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -24,7 +24,7 @@ struct LP_forwardinfo bits256 pubkey; char pushaddr[64]; int32_t pushsock; - uint32_t lasttime; + uint32_t lasttime,hello; } *LP_forwardinfos; #define LP_KEEPALIVE (3600 * 24) @@ -48,9 +48,39 @@ char *LP_lookup(bits256 pubkey) else return(clonestr("{\"error\":\"notfound\"}")); } -int32_t LP_pushsock_create(char *pushaddr) +int32_t LP_hello(struct LP_forwardinfo *ptr) { - int32_t pushsock,timeout,i,n=10; char msg[512]; struct nn_pollfd pfd; + int32_t i,n=10; char msg[512]; struct nn_pollfd pfd; + pfd.fd = ptr->pushsock; + pfd.events = NN_POLLOUT; + for (i=0; i 0 ) + { + sprintf(msg,"{\"method\":\"hello\",\"from\":\"%s\"}",LP_mypeer != 0 ? LP_mypeer->ipaddr : ""); + printf("HELLO sent.%d bytes to %s on i.%d\n",LP_send(ptr->pushsock,msg,0),ptr->pushaddr,i); + ptr->hello = (uint32_t)time(NULL); + return(i); + } + } + printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); + return(-1); +} + +int32_t LP_hellos() +{ + struct LP_forwardinfo *ptr,*tmp; int32_t nonz = 0; + HASH_ITER(hh,LP_forwardinfos,ptr,tmp) + { + if ( ptr->hello == 0 && LP_hello(ptr) >= 0 ) + nonz++; + } + return(nonz); +} + +int32_t LP_pushsock_create(struct LP_forwardinfo *ptr,char *pushaddr) +{ + int32_t pushsock,timeout; if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) { printf("LP_pushsock_create couldnt allocate socket for %s\n",pushaddr); @@ -64,19 +94,8 @@ int32_t LP_pushsock_create(char *pushaddr) } timeout = 1; nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - pfd.fd = pushsock; - pfd.events = NN_POLLOUT; - for (i=0; i 0 ) - { - sprintf(msg,"{\"method\":\"hello\",\"from\":\"%s\"}",LP_mypeer != 0 ? LP_mypeer->ipaddr : ""); - printf("HELLO sent.%d bytes to %s\n",LP_send(pushsock,msg,0),pushaddr); - break; - } - } - if ( i == n ) - printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,pushaddr); + if ( ptr != 0 ) + LP_hello(ptr); return(pushsock); } @@ -96,12 +115,12 @@ char *LP_register(bits256 pubkey,char *ipaddr) { nn_close(ptr->pushsock); printf("recreate pushsock for %s\n",pushaddr); - if ( (ptr->pushsock= LP_pushsock_create(pushaddr)) < 0 ) + if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 ) return(clonestr("{\"error\":\"couldnt recreate pushsock\",\"registered\":0}")); } return(clonestr("{\"error\":\"already registered\",\"registered\":1}")); } - else if ( (pushsock= LP_pushsock_create(pushaddr)) < 0 ) + else if ( (pushsock= LP_pushsock_create(0,pushaddr)) < 0 ) return(clonestr("{\"error\":\"couldnt create pushsock\"}")); else { @@ -114,6 +133,7 @@ char *LP_register(bits256 pubkey,char *ipaddr) HASH_ADD_KEYPTR(hh,LP_forwardinfos,&ptr->pubkey,sizeof(ptr->pubkey),ptr); portable_mutex_unlock(&LP_forwardmutex); char str[65]; printf("registered (%s) -> (%s) pushsock.%d\n",bits256_str(str,pubkey),pushaddr,ptr->pushsock); + LP_hello(ptr); return(LP_lookup(pubkey)); } } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d2c8bc2f8..59929ce45 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -281,6 +281,8 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } } nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); + if ( (counter % 60) == 42 ) + LP_hellos(); counter++; return(nonz); } From ae9be1f4d8e82b3ab692e42fa521fcd6312f2f26 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:54:43 +0300 Subject: [PATCH 1589/2705] Test --- iguana/exchanges/LP_forwarding.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 3ded921fd..fac22d1f0 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -51,20 +51,24 @@ char *LP_lookup(bits256 pubkey) int32_t LP_hello(struct LP_forwardinfo *ptr) { int32_t i,n=10; char msg[512]; struct nn_pollfd pfd; - pfd.fd = ptr->pushsock; - pfd.events = NN_POLLOUT; - for (i=0; ipubkey,LP_mypubkey) != 0 ) { - if ( nn_poll(&pfd,1,1) > 0 ) + pfd.fd = ptr->pushsock; + pfd.events = NN_POLLOUT; + for (i=0; iipaddr : ""); - printf("HELLO sent.%d bytes to %s on i.%d\n",LP_send(ptr->pushsock,msg,0),ptr->pushaddr,i); - ptr->hello = (uint32_t)time(NULL); - return(i); + if ( nn_poll(&pfd,1,1) > 0 ) + { + sprintf(msg,"{\"method\":\"hello\",\"from\":\"%s\"}",LP_mypeer != 0 ? LP_mypeer->ipaddr : ""); + printf("HELLO sent.%d bytes to %s on i.%d\n",LP_send(ptr->pushsock,msg,0),ptr->pushaddr,i); + ptr->hello = (uint32_t)time(NULL); + return(i); + } } + printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); + return(-1); } - printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); - return(-1); + return(0); } int32_t LP_hellos() From fec438de939c44dbbe67f8cf91c7c0a38f3b6dce Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:57:41 +0300 Subject: [PATCH 1590/2705] Test --- iguana/exchanges/LP_forwarding.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index fac22d1f0..7962e0273 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -203,7 +203,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) } else if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { - if ( ptr->pushsock >= 0 ) + if ( ptr->pushsock >= 0 && ptr->hello != 0 ) { //printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data); sentbytes = LP_send(ptr->pushsock,(char *)data,0); @@ -220,6 +220,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) jaddstr(retjson,"error","send error"); jaddnum(retjson,"sentbytes",sentbytes); jaddnum(retjson,"datalen",datalen); + jaddnum(retjson,"hello",ptr->hello); retstr = jprint(retjson,1); } } From ed7fe542ce498f36f3f6e98aa65d96a4620b8221 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 13:59:17 +0300 Subject: [PATCH 1591/2705] Test --- iguana/exchanges/LP_commands.c | 4 +++- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 57454830f..92deb8e0f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -50,7 +50,9 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs printf("stats_JSON no method: (%s) (%s:%u)\n",jprint(argjson,0),ipaddr,argport); return(0); } - if ( strcmp(method,"help") == 0 ) + if ( strcmp(method,"hello") == 0 ) + return(0); + else if ( strcmp(method,"help") == 0 ) return(clonestr("{\"result\":\" \ available localhost RPC commands:\n \ setprice(base, rel, price)\n\ diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 7962e0273..2c6e573e8 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -65,7 +65,7 @@ int32_t LP_hello(struct LP_forwardinfo *ptr) return(i); } } - printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); + //printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); return(-1); } return(0); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 59929ce45..c40d28861 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -281,7 +281,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } } nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); - if ( (counter % 60) == 42 ) + if ( (counter % 600) == 42 ) LP_hellos(); counter++; return(nonz); From b040ca290f347a47a4daf42cc30069866e9674af Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:36:19 +0300 Subject: [PATCH 1592/2705] Test --- iguana/exchanges/LP_rpc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 0003c99da..fd0ff067f 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -59,9 +59,12 @@ char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn, char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t lastn) { - char url[512]; + char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); - return(issue_curlt(url,LP_HTTP_TIMEOUT)); + retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + + printf("%s clientgetutxos.(%s)\n",url,retstr); + return(retstr); } char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) From b585a93f1097d9b816cc8a932240c73b067ef196 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:40:11 +0300 Subject: [PATCH 1593/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c40d28861..c3dc3f9b8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -207,6 +207,7 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso if ( mypeer == 0 || strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) { peer->lastutxos = now; + printf("query utxos from %s\n",peer->ipaddr); LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } } //else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); From 7abecd195c1a6b53dd2a093d22ff7784a0546739 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:43:11 +0300 Subject: [PATCH 1594/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c3dc3f9b8..862778207 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -241,6 +241,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso nonz += LP_subsock_check(myipaddr,pubsock,peer->subsock,profitmargin); if ( peer->diduquery == 0 ) { + printf("do initial queries\n"); LP_peer_utxosquery(mypeer,myport,pubsock,peer,now,profitmargin,60); LP_peer_pricesquery(peer->ipaddr,peer->port); peer->diduquery = now; From cf631adfaa35b9664244370a48ac5ccdb4f26284 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:44:59 +0300 Subject: [PATCH 1595/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 862778207..a3de37bf3 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -247,6 +247,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso peer->diduquery = now; } } + printf("counter.%d numpeers %d\n",counter,numpeers); if ( (counter % 600) == 60 ) { nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); From 0b53fc75843b6a8f1d500af60e5eeaf13c775a94 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:46:26 +0300 Subject: [PATCH 1596/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a3de37bf3..f64997a06 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -394,6 +394,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } } + printf("my command address is (%s)\n",pushaddr); if ( IAMLP != 0 ) { if ( myipaddr != 0 ) From bb8dde925c7613c99e52a053e82ff92f6e502117 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:48:42 +0300 Subject: [PATCH 1597/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f64997a06..218bf1cd2 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -220,12 +220,13 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso now = (uint32_t)time(NULL); if ( mypeer == 0 ) myipaddr = "127.0.0.1"; - //printf("start peers updates\n"); + printf("start peers updates\n"); numpeers = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { numpeers++; } + printf("counter.%d numpeers %d\n",counter,numpeers); HASH_ITER(hh,LP_peerinfos,peer,tmp) { nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); @@ -319,6 +320,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } for (i=0; i Date: Sun, 18 Jun 2017 14:50:35 +0300 Subject: [PATCH 1598/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 218bf1cd2..9023925f6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -229,7 +229,6 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso printf("counter.%d numpeers %d\n",counter,numpeers); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) { printf("numpeers.%d updatepeer.%s lag.%d\n",numpeers,peer->ipaddr,now-peer->lastpeers); @@ -239,7 +238,6 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); } - nonz += LP_subsock_check(myipaddr,pubsock,peer->subsock,profitmargin); if ( peer->diduquery == 0 ) { printf("do initial queries\n"); @@ -251,12 +249,10 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso printf("counter.%d numpeers %d\n",counter,numpeers); if ( (counter % 600) == 60 ) { - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); LP_myutxo_updates(pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) { LP_forwarding_register(LP_mypubkey,pushaddr,10); - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); lastforward = now; } } @@ -264,12 +260,10 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) { - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); LP_utxo_spentcheck(pubsock,utxo,profitmargin); } HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp) { - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); LP_utxo_spentcheck(pubsock,utxo,profitmargin); if ( utxo->T.lasttime == 0 ) LP_utxo_clientpublish(utxo); @@ -277,16 +271,18 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } if ( (counter % 600) == 599 ) { - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); + printf("check swaps\n"); if ( (retstr= basilisk_swapentry(0,0)) != 0 ) { //printf("SWAPS.(%s)\n",retstr); free(retstr); } } + printf("check pullsock\n"); nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); - if ( (counter % 600) == 42 ) + if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); + printf("done pullsock\n"); counter++; return(nonz); } From 391a8b5ed0a061c3c4b6bbaa21dfb761c44f9b7c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:52:50 +0300 Subject: [PATCH 1599/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9023925f6..ef7875a04 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -135,8 +135,10 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { void *ptr; int32_t recvlen,nonz = 0; + printf("call nn_recv\n"); while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { + printf("got %d\n",recvlen); nonz++; if ( IAMLP == 0 ) printf("pulled.%d (%s)\n",recvlen,(char *)ptr); From c8d84d722b7032ed5c92d3d027db13544ad9072c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:54:52 +0300 Subject: [PATCH 1600/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ef7875a04..7ea1870a3 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -392,8 +392,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - maxsize = 2 * 1024 * 1024; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + //maxsize = 2 * 1024 * 1024; + //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } } printf("my command address is (%s)\n",pushaddr); From c28f94520a829063a98fe8ac720f93c3ce72c8cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:58:20 +0300 Subject: [PATCH 1601/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 21 ++++++++++----------- iguana/exchanges/LP_rpc.c | 3 +-- iguana/exchanges/LP_utxos.c | 9 +++++---- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7ea1870a3..6d2fc9368 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -198,9 +198,9 @@ void LP_myutxo_updates(int32_t pubsock,char *passphrase,double profitmargin) LP_privkey_updates(pubsock,passphrase,0); } -void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubsock,struct LP_peerinfo *peer,uint32_t now,double profitmargin,int32_t interval) +int32_t LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubsock,struct LP_peerinfo *peer,uint32_t now,double profitmargin,int32_t interval) { - int32_t lastn; + int32_t lastn,n = -1; if ( peer->lastutxos < now-interval ) { //lastn = peer->numutxos - mypeer->numutxos + LP_PROPAGATION_SLACK; @@ -210,25 +210,24 @@ void LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubso { peer->lastutxos = now; printf("query utxos from %s\n",peer->ipaddr); - LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); + n = LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } } //else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); + return(n); } int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) { static uint32_t counter,lastforward,numpeers; - struct LP_utxoinfo *utxo,*utmp; char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0; + struct LP_utxoinfo *utxo,*utmp; char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0,n=0,lastn=-1; now = (uint32_t)time(NULL); if ( mypeer == 0 ) myipaddr = "127.0.0.1"; - printf("start peers updates\n"); numpeers = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { numpeers++; } - printf("counter.%d numpeers %d\n",counter,numpeers); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) @@ -242,13 +241,15 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } if ( peer->diduquery == 0 ) { - printf("do initial queries\n"); - LP_peer_utxosquery(mypeer,myport,pubsock,peer,now,profitmargin,60); + if ( lastn != n || n < 20 ) + { + lastn = n; + n = LP_peer_utxosquery(mypeer,myport,pubsock,peer,now,profitmargin,60); + } LP_peer_pricesquery(peer->ipaddr,peer->port); peer->diduquery = now; } } - printf("counter.%d numpeers %d\n",counter,numpeers); if ( (counter % 600) == 60 ) { LP_myutxo_updates(pubsock,passphrase,profitmargin); @@ -280,11 +281,9 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso free(retstr); } } - printf("check pullsock\n"); nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); - printf("done pullsock\n"); counter++; return(nonz); } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index fd0ff067f..c624cd7ac 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -62,8 +62,7 @@ char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); retstr = issue_curlt(url,LP_HTTP_TIMEOUT); - - printf("%s clientgetutxos.(%s)\n",url,retstr); + //printf("%s clientgetutxos.(%s)\n",url,retstr); return(retstr); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7640f424b..e84276fb0 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -554,9 +554,9 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n return(n); } -void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) +int32_t LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *coin,int32_t lastn,char *myipaddr,uint16_t myport,double myprofit) { - char *retstr; struct LP_peerinfo *peer; uint32_t now; + char *retstr; struct LP_peerinfo *peer; uint32_t now; int32_t retval = -1; peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport); if ( coin == 0 ) coin = ""; @@ -567,7 +567,7 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr if ( retstr != 0 ) { now = (uint32_t)time(NULL); - LP_utxosparse(destipaddr,destport,retstr,now); + retval = LP_utxosparse(destipaddr,destport,retstr,now); //printf("got.(%s)\n",retstr); free(retstr); /*i = 0; @@ -588,7 +588,8 @@ void LP_utxosquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr } if ( flag != 0 ) printf(" <- missing utxos\n");*/ - } + } + return(retval); } cJSON *LP_inventory(char *symbol,int32_t iambob) From 738e3ef8c46e7a983f5528665bb666266de42cbe Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 14:59:51 +0300 Subject: [PATCH 1602/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6d2fc9368..f8811e832 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -349,7 +349,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0; long filesize,n; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128]; + char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128]; IAMLP = !amclient; LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 6b83a356f..b2f820216 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -40,7 +40,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) { pfd.fd = sock; pfd.events = NN_POLLOUT; - portable_mutex_lock(&LP_networkmutex); + //portable_mutex_lock(&LP_networkmutex); if ( nn_poll(&pfd,1,1) > 0 ) { if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) @@ -48,10 +48,10 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); - portable_mutex_unlock(&LP_networkmutex); + //portable_mutex_unlock(&LP_networkmutex); return(sentbytes); } - portable_mutex_unlock(&LP_networkmutex); + //portable_mutex_unlock(&LP_networkmutex); usleep(1000); } printf("error LP_send sock.%d, pipeline timeout.(%s) %s\n",sock,msg,nn_strerror(nn_errno())); From d766303be962cda99ef24d7c1ec7dd8bc76d37ac Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 15:02:32 +0300 Subject: [PATCH 1603/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_statemachine.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f8811e832..927cfb3dd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -136,7 +136,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double { void *ptr; int32_t recvlen,nonz = 0; printf("call nn_recv\n"); - while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) { printf("got %d\n",recvlen); nonz++; @@ -150,7 +150,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double profitmargin) { int32_t recvlen,nonz = 0; void *ptr; - while ( sock >= 0 && (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) + while ( sock >= 0 && (recvlen= nn_recv(sock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) { nonz++; LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen); diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index f42043ab3..70e6d1c7b 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -204,7 +204,7 @@ void basilisk_swapgotdata(struct basilisk_swap *swap,uint32_t crc32,bits256 srch int32_t basilisk_swapget(struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(void *ptr,uint8_t *data,int32_t datalen)) { uint8_t *ptr; bits256 srchash,desthash; uint32_t crc32,_msgbits,quoteid; int32_t i,size,offset,retval = -1; struct basilisk_swapmessage *mp = 0; - while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,0)) >= 0 ) + while ( (size= nn_recv(swap->subsock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) { swap->lasttime = (uint32_t)time(NULL); memset(srchash.bytes,0,sizeof(srchash)); From 9ead3107d7c952d7c499ad17fbd0891929985b71 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 15:03:18 +0300 Subject: [PATCH 1604/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 927cfb3dd..ca7eccd2c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -135,10 +135,8 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { void *ptr; int32_t recvlen,nonz = 0; - printf("call nn_recv\n"); while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) { - printf("got %d\n",recvlen); nonz++; if ( IAMLP == 0 ) printf("pulled.%d (%s)\n",recvlen,(char *)ptr); From 24f201bb367c9601f009b8ddb82028afe13f5f76 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 15:06:37 +0300 Subject: [PATCH 1605/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ca7eccd2c..c7f3f1444 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -101,7 +101,8 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - //printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); + if ( IAMLP == 0 ) + printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { len = (int32_t)strlen(jsonstr) + 1; @@ -138,8 +139,6 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) { nonz++; - if ( IAMLP == 0 ) - printf("pulled.%d (%s)\n",recvlen,(char *)ptr); LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); } return(nonz); From 57f4c10b04a40faa75fed7763db009bfa3a0a284 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 15:18:16 +0300 Subject: [PATCH 1606/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 2c6e573e8..7e537d3f0 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -203,7 +203,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) } else if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { - if ( ptr->pushsock >= 0 && ptr->hello != 0 ) + if ( ptr->pushsock >= 0 )//&& ptr->hello != 0 ) { //printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data); sentbytes = LP_send(ptr->pushsock,(char *)data,0); From 77dc0f63f6ed7f93aeee4932fe40380c5f62a93f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 15:20:49 +0300 Subject: [PATCH 1607/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c7f3f1444..693d498f8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -246,6 +246,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_peer_pricesquery(peer->ipaddr,peer->port); peer->diduquery = now; } + nonz += LP_subsock_check(myipaddr,pubsock,peer->subsock,profitmargin); } if ( (counter % 600) == 60 ) { @@ -271,7 +272,6 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } if ( (counter % 600) == 599 ) { - printf("check swaps\n"); if ( (retstr= basilisk_swapentry(0,0)) != 0 ) { //printf("SWAPS.(%s)\n",retstr); From b4b56dbf19b8604f3432a8bafcc9565d8bd3b930 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 15:29:18 +0300 Subject: [PATCH 1608/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_ordermatch.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index b66e2c47c..da587d194 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -26,6 +26,7 @@ #define LP_SWAPSTEP_TIMEOUT 3 #define LP_AUTOTRADE_TIMEOUT 3 #define LP_MIN_TXFEE 10000 +#define LP_MINVOL 3 #define LP_DEXFEE(destsatoshis) ((destsatoshis) / INSTANTDEX_INSURANCEDIV) #define LP_DEPOSITSATOSHIS(satoshis) ((satoshis) + (satoshis >> 3)) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index cdac078d2..20a3acc61 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -268,12 +268,12 @@ double LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxop return(-11); } qprice = ((double)qp->destsatoshis / qp->satoshis); - if ( qp->satoshis < (srcvalue >> 1) ) + if ( qp->satoshis < (srcvalue >> LP_MINVOL) ) { printf("utxo payment %.8f is less than half covered by Q %.8f\n",dstr(srcvalue),dstr(qp->satoshis)); return(-12); } - if ( qp->destsatoshis < (destvalue >> 1) ) + if ( qp->destsatoshis < (destvalue >> LP_MINVOL) ) { printf("destsatoshis %.8f is less than half of value %.8f\n",dstr(qp->destsatoshis),dstr(destvalue)); return(-13); @@ -575,7 +575,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba if ( destsatoshis > autxo->payment.value-desttxfee-1 ) destsatoshis = autxo->payment.value-desttxfee-1; satoshis = destsatoshis / price; - if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> 1) && satoshis-txfee > (butxo->S.satoshis >> 1) && satoshis < butxo->payment.value-txfee ) + if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> LP_MINVOL) && satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL) && satoshis < butxo->payment.value-txfee ) { printf("value %.8f price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",dstr(autxo->payment.value),price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; @@ -587,7 +587,7 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba bestmetric = metric; printf("set best!\n"); } - } else printf("skip.(%d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> 1),destsatoshis/price > (butxo->S.satoshis >> 1),metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); + } else printf("skip.(%d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> LP_MINVOL),destsatoshis/price > (butxo->S.satoshis >> LP_MINVOL),metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); } else { From c75ffee2500d2dc332c4e651019cc0bffb8ccf0a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 15:39:38 +0300 Subject: [PATCH 1609/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 693d498f8..591265d0d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -101,7 +101,7 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - if ( IAMLP == 0 ) + if ( 0 && IAMLP == 0 ) printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { From 2de0639d79aea06a50a7a97d2d9fc7e72d6ed443 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 20:09:58 +0300 Subject: [PATCH 1610/2705] Test --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index f166a52e6..ca8b97239 100755 --- a/.gitignore +++ b/.gitignore @@ -467,3 +467,7 @@ iguana/DB/SWAPS/1819165332-1507632737 iguana/DB/SWAPS/283982730-556239841 iguana/marketmaker.dSYM/Contents/Info.plist + +iguana/client + +iguana/marketmaker.dSYM/Contents/Resources/DWARF/marketmaker From 4ad4e8563bdb124c713a6414a194ad290da068c1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 20:58:04 +0300 Subject: [PATCH 1611/2705] Test --- iguana/exchanges/mm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index 05b95a9a8..a80982185 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -28,7 +28,8 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs #include "stats.c" void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]); -#if defined(__APPLE__) || defined(WIN32) || defined(USE_STATIC_NANOMSG) +//defined(__APPLE__) || +#if defined(WIN32) || defined(USE_STATIC_NANOMSG) #include "../../crypto777/nanosrc/nn.h" #include "../../crypto777/nanosrc/bus.h" #include "../../crypto777/nanosrc/pubsub.h" From 811129820c975a31aaa5c8b0d861229eeb24e1ec Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 21:19:41 +0300 Subject: [PATCH 1612/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 14 +++++++++++--- iguana/exchanges/LP_ordermatch.c | 8 +++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 591265d0d..794f98dff 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -344,9 +344,14 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } } +void nn_tests() +{ + +} + void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128]; + char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; IAMLP = !amclient; LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); @@ -382,9 +387,11 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); + nn_tests(); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { - if ( nn_bind(pullsock,pushaddr) >= 0 ) + nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); + if ( nn_bind(pullsock,bindaddr) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); @@ -399,9 +406,10 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { pubsock = -1; nanomsg_tcpname(subaddr,myipaddr,mypubport); + nanomsg_tcpname(bindaddr,"0.0.0.0",mypubport); if ( (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) { - if ( nn_bind(pubsock,subaddr) >= 0 ) + if ( nn_bind(pubsock,bindaddr) >= 0 ) { timeout = 10; nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 20a3acc61..d48b70548 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -340,11 +340,13 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) { - int32_t i,timeout; + int32_t i,timeout,r; char bindaddr[128]; for (i=0; i<10; i++) { - nanomsg_tcpname(pairstr,myipaddr,10000+(rand() % 50000)); - if ( nn_bind(pair,pairstr) >= 0 ) + r = (10000 + (rand() % 50000)) & 0xffff; + nanomsg_tcpname(pairstr,myipaddr,r); + nanomsg_tcpname(bindaddr,myipaddr,r); + if ( nn_bind(pair,bindaddr) >= 0 ) { timeout = 100; nn_setsockopt(pair,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); From 44ae52415447987e4b2d5148bdca453060ec6ec2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 21:24:47 +0300 Subject: [PATCH 1613/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_ordermatch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 794f98dff..c42b83a90 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -397,7 +397,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); //maxsize = 2 * 1024 * 1024; //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - } + } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); } printf("my command address is (%s)\n",pushaddr); if ( IAMLP != 0 ) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index d48b70548..0f82b46b0 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -353,7 +353,7 @@ int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) nn_setsockopt(pair,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); printf("nanobind %s to %d\n",pairstr,pair); return(0); - } + } else printf("error binding to %s for %s\n",bindaddr,pairstr); } return(-1); } From 0973c5e218844d227a6a487b5f19623e08823b5f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 21:26:50 +0300 Subject: [PATCH 1614/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c42b83a90..a0b69d234 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -399,7 +399,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); } - printf("my command address is (%s)\n",pushaddr); + printf("my command address is (%s) pullsock.%d\n",pushaddr,pullsock); if ( IAMLP != 0 ) { if ( myipaddr != 0 ) From 2946510a21af99ac392803fcb317fbe728bbedf6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 21:27:49 +0300 Subject: [PATCH 1615/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a0b69d234..1949357a9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -346,7 +346,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests() { - + nn_socket(AF_SP,NN_BUS); } void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) From 0ca4561fc11cfca6a9678ee65c26e2a92f03cd29 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 21:30:55 +0300 Subject: [PATCH 1616/2705] test --- iguana/exchanges/LP_nativeDEX.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1949357a9..bc6c7a40f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -344,9 +344,19 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } } -void nn_tests() +void nn_tests(char *pushaddr) { - nn_socket(AF_SP,NN_BUS); + int32_t sock,n; + if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + { + if ( nn_connect(sock,pushaddr) < 0 ) + printf("connect error %s\n",nn_strerror(nn_errno())); + else + { + n = LP_send(sock,"nn_tests",0); + printf("sent %d bytes\n",n); + } + } } void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) @@ -387,7 +397,6 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - nn_tests(); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); @@ -399,6 +408,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); } + nn_tests(pushaddr); printf("my command address is (%s) pullsock.%d\n",pushaddr,pullsock); if ( IAMLP != 0 ) { From e347e3b1c5b91104fb19229a53192387d83b2c2e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 21:34:18 +0300 Subject: [PATCH 1617/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index bc6c7a40f..6b929623a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -399,7 +399,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nanomsg_tcpname(pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { - nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); + nanomsg_tcpname(bindaddr,"127.0.0.1",mypullport); if ( nn_bind(pullsock,bindaddr) >= 0 ) { timeout = 1; From a7b629e579fe6d93022312c1ea5c5d30889607df Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 21:40:44 +0300 Subject: [PATCH 1618/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6b929623a..0c63d2c16 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -361,7 +361,7 @@ void nn_tests(char *pushaddr) void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; + char *myipaddr=0; long filesize,n; int32_t maxsize,timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; IAMLP = !amclient; LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); @@ -399,13 +399,13 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nanomsg_tcpname(pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { + timeout = 100; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); nanomsg_tcpname(bindaddr,"127.0.0.1",mypullport); if ( nn_bind(pullsock,bindaddr) >= 0 ) { - timeout = 1; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - //maxsize = 2 * 1024 * 1024; - //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + maxsize = 2 * 1024 * 1024; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); } nn_tests(pushaddr); From f5d0d3dc669ea40be4a497484ecdfa1ecbd2330b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 21:56:54 +0300 Subject: [PATCH 1619/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_ordermatch.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0c63d2c16..95c0d966d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -401,7 +401,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { timeout = 100; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nanomsg_tcpname(bindaddr,"127.0.0.1",mypullport); + nanomsg_tcpname(bindaddr,myipaddr,mypullport); if ( nn_bind(pullsock,bindaddr) >= 0 ) { maxsize = 2 * 1024 * 1024; @@ -416,7 +416,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { pubsock = -1; nanomsg_tcpname(subaddr,myipaddr,mypubport); - nanomsg_tcpname(bindaddr,"0.0.0.0",mypubport); + nanomsg_tcpname(bindaddr,myipaddr,mypubport); if ( (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) { if ( nn_bind(pubsock,bindaddr) >= 0 ) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 0f82b46b0..2790df60c 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -345,7 +345,7 @@ int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) { r = (10000 + (rand() % 50000)) & 0xffff; nanomsg_tcpname(pairstr,myipaddr,r); - nanomsg_tcpname(bindaddr,myipaddr,r); + nanomsg_tcpname(bindaddr,"0.0.0.0",r); if ( nn_bind(pair,bindaddr) >= 0 ) { timeout = 100; From abd3054fb60818c2dbba5d57c7d120f254cf55c7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:10:40 +0300 Subject: [PATCH 1620/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 95c0d966d..070eb314d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -401,7 +401,11 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { timeout = 100; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); +#ifdef __APPLE__ + nanomsg_tcpname(bindaddr,"eth0",mypullport); +#else nanomsg_tcpname(bindaddr,myipaddr,mypullport); +#endif if ( nn_bind(pullsock,bindaddr) >= 0 ) { maxsize = 2 * 1024 * 1024; From bb6d25858eeacbd47e0fcfb539fe9218bd373839 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:19:20 +0300 Subject: [PATCH 1621/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_ordermatch.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 070eb314d..0a4c4b334 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -402,7 +402,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 100; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"eth0",mypullport); + nanomsg_tcpname(bindaddr,"*",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 2790df60c..b19679ae3 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -345,7 +345,11 @@ int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) { r = (10000 + (rand() % 50000)) & 0xffff; nanomsg_tcpname(pairstr,myipaddr,r); - nanomsg_tcpname(bindaddr,"0.0.0.0",r); +#ifdef __APPLE__ + nanomsg_tcpname(bindaddr,"*",r); +#else + nanomsg_tcpname(bindaddr,myipaddr,r); +#endif if ( nn_bind(pair,bindaddr) >= 0 ) { timeout = 100; From ddbd1e9dc1f37234d7fb78e45a8653e9111796ff Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:20:01 +0300 Subject: [PATCH 1622/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0a4c4b334..b33d8827b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -399,7 +399,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nanomsg_tcpname(pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { - timeout = 100; + timeout = 10000; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ nanomsg_tcpname(bindaddr,"*",mypullport); From 8cf858ab646126d9f7cc50921ae3bd81d45ee10d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:21:44 +0300 Subject: [PATCH 1623/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b33d8827b..b1dab346c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -399,7 +399,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nanomsg_tcpname(pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { - timeout = 10000; + timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ nanomsg_tcpname(bindaddr,"*",mypullport); diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index b2f820216..eb75a8e34 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -43,7 +43,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) //portable_mutex_lock(&LP_networkmutex); if ( nn_poll(&pfd,1,1) > 0 ) { - if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) + if ( (sentbytes= nn_send(sock,msg,len,NN_DONTWAIT)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) From 592c1b3a6611ea37b7ea4328a4c8ef640dd1f990 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:23:29 +0300 Subject: [PATCH 1624/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b1dab346c..e7b927ed6 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -353,7 +353,8 @@ void nn_tests(char *pushaddr) printf("connect error %s\n",nn_strerror(nn_errno())); else { - n = LP_send(sock,"nn_tests",0); + n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,NN_DONTWAIT); + // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes\n",n); } } From 1e557a607dd7677c7782be666c2b03f5521c4a10 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:24:31 +0300 Subject: [PATCH 1625/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e7b927ed6..7bfc15d83 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -353,7 +353,7 @@ void nn_tests(char *pushaddr) printf("connect error %s\n",nn_strerror(nn_errno())); else { - n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,NN_DONTWAIT); + n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes\n",n); } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index eb75a8e34..4a328a213 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -43,7 +43,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) //portable_mutex_lock(&LP_networkmutex); if ( nn_poll(&pfd,1,1) > 0 ) { - if ( (sentbytes= nn_send(sock,msg,len,NN_DONTWAIT)) != len ) + if ( (sentbytes= nn_send(sock,msg,len,0*NN_DONTWAIT)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) From 3680d4fb4b89e0f019fbc27c06ed02f3c0a850d9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:28:27 +0300 Subject: [PATCH 1626/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7bfc15d83..85fd808c9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -403,7 +403,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"*",mypullport); + nanomsg_tcpname(bindaddr,"en0",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From e1e3c1d38b2dbf4949009b9786ebaac86ad41d7f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:31:12 +0300 Subject: [PATCH 1627/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 85fd808c9..7bfc15d83 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -403,7 +403,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"en0",mypullport); + nanomsg_tcpname(bindaddr,"*",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From 8982a16594b15333e32d4f34450e04555d5be7ae Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:34:22 +0300 Subject: [PATCH 1628/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7bfc15d83..0390d6cc9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -344,17 +344,20 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in } } -void nn_tests(char *pushaddr) +void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n; + int32_t sock,n,timeout; if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); else { + timeout = 1000; + nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); - // n = LP_send(sock,"nn_tests",0); + LP_pullsock_check("127.0.0.1",-1,pullsock,0.); + // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes\n",n); } } @@ -411,9 +414,10 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + LP_pullsock_check(myipaddr,-1,pullsock,0.); } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); } - nn_tests(pushaddr); + nn_tests(pullsock,pushaddr); printf("my command address is (%s) pullsock.%d\n",pushaddr,pullsock); if ( IAMLP != 0 ) { From 37477da46ce40a549b8fa743bdb3aa6fe17acd8e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:35:05 +0300 Subject: [PATCH 1629/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0390d6cc9..4c81fc778 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout; - if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -401,7 +401,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); From 441ac65b71eac07b1f8a0780a4a1fcbf7495c9c4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:36:00 +0300 Subject: [PATCH 1630/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4c81fc778..d51900fa2 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout; - if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_PAIR)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -401,7 +401,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_PAIR)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); From 68e08938df89563bf78f85285fe899149e20a88d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:51:47 +0300 Subject: [PATCH 1631/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d51900fa2..fbf9cde25 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -346,14 +346,15 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout; + int32_t sock,n,timeout,sndprio = 1; if ( (sock= nn_socket(AF_SP,NN_PAIR)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); else { - timeout = 1000; + timeout = 100; + nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDPRIO,&sndprio,sizeof(sndprio)); nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); @@ -365,7 +366,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0; long filesize,n; int32_t maxsize,timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; + char *myipaddr=0; long filesize,n; int32_t rcvprio,maxsize,timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; IAMLP = !amclient; LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); @@ -404,7 +405,9 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit if ( (pullsock= nn_socket(AF_SP,NN_PAIR)) >= 0 ) { timeout = 1; + rcvprio = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVPRIO,&rcvprio,sizeof(rcvprio)); #ifdef __APPLE__ nanomsg_tcpname(bindaddr,"*",mypullport); #else From 045c6aa0145f45ac7999a68ce03d46bec23fef2b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 22:52:37 +0300 Subject: [PATCH 1632/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fbf9cde25..aa36463e0 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -353,10 +353,10 @@ void nn_tests(int32_t pullsock,char *pushaddr) printf("connect error %s\n",nn_strerror(nn_errno())); else { - timeout = 100; + timeout = 3000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDPRIO,&sndprio,sizeof(sndprio)); nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); + n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes\n",n); From a8b73d77b3b42740fbdeb6a61dd5cf3ef5553d56 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:00:09 +0300 Subject: [PATCH 1633/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index aa36463e0..dae7a1388 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -346,15 +346,15 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout,sndprio = 1; - if ( (sock= nn_socket(AF_SP,NN_PAIR)) >= 0 ) + int32_t sock,n,timeout;//,sndprio = 1; + if ( (sock= nn_socket(AF_SP,NN_REQ)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); else { - timeout = 3000; - nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDPRIO,&sndprio,sizeof(sndprio)); + timeout = 100; + //nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDPRIO,&sndprio,sizeof(sndprio)); nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); @@ -366,7 +366,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0; long filesize,n; int32_t rcvprio,maxsize,timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; + char *myipaddr=0; long filesize,n; int32_t maxsize,timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; IAMLP = !amclient; LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); @@ -402,12 +402,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_PAIR)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_REP)) >= 0 ) { timeout = 1; - rcvprio = 1; + //rcvprio = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVPRIO,&rcvprio,sizeof(rcvprio)); + //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVPRIO,&rcvprio,sizeof(rcvprio)); #ifdef __APPLE__ nanomsg_tcpname(bindaddr,"*",mypullport); #else From 4c5b6727e2f6363bdbb0d7f0c4d79e2537779473 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:02:12 +0300 Subject: [PATCH 1634/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index dae7a1388..b17303474 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -353,9 +353,11 @@ void nn_tests(int32_t pullsock,char *pushaddr) printf("connect error %s\n",nn_strerror(nn_errno())); else { - timeout = 100; + timeout = 1; //nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDPRIO,&sndprio,sizeof(sndprio)); nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + timeout = 1000; + nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); @@ -407,6 +409,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; //rcvprio = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + timeout = 100; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVPRIO,&rcvprio,sizeof(rcvprio)); #ifdef __APPLE__ nanomsg_tcpname(bindaddr,"*",mypullport); From 7ccded019b4e7d3915a2a210a005330b4999b4b5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:03:40 +0300 Subject: [PATCH 1635/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b17303474..9325751f1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -101,7 +101,7 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - if ( 0 && IAMLP == 0 ) + if ( 1 && IAMLP == 0 ) printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { @@ -139,7 +139,8 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) { nonz++; - LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); + //LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); + LP_process_message("PULL",myipaddr,pullsock,profitmargin,ptr,recvlen); } return(nonz); } From 53ef74e20eab41b577b308184c9aae2169246663 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:06:39 +0300 Subject: [PATCH 1636/2705] Test --- iguana/exchanges/LP_commands.c | 5 +++++ iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 92deb8e0f..2a22c49c6 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -52,6 +52,11 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs } if ( strcmp(method,"hello") == 0 ) return(0); + else if ( strcmp(method,"nn_tests") == 0 ) + { + LP_send(pubsock,"nn_test return",0); + return(0); + } else if ( strcmp(method,"help") == 0 ) return(clonestr("{\"result\":\" \ available localhost RPC commands:\n \ diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9325751f1..fad2d3d0d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -359,7 +359,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0); + n = nn_send(sock,"{\"method\":\"nn_tests\"}",(int32_t)strlen("{\"method\":\"nn_tests\"}")+1,0); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes\n",n); From e067601abf0cd784813b8a3f0ddaa551b8568692 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:07:25 +0300 Subject: [PATCH 1637/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fad2d3d0d..c289e0c2a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -360,7 +360,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"{\"method\":\"nn_tests\"}",(int32_t)strlen("{\"method\":\"nn_tests\"}")+1,0); - LP_pullsock_check("127.0.0.1",-1,pullsock,0.); + //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes\n",n); } From 7805faff0a535918bf74983ad6f645b6d24f5899 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:07:57 +0300 Subject: [PATCH 1638/2705] Test --- iguana/exchanges/LP_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2a22c49c6..a362f2c52 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -55,6 +55,7 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs else if ( strcmp(method,"nn_tests") == 0 ) { LP_send(pubsock,"nn_test return",0); + printf("send back nn_test return -> %d\n",pubsock); return(0); } else if ( strcmp(method,"help") == 0 ) From ca809e0b723b16a7ca32d577df055e0f0aa32d31 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:09:11 +0300 Subject: [PATCH 1639/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c289e0c2a..5754fe923 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -360,7 +360,8 @@ void nn_tests(int32_t pullsock,char *pushaddr) timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"{\"method\":\"nn_tests\"}",(int32_t)strlen("{\"method\":\"nn_tests\"}")+1,0); - //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); + usleep(100000); + LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes\n",n); } From d30c4280aa8480f71a4d3a2130d86a36fdc1c631 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:11:05 +0300 Subject: [PATCH 1640/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5754fe923..fc49af080 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout;//,sndprio = 1; + int32_t sock,n,m,timeout; void *ptr; if ( (sock= nn_socket(AF_SP,NN_REQ)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) @@ -362,8 +362,9 @@ void nn_tests(int32_t pullsock,char *pushaddr) n = nn_send(sock,"{\"method\":\"nn_tests\"}",(int32_t)strlen("{\"method\":\"nn_tests\"}")+1,0); usleep(100000); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); + m = nn_recv(sock,&ptr,NN_MSG,0); // n = LP_send(sock,"nn_tests",0); - printf("sent %d bytes\n",n); + printf("sent %d bytes, recv.%d\n",n,m); } } } From 684500ae40033890635c4295f556b90fcddab48e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:13:28 +0300 Subject: [PATCH 1641/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fc49af080..62d554657 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -416,7 +416,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVPRIO,&rcvprio,sizeof(rcvprio)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"*",mypullport); + nanomsg_tcpname(bindaddr,myipaddr,mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From 1340e0c49a37de5a83e1fcd324c7285d56ac0277 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:14:56 +0300 Subject: [PATCH 1642/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 62d554657..3ae88cee0 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -416,7 +416,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVPRIO,&rcvprio,sizeof(rcvprio)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,myipaddr,mypullport); + nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif @@ -424,7 +424,6 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - LP_pullsock_check(myipaddr,-1,pullsock,0.); } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); } nn_tests(pullsock,pushaddr); From 0f5d655ed6558b7bf10bb3190d88b05d5bba2cc8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:15:49 +0300 Subject: [PATCH 1643/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3ae88cee0..4d45bf88d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -348,7 +348,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,m,timeout; void *ptr; - if ( (sock= nn_socket(AF_SP,NN_REQ)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -407,7 +407,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_REP)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { timeout = 1; //rcvprio = 1; From 775e1bf9d04ceff18a1476c3d992e4aa08eda13c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:17:04 +0300 Subject: [PATCH 1644/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4d45bf88d..4c81fc778 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -101,7 +101,7 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - if ( 1 && IAMLP == 0 ) + if ( 0 && IAMLP == 0 ) printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { @@ -139,8 +139,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) { nonz++; - //LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); - LP_process_message("PULL",myipaddr,pullsock,profitmargin,ptr,recvlen); + LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); } return(nonz); } @@ -347,24 +346,19 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,m,timeout; void *ptr; + int32_t sock,n,timeout; if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); else { - timeout = 1; - //nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDPRIO,&sndprio,sizeof(sndprio)); - nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); timeout = 1000; - nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - n = nn_send(sock,"{\"method\":\"nn_tests\"}",(int32_t)strlen("{\"method\":\"nn_tests\"}")+1,0); - usleep(100000); + nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); - m = nn_recv(sock,&ptr,NN_MSG,0); // n = LP_send(sock,"nn_tests",0); - printf("sent %d bytes, recv.%d\n",n,m); + printf("sent %d bytes\n",n); } } } @@ -410,13 +404,9 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { timeout = 1; - //rcvprio = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - timeout = 100; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVPRIO,&rcvprio,sizeof(rcvprio)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); + nanomsg_tcpname(bindaddr,"*",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif @@ -424,6 +414,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + LP_pullsock_check(myipaddr,-1,pullsock,0.); } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); } nn_tests(pullsock,pushaddr); From 8de0aa157b3a63cd403dc6b40b4156a3f91c6f04 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:17:57 +0300 Subject: [PATCH 1645/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4c81fc778..f0b843317 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -414,7 +414,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - LP_pullsock_check(myipaddr,-1,pullsock,0.); + //LP_pullsock_check(myipaddr,-1,pullsock,0.); } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); } nn_tests(pullsock,pushaddr); From b02a6edfe005e52ab1cb1955c030b4917aefdd62 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:18:28 +0300 Subject: [PATCH 1646/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index f0b843317..785b44853 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -101,7 +101,7 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - if ( 0 && IAMLP == 0 ) + if ( 1 && IAMLP == 0 ) printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { From ae346f757e343ccd470870ea0c56ad7acbf19671 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:19:43 +0300 Subject: [PATCH 1647/2705] test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 785b44853..00939e67c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -136,7 +136,7 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { void *ptr; int32_t recvlen,nonz = 0; - while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) + while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); @@ -147,7 +147,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double profitmargin) { int32_t recvlen,nonz = 0; void *ptr; - while ( sock >= 0 && (recvlen= nn_recv(sock,&ptr,NN_MSG,NN_DONTWAIT)) >= 0 ) + while ( sock >= 0 && (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen); From e833e776a6047848ff8d31687b09dfb246d3df99 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:21:48 +0300 Subject: [PATCH 1648/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 00939e67c..bb796b70d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -346,7 +346,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout; + int32_t sock,n,timeout,m; void *ptr; if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) @@ -356,9 +356,10 @@ void nn_tests(int32_t pullsock,char *pushaddr) timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); - LP_pullsock_check("127.0.0.1",-1,pullsock,0.); + m = nn_recv(pullsock,&ptr,NN_MSG,0); + //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); - printf("sent %d bytes\n",n); + printf("sent %d bytes, recv.%d\n",n,m); } } } From 2a53928af950cbed21f5e21e66d533dac31e981e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:23:34 +0300 Subject: [PATCH 1649/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index bb796b70d..ccd754b46 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -407,7 +407,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"*",mypullport); + nanomsg_tcpname(bindaddr,myipaddr,mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From 6be44c24235041e8f69fc8bfb8f34503a5ae3f56 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:24:17 +0300 Subject: [PATCH 1650/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ccd754b46..234695aa1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -407,7 +407,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,myipaddr,mypullport); + nanomsg_tcpname(bindaddr,"127.0.0.1",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From 85db6f534acb0e3b0d95125a228781356aefe541 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:26:38 +0300 Subject: [PATCH 1651/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 234695aa1..3146929fa 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -355,7 +355,8 @@ void nn_tests(int32_t pullsock,char *pushaddr) { timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); + //n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); + n = LP_send(sock,"nn_tests",0);// m = nn_recv(pullsock,&ptr,NN_MSG,0); //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); @@ -404,7 +405,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nanomsg_tcpname(pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { - timeout = 1; + timeout = 100; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ nanomsg_tcpname(bindaddr,"127.0.0.1",mypullport); From 28b274e5789a7c8997622fac0052ce97146990c0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:29:17 +0300 Subject: [PATCH 1652/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3146929fa..e83338d2a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -405,7 +405,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nanomsg_tcpname(pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { - timeout = 100; + timeout = 1000; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ nanomsg_tcpname(bindaddr,"127.0.0.1",mypullport); From e3aacef829b4f8d250276ca6ead8744135d0e2f1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:29:59 +0300 Subject: [PATCH 1653/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a362f2c52..bdc6a5593 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -52,7 +52,7 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs } if ( strcmp(method,"hello") == 0 ) return(0); - else if ( strcmp(method,"nn_tests") == 0 ) + else if ( 0 && strcmp(method,"nn_tests") == 0 ) { LP_send(pubsock,"nn_test return",0); printf("send back nn_test return -> %d\n",pubsock); From 027b19da8b571362fc83bbc0dbfa75198f69697d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:30:48 +0300 Subject: [PATCH 1654/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e83338d2a..eb415b3bd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -346,7 +346,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout,m; void *ptr; + int32_t sock,n,timeout,m=0; //void *ptr; if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) @@ -357,7 +357,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); //n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); n = LP_send(sock,"nn_tests",0);// - m = nn_recv(pullsock,&ptr,NN_MSG,0); + //m = nn_recv(pullsock,&ptr,NN_MSG,0); //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes, recv.%d\n",n,m); @@ -405,7 +405,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nanomsg_tcpname(pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { - timeout = 1000; + timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ nanomsg_tcpname(bindaddr,"127.0.0.1",mypullport); From 275ea728cce20ee5738389a9083ce08abb18d3bf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:32:17 +0300 Subject: [PATCH 1655/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index eb415b3bd..3ff655556 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout,m=0; //void *ptr; - if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -403,12 +403,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"127.0.0.1",mypullport); + nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From 2f5cea7bfb080eebdde45245ea15ed9e95900fe3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:33:26 +0300 Subject: [PATCH 1656/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3ff655556..3e2916c1d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -355,8 +355,8 @@ void nn_tests(int32_t pullsock,char *pushaddr) { timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - //n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); - n = LP_send(sock,"nn_tests",0);// + n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); + //n = LP_send(sock,"nn_tests",0);// //m = nn_recv(pullsock,&ptr,NN_MSG,0); //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); @@ -408,7 +408,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); + nanomsg_tcpname(bindaddr,myipaddr,mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From f07d7fc23c12beb4ca1810ce43eab2003c805339 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:36:19 +0300 Subject: [PATCH 1657/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3e2916c1d..1743f2129 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -408,7 +408,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,myipaddr,mypullport); + nanomsg_tcpname(bindaddr,"*",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From d8a449d4bab32b7c1b4b9f709d75c9456c5991e5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:37:55 +0300 Subject: [PATCH 1658/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1743f2129..de03bf214 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -403,7 +403,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); From 9a4d381f3265aed32a489fbfcbe6ff1c61c7742b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:38:31 +0300 Subject: [PATCH 1659/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index de03bf214..9430616a7 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -403,12 +403,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"*",mypullport); + nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From 5437aebb60569d3da6ae511f91ee4f682ec7eee7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:39:21 +0300 Subject: [PATCH 1660/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9430616a7..a9923fc48 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout,m=0; //void *ptr; - if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_REQ)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -403,7 +403,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_REP)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); From f486972b4e98ec5ed63bcaf257fc5feb9918f30c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:41:37 +0300 Subject: [PATCH 1661/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a9923fc48..c7b8e5cf5 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,15 +347,17 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout,m=0; //void *ptr; - if ( (sock= nn_socket(AF_SP,NN_REQ)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_SUB)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); else { - timeout = 1000; - nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); + timeout = 1; + nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(sock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + n = nn_send(pullsock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); //n = LP_send(sock,"nn_tests",0);// //m = nn_recv(pullsock,&ptr,NN_MSG,0); //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); @@ -403,7 +405,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_REP)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); From 0fc8db34834d1e98f615322e886e2f10f20b3fcb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:42:23 +0300 Subject: [PATCH 1662/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c7b8e5cf5..603daf5a9 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -346,7 +346,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout,m=0; //void *ptr; + int32_t sock,n,timeout,m=0; void *ptr; if ( (sock= nn_socket(AF_SP,NN_SUB)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) @@ -359,7 +359,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); n = nn_send(pullsock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); //n = LP_send(sock,"nn_tests",0);// - //m = nn_recv(pullsock,&ptr,NN_MSG,0); + m = nn_recv(sock,&ptr,NN_MSG,0); //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes, recv.%d\n",n,m); From ae1e0cbf04baee9b88b3598e7760cb31a648e62d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:44:01 +0300 Subject: [PATCH 1663/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 603daf5a9..838c50d26 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -353,7 +353,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) printf("connect error %s\n",nn_strerror(nn_errno())); else { - timeout = 1; + timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(sock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); From 6e001b90bfc0ae1157c2ec19f3dc6eb132ea9c92 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 18 Jun 2017 23:45:47 +0300 Subject: [PATCH 1664/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 838c50d26..1743f2129 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -346,20 +346,18 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout,m=0; void *ptr; - if ( (sock= nn_socket(AF_SP,NN_SUB)) >= 0 ) + int32_t sock,n,timeout,m=0; //void *ptr; + if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); else { timeout = 1000; - nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(sock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - n = nn_send(pullsock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); + nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); //n = LP_send(sock,"nn_tests",0);// - m = nn_recv(sock,&ptr,NN_MSG,0); + //m = nn_recv(pullsock,&ptr,NN_MSG,0); //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); printf("sent %d bytes, recv.%d\n",n,m); @@ -405,12 +403,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"0.0.0.0",mypullport); + nanomsg_tcpname(bindaddr,"*",mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From caf44fb48d8f1f5eb2f42b203e6a1e5224c48fa6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 09:30:16 +0300 Subject: [PATCH 1665/2705] Test --- crypto777/nanosrc/aio/worker_posix.c | 2 +- crypto777/nanosrc/core/global.c | 46 ++++++++++++++-------------- crypto777/nanosrc/utils/efd_pipe.c | 4 +-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/crypto777/nanosrc/aio/worker_posix.c b/crypto777/nanosrc/aio/worker_posix.c index a2662d078..070a87a86 100755 --- a/crypto777/nanosrc/aio/worker_posix.c +++ b/crypto777/nanosrc/aio/worker_posix.c @@ -103,7 +103,7 @@ int nn_worker_init(struct nn_worker *self) { int32_t rc; PNACL_message("nn_worker_init %p\n",self); - sleep(1); + //sleep(1); rc = nn_efd_init(&self->efd); PNACL_message("efd init: rc.%d\n",rc); if ( rc < 0 ) diff --git a/crypto777/nanosrc/core/global.c b/crypto777/nanosrc/core/global.c index 51ab91709..e8f750f88 100755 --- a/crypto777/nanosrc/core/global.c +++ b/crypto777/nanosrc/core/global.c @@ -240,7 +240,7 @@ PNACL_message("list init\n"); // Initialise other parts of the global state. nn_list_init(&SELF.transports); nn_list_init(&SELF.socktypes); - sleep(1); + //sleep(1); PNACL_message("transports init\n"); // Plug in individual transports. //nn_global_add_transport(nn_ipc); @@ -248,36 +248,36 @@ PNACL_message("transports init\n"); //nn_global_add_transport(nn_inproc); //nn_global_add_transport(nn_ws); //nn_global_add_transport(nn_tcpmux); - sleep(1); + //sleep(1); PNACL_message("socktypes init\n"); // Plug in individual socktypes nn_global_add_socktype(nn_pair_socktype); - sleep(1); + //sleep(1); PNACL_message("nn_xpair_socktype init\n"); nn_global_add_socktype(nn_xpair_socktype); PNACL_message("did nn_xpair_socktype init\n"); - //nn_global_add_socktype(nn_rep_socktype); - //nn_global_add_socktype(nn_req_socktype); - //nn_global_add_socktype(nn_xrep_socktype); - //nn_global_add_socktype(nn_xreq_socktype); - //nn_global_add_socktype(nn_respondent_socktype); - //nn_global_add_socktype(nn_surveyor_socktype); - //nn_global_add_socktype(nn_xrespondent_socktype); - //nn_global_add_socktype(nn_xsurveyor_socktype); - //nn_global_add_socktype(nn_pub_socktype); - //nn_global_add_socktype(nn_sub_socktype); - //nn_global_add_socktype(nn_xpub_socktype); - //nn_global_add_socktype(nn_xsub_socktype); - //nn_global_add_socktype(nn_push_socktype); - //nn_global_add_socktype(nn_xpush_socktype); - //nn_global_add_socktype(nn_pull_socktype); - //nn_global_add_socktype(nn_xpull_socktype); - //nn_global_add_socktype(nn_bus_socktype); - //nn_global_add_socktype(nn_xbus_socktype); - sleep(1); + nn_global_add_socktype(nn_rep_socktype); + nn_global_add_socktype(nn_req_socktype); + nn_global_add_socktype(nn_xrep_socktype); + nn_global_add_socktype(nn_xreq_socktype); + nn_global_add_socktype(nn_respondent_socktype); + nn_global_add_socktype(nn_surveyor_socktype); + nn_global_add_socktype(nn_xrespondent_socktype); + nn_global_add_socktype(nn_xsurveyor_socktype); + nn_global_add_socktype(nn_pub_socktype); + nn_global_add_socktype(nn_sub_socktype); + nn_global_add_socktype(nn_xpub_socktype); + nn_global_add_socktype(nn_xsub_socktype); + nn_global_add_socktype(nn_push_socktype); + nn_global_add_socktype(nn_xpush_socktype); + nn_global_add_socktype(nn_pull_socktype); + nn_global_add_socktype(nn_xpull_socktype); + nn_global_add_socktype(nn_bus_socktype); + nn_global_add_socktype(nn_xbus_socktype); + //sleep(1); PNACL_message("do pool init\n"); nn_pool_init(&SELF.pool); // Start the worker threads - sleep(1); + //sleep(1); PNACL_message("do FSM init\n"); nn_fsm_init_root(&SELF.fsm,nn_global_handler,nn_global_shutdown,&SELF.ctx); // Start FSM SELF.state = NN_GLOBAL_STATE_IDLE; diff --git a/crypto777/nanosrc/utils/efd_pipe.c b/crypto777/nanosrc/utils/efd_pipe.c index ddce06119..4df5fd3b3 100755 --- a/crypto777/nanosrc/utils/efd_pipe.c +++ b/crypto777/nanosrc/utils/efd_pipe.c @@ -34,14 +34,14 @@ int nn_efd_init(struct nn_efd *self) { int rc,flags,p[2]; PNACL_message("inside efd_init: pipe\n"); - sleep(1); + //sleep(1); #if defined NN_HAVE_PIPE2 rc = pipe2(p, O_NONBLOCK | O_CLOEXEC); #else rc = pipe(p); #endif PNACL_message("rc efd_init: %d\n",rc); - sleep(1); + //sleep(1); if (rc != 0 && (errno == EMFILE || errno == ENFILE)) return -EMFILE; errno_assert (rc == 0); From a8dcf0c8006245de8ff4940354a7bcc9b2a1ab58 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 09:37:31 +0300 Subject: [PATCH 1666/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1743f2129..c8d1eda08 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -353,6 +353,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) printf("connect error %s\n",nn_strerror(nn_errno())); else { + sleep(3); timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); @@ -360,7 +361,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) //m = nn_recv(pullsock,&ptr,NN_MSG,0); //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); - printf("sent %d bytes, recv.%d\n",n,m); + printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes, recv.%d\n",n,m); } } } @@ -408,7 +409,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"*",mypullport); + nanomsg_tcpname(bindaddr,myipaddr,mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From f36e7b2a331678a52e4eedb97b679235dab82725 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 09:38:23 +0300 Subject: [PATCH 1667/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c8d1eda08..897e11547 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -353,7 +353,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) printf("connect error %s\n",nn_strerror(nn_errno())); else { - sleep(3); + sleep(2); timeout = 1000; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); From dbb0ee985a592fb049bf183f294242bcd53003a6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 09:41:31 +0300 Subject: [PATCH 1668/2705] Test --- crypto777/nanosrc/nn_config.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 4 ++-- includes/iguana_defines.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crypto777/nanosrc/nn_config.h b/crypto777/nanosrc/nn_config.h index d9e9c6468..bb34eaf01 100755 --- a/crypto777/nanosrc/nn_config.h +++ b/crypto777/nanosrc/nn_config.h @@ -56,7 +56,7 @@ void PNACL_message(const char* format, ...); #else #if !defined(WIN32) //#define NN_ENABLE_EXTRA 1 -#define PNACL_message printf +#define PNACL_message //printf #include #include #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 897e11547..48e901726 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout,m=0; //void *ptr; - if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -404,7 +404,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); diff --git a/includes/iguana_defines.h b/includes/iguana_defines.h index ba7e106cb..0133fb0d3 100755 --- a/includes/iguana_defines.h +++ b/includes/iguana_defines.h @@ -108,7 +108,7 @@ extern int32_t IGUANA_NUMHELPERS; #define MS_ASYNC 1 /* Sync memory asynchronously. */ #define MS_SYNC 4 /* Synchronous memory sync. */ #else -#define PNACL_message printf +#define PNACL_message //printf #endif #ifndef WIN32 From d4f15d6744fef68f4a02a0524e5c5b3c65e93320 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 09:41:52 +0300 Subject: [PATCH 1669/2705] Test --- crypto777/nanosrc/nn_config.h | 2 +- includes/iguana_defines.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto777/nanosrc/nn_config.h b/crypto777/nanosrc/nn_config.h index bb34eaf01..d9e9c6468 100755 --- a/crypto777/nanosrc/nn_config.h +++ b/crypto777/nanosrc/nn_config.h @@ -56,7 +56,7 @@ void PNACL_message(const char* format, ...); #else #if !defined(WIN32) //#define NN_ENABLE_EXTRA 1 -#define PNACL_message //printf +#define PNACL_message printf #include #include #endif diff --git a/includes/iguana_defines.h b/includes/iguana_defines.h index 0133fb0d3..ba7e106cb 100755 --- a/includes/iguana_defines.h +++ b/includes/iguana_defines.h @@ -108,7 +108,7 @@ extern int32_t IGUANA_NUMHELPERS; #define MS_ASYNC 1 /* Sync memory asynchronously. */ #define MS_SYNC 4 /* Synchronous memory sync. */ #else -#define PNACL_message //printf +#define PNACL_message printf #endif #ifndef WIN32 From aafffa2cbc088fe5e5df9146075798ddb02e3946 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 10:57:26 +0300 Subject: [PATCH 1670/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 48e901726..fc5c9d976 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout,m=0; //void *ptr; - if ( (sock= nn_socket(AF_SP,NN_BUS)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -404,12 +404,13 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_tcpname(pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_BUS)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - nanomsg_tcpname(bindaddr,myipaddr,mypullport); + sprintf(bindaddr,"ws://%s:%u",myipaddr,mypullport); + //nanomsg_tcpname(bindaddr,myipaddr,mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); #endif From 67a17d20975d3737ab480a67218ef029186cbacf Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:02:56 +0300 Subject: [PATCH 1671/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fc5c9d976..5dc541d77 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -409,7 +409,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - sprintf(bindaddr,"ws://%s:%u",myipaddr,mypullport); + sprintf(bindaddr,"ws://[*]:%u",mypullport); //nanomsg_tcpname(bindaddr,myipaddr,mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); From c2b3980ee168174231e25dca3e499cb9c5d81d7d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:03:50 +0300 Subject: [PATCH 1672/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5dc541d77..eda8b02f3 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -409,7 +409,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - sprintf(bindaddr,"ws://[*]:%u",mypullport); + sprintf(bindaddr,"tcp://*:%u",mypullport); //nanomsg_tcpname(bindaddr,myipaddr,mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); @@ -419,7 +419,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); //LP_pullsock_check(myipaddr,-1,pullsock,0.); - } else printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); + } + else + { + printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); + exit(-1); + } } nn_tests(pullsock,pushaddr); printf("my command address is (%s) pullsock.%d\n",pushaddr,pullsock); From f0f4918cd5dc03be67ff22d6dcd571c0e9c5c890 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:05:15 +0300 Subject: [PATCH 1673/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index eda8b02f3..a0a0d860f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -409,7 +409,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); #ifdef __APPLE__ - sprintf(bindaddr,"tcp://*:%u",mypullport); + sprintf(bindaddr,"ws://*:%u",mypullport); //nanomsg_tcpname(bindaddr,myipaddr,mypullport); #else nanomsg_tcpname(bindaddr,myipaddr,mypullport); From 4c816fd1e4b76908aaca6b38bd85eb503f3f9c22 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:08:46 +0300 Subject: [PATCH 1674/2705] Test --- iguana/exchanges/LP_forwarding.c | 4 +--- iguana/exchanges/LP_nativeDEX.c | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 7e537d3f0..899addd23 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -108,9 +108,7 @@ char *LP_register(bits256 pubkey,char *ipaddr) struct LP_forwardinfo *ptr=0; int32_t pushsock; char pushaddr[64]; if ( ipaddr == 0 || ipaddr[0] == 0 || is_ipaddr(ipaddr) == 0 || bits256_nonz(pubkey) == 0 ) return(clonestr("{\"error\":\"illegal ipaddr or null pubkey\"}")); - //if ( strlen(pushaddr) <= strlen("tcp://") || is_ipaddr(pushaddr+strlen("tcp://")) == 0 ) - // return(clonestr("{\"error\":\"illegal ipaddr\"}")); - sprintf(pushaddr,"tcp://%s",ipaddr); + sprintf(pushaddr,"ws://%s:%u",ipaddr,7780); char str[65]; printf("register.(%s) %s\n",pushaddr,bits256_str(str,pubkey)); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a0a0d860f..4019b1d28 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -403,7 +403,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit myipaddr[--n] = 0; } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); - nanomsg_tcpname(pushaddr,myipaddr,mypullport); + sprintf(pushaddr,"ws://%s:%u",myipaddr,mypullport); + //nanomsg_tcpname(pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { timeout = 1; From 92188ecaf5532fbc772d8d0b5034b6211ef85211 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:09:53 +0300 Subject: [PATCH 1675/2705] Test --- iguana/exchanges/LP_forwarding.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 899addd23..63e5fb4b8 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -103,12 +103,12 @@ int32_t LP_pushsock_create(struct LP_forwardinfo *ptr,char *pushaddr) return(pushsock); } -char *LP_register(bits256 pubkey,char *ipaddr) +char *LP_register(bits256 pubkey,char *ip_port) { struct LP_forwardinfo *ptr=0; int32_t pushsock; char pushaddr[64]; - if ( ipaddr == 0 || ipaddr[0] == 0 || is_ipaddr(ipaddr) == 0 || bits256_nonz(pubkey) == 0 ) - return(clonestr("{\"error\":\"illegal ipaddr or null pubkey\"}")); - sprintf(pushaddr,"ws://%s:%u",ipaddr,7780); + if ( ip_port == 0 || ip_port[0] == 0 || is_ipaddr(ip_port) == 0 || bits256_nonz(pubkey) == 0 ) + return(clonestr("{\"error\":\"illegal ip_port or null pubkey\"}")); + sprintf(pushaddr,"ws://%s",ip_port); char str[65]; printf("register.(%s) %s\n",pushaddr,bits256_str(str,pubkey)); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { From 39b7b043b23d9eaff04e460e5f1bb45a3a52ba3e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:14:05 +0300 Subject: [PATCH 1676/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 14 ++++---------- iguana/exchanges/LP_network.c | 4 ++-- iguana/exchanges/LP_ordermatch.c | 8 ++------ iguana/exchanges/LP_peers.c | 4 ++-- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4019b1d28..fac19be10 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -403,18 +403,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit myipaddr[--n] = 0; } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); - sprintf(pushaddr,"ws://%s:%u",myipaddr,mypullport); - //nanomsg_tcpname(pushaddr,myipaddr,mypullport); + nanomsg_transportname(0,pushaddr,myipaddr,mypullport); if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); -#ifdef __APPLE__ - sprintf(bindaddr,"ws://*:%u",mypullport); - //nanomsg_tcpname(bindaddr,myipaddr,mypullport); -#else - nanomsg_tcpname(bindaddr,myipaddr,mypullport); -#endif + nanomsg_transportname(1,bindaddr,myipaddr,mypullport); if ( nn_bind(pullsock,bindaddr) >= 0 ) { maxsize = 2 * 1024 * 1024; @@ -434,8 +428,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit if ( myipaddr != 0 ) { pubsock = -1; - nanomsg_tcpname(subaddr,myipaddr,mypubport); - nanomsg_tcpname(bindaddr,myipaddr,mypubport); + nanomsg_transportname(0,subaddr,myipaddr,mypubport); + nanomsg_transportname(1,bindaddr,myipaddr,mypubport); if ( (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) { if ( nn_bind(pubsock,bindaddr) >= 0 ) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 4a328a213..da995ef5f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -19,9 +19,9 @@ // // jl777: might need to queue outbound packets and send via separate thread -char *nanomsg_tcpname(char *str,char *ipaddr,uint16_t port) +char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { - sprintf(str,"tcp://%s:%u",ipaddr,port); + sprintf(str,"ws://%s:%u",bindflag == 0 ? ipaddr : "*",port); return(str); } diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index b19679ae3..f9562a7b7 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -344,12 +344,8 @@ int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) for (i=0; i<10; i++) { r = (10000 + (rand() % 50000)) & 0xffff; - nanomsg_tcpname(pairstr,myipaddr,r); -#ifdef __APPLE__ - nanomsg_tcpname(bindaddr,"*",r); -#else - nanomsg_tcpname(bindaddr,myipaddr,r); -#endif + nanomsg_transportname(0,pairstr,myipaddr,r); + nanomsg_transportname(1,bindaddr,myipaddr,r); if ( nn_bind(pair,bindaddr) >= 0 ) { timeout = 100; diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 89fac7909..7207e53a7 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -72,7 +72,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char strcpy(peer->ipaddr,ipaddr); if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) { - nanomsg_tcpname(pushaddr,peer->ipaddr,pushport); + nanomsg_transportname(0,pushaddr,peer->ipaddr,pushport); if ( nn_connect(pushsock,pushaddr) >= 0 ) { timeout = 100; @@ -87,7 +87,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char timeout = 1; nn_setsockopt(subsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(subsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - nanomsg_tcpname(subaddr,peer->ipaddr,subport); + nanomsg_transportname(0,subaddr,peer->ipaddr,subport); if ( nn_connect(subsock,subaddr) >= 0 ) { peer->subsock = subsock; From 8bb7d8e54922c677ce47726d70f268fd1665e5fd Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:20:26 +0300 Subject: [PATCH 1677/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index fac19be10..4d21177f4 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout,m=0; //void *ptr; - if ( (sock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) + if ( (sock= nn_socket(AF_SP,NN_REQ)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -404,7 +404,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_transportname(0,pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_PULL)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,NN_REP)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); From fc488f6b866fb92e61b9b1d3935d5889aa4f1aaf Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:22:15 +0300 Subject: [PATCH 1678/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4d21177f4..5742b3a65 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -354,12 +354,14 @@ void nn_tests(int32_t pullsock,char *pushaddr) else { sleep(2); - timeout = 1000; + timeout = 1; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); - //n = LP_send(sock,"nn_tests",0);// + nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + //n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); + n = LP_send(sock,"nn_tests",0);// //m = nn_recv(pullsock,&ptr,NN_MSG,0); - //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); + sleep(1); + LP_pullsock_check("127.0.0.1",-1,pullsock,0.); // n = LP_send(sock,"nn_tests",0); printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes, recv.%d\n",n,m); } @@ -408,6 +410,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nanomsg_transportname(1,bindaddr,myipaddr,mypullport); if ( nn_bind(pullsock,bindaddr) >= 0 ) { From 8dfc5a7dbc1e5d0b178e0923d01a554c0db1388d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:23:10 +0300 Subject: [PATCH 1679/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index da995ef5f..4f893fef1 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -21,7 +21,7 @@ char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { - sprintf(str,"ws://%s:%u",bindflag == 0 ? ipaddr : "*",port); + sprintf(str,"tcp://%s:%u",bindflag == 0 ? ipaddr : "*",port); return(str); } From b5fa84dc0b954200cc2b4e93a791a1125c70ccac Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:25:10 +0300 Subject: [PATCH 1680/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 821acca4c..d2c4b994c 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -119,7 +119,7 @@ void LP_statefname(char *fname,char *symbol,char *assetname,char *str) strcat(fname,"/"); #endif strcat(fname,str); - printf("LP_statefname.(%s) <- %s %s %s\n",fname,symbol,assetname,str); + //printf("LP_statefname.(%s) <- %s %s %s\n",fname,symbol,assetname,str); } int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) From 4e4028b6433b21df5167c7be187805f707f5d0ac Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:31:54 +0300 Subject: [PATCH 1681/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_forwarding.c | 13 +++++++------ iguana/exchanges/LP_nativeDEX.c | 10 +++++----- iguana/exchanges/LP_rpc.c | 6 ++---- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bdc6a5593..38d2fc3d2 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -225,7 +225,7 @@ forwardhex(pubkey,hex)\n\ { if ( strcmp(method,"register") == 0 ) { - retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr")); + retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr"),juint(argjson,"pushport")); //printf("got (%s) from register\n",retstr!=0?retstr:""); return(retstr); } diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 63e5fb4b8..36edbf176 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -98,17 +98,18 @@ int32_t LP_pushsock_create(struct LP_forwardinfo *ptr,char *pushaddr) } timeout = 1; nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); if ( ptr != 0 ) LP_hello(ptr); return(pushsock); } -char *LP_register(bits256 pubkey,char *ip_port) +char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) { struct LP_forwardinfo *ptr=0; int32_t pushsock; char pushaddr[64]; - if ( ip_port == 0 || ip_port[0] == 0 || is_ipaddr(ip_port) == 0 || bits256_nonz(pubkey) == 0 ) - return(clonestr("{\"error\":\"illegal ip_port or null pubkey\"}")); - sprintf(pushaddr,"ws://%s",ip_port); + if ( ipaddr == 0 || ipaddr[0] == 0 || is_ipaddr(ipaddr) == 0 || bits256_nonz(pubkey) == 0 ) + return(clonestr("{\"error\":\"illegal ipaddr or null pubkey\"}")); + nanomsg_transportname(0,pushaddr,ipaddr,port); char str[65]; printf("register.(%s) %s\n",pushaddr,bits256_str(str,pubkey)); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) { @@ -140,7 +141,7 @@ char *LP_register(bits256 pubkey,char *ip_port) } } -void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) +void LP_forwarding_register(bits256 pubkey,char *pushaddr,uint16_t pushport,int32_t max) { char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) @@ -151,7 +152,7 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,int32_t max) HASH_ITER(hh,LP_peerinfos,peer,tmp) { //printf("register with (%s)\n",peer->ipaddr); - if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr)) != 0 ) + if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr,pushport)) != 0 ) { //printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5742b3a65..5ed772c85 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -213,7 +213,7 @@ int32_t LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pu return(n); } -int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) +int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,uint16_t pushport,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) { static uint32_t counter,lastforward,numpeers; struct LP_utxoinfo *utxo,*utmp; char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0,n=0,lastn=-1; @@ -253,7 +253,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_myutxo_updates(pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) { - LP_forwarding_register(LP_mypubkey,pushaddr,10); + LP_forwarding_register(LP_mypubkey,myipaddr,pushport,10); lastforward = now; } } @@ -285,7 +285,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso return(nonz); } -void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) +void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,uint16_t pushport,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) { uint8_t r; int32_t i,n,j; cJSON *item; if ( IAMLP != 0 ) @@ -339,7 +339,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in { if ( 0 && (rand() % 100) == 0 ) printf("mainloop\n"); - if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,pullsock,myport,passphrase,profitmargin) == 0 ) + if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,pushport,pullsock,myport,passphrase,profitmargin) == 0 ) usleep(100000); } } @@ -462,7 +462,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit printf("couldnt get myipaddr\n"); exit(-1); } -LP_mainloop(myipaddr,mypeer,mypubport,pubsock,pushaddr,pullsock,myport,passphrase,profitmargin,jobj(argjson,"coins"),jstr(argjson,"seednode")); +LP_mainloop(myipaddr,mypeer,mypubport,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin,jobj(argjson,"coins"),jstr(argjson,"seednode")); } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index c624cd7ac..89e52a64b 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -106,12 +106,10 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx } } -char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *pushaddr) +char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *ipaddr,uint16_t pushport) { char url[512],str[65],*retstr; - if ( strncmp("tcp://",pushaddr,strlen("tcp://")) != 0 || strlen(pushaddr) <= strlen("tcp://") ) - return(clonestr("{\"error\":\"illegal pushaddr\"}")); - sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s",destip,destport,bits256_str(str,pubkey),pushaddr+strlen("tcp://")); + sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s&pushport=%u",destip,destport,bits256_str(str,pubkey),ipaddr,pushport); retstr = issue_curlt(url,LP_HTTP_TIMEOUT); //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); return(retstr); From c7ae7076594529d130942fbae7632f5923f3f244 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:35:42 +0300 Subject: [PATCH 1682/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 5ed772c85..9c301c0ae 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -218,7 +218,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso static uint32_t counter,lastforward,numpeers; struct LP_utxoinfo *utxo,*utmp; char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0,n=0,lastn=-1; now = (uint32_t)time(NULL); - if ( mypeer == 0 ) + if ( myipaddr == 0 ) myipaddr = "127.0.0.1"; numpeers = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) From 7cac6d532cca9cf8dcaa5bf57634c71fa36c1637 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:36:42 +0300 Subject: [PATCH 1683/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9c301c0ae..10bfe93e1 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -216,9 +216,11 @@ int32_t LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pu int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,uint16_t pushport,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) { static uint32_t counter,lastforward,numpeers; - struct LP_utxoinfo *utxo,*utmp; char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0,n=0,lastn=-1; + struct LP_utxoinfo *utxo,*utmp; char *retstr,*origipaddr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0,n=0,lastn=-1; now = (uint32_t)time(NULL); - if ( myipaddr == 0 ) + if ( (origipaddr= myipaddr) == 0 ) + origipaddr = "127.0.0.1"; + if ( mypeer == 0 ) myipaddr = "127.0.0.1"; numpeers = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) @@ -253,7 +255,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_myutxo_updates(pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) { - LP_forwarding_register(LP_mypubkey,myipaddr,pushport,10); + LP_forwarding_register(LP_mypubkey,origipaddr,pushport,10); lastforward = now; } } From 491c51105c5439e802b150db795f97f6c229ddad Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:37:55 +0300 Subject: [PATCH 1684/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 10bfe93e1..31b684c8e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -348,7 +348,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout,m=0; //void *ptr; + int32_t sock,n,timeout,m=0; char msg[512];//void *ptr; if ( (sock= nn_socket(AF_SP,NN_REQ)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) @@ -360,7 +360,8 @@ void nn_tests(int32_t pullsock,char *pushaddr) nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); //n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); - n = LP_send(sock,"nn_tests",0);// + sprintf(msg,"{\"nn_tests\":\"%s\"}",pushaddr); + n = LP_send(sock,msg,0);// //m = nn_recv(pullsock,&ptr,NN_MSG,0); sleep(1); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); From f6e15c7d144ca8b60990ad10b4e3a083a48c3700 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:41:27 +0300 Subject: [PATCH 1685/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_include.h | 3 +++ iguana/exchanges/LP_nativeDEX.c | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 36edbf176..74a00a427 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -85,7 +85,7 @@ int32_t LP_hellos() int32_t LP_pushsock_create(struct LP_forwardinfo *ptr,char *pushaddr) { int32_t pushsock,timeout; - if ( (pushsock= nn_socket(AF_SP,NN_PUSH)) < 0 ) + if ( (pushsock= nn_socket(AF_SP,LP_COMMAND_SENDSOCK)) < 0 ) { printf("LP_pushsock_create couldnt allocate socket for %s\n",pushaddr); return(-1); diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index da587d194..9fd54eb64 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -21,6 +21,9 @@ #ifndef LP_INCLUDE_H #define LP_INCLUDE_H +#define LP_COMMAND_SENDSOCK NN_REQ +#define LP_COMMAND_RECVSOCK NN_REP + #define LP_HTTP_TIMEOUT 1 #define LP_MAXPEER_ERRORS 3 #define LP_SWAPSTEP_TIMEOUT 3 diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 31b684c8e..bedd2e18d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -349,7 +349,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { int32_t sock,n,timeout,m=0; char msg[512];//void *ptr; - if ( (sock= nn_socket(AF_SP,NN_REQ)) >= 0 ) + if ( (sock= nn_socket(AF_SP,LP_COMMAND_SENDSOCK)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) printf("connect error %s\n",nn_strerror(nn_errno())); @@ -409,7 +409,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); nanomsg_transportname(0,pushaddr,myipaddr,mypullport); - if ( (pullsock= nn_socket(AF_SP,NN_REP)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,LP_COMMAND_RECVSOCK)) >= 0 ) { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); From 7eaf2dd85d6f78c5bdea8210153da1e60f9c96c0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:42:46 +0300 Subject: [PATCH 1686/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 74a00a427..ab03abc87 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -65,7 +65,7 @@ int32_t LP_hello(struct LP_forwardinfo *ptr) return(i); } } - //printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); + printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); return(-1); } return(0); From bc43cad51d0db5f930ef950843af7d5f88a4ae57 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:49:53 +0300 Subject: [PATCH 1687/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index bedd2e18d..76d022378 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -414,6 +414,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_MAXTTL,&timeout,sizeof(timeout)); nanomsg_transportname(1,bindaddr,myipaddr,mypullport); if ( nn_bind(pullsock,bindaddr) >= 0 ) { From 0164604e29cd6df7332e7468420aa20a3633c541 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:51:23 +0300 Subject: [PATCH 1688/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 76d022378..6ed6f9f85 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -348,7 +348,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout,m=0; char msg[512];//void *ptr; + int32_t sock,n,timeout,m=0; char msg[512]; void *ptr; if ( (sock= nn_socket(AF_SP,LP_COMMAND_SENDSOCK)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) @@ -362,10 +362,9 @@ void nn_tests(int32_t pullsock,char *pushaddr) //n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); sprintf(msg,"{\"nn_tests\":\"%s\"}",pushaddr); n = LP_send(sock,msg,0);// - //m = nn_recv(pullsock,&ptr,NN_MSG,0); sleep(1); - LP_pullsock_check("127.0.0.1",-1,pullsock,0.); - // n = LP_send(sock,"nn_tests",0); + m = nn_recv(pullsock,&ptr,NN_MSG,0); + //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes, recv.%d\n",n,m); } } From 7e6b0891fc1e3942949e5c3dd093dc641ae8d3f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:56:07 +0300 Subject: [PATCH 1689/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 6ed6f9f85..372e75fe7 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -91,7 +91,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * return(retstr); } -void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen) +void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen,int32_t recvsock) { int32_t len,datalen=0; char *retstr,*jsonstr=0; cJSON *argjson,*reqjson; if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) @@ -111,7 +111,7 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof { //printf("got forwardhex\n"); if ( (retstr= LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) - free(retstr); + free(retstr), retstr = 0; } else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) { @@ -123,8 +123,18 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof LP_send(pubsock,jprint(reqjson,1),1); } else if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvlen - len,profitmargin)) != 0 ) - free(retstr); + { + } portable_mutex_unlock(&LP_commandmutex); + if ( retstr != 0 ) + { + if ( strcmp("PULL",typestr) == 0 && LP_COMMAND_RECVSOCK == NN_REP ) + { + printf("got REQ.(%s) -> (%s)\n",jprint(argjson,0),retstr); + LP_send(recvsock,retstr,0); + } + free(retstr); + } free_json(argjson); } else printf("error parsing(%s)\n",jsonstr); if ( (void *)jsonstr != ptr ) @@ -139,7 +149,7 @@ int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen); + LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); } return(nonz); } @@ -150,7 +160,7 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof while ( sock >= 0 && (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen); + LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock); /*if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); From 4c45b3774979e1bf5cba3439a45d8c0fc0fbf5b5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:56:55 +0300 Subject: [PATCH 1690/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 372e75fe7..3ee58231d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -358,7 +358,7 @@ void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,in void nn_tests(int32_t pullsock,char *pushaddr) { - int32_t sock,n,timeout,m=0; char msg[512]; void *ptr; + int32_t sock,n,timeout,m=0; char msg[512]; //void *ptr; if ( (sock= nn_socket(AF_SP,LP_COMMAND_SENDSOCK)) >= 0 ) { if ( nn_connect(sock,pushaddr) < 0 ) @@ -373,8 +373,8 @@ void nn_tests(int32_t pullsock,char *pushaddr) sprintf(msg,"{\"nn_tests\":\"%s\"}",pushaddr); n = LP_send(sock,msg,0);// sleep(1); - m = nn_recv(pullsock,&ptr,NN_MSG,0); - //LP_pullsock_check("127.0.0.1",-1,pullsock,0.); + //m = nn_recv(pullsock,&ptr,NN_MSG,0); + LP_pullsock_check("127.0.0.1",-1,pullsock,0.); printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes, recv.%d\n",n,m); } } From 1298841a128efcc9dc49018ccc22e64d91b4c37a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 11:58:29 +0300 Subject: [PATCH 1691/2705] Test --- iguana/exchanges/LP_commands.c | 4 ++-- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 38d2fc3d2..c4cbf97dd 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -52,11 +52,11 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs } if ( strcmp(method,"hello") == 0 ) return(0); - else if ( 0 && strcmp(method,"nn_tests") == 0 ) + else if ( strcmp(method,"nn_tests") == 0 ) { LP_send(pubsock,"nn_test return",0); printf("send back nn_test return -> %d\n",pubsock); - return(0); + return(clonestr("{\"result\":\"success\"}")); } else if ( strcmp(method,"help") == 0 ) return(clonestr("{\"result\":\" \ diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 3ee58231d..7f3ff41ad 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -370,7 +370,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); //n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); - sprintf(msg,"{\"nn_tests\":\"%s\"}",pushaddr); + sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); n = LP_send(sock,msg,0);// sleep(1); //m = nn_recv(pullsock,&ptr,NN_MSG,0); From f4d11eff0eac419d545dac7b961f714f70edb702 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:02:17 +0300 Subject: [PATCH 1692/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7f3ff41ad..a58bc493f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -93,7 +93,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen,int32_t recvsock) { - int32_t len,datalen=0; char *retstr,*jsonstr=0; cJSON *argjson,*reqjson; + int32_t len,datalen=0; char *retstr=0,*jsonstr=0; cJSON *argjson,*reqjson; if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) { datalen >>= 1; @@ -126,14 +126,22 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof { } portable_mutex_unlock(&LP_commandmutex); - if ( retstr != 0 ) + if ( LP_COMMAND_RECVSOCK == NN_REP ) { - if ( strcmp("PULL",typestr) == 0 && LP_COMMAND_RECVSOCK == NN_REP ) + if ( retstr != 0 ) { - printf("got REQ.(%s) -> (%s)\n",jprint(argjson,0),retstr); - LP_send(recvsock,retstr,0); + if ( strcmp("PULL",typestr) == 0 ) + { + printf("%d got REQ.(%s) -> (%s)\n",recvsock,jprint(argjson,0),retstr); + LP_send(recvsock,retstr,0); + } + free(retstr); + } + if ( strcmp("PULL",typestr) == 0 ) + { + printf("%d got REQ.(%s) -> null\n",recvsock,jprint(argjson,0)); + LP_send(recvsock,"{\"result\":null}",0); } - free(retstr); } free_json(argjson); } else printf("error parsing(%s)\n",jsonstr); @@ -375,7 +383,7 @@ void nn_tests(int32_t pullsock,char *pushaddr) sleep(1); //m = nn_recv(pullsock,&ptr,NN_MSG,0); LP_pullsock_check("127.0.0.1",-1,pullsock,0.); - printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes, recv.%d\n",n,m); + printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes -> %d, recv.%d\n",n,pullsock,m); } } } From aa7ddba14319834a4d2069cfd0389db6f3e1e32d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:04:24 +0300 Subject: [PATCH 1693/2705] Test --- iguana/exchanges/LP_commands.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index c4cbf97dd..7a957a052 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -53,11 +53,7 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs if ( strcmp(method,"hello") == 0 ) return(0); else if ( strcmp(method,"nn_tests") == 0 ) - { - LP_send(pubsock,"nn_test return",0); - printf("send back nn_test return -> %d\n",pubsock); return(clonestr("{\"result\":\"success\"}")); - } else if ( strcmp(method,"help") == 0 ) return(clonestr("{\"result\":\" \ available localhost RPC commands:\n \ From 3f335fa34d5bcac2d61ec9234a6aab84d49c8072 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:06:05 +0300 Subject: [PATCH 1694/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a58bc493f..456253d33 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -137,7 +137,7 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof } free(retstr); } - if ( strcmp("PULL",typestr) == 0 ) + else if ( strcmp("PULL",typestr) == 0 ) { printf("%d got REQ.(%s) -> null\n",recvsock,jprint(argjson,0)); LP_send(recvsock,"{\"result\":null}",0); From b2aa023163d1032dc4a85f48a168ddfef5e49589 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:07:50 +0300 Subject: [PATCH 1695/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 4f893fef1..da995ef5f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -21,7 +21,7 @@ char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { - sprintf(str,"tcp://%s:%u",bindflag == 0 ? ipaddr : "*",port); + sprintf(str,"ws://%s:%u",bindflag == 0 ? ipaddr : "*",port); return(str); } From 1c2840ead6e8c93d466cc16c0261c0bafb26b5b1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:15:58 +0300 Subject: [PATCH 1696/2705] Test --- iguana/exchanges/LP_include.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 9fd54eb64..87c53db39 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -21,8 +21,8 @@ #ifndef LP_INCLUDE_H #define LP_INCLUDE_H -#define LP_COMMAND_SENDSOCK NN_REQ -#define LP_COMMAND_RECVSOCK NN_REP +#define LP_COMMAND_SENDSOCK NN_BUS +#define LP_COMMAND_RECVSOCK NN_BUS #define LP_HTTP_TIMEOUT 1 #define LP_MAXPEER_ERRORS 3 From 79073e3c62d0e935ad8dfa0be32539a0c015242d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:17:51 +0300 Subject: [PATCH 1697/2705] Test --- iguana/exchanges/LP_commands.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 7a957a052..bd0b5a21f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -51,7 +51,10 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs return(0); } if ( strcmp(method,"hello") == 0 ) + { + printf("got hello from %s:%u\n",ipaddr!=0?ipaddr:"",argport); return(0); + } else if ( strcmp(method,"nn_tests") == 0 ) return(clonestr("{\"result\":\"success\"}")); else if ( strcmp(method,"help") == 0 ) From 57431ba7c7d7a4427dfe0f0b2c6276fe90f5cb4e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:20:58 +0300 Subject: [PATCH 1698/2705] Test --- iguana/exchanges/LP_include.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 87c53db39..400feb53c 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -21,8 +21,8 @@ #ifndef LP_INCLUDE_H #define LP_INCLUDE_H -#define LP_COMMAND_SENDSOCK NN_BUS -#define LP_COMMAND_RECVSOCK NN_BUS +#define LP_COMMAND_SENDSOCK NN_PUSH +#define LP_COMMAND_RECVSOCK NN_PULL #define LP_HTTP_TIMEOUT 1 #define LP_MAXPEER_ERRORS 3 From e886038d5b53c79e6df3f4aacbfebb04715671bc Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:30:00 +0300 Subject: [PATCH 1699/2705] Test --- iguana/exchanges/LP_swap.c | 2 +- iguana/exchanges/LP_transaction.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index b3fd8fc71..b45181822 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -642,7 +642,7 @@ int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t } if ( retjson != 0 ) { - printf("SWAP completed! %u-%u %s\n",requestid,quoteid,jprint(retjson,0)); + printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>\nSWAP completed! %u-%u %s\n",requestid,quoteid,jprint(retjson,0)); free_json(retjson); if ( (retstr= basilisk_swapentry(requestid,quoteid)) != 0 ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index f3038a967..67d5b7fca 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1494,6 +1494,7 @@ void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,s int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { char coinaddr[64]; int32_t i,retval = -1; + printf("alicetx\n"); if ( swap->alicepayment.I.datalen == 0 ) basilisk_alicepayment(swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) @@ -1513,16 +1514,17 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d } if ( swap->myfee.I.datalen == 0 ) { - //printf("generate fee\n"); + printf("generate fee\n"); bitcoin_address(coinaddr,swap->alicecoin.pubtype,swap->changermd160,20); if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr) == 0 ) { + printf("rawtxsend\n"); swap->I.statebits |= LP_swapdata_rawtxsend(pairsock,swap,0x80,data,maxlen,&swap->myfee,0x40,0); LP_unspents_mark(swap->I.iambob!=0?swap->bobcoin.symbol:swap->alicecoin.symbol,swap->myfee.vins); //basilisk_txlog(swap,&swap->myfee,-1); - //for (i=0; imyfee.I.datalen; i++) - // printf("%02x",swap->myfee.txbytes[i]); - //printf(" <- fee state.%x\n",swap->I.statebits); + for (i=0; imyfee.I.datalen; i++) + printf("%02x",swap->myfee.txbytes[i]); + printf(" <- fee state.%x\n",swap->I.statebits); swap->I.statebits |= 0x40; } else From 3cb22ee165e2ed34fb9f58df8856362f5e416138 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:32:33 +0300 Subject: [PATCH 1700/2705] Test --- iguana/exchanges/LP_transaction.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 67d5b7fca..dba8acc98 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -735,7 +735,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) locktime = expiration; - //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 ) return(0); #ifndef BASILISK_DISABLESENDTX @@ -752,7 +752,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch { if ( value > satoshis+txfee ) change = value - (satoshis + txfee); - //printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(change),dstr(txfee)); + printf("utxo %.8f, destamount %.8f change %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(change),dstr(txfee)); } else if ( value > txfee ) satoshis = value - txfee; else printf("unexpected small value %.8f vs txfee %.8f\n",dstr(value),dstr(txfee)); @@ -834,7 +834,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch char str[65]; completed = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); - //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); + printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); if ( (completed= iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) //if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); @@ -854,7 +854,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160,char *vinaddr) { int32_t retval=-1,len,iter; char *signedtx,*changeaddr = 0,_changeaddr[64]; struct iguana_info *coin; int64_t newtxfee=0,destamount; - //char str2[65]; printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str2,rawtx->utxotxid),rawtx->utxovout); + char str2[65]; printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str2,rawtx->utxotxid),rawtx->utxovout); if ( (coin= rawtx->coin) == 0 ) return(-1); //return(_basilisk_rawtx_gen(str,swapstarted,pubkey33,iambob,lockinputs,rawtx,locktime,script,scriptlen,txfee,minconf,delay,privkey)); From 594e3c4fd7db79e74098ad1b4072997215e42bc2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:41:33 +0300 Subject: [PATCH 1701/2705] Test --- iguana/exchanges/LP_transaction.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index dba8acc98..69dc5b5d3 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -768,6 +768,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jaddistr(privkeys,wifstr); V[0].N = V[0].M = 2; } else V[0].N = V[0].M = 1; + printf("what?\n"); V[0].signers[0].privkey = privkey; bitcoin_pubkey33(ctx,V[0].signers[0].pubkey,privkey); bitcoin_priv2wif(wifstr,privkey,wiftype); @@ -790,6 +791,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jaddnum(item,"vout",vout); bitcoin_address(tmpaddr,pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); + printf("before redeem\n"); if ( redeemlen != 0 ) { init_hexbytes_noT(hexstr,redeemscript,redeemlen); @@ -829,6 +831,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch changelen = bitcoin_standardspend(changescript,0,changermd160); txobj = bitcoin_txoutput(txobj,changescript,changelen,change); } + printf("call json2hex\n"); if ( (rawtxbytes= bitcoin_json2hex(isPoS,&txid,txobj,V)) != 0 ) { char str[65]; From 94235c6051b35d41713d4d001f0c2b60f442f520 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:44:35 +0300 Subject: [PATCH 1702/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_transaction.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 456253d33..472833f71 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -445,7 +445,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit exit(-1); } } - nn_tests(pullsock,pushaddr); + //nn_tests(pullsock,pushaddr); printf("my command address is (%s) pullsock.%d\n",pushaddr,pullsock); if ( IAMLP != 0 ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 69dc5b5d3..1fec85240 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -756,9 +756,13 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } else if ( value > txfee ) satoshis = value - txfee; else printf("unexpected small value %.8f vs txfee %.8f\n",dstr(value),dstr(txfee)); - *destamountp = satoshis; + if ( destamountp != 0 ) + *destamountp = satoshis; + printf("destamountp %p\n",destamountp); timestamp = (uint32_t)time(NULL); + printf("t %u V.%p %ld\n",timestamp,V,sizeof(V)); memset(V,0,sizeof(V)); + printf("cleared V\n"); privkeys = cJSON_CreateArray(); if ( privkey2p != 0 ) { From 9bde8c06bd0971fa3b658348e7e6a81c9f5ea4ea Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 12:57:07 +0300 Subject: [PATCH 1703/2705] Test --- iguana/exchanges/LP_transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 1fec85240..ef3d623c6 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -730,7 +730,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr,int32_t suppress_pubkeys) { - char *rawtxbytes=0,*signedtx=0,tmpaddr[64],hexstr[999],wifstr[128],txdestaddr[64],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1; struct vin_info V[16]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; + char *rawtxbytes=0,*signedtx=0,tmpaddr[64],hexstr[999],wifstr[128],txdestaddr[64],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1; struct vin_info V[2]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; *destamountp = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) From b2f5e3e426d985ff4afc9a4c14d71cf3d6c72343 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 22:24:46 +0300 Subject: [PATCH 1704/2705] Test --- iguana/exchanges/LP_commands.c | 8 + iguana/exchanges/LP_forwarding.c | 11 +- iguana/exchanges/LP_include.h | 2 + iguana/exchanges/LP_nativeDEX.c | 226 +++++++++++---------- iguana/exchanges/LP_network.c | 315 +++++++++++++++++++++++++++++- iguana/exchanges/LP_ordermatch.c | 42 ++-- iguana/exchanges/LP_rpc.c | 37 +++- iguana/exchanges/LP_transaction.c | 11 +- 8 files changed, 501 insertions(+), 151 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index bd0b5a21f..ade4ba249 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -211,6 +211,12 @@ forwardhex(pubkey,hex)\n\ } else retstr = clonestr("{\"error\":\"cant recurse forwards\"}"); } + else if ( strcmp(method,"keepalive") == 0 ) + { + printf("got keepalive lag.%d\n",(int32_t)time(NULL) - LP_deadman_switch); + LP_deadman_switch = (uint32_t)time(NULL); + return(0); + } else if ( strcmp(method,"getpeers") == 0 ) return(LP_peers()); else if ( strcmp(method,"getutxos") == 0 ) @@ -232,6 +238,8 @@ forwardhex(pubkey,hex)\n\ return(LP_lookup(jbits256(argjson,"client"))); else if ( strcmp(method,"forwardhex") == 0 ) retstr = LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex")); + else if ( strcmp(method,"psock") == 0 ) + return(LP_psock(myipaddr,jint(argjson,"ispaired"))); else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); } diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index ab03abc87..5bd361ae4 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -116,10 +116,13 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) ptr->lasttime = (uint32_t)time(NULL); if ( ptr->pushsock >= 0 ) { - nn_close(ptr->pushsock); - printf("recreate pushsock for %s\n",pushaddr); - if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 ) - return(clonestr("{\"error\":\"couldnt recreate pushsock\",\"registered\":0}")); + if ( strcmp(pushaddr,ptr->pushaddr) != 0 ) + { + nn_close(ptr->pushsock); + printf("recreate pushsock for %s\n",pushaddr); + if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 ) + return(clonestr("{\"error\":\"couldnt recreate pushsock\",\"registered\":0}")); + } else printf("no need to create identical endpoint\n"); } return(clonestr("{\"error\":\"already registered\",\"registered\":1}")); } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 400feb53c..e706d124c 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -235,6 +235,8 @@ struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port); char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin); void LP_availableset(struct LP_utxoinfo *utxo); int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2,bits256 pubkey); +int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin); +uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired); #endif diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 472833f71..e61d6f4f5 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -20,12 +20,13 @@ #include #include "LP_include.h" -portable_mutex_t LP_peermutex,LP_UTXOmutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex,LP_networkmutex; - +portable_mutex_t LP_peermutex,LP_UTXOmutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex,LP_networkmutex,LP_psockmutex; +int32_t LP_canbind; #include "LP_network.c" struct LP_utxoinfo *LP_utxoinfos[2],*LP_utxoinfos2[2]; struct LP_peerinfo *LP_peerinfos,*LP_mypeer; +struct LP_forwardinfo *LP_forwardinfos; char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; @@ -33,6 +34,7 @@ char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // +uint32_t LP_deadman_switch; int32_t LP_mypubsock = -1; int32_t USERPASS_COUNTER,IAMLP = 0; double LP_profitratio = 1.; @@ -91,7 +93,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * return(retstr); } -void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen,int32_t recvsock) +char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen,int32_t recvsock) { int32_t len,datalen=0; char *retstr=0,*jsonstr=0; cJSON *argjson,*reqjson; if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) @@ -111,7 +113,8 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof { //printf("got forwardhex\n"); if ( (retstr= LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) - free(retstr), retstr = 0; + { + } } else if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"publish") == 0 ) { @@ -135,7 +138,6 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof printf("%d got REQ.(%s) -> (%s)\n",recvsock,jprint(argjson,0),retstr); LP_send(recvsock,retstr,0); } - free(retstr); } else if ( strcmp("PULL",typestr) == 0 ) { @@ -149,26 +151,29 @@ void LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double prof free(jsonstr); if ( ptr != 0 ) nn_freemsg(ptr), ptr = 0; + return(retstr); } -int32_t LP_pullsock_check(char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) +int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { void *ptr; int32_t recvlen,nonz = 0; + *retstrp = 0; while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); + *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); } return(nonz); } int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double profitmargin) { - int32_t recvlen,nonz = 0; void *ptr; + int32_t recvlen,nonz = 0; void *ptr; char *retstr; while ( sock >= 0 && (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; - LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock); + if ( (retstr= LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock)) != 0 ) + free(retstr); /*if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) { printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); @@ -298,40 +303,18 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso free(retstr); } } - nonz += LP_pullsock_check(myipaddr,pubsock,pullsock,profitmargin); + nonz += LP_pullsock_check(&retstr,myipaddr,pubsock,pullsock,profitmargin); + if ( retstr != 0 ) + free(retstr); if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); counter++; return(nonz); } -void LP_mainloop(char *myipaddr,struct LP_peerinfo *mypeer,uint16_t mypubport,int32_t pubsock,char *pushaddr,uint16_t pushport,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin,cJSON *coins,char *seednode) +void LP_initcoins(int32_t pubsock,cJSON *coins,char *passphrase) { - uint8_t r; int32_t i,n,j; cJSON *item; - if ( IAMLP != 0 ) - { - if ( seednode == 0 || seednode[0] == 0 ) - { - for (i=0; i 25 ) - continue; - LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport,profitmargin); - } - } else LP_peersquery(mypeer,pubsock,seednode,myport,mypeer->ipaddr,myport,profitmargin); - } - else - { - if ( seednode == 0 || seednode[0] == 0 ) - { - OS_randombytes((void *)&r,sizeof(r)); - for (j=0; j= 0 ) + int32_t i,j; uint32_t r; + if ( IAMLP != 0 ) { - if ( nn_connect(sock,pushaddr) < 0 ) - printf("connect error %s\n",nn_strerror(nn_errno())); - else + LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); + if ( myipaddr == 0 || mypeer == 0 ) { - sleep(2); - timeout = 1; - nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - //n = nn_send(sock,"nn_tests",(int32_t)strlen("nn_tests")+1,0*NN_DONTWAIT); - sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); - n = LP_send(sock,msg,0);// - sleep(1); - //m = nn_recv(pullsock,&ptr,NN_MSG,0); - LP_pullsock_check("127.0.0.1",-1,pullsock,0.); - printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes -> %d, recv.%d\n",n,pullsock,m); + printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); + exit(-1); } + if ( seednode == 0 || seednode[0] == 0 ) + { + for (i=0; i 25 ) + continue; + LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport,profitmargin); + } + } else LP_peersquery(mypeer,pubsock,seednode,myport,mypeer->ipaddr,myport,profitmargin); + } + else + { + if ( myipaddr == 0 ) + { + printf("couldnt get myipaddr\n"); + exit(-1); + } + if ( seednode == 0 || seednode[0] == 0 ) + { + OS_randombytes((void *)&r,sizeof(r)); + for (j=0; j= 0 ) - { - timeout = 1; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_MAXTTL,&timeout,sizeof(timeout)); - nanomsg_transportname(1,bindaddr,myipaddr,mypullport); - if ( nn_bind(pullsock,bindaddr) >= 0 ) - { - maxsize = 2 * 1024 * 1024; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - //LP_pullsock_check(myipaddr,-1,pullsock,0.); - } - else - { - printf("bind to %s error for %s: %s\n",bindaddr,pushaddr,nn_strerror(nn_errno())); - exit(-1); - } - } - //nn_tests(pullsock,pushaddr); - printf("my command address is (%s) pullsock.%d\n",pushaddr,pullsock); if ( IAMLP != 0 ) { - if ( myipaddr != 0 ) + pubsock = -1; + nanomsg_transportname(0,subaddr,myipaddr,mypubport); + nanomsg_transportname(1,bindaddr,myipaddr,mypubport); + if ( (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) { - pubsock = -1; - nanomsg_transportname(0,subaddr,myipaddr,mypubport); - nanomsg_transportname(1,bindaddr,myipaddr,mypubport); - if ( (pubsock= nn_socket(AF_SP,NN_PUB)) >= 0 ) + if ( nn_bind(pubsock,bindaddr) >= 0 ) { - if ( nn_bind(pubsock,bindaddr) >= 0 ) - { - timeout = 10; - nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - } - else - { - printf("error binding to (%s).%d (%s).%d\n",pushaddr,pullsock,subaddr,pubsock); - if ( pubsock >= 0 ) - nn_close(pubsock), pubsock = -1; - } - } else printf("error getting sockets %d %d\n",pullsock,pubsock); - printf(">>>>>>>>> myipaddr.%s (%s %s) pubsock.%d pullsock.%d\n",myipaddr,pushaddr,subaddr,pubsock,pullsock); - LP_mypubsock = pubsock; - LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,profitmargin,0,0); - } - if ( myipaddr == 0 || mypeer == 0 ) - { - printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); - exit(-1); - } + timeout = 10; + nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + } + else + { + printf("error binding to (%s).%d\n",subaddr,pubsock); + if ( pubsock >= 0 ) + nn_close(pubsock), pubsock = -1; + } + } else printf("error getting pubsock %d\n",pubsock); + printf(">>>>>>>>> myipaddr.%s (%s) pullsock.%d\n",myipaddr,subaddr,pubsock); + LP_mypubsock = pubsock; } - else if ( myipaddr == 0 ) + LP_initpeers(pubsock,mypeer,myipaddr,myport,jstr(argjson,"seednode"),profitmargin); + pullsock = LP_initpublicaddr(&mypullport,pushaddr,myipaddr,mypullport,0); + LP_deadman_switch = (uint32_t)time(NULL); + printf("my command address is (%s) pullsock.%d pullport.%u\n",pushaddr,pullsock,mypullport); + LP_initcoins(pubsock,jobj(argjson,"coins"),passphrase); + if ( IAMLP != 0 && OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_psockloop,(void *)&myipaddr) != 0 ) { - printf("couldnt get myipaddr\n"); + printf("error launching LP_psockloop for (%s)\n",myipaddr); exit(-1); } -LP_mainloop(myipaddr,mypeer,mypubport,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin,jobj(argjson,"coins"),jstr(argjson,"seednode")); + if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport) != 0 ) + { + printf("error launching stats rpcloop for port.%u\n",myport); + exit(-1); + } + while ( 1 ) + { + if ( 0 && (rand() % 100) == 0 ) + printf("mainloop\n"); + if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin) == 0 ) + usleep(100000); + if ( LP_canbind == 0 && LP_deadman_switch < time(NULL)-777 ) + { + printf("DEAD man's switch activated, register forwarding again\n"); + if ( pullsock >= 0 ) + nn_close(pullsock); + pullsock = LP_initpublicaddr(&mypullport,pushaddr,myipaddr,mypullport,0); + LP_deadman_switch = (uint32_t)time(NULL); + LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,100000); + } + } } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index da995ef5f..ca3204cf5 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -17,7 +17,17 @@ // LP_network.c // marketmaker // -// jl777: might need to queue outbound packets and send via separate thread + +#define PSOCK_IDLETIMEOUT (2 * INSTANTDEX_LOCKTIME + 600) +struct psock +{ + uint32_t lasttime,lastping; + int32_t recvsock,sendsock,ispaired; + uint16_t recvport,sendport; + char sendaddr[128]; +} *PSOCKS; + +uint16_t Numpsocks,Psockport = 10000; char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { @@ -43,7 +53,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) //portable_mutex_lock(&LP_networkmutex); if ( nn_poll(&pfd,1,1) > 0 ) { - if ( (sentbytes= nn_send(sock,msg,len,0*NN_DONTWAIT)) != len ) + if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) printf("LP_send sent %d instead of %d\n",sentbytes,len); //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) @@ -86,3 +96,304 @@ uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbit free(buf); return(nextbits); } + +void LP_psockloop(void *_ptr) +{ + int32_t i,n,nonz,iter,size=0,sentbytes,sendsock = -1; uint32_t now; struct psock *ptr=0; void *buf=0; struct nn_pollfd pfd,*pfds; char keepalive[512];//,*myipaddr = _ptr; + while ( 1 ) + { + now = (uint32_t)time(NULL); + if ( buf != 0 && ptr != 0 && sendsock >= 0 ) + { + if ( size > 0 ) + { + pfd.fd = ptr->sendsock; + pfd.events = NN_POLLOUT; + if ( nn_poll(&pfd,1,1) > 0 ) + { + if ( (sentbytes= nn_send(sendsock,buf,size,0)) > 0 ) + { + ptr->lasttime = now; + printf("PSOCKS (%d %d %d) -> %d/%d bytes\n",ptr->recvsock,ptr->sendsock,sendsock,size,sentbytes); + } else printf("send error to %s\n",ptr->sendaddr); + if ( buf != 0 ) + { + if ( buf != keepalive ) + nn_freemsg(buf); + buf = 0; + size = 0; + ptr = 0; + sendsock = -1; + } + } + } + } + else if ( Numpsocks > 0 ) + { + pfds = calloc(Numpsocks,sizeof(*pfds) * 2); + portable_mutex_lock(&LP_psockmutex); + for (iter=0; iter<2; iter++) + { + for (i=n=0; irecvsock; + pfds[n].events = POLLIN; + } + else + { + if ( pfds[n].fd != ptr->recvsock ) + { + printf("unexpected fd.%d mismatched recvsock.%d\n",pfds[n].fd,ptr->recvsock); + break; + } + else if ( (pfds[n].revents & POLLIN) != 0 ) + { + if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) + { + ptr->lasttime = now; + sendsock = ptr->sendsock; + break; + } + } + } + n++; + if ( ptr->ispaired != 0 ) + { + if ( iter == 0 ) + { + pfds[n].fd = ptr->sendsock; + pfds[n].events = POLLIN; + } + else + { + if ( pfds[n].fd != ptr->sendsock ) + { + printf("unexpected fd.%d mismatched sendsock.%d\n",pfds[n].fd,ptr->sendsock); + break; + } + else if ( (pfds[n].revents & POLLIN) != 0 ) + { + ptr->lasttime = now; + sendsock = ptr->recvsock; + } + } + n++; + } + } + if ( iter == 0 && nn_poll(pfds,n,10) <= 0 ) + break; + } + portable_mutex_unlock(&LP_psockmutex); + if ( sendsock < 0 ) + { + for (i=nonz=0; i ptr->lasttime+PSOCK_IDLETIMEOUT ) + { + printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->recvport,ptr->sendport,now - ptr->lasttime); + if ( ptr->recvsock >= 0 ) + nn_close(ptr->recvsock); + if ( ptr->sendsock >= 0 ) + nn_close(ptr->sendsock); + portable_mutex_lock(&LP_psockmutex); + if ( Numpsocks > 1 ) + { + PSOCKS[i] = PSOCKS[--Numpsocks]; + memset(&PSOCKS[Numpsocks],0,sizeof(*ptr)); + } else Numpsocks = 0; + portable_mutex_unlock(&LP_psockmutex); + break; + } + else if ( now > ptr->lastping+600 ) + { + ptr->lastping = now; + sendsock = ptr->sendsock; + printf("keep %s alive\n",ptr->sendaddr); + sprintf(keepalive,"{\"method\":\"keepalive\",\"endpoint\":\"%s\"}",ptr->sendaddr); + size = (int32_t)strlen(keepalive) + 1; + buf = keepalive; + break; + } + } + } + if ( nonz == 0 && i == Numpsocks ) + usleep(100000); + } + } else usleep(100000); + } +} + +void LP_psockadd(int32_t ispaired,int32_t recvsock,uint16_t recvport,int32_t sendsock,uint16_t sendport,char *subaddr) +{ + struct psock *ptr; + portable_mutex_lock(&LP_psockmutex); + PSOCKS = realloc(PSOCKS,sizeof(*PSOCKS) * (Numpsocks + 1)); + ptr = &PSOCKS[Numpsocks++]; + ptr->ispaired = ispaired; + ptr->recvsock = recvsock; + ptr->recvport = recvport; + ptr->sendsock = sendsock; + ptr->sendport = sendport; + safecopy(ptr->sendaddr,subaddr,sizeof(ptr->sendaddr)); + ptr->lasttime = (uint32_t)time(NULL); + portable_mutex_unlock(&LP_psockmutex); +} + +char *LP_psock(char *myipaddr,int32_t ispaired) +{ + char pushaddr[128],subaddr[128]; uint16_t i,pushport,subport; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; cJSON *retjson=0; + retjson = cJSON_CreateObject(); + pushport = Psockport++; + subport = Psockport++; + for (i=0; i<100; i++) + { + if ( pushport < 10000 ) + pushport = 10001; + if ( subport <= pushport ) + subport = pushport + 1; + pullsock = pubsock = -1; + nanomsg_transportname(1,pushaddr,myipaddr,pushport), pushport += 2; + nanomsg_transportname(1,subaddr,myipaddr,subport), subport += 2; + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PUB)) >= 0 ) + { + if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) + { + timeout = 1; + nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + maxsize = 1024 * 1024; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + if ( ispaired != 0 ) + { + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + } + LP_psockadd(ispaired,pullsock,pushport,pubsock,subport,subaddr); + jaddstr(retjson,"result","success"); + jaddstr(retjson,"connectaddr",subaddr); + jaddstr(retjson,"LPipaddr",myipaddr); + jaddnum(retjson,"connectport",subport); + jaddnum(retjson,"ispaired",ispaired); + jaddstr(retjson,"publicaddr",pushaddr); + jaddnum(retjson,"publicport",pushport); + break; + } + if ( pullsock >= 0 ) + nn_close(pullsock); + if ( pubsock >= 0 ) + nn_close(pubsock); + } + } + if ( Psockport > 60000 ) + Psockport = 10000; + if ( i == 100 ) + jaddstr(retjson,"error","cant find psock ports"); + return(jprint(retjson,1)); +} + +/* + LP_pushaddr_get makes transparent the fact that most nodes cannot bind()! + + The idea is to create an LP node NN_PAIR sock that the LP node binds to and client node connects to. Additionally, the LP node creates an NN_PULL that other nodes can NN_PUSH to and returns this address in pushaddr/retval for the client node to register with. The desired result is that other than the initial LP node, all the other nodes do a normal NN_PUSH, requiring no change to the NN_PUSH/NN_PULL logic. Of course, the initial LP node needs to autoforward all packets from the public NN_PULL to the NN_PUB + + similar to LP_pushaddr_get, create an NN_PAIR for DEX atomic data, can be assumed to have a max lifetime of 2*INSTANTDEX_LOCKTIME + + both are combined in LP_psock_get + +*/ + +int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) +{ + int32_t sock,n,timeout,retval = -1; char msg[512],*retstr; + printf("nn_tests.(%s)\n",pushaddr); + if ( (sock= nn_socket(AF_SP,nnother)) >= 0 ) + { + if ( nn_connect(sock,pushaddr) < 0 ) + printf("connect error %s\n",nn_strerror(nn_errno())); + else + { + timeout = 1; + //nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); + n = LP_send(sock,msg,0); + LP_pullsock_check(&retstr,"127.0.0.1",-1,pullsock,0.); + printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes -> %d (%s)\n",n,pullsock,retstr!=0?retstr:""); + if ( retstr != 0 ) + { + free(retstr); + retval = 0; + } + } + nn_close(sock); + } + return(retval); +} + +int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr,uint16_t mypullport,int32_t ispaired) +{ + int32_t nntype,pullsock,timeout,maxsize; char bindaddr[128],connectaddr[128]; + *mypullportp = mypullport; + if ( ispaired == 0 ) + { + if ( LP_canbind != 0 ) + nntype = LP_COMMAND_RECVSOCK; + else nntype = NN_SUB; + } + else nntype = NN_PAIR; + if ( LP_canbind != 0 ) + { + nanomsg_transportname(0,publicaddr,myipaddr,mypullport); + nanomsg_transportname(1,bindaddr,myipaddr,mypullport); + } + else + { + *mypullportp = 0; + while ( *mypullportp == 0 ) + { + *mypullportp = LP_psock_get(connectaddr,publicaddr,ispaired); + sleep(10); + printf("try to get publicaddr again\n"); + } + } + if ( (pullsock= nn_socket(AF_SP,nntype)) >= 0 ) + { + timeout = 1; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_MAXTTL,&timeout,sizeof(timeout)); + maxsize = 2 * 1024 * 1024; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + if ( LP_canbind == 0 ) + { + if ( nn_connect(pullsock,connectaddr) < 0 ) + { + printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); + exit(-1); + } + if ( nntype == NN_SUB ) + nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + } + else + { + if ( nn_bind(pullsock,bindaddr) < 0 ) + { + printf("bind to %s error for %s: %s\n",bindaddr,publicaddr,nn_strerror(nn_errno())); + exit(-1); + } + } + } + if ( ispaired == 0 && nn_tests(pullsock,publicaddr,LP_COMMAND_SENDSOCK) < 0 ) + { + printf("command socket didnt work\n"); + exit(-1); + } + return(pullsock); +} diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index f9562a7b7..376cd8a91 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -338,24 +338,32 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho return(price); } -int32_t LP_nanobind(int32_t pair,char *pairstr,char *myipaddr) +int32_t LP_nanobind(char *pairstr,char *myipaddr) { - int32_t i,timeout,r; char bindaddr[128]; - for (i=0; i<10; i++) + int32_t i,timeout,r,pairsock = -1; uint16_t mypullport; char bindaddr[128]; + if ( LP_canbind != 0 ) { - r = (10000 + (rand() % 50000)) & 0xffff; - nanomsg_transportname(0,pairstr,myipaddr,r); - nanomsg_transportname(1,bindaddr,myipaddr,r); - if ( nn_bind(pair,bindaddr) >= 0 ) + if ( (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) + printf("error creating utxo->pair\n"); + else { - timeout = 100; - nn_setsockopt(pair,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(pair,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - printf("nanobind %s to %d\n",pairstr,pair); - return(0); - } else printf("error binding to %s for %s\n",bindaddr,pairstr); - } - return(-1); + for (i=0; i<10; i++) + { + r = (10000 + (rand() % 50000)) & 0xffff; + nanomsg_transportname(0,pairstr,myipaddr,r); + nanomsg_transportname(1,bindaddr,myipaddr,r); + if ( nn_bind(pairsock,bindaddr) >= 0 ) + { + timeout = 100; + nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + printf("nanobind %s to %d\n",pairstr,pairsock); + return(pairsock); + } else printf("error binding to %s for %s\n",bindaddr,pairstr); + } + } + } else pairsock = LP_initpublicaddr(&mypullport,pairstr,myipaddr,0,0); + return(pairsock); } int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin,double price,struct LP_quoteinfo *qp) @@ -366,9 +374,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(privkey) != 0 && qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending && bits256_cmp(LP_mypubkey,qp->srchash) == 0 ) { - if ( (pair= nn_socket(AF_SP,NN_PAIR)) < 0 ) - printf("error creating utxo->pair\n"); - else if ( LP_nanobind(pair,pairstr,myipaddr) >= 0 ) + if ( (pair= LP_nanobind(pairstr,myipaddr)) >= 0 ) { LP_requestinit(&qp->R,qp->srchash,qp->desthash,base,qp->satoshis,rel,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); swap = LP_swapinit(1,0,privkey,&qp->R,qp); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 89e52a64b..751696ceb 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -109,12 +109,47 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *ipaddr,uint16_t pushport) { char url[512],str[65],*retstr; - sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s&pushport=%u",destip,destport,bits256_str(str,pubkey),ipaddr,pushport); + sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s&pushport=%u",destip,destport,bits256_str(str,pubkey),ipaddr,pushport); retstr = issue_curlt(url,LP_HTTP_TIMEOUT); //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); return(retstr); } +char *issue_LP_psock(char *destip,uint16_t destport,int32_t ispaired) +{ + char url[512],*retstr; + sprintf(url,"http://%s:%u/api/stats/psock?ispaired=%d",destip,destport,ispaired); + retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); + return(retstr); +} + +uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired) +{ + uint16_t publicport = 0; char *retstr,*addr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; + connectaddr[0] = publicaddr[0] = 0; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + if ( (retstr= issue_LP_psock(peer->ipaddr,peer->port,ispaired)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (addr= jstr(retjson,"publicaddr")) != 0 ) + safecopy(publicaddr,addr,128); + if ( (addr= jstr(retjson,"connectaddr")) != 0 ) + safecopy(connectaddr,addr,128); + if ( publicaddr[0] != 0 && connectaddr[0] != 0 ) + publicport = juint(retjson,"publicport"); + free_json(retjson); + } + free(retstr); + } + if ( publicport != 0 ) + break; + } + return(publicport); +} + char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) { char url[512],str[65]; diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index ef3d623c6..28f3b6aa4 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -735,7 +735,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch memset(signedtxidp,0,sizeof(*signedtxidp)); if ( finalseqid == 0 ) locktime = expiration; - printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); + //printf("bobtxspend.%s redeem.[%d]\n",symbol,redeemlen); if ( redeemlen < 0 ) return(0); #ifndef BASILISK_DISABLESENDTX @@ -758,11 +758,8 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch else printf("unexpected small value %.8f vs txfee %.8f\n",dstr(value),dstr(txfee)); if ( destamountp != 0 ) *destamountp = satoshis; - printf("destamountp %p\n",destamountp); timestamp = (uint32_t)time(NULL); - printf("t %u V.%p %ld\n",timestamp,V,sizeof(V)); memset(V,0,sizeof(V)); - printf("cleared V\n"); privkeys = cJSON_CreateArray(); if ( privkey2p != 0 ) { @@ -772,7 +769,6 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jaddistr(privkeys,wifstr); V[0].N = V[0].M = 2; } else V[0].N = V[0].M = 1; - printf("what?\n"); V[0].signers[0].privkey = privkey; bitcoin_pubkey33(ctx,V[0].signers[0].pubkey,privkey); bitcoin_priv2wif(wifstr,privkey,wiftype); @@ -795,7 +791,6 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch jaddnum(item,"vout",vout); bitcoin_address(tmpaddr,pubtype,pubkey33,33); bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); - printf("before redeem\n"); if ( redeemlen != 0 ) { init_hexbytes_noT(hexstr,redeemscript,redeemlen); @@ -835,13 +830,12 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch changelen = bitcoin_standardspend(changescript,0,changermd160); txobj = bitcoin_txoutput(txobj,changescript,changelen,change); } - printf("call json2hex\n"); if ( (rawtxbytes= bitcoin_json2hex(isPoS,&txid,txobj,V)) != 0 ) { char str[65]; completed = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); - printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); + //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); if ( (completed= iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) //if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); @@ -1501,7 +1495,6 @@ void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,s int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { char coinaddr[64]; int32_t i,retval = -1; - printf("alicetx\n"); if ( swap->alicepayment.I.datalen == 0 ) basilisk_alicepayment(swap,swap->alicepayment.coin,&swap->alicepayment,swap->I.pubAm,swap->I.pubBn); if ( swap->alicepayment.I.datalen == 0 || swap->alicepayment.I.spendlen == 0 ) From 752ba42479f9d21416697ff4f2314250342a3c8f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 22:33:42 +0300 Subject: [PATCH 1705/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 6 +++--- iguana/exchanges/LP_ordermatch.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 5bd361ae4..f11f17828 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -250,7 +250,7 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu { if ( bits256_cmp(pubkey,LP_mypubkey) == 0 ) { - //printf("GOT FORWARDED.(%s)\n",jsonstr); + printf("GOT FORWARDED.(%s)\n",myipaddr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,0,0,profitmargin)) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e61d6f4f5..837f94dfb 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -229,7 +229,7 @@ int32_t LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pu if ( mypeer == 0 || strcmp(peer->ipaddr,mypeer->ipaddr) != 0 ) { peer->lastutxos = now; - printf("query utxos from %s\n",peer->ipaddr); + //printf("query utxos from %s\n",peer->ipaddr); n = LP_utxosquery(mypeer,pubsock,peer->ipaddr,peer->port,"",lastn,mypeer != 0 ? mypeer->ipaddr : "127.0.0.1",myport,profitmargin); } } //else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos); @@ -271,7 +271,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_peer_pricesquery(peer->ipaddr,peer->port); peer->diduquery = now; } - nonz += LP_subsock_check(myipaddr,pubsock,peer->subsock,profitmargin); + nonz += LP_subsock_check(origipaddr,pubsock,peer->subsock,profitmargin); } if ( (counter % 600) == 60 ) { @@ -303,7 +303,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso free(retstr); } } - nonz += LP_pullsock_check(&retstr,myipaddr,pubsock,pullsock,profitmargin); + nonz += LP_pullsock_check(&retstr,origipaddr,pubsock,pullsock,profitmargin); if ( retstr != 0 ) free(retstr); if ( IAMLP != 0 && (counter % 600) == 42 ) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 376cd8a91..f03da6a7e 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -369,7 +369,7 @@ int32_t LP_nanobind(char *pairstr,char *myipaddr) int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin,double price,struct LP_quoteinfo *qp) { char pairstr[512]; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; - printf("LP_connectstartbob with.(%s)\n",jprint(argjson,0)); + printf("LP_connectstartbob.(%s) with.(%s)\n",myipaddr,jprint(argjson,0)); qp->quotetime = (uint32_t)time(NULL); privkey = LP_privkey(utxo->coinaddr); if ( bits256_nonz(privkey) != 0 && qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending && bits256_cmp(LP_mypubkey,qp->srchash) == 0 ) From 95c6ac69007971fe57fa28550c529fcc37a8d6a0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 22:37:53 +0300 Subject: [PATCH 1706/2705] Test --- iguana/exchanges/LP_network.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index ca3204cf5..7a1044edf 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -275,6 +275,8 @@ char *LP_psock(char *myipaddr,int32_t ispaired) nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); } + nanomsg_transportname(0,pushaddr,myipaddr,pushport); + nanomsg_transportname(0,subaddr,myipaddr,subport); LP_psockadd(ispaired,pullsock,pushport,pubsock,subport,subaddr); jaddstr(retjson,"result","success"); jaddstr(retjson,"connectaddr",subaddr); From c5f600267f90ecc9313a00f0d9a0a41b060deeff Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 22:43:26 +0300 Subject: [PATCH 1707/2705] Test --- iguana/exchanges/LP_commands.c | 8 ++++++++ iguana/exchanges/LP_rpc.c | 1 + 2 files changed, 9 insertions(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index ade4ba249..2a1880b42 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -239,7 +239,15 @@ forwardhex(pubkey,hex)\n\ else if ( strcmp(method,"forwardhex") == 0 ) retstr = LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex")); else if ( strcmp(method,"psock") == 0 ) + { + if ( myipaddr == 0 || myipaddr[0] == 0 || strcmp(myipaddr,"127.0.0.1") == 0 ) + { + if ( LP_mypeer != 0 ) + myipaddr = LP_mypeer->ipaddr; + else printf("LP_psock dont have actual ipaddr?\n"); + } return(LP_psock(myipaddr,jint(argjson,"ispaired"))); + } else if ( strcmp(method,"notify") == 0 ) retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}"); } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 751696ceb..cd9155e5c 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -132,6 +132,7 @@ uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired) { if ( (retstr= issue_LP_psock(peer->ipaddr,peer->port,ispaired)) != 0 ) { + printf("got.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (addr= jstr(retjson,"publicaddr")) != 0 ) From 6ad435df91c6b4d0aead1463fb6eb2f5f94e6e6e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 22:50:35 +0300 Subject: [PATCH 1708/2705] Test --- iguana/exchanges/LP_network.c | 3 ++- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 7a1044edf..ec3bf6c42 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -279,8 +279,8 @@ char *LP_psock(char *myipaddr,int32_t ispaired) nanomsg_transportname(0,subaddr,myipaddr,subport); LP_psockadd(ispaired,pullsock,pushport,pubsock,subport,subaddr); jaddstr(retjson,"result","success"); - jaddstr(retjson,"connectaddr",subaddr); jaddstr(retjson,"LPipaddr",myipaddr); + jaddstr(retjson,"connectaddr",subaddr); jaddnum(retjson,"connectport",subport); jaddnum(retjson,"ispaired",ispaired); jaddstr(retjson,"publicaddr",pushaddr); @@ -321,6 +321,7 @@ int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) printf("connect error %s\n",nn_strerror(nn_errno())); else { + sleep(3); timeout = 1; //nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(sock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index cd9155e5c..5f3007957 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -132,7 +132,7 @@ uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired) { if ( (retstr= issue_LP_psock(peer->ipaddr,peer->port,ispaired)) != 0 ) { - printf("got.(%s)\n",retstr); + //printf("got.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (addr= jstr(retjson,"publicaddr")) != 0 ) From a7529c86d9242c236e453773efac2a5a8ff4bab7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 22:58:40 +0300 Subject: [PATCH 1709/2705] Test --- iguana/exchanges/LP_network.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index ec3bf6c42..a1279b840 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -99,7 +99,7 @@ uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbit void LP_psockloop(void *_ptr) { - int32_t i,n,nonz,iter,size=0,sentbytes,sendsock = -1; uint32_t now; struct psock *ptr=0; void *buf=0; struct nn_pollfd pfd,*pfds; char keepalive[512];//,*myipaddr = _ptr; + int32_t i,n,nonz,iter,retval,size=0,sentbytes,sendsock = -1; uint32_t now; struct psock *ptr=0; void *buf=0; struct nn_pollfd pfd,*pfds; char keepalive[512];//,*myipaddr = _ptr; while ( 1 ) { now = (uint32_t)time(NULL); @@ -151,6 +151,7 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { + printf("%s has pollin\n",ptr->sendaddr); if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) { ptr->lasttime = now; @@ -176,17 +177,29 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - ptr->lasttime = now; - sendsock = ptr->recvsock; + printf("%s paired has pollin\n",ptr->sendaddr); + if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) + { + ptr->lasttime = now; + sendsock = ptr->recvsock; + break; + } } } n++; } } - if ( iter == 0 && nn_poll(pfds,n,10) <= 0 ) - break; + if ( iter == 0 ) + { + if ( (retval= nn_poll(pfds,n,10)) <= 0 ) + { + printf("nn_poll retval.%d\n",retval); + break; + } + } } portable_mutex_unlock(&LP_psockmutex); + free(pfds); if ( sendsock < 0 ) { for (i=nonz=0; i Date: Mon, 19 Jun 2017 23:05:55 +0300 Subject: [PATCH 1710/2705] Test --- iguana/exchanges/LP_network.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index a1279b840..5f6f653d6 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -193,7 +193,8 @@ void LP_psockloop(void *_ptr) { if ( (retval= nn_poll(pfds,n,10)) <= 0 ) { - printf("nn_poll retval.%d\n",retval); + if ( retval != 0 ) + printf("nn_poll retval.%d\n",retval); break; } } @@ -207,7 +208,14 @@ void LP_psockloop(void *_ptr) if ( i < Numpsocks ) { ptr = &PSOCKS[i]; - if ( now > ptr->lasttime+PSOCK_IDLETIMEOUT ) + if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) + { + printf("got %d bytes for %s\n",size,ptr->sendaddr); + ptr->lasttime = now; + sendsock = ptr->sendsock; + break; + } + else if ( now > ptr->lasttime+PSOCK_IDLETIMEOUT ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->recvport,ptr->sendport,now - ptr->lasttime); if ( ptr->recvsock >= 0 ) From 4e6b7b4db9ed9b5b3b1da3a2d5871a5c61a2ff7a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 23:13:09 +0300 Subject: [PATCH 1711/2705] Test --- iguana/exchanges/LP_network.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 5f6f653d6..a01263ea4 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -306,6 +306,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) jaddnum(retjson,"ispaired",ispaired); jaddstr(retjson,"publicaddr",pushaddr); jaddnum(retjson,"publicport",pushport); + printf("pushaddr.(%s) for %s\n",pushaddr,subaddr); break; } if ( pullsock >= 0 ) @@ -413,7 +414,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, } } } - if ( ispaired == 0 && nn_tests(pullsock,publicaddr,LP_COMMAND_SENDSOCK) < 0 ) + if ( 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,LP_COMMAND_SENDSOCK) < 0 ) { printf("command socket didnt work\n"); exit(-1); From 31a9d64ece7b0c44f739f23d3896e2da0e19c8fb Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 23:15:56 +0300 Subject: [PATCH 1712/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index f11f17828..3f781bac9 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -154,7 +154,7 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,uint16_t pushport,int3 } HASH_ITER(hh,LP_peerinfos,peer,tmp) { - //printf("register with (%s)\n",peer->ipaddr); + printf("register %s %u with (%s)\n",pushaddr,pushport,peer->ipaddr); if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr,pushport)) != 0 ) { //printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); From 798c2b20dab81f57a4782a4817e2412f44fbbc54 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 23:19:14 +0300 Subject: [PATCH 1713/2705] Test --- iguana/exchanges/LP_forwarding.c | 7 ++++--- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 3f781bac9..d1d94f943 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -146,16 +146,17 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) void LP_forwarding_register(bits256 pubkey,char *pushaddr,uint16_t pushport,int32_t max) { - char *retstr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; + char *retstr,ipaddr[64];; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) { printf("LP_forwarding_register illegal pushaddr or null pubkey\n"); return; } + parse_ipaddr(ipaddr,pushaddr); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("register %s %u with (%s)\n",pushaddr,pushport,peer->ipaddr); - if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,pushaddr,pushport)) != 0 ) + printf("register %s %u with (%s)\n",ipaddr,pushport,peer->ipaddr); + if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,ipaddr,pushport)) != 0 ) { //printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 837f94dfb..c475c64e8 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -278,7 +278,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_myutxo_updates(pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) { - LP_forwarding_register(LP_mypubkey,origipaddr,pushport,10); + LP_forwarding_register(LP_mypubkey,pushaddr,pushport,10); lastforward = now; } } From cbb169d8a714d0ec32b421b7d923748335ad8864 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 23:21:37 +0300 Subject: [PATCH 1714/2705] Test --- iguana/exchanges/LP_forwarding.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index d1d94f943..7d629226f 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -146,16 +146,19 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) void LP_forwarding_register(bits256 pubkey,char *pushaddr,uint16_t pushport,int32_t max) { - char *retstr,ipaddr[64];; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t n=0,retval = -1; + char *retstr,ipaddr[64]; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t j,n=0,retval = -1; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) { printf("LP_forwarding_register illegal pushaddr or null pubkey\n"); return; } - parse_ipaddr(ipaddr,pushaddr); + for (j=0; pushaddr[j]!=0; j++) + if ( pushaddr[j] >= '0' && pushaddr[j] <= '9' ) + break; + parse_ipaddr(ipaddr,pushaddr+j); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("register %s %u with (%s)\n",ipaddr,pushport,peer->ipaddr); + printf("register.(%s) %s %u with (%s)\n",pushaddr,ipaddr,pushport,peer->ipaddr); if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,ipaddr,pushport)) != 0 ) { //printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); From bdebe8a6b2f485a8cd1a1f1efca39f7ea4e5a14c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 23:23:10 +0300 Subject: [PATCH 1715/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index a01263ea4..7b0491b73 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -31,7 +31,7 @@ uint16_t Numpsocks,Psockport = 10000; char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { - sprintf(str,"ws://%s:%u",bindflag == 0 ? ipaddr : "*",port); + sprintf(str,"tcp://%s:%u",bindflag == 0 ? ipaddr : "*",port); return(str); } From 6fb2469baa406ab72e0c3c5a70443ee0d80e68c6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 23:31:08 +0300 Subject: [PATCH 1716/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c475c64e8..7cb8c592a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -303,7 +303,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso free(retstr); } } - nonz += LP_pullsock_check(&retstr,origipaddr,pubsock,pullsock,profitmargin); + nonz += LP_pullsock_check(&retstr,myipaddr,pubsock,pullsock,profitmargin); if ( retstr != 0 ) free(retstr); if ( IAMLP != 0 && (counter % 600) == 42 ) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 7b0491b73..2840d3a95 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -401,7 +401,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); exit(-1); - } + } else printf("nntype.%d NN_SUB.%d to %s\n",nntype,NN_SUB,connectaddr); if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); } From 524699a3c752493eb60c4542c677a1acce655479 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 23:40:48 +0300 Subject: [PATCH 1717/2705] Test --- iguana/exchanges/LP_forwarding.c | 1 + iguana/exchanges/LP_network.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 7d629226f..f7096f3fc 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -120,6 +120,7 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) { nn_close(ptr->pushsock); printf("recreate pushsock for %s\n",pushaddr); + strcpy(ptr->pushaddr,pushaddr); if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 ) return(clonestr("{\"error\":\"couldnt recreate pushsock\",\"registered\":0}")); } else printf("no need to create identical endpoint\n"); diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 2840d3a95..163fe57f7 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -114,7 +114,7 @@ void LP_psockloop(void *_ptr) if ( (sentbytes= nn_send(sendsock,buf,size,0)) > 0 ) { ptr->lasttime = now; - printf("PSOCKS (%d %d %d) -> %d/%d bytes\n",ptr->recvsock,ptr->sendsock,sendsock,size,sentbytes); + printf("PSOCKS (%d %d %d) -> %d/%d bytes %s\n",ptr->recvsock,ptr->sendsock,sendsock,size,sentbytes,ptr->sendaddr); } else printf("send error to %s\n",ptr->sendaddr); if ( buf != 0 ) { @@ -156,6 +156,7 @@ void LP_psockloop(void *_ptr) { ptr->lasttime = now; sendsock = ptr->sendsock; + printf("[%s]\n",(char *)buf); break; } } @@ -208,14 +209,14 @@ void LP_psockloop(void *_ptr) if ( i < Numpsocks ) { ptr = &PSOCKS[i]; - if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) + /*if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) { printf("got %d bytes for %s\n",size,ptr->sendaddr); ptr->lasttime = now; sendsock = ptr->sendsock; break; } - else if ( now > ptr->lasttime+PSOCK_IDLETIMEOUT ) + else*/ if ( now > ptr->lasttime+PSOCK_IDLETIMEOUT ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->recvport,ptr->sendport,now - ptr->lasttime); if ( ptr->recvsock >= 0 ) From 58e085cd9c04d32ca1fd356498e9ebe1d4506897 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 19 Jun 2017 23:57:18 +0300 Subject: [PATCH 1718/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 163fe57f7..ecabf3e4e 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -392,8 +392,8 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_MAXTTL,&timeout,sizeof(timeout)); + if ( nntype == NN_PAIR ) + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); if ( LP_canbind == 0 ) From dba572ca23254beff47fe0f6aeb5d127d4b7d0d9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 00:06:35 +0300 Subject: [PATCH 1719/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 ++ iguana/exchanges/LP_network.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7cb8c592a..7f720ef5e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -160,6 +160,8 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t *retstrp = 0; while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { + if ( IAMLP == 0 ) + printf("pullsock.%d recv.%d (%s)\n",pullsock,recvlen,(char *)ptr); nonz++; *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index ecabf3e4e..0c7c4b60e 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -383,7 +383,8 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, *mypullportp = 0; while ( *mypullportp == 0 ) { - *mypullportp = LP_psock_get(connectaddr,publicaddr,ispaired); + if ( (*mypullportp= LP_psock_get(connectaddr,publicaddr,ispaired)) != 0 ) + break; sleep(10); printf("try to get publicaddr again\n"); } From 2c38bf9e42da502a389d1637c53ab9ab2737d621 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 00:10:10 +0300 Subject: [PATCH 1720/2705] Test --- iguana/exchanges/LP_network.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 0c7c4b60e..1b063d9ba 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -403,9 +403,15 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); exit(-1); - } else printf("nntype.%d NN_SUB.%d to %s\n",nntype,NN_SUB,connectaddr); + } else printf("nntype.%d NN_SUB.%d connect to %s\n",nntype,NN_SUB,connectaddr); if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + while ( 1 ) + { + int32_t size; void *buf; + if ( (size= nn_recv(pullsock,&buf,NN_MSG,0)) > 0 ) + printf("SUBPULL.(%s)\n",(char *)buf); + } } else { From 8aac839d06a4e26badba76b2a90b96dfd3fb5094 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 00:17:20 +0300 Subject: [PATCH 1721/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_network.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index f7096f3fc..b2fec4bbf 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -65,7 +65,7 @@ int32_t LP_hello(struct LP_forwardinfo *ptr) return(i); } } - printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); + //printf("%d iterations on nn_poll and %s pushsock still not ready\n",i,ptr->pushaddr); return(-1); } return(0); diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 1b063d9ba..8f0a2f64e 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -232,7 +232,7 @@ void LP_psockloop(void *_ptr) portable_mutex_unlock(&LP_psockmutex); break; } - else if ( now > ptr->lastping+600 ) + else if ( now > ptr->lastping+60 ) { ptr->lastping = now; sendsock = ptr->sendsock; @@ -286,8 +286,9 @@ char *LP_psock(char *myipaddr,int32_t ispaired) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { - timeout = 1; + timeout = 10; nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); maxsize = 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); @@ -406,7 +407,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, } else printf("nntype.%d NN_SUB.%d connect to %s\n",nntype,NN_SUB,connectaddr); if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - while ( 1 ) + while ( 0 ) { int32_t size; void *buf; if ( (size= nn_recv(pullsock,&buf,NN_MSG,0)) > 0 ) From 2b79dff117f838f8ca30a37f7e6f5bcf6abae97f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 00:19:49 +0300 Subject: [PATCH 1722/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 8f0a2f64e..9fd93d54e 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -310,7 +310,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) jaddnum(retjson,"publicport",pushport); printf("pushaddr.(%s) for %s\n",pushaddr,subaddr); break; - } + } else printf("bind error on %s or %s\n",pushaddr,subaddr); if ( pullsock >= 0 ) nn_close(pullsock); if ( pubsock >= 0 ) From 51b18b1dea7452df95aaabbca110dff7d6da921e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 09:44:49 +0300 Subject: [PATCH 1723/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 ++ iguana/exchanges/LP_network.c | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index b2fec4bbf..505ae8a33 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -119,6 +119,8 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) if ( strcmp(pushaddr,ptr->pushaddr) != 0 ) { nn_close(ptr->pushsock); + if ( LP_psockmark(ptr->pushaddr) < 0 ) + printf("cant mark (%s)\n",ptr->pushaddr); printf("recreate pushsock for %s\n",pushaddr); strcpy(ptr->pushaddr,pushaddr); if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 ) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 9fd93d54e..71cc904f8 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -24,7 +24,7 @@ struct psock uint32_t lasttime,lastping; int32_t recvsock,sendsock,ispaired; uint16_t recvport,sendport; - char sendaddr[128]; + char sendaddr[128],publicaddr[128]; } *PSOCKS; uint16_t Numpsocks,Psockport = 10000; @@ -113,7 +113,6 @@ void LP_psockloop(void *_ptr) { if ( (sentbytes= nn_send(sendsock,buf,size,0)) > 0 ) { - ptr->lasttime = now; printf("PSOCKS (%d %d %d) -> %d/%d bytes %s\n",ptr->recvsock,ptr->sendsock,sendsock,size,sentbytes,ptr->sendaddr); } else printf("send error to %s\n",ptr->sendaddr); if ( buf != 0 ) @@ -251,7 +250,7 @@ void LP_psockloop(void *_ptr) } } -void LP_psockadd(int32_t ispaired,int32_t recvsock,uint16_t recvport,int32_t sendsock,uint16_t sendport,char *subaddr) +void LP_psockadd(int32_t ispaired,int32_t recvsock,uint16_t recvport,int32_t sendsock,uint16_t sendport,char *subaddr,char *publicaddr) { struct psock *ptr; portable_mutex_lock(&LP_psockmutex); @@ -263,10 +262,30 @@ void LP_psockadd(int32_t ispaired,int32_t recvsock,uint16_t recvport,int32_t sen ptr->sendsock = sendsock; ptr->sendport = sendport; safecopy(ptr->sendaddr,subaddr,sizeof(ptr->sendaddr)); + safecopy(ptr->publicaddr,publicaddr,sizeof(ptr->publicaddr)); ptr->lasttime = (uint32_t)time(NULL); portable_mutex_unlock(&LP_psockmutex); } +int32_t LP_psockmark(char *publicaddr) +{ + int32_t i,retval = -1; struct psock *ptr; + portable_mutex_lock(&LP_psockmutex); + for (i=0; ipublicaddr) == 0 ) + { + printf("mark PSOCKS[%d] %s for deletion\n",i,publicaddr); + ptr->lasttime = 0; + retval = i; + break; + } + } + portable_mutex_unlock(&LP_psockmutex); + return(retval); +} + char *LP_psock(char *myipaddr,int32_t ispaired) { char pushaddr[128],subaddr[128]; uint16_t i,pushport,subport; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; cJSON *retjson=0; @@ -300,7 +319,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) } nanomsg_transportname(0,pushaddr,myipaddr,pushport); nanomsg_transportname(0,subaddr,myipaddr,subport); - LP_psockadd(ispaired,pullsock,pushport,pubsock,subport,subaddr); + LP_psockadd(ispaired,pullsock,pushport,pubsock,subport,subaddr,pushaddr); jaddstr(retjson,"result","success"); jaddstr(retjson,"LPipaddr",myipaddr); jaddstr(retjson,"connectaddr",subaddr); From 7e01c0abc2bc36ac4112d58cd8445ab6500a42d6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:02:00 +0300 Subject: [PATCH 1724/2705] Test --- iguana/exchanges/LP_coins.c | 1 + iguana/exchanges/LP_network.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index d2c4b994c..06ea91849 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -256,6 +256,7 @@ struct iguana_info *LP_coinfind(char *symbol) } // "coins":[{"coin":"", "rpcport":pppp}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }] +// {"coin":"HUSH", "name":"hushcoin", "rpcport":8822, "taddr":28, "pubtype":184, "p2shtype":189, "wiftype":128, "txfee":10000 } struct iguana_info *LP_coincreate(cJSON *item) { diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 71cc904f8..7b29283c9 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -327,7 +327,12 @@ char *LP_psock(char *myipaddr,int32_t ispaired) jaddnum(retjson,"ispaired",ispaired); jaddstr(retjson,"publicaddr",pushaddr); jaddnum(retjson,"publicport",pushport); - printf("pushaddr.(%s) for %s\n",pushaddr,subaddr); + printf("publicaddr.(%s) for %s\n",pushaddr,subaddr); + while ( 1 ) + { + LP_send(pubsock,"hello",0); + sleep(10); + } break; } else printf("bind error on %s or %s\n",pushaddr,subaddr); if ( pullsock >= 0 ) @@ -426,11 +431,13 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, } else printf("nntype.%d NN_SUB.%d connect to %s\n",nntype,NN_SUB,connectaddr); if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - while ( 0 ) + while ( 1 ) { int32_t size; void *buf; if ( (size= nn_recv(pullsock,&buf,NN_MSG,0)) > 0 ) printf("SUBPULL.(%s)\n",(char *)buf); + else printf("size.%d\n",size); + sleep(10); } } else From 1a3d64ac2c1c0dcae664a518b055fd90ecad2646 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:05:59 +0300 Subject: [PATCH 1725/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7f720ef5e..88b064f4e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -32,7 +32,7 @@ char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; -char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // +char *default_LPnodes[] = { "5.9.253.195", };//"5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // uint32_t LP_deadman_switch; int32_t LP_mypubsock = -1; diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 7b29283c9..1f9eaeb4e 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -330,7 +330,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) printf("publicaddr.(%s) for %s\n",pushaddr,subaddr); while ( 1 ) { - LP_send(pubsock,"hello",0); + printf("LP_Send %d\n",LP_send(pubsock,"hello",0)); sleep(10); } break; From 6e48150672545efaa456135df748509b7f6d4712 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:11:54 +0300 Subject: [PATCH 1726/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 1f9eaeb4e..a189d1bf5 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -431,7 +431,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, } else printf("nntype.%d NN_SUB.%d connect to %s\n",nntype,NN_SUB,connectaddr); if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - while ( 1 ) + while ( 0 ) { int32_t size; void *buf; if ( (size= nn_recv(pullsock,&buf,NN_MSG,0)) > 0 ) From c8d2cb7e1fc691d736390c92b1f165dd395806b8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:24:48 +0300 Subject: [PATCH 1727/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 13 ------------- iguana/exchanges/LP_network.c | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 88b064f4e..10b06b80d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -176,19 +176,6 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof nonz++; if ( (retstr= LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock)) != 0 ) free(retstr); - /*if ( (argjson= cJSON_Parse((char *)ptr)) != 0 ) - { - printf("%s SUB.[%d] %s\n",myipaddr,recvsize,jprint(argjson,0)); - portable_mutex_lock(&LP_commandmutex); - if ( (retstr= LP_command_process(myipaddr,-1,argjson,0,0,profitmargin)) != 0 ) - { - free(retstr); - } - portable_mutex_unlock(&LP_commandmutex); - free_json(argjson); - } else printf("error parsing.(%s)\n",(char *)ptr); - if ( ptr != 0 ) - nn_freemsg(ptr), ptr = 0;*/ } return(nonz); } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index a189d1bf5..8dfdd478f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -231,7 +231,7 @@ void LP_psockloop(void *_ptr) portable_mutex_unlock(&LP_psockmutex); break; } - else if ( now > ptr->lastping+60 ) + else if ( now > ptr->lastping+6 ) { ptr->lastping = now; sendsock = ptr->sendsock; @@ -328,7 +328,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) jaddstr(retjson,"publicaddr",pushaddr); jaddnum(retjson,"publicport",pushport); printf("publicaddr.(%s) for %s\n",pushaddr,subaddr); - while ( 1 ) + while ( 0 ) { printf("LP_Send %d\n",LP_send(pubsock,"hello",0)); sleep(10); From fad2841f0aebf5b29a48292ba334620c67fdb50d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:34:20 +0300 Subject: [PATCH 1728/2705] test --- iguana/exchanges/LP_nativeDEX.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 10b06b80d..1743f8e42 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -156,14 +156,17 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { - void *ptr; int32_t recvlen,nonz = 0; + void *ptr; int32_t recvlen=-1,nonz = 0; *retstrp = 0; - while ( pullsock >= 0 && (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + while ( pullsock >= 0 ) { - if ( IAMLP == 0 ) - printf("pullsock.%d recv.%d (%s)\n",pullsock,recvlen,(char *)ptr); - nonz++; - *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); + if ( (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + { + if ( IAMLP == 0 ) + printf("pullsock.%d recv.%d (%s)\n",pullsock,recvlen,(char *)ptr); + nonz++; + *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); + } else printf("pullsock.%d recvlen.%d\n",pullsock,recvlen); } return(nonz); } From ecdbef648a4a9323afa68144b641d169441cba41 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:35:04 +0300 Subject: [PATCH 1729/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1743f8e42..60065b77b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -166,7 +166,7 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t printf("pullsock.%d recv.%d (%s)\n",pullsock,recvlen,(char *)ptr); nonz++; *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); - } else printf("pullsock.%d recvlen.%d\n",pullsock,recvlen); + } //else printf("pullsock.%d recvlen.%d\n",pullsock,recvlen); } return(nonz); } From a326077dbee98da75e4940a9dfbc9af3a7883360 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:36:55 +0300 Subject: [PATCH 1730/2705] Test --- iguana/exchanges/LP_network.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 8dfdd478f..3ec9983dd 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -424,13 +424,13 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); if ( LP_canbind == 0 ) { + if ( nntype == NN_SUB ) + nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); if ( nn_connect(pullsock,connectaddr) < 0 ) { printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); exit(-1); - } else printf("nntype.%d NN_SUB.%d connect to %s\n",nntype,NN_SUB,connectaddr); - if ( nntype == NN_SUB ) - nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + } else printf("nntype.%d NN_SUB.%d connect to %s pullsock.%d\n",nntype,NN_SUB,connectaddr,pullsock); while ( 0 ) { int32_t size; void *buf; From 5ab9a062ec38afe337f343df7f7ee4705da61ccd Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:50:40 +0300 Subject: [PATCH 1731/2705] Test --- iguana/exchanges/LP_network.c | 51 ++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 3ec9983dd..68250d23d 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -107,25 +107,37 @@ void LP_psockloop(void *_ptr) { if ( size > 0 ) { - pfd.fd = ptr->sendsock; - pfd.events = NN_POLLOUT; - if ( nn_poll(&pfd,1,1) > 0 ) + if ( (sentbytes= LP_send(sendsock,buf,0)) > 0 ) + printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->recvsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); + else printf("send error to %s\n",ptr->sendaddr); + if ( buf != 0 ) { - if ( (sentbytes= nn_send(sendsock,buf,size,0)) > 0 ) - { - printf("PSOCKS (%d %d %d) -> %d/%d bytes %s\n",ptr->recvsock,ptr->sendsock,sendsock,size,sentbytes,ptr->sendaddr); - } else printf("send error to %s\n",ptr->sendaddr); - if ( buf != 0 ) - { - if ( buf != keepalive ) - nn_freemsg(buf); - buf = 0; - size = 0; - ptr = 0; - sendsock = -1; - } + if ( buf != keepalive ) + nn_freemsg(buf); + buf = 0; + size = 0; + ptr = 0; + sendsock = -1; } } + /* pfd.fd = ptr->sendsock; + pfd.events = NN_POLLOUT; + if ( nn_poll(&pfd,1,1) > 0 ) + { + if ( (sentbytes= nn_send(sendsock,buf,size,0)) > 0 ) + { + printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->recvsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); + } else printf("send error to %s\n",ptr->sendaddr); + if ( buf != 0 ) + { + if ( buf != keepalive ) + nn_freemsg(buf); + buf = 0; + size = 0; + ptr = 0; + sendsock = -1; + } + }*/ } else if ( Numpsocks > 0 ) { @@ -327,12 +339,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) jaddnum(retjson,"ispaired",ispaired); jaddstr(retjson,"publicaddr",pushaddr); jaddnum(retjson,"publicport",pushport); - printf("publicaddr.(%s) for %s\n",pushaddr,subaddr); - while ( 0 ) - { - printf("LP_Send %d\n",LP_send(pubsock,"hello",0)); - sleep(10); - } + printf("i.%d publicaddr.(%s) for %s\n",i,pushaddr,subaddr); break; } else printf("bind error on %s or %s\n",pushaddr,subaddr); if ( pullsock >= 0 ) From e4673d49c9ac509bd35fa408436969e4e29a63c5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:52:22 +0300 Subject: [PATCH 1732/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 68250d23d..f069a9d84 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -31,7 +31,7 @@ uint16_t Numpsocks,Psockport = 10000; char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { - sprintf(str,"tcp://%s:%u",bindflag == 0 ? ipaddr : "*",port); + sprintf(str,"ws://%s:%u",bindflag == 0 ? ipaddr : "*",port); return(str); } From d68173a40d65572c9cdbd5043535efa1d7a3009a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:53:55 +0300 Subject: [PATCH 1733/2705] Test --- iguana/exchanges/LP_network.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index f069a9d84..8c7e3d806 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -313,7 +313,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,pushport), pushport += 2; nanomsg_transportname(1,subaddr,myipaddr,subport), subport += 2; - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PUB)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -404,7 +404,8 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, nntype = LP_COMMAND_RECVSOCK; else nntype = NN_SUB; } - else nntype = NN_PAIR; + //else + nntype = NN_PAIR; if ( LP_canbind != 0 ) { nanomsg_transportname(0,publicaddr,myipaddr,mypullport); From 629542a6ffb0dc2dc8403e2316261cca44630b1e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:55:49 +0300 Subject: [PATCH 1734/2705] Test --- iguana/exchanges/LP_network.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 8c7e3d806..be7cb8bb3 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -402,10 +402,9 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_SUB; + else nntype = NN_PAIR; //NN_SUB; } - //else - nntype = NN_PAIR; + else nntype = NN_PAIR; if ( LP_canbind != 0 ) { nanomsg_transportname(0,publicaddr,myipaddr,mypullport); From 9259d38583a1a836213db9e6ce411e3bc9f574e1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:57:29 +0300 Subject: [PATCH 1735/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index be7cb8bb3..2c72aced1 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -65,8 +65,8 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) usleep(1000); } printf("error LP_send sock.%d, pipeline timeout.(%s) %s\n",sock,msg,nn_strerror(nn_errno())); - //if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) - // printf("LP_send sent %d instead of %d\n",sentbytes,len); + if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) + printf("LP_send sent %d instead of %d\n",sentbytes,len); if ( freeflag != 0 ) free(msg); return(-1); From b6771da96ae7bb612c07ba0e4546dfc61320b667 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 11:58:21 +0300 Subject: [PATCH 1736/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 2c72aced1..25506230b 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -31,7 +31,7 @@ uint16_t Numpsocks,Psockport = 10000; char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { - sprintf(str,"ws://%s:%u",bindflag == 0 ? ipaddr : "*",port); + sprintf(str,"tcp://%s:%u",bindflag == 0 ? ipaddr : "*",port); return(str); } From e9c3536f80ef6106a2a521646e86fea0f203716d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:00:43 +0300 Subject: [PATCH 1737/2705] Test --- iguana/exchanges/LP_network.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 25506230b..d8a7d2121 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -64,9 +64,9 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) //portable_mutex_unlock(&LP_networkmutex); usleep(1000); } - printf("error LP_send sock.%d, pipeline timeout.(%s) %s\n",sock,msg,nn_strerror(nn_errno())); - if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) - printf("LP_send sent %d instead of %d\n",sentbytes,len); + printf("error LP_send sock.%d, i.%d timeout.(%s) %s\n",sock,i,msg,nn_strerror(nn_errno())); + //if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) + // printf("LP_send sent %d instead of %d\n",sentbytes,len); if ( freeflag != 0 ) free(msg); return(-1); @@ -339,7 +339,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) jaddnum(retjson,"ispaired",ispaired); jaddstr(retjson,"publicaddr",pushaddr); jaddnum(retjson,"publicport",pushport); - printf("i.%d publicaddr.(%s) for %s\n",i,pushaddr,subaddr); + printf("i.%d publicaddr.(%s) for %s, pullsock.%d pubsock.%d\n",i,pushaddr,subaddr,pullsock,pubsock); break; } else printf("bind error on %s or %s\n",pushaddr,subaddr); if ( pullsock >= 0 ) From c94ad82fe6238aa97f0dacc5bbb7347518e51b19 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:01:56 +0300 Subject: [PATCH 1738/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index d8a7d2121..de0d94a8e 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -313,7 +313,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,pushport), pushport += 2; nanomsg_transportname(1,subaddr,myipaddr,subport), subport += 2; - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -402,7 +402,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_PAIR; //NN_SUB; + else nntype = NN_BUS; //NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) From 04794a9c0e9890c85537d1fce21184ab738ac801 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:09:47 +0300 Subject: [PATCH 1739/2705] Test --- iguana/exchanges/LP_network.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index de0d94a8e..b1b3d83e7 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -313,7 +313,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,pushport), pushport += 2; nanomsg_transportname(1,subaddr,myipaddr,subport), subport += 2; - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PUB)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -402,7 +402,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_BUS; //NN_SUB; + else nntype = NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) @@ -423,16 +423,8 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, } if ( (pullsock= nn_socket(AF_SP,nntype)) >= 0 ) { - timeout = 1; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - if ( nntype == NN_PAIR ) - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - maxsize = 2 * 1024 * 1024; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); if ( LP_canbind == 0 ) { - if ( nntype == NN_SUB ) - nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); if ( nn_connect(pullsock,connectaddr) < 0 ) { printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); @@ -455,6 +447,14 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, exit(-1); } } + timeout = 1; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + if ( nntype == NN_PAIR ) + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + maxsize = 2 * 1024 * 1024; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + if ( nntype == NN_SUB ) + nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); } if ( 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,LP_COMMAND_SENDSOCK) < 0 ) { From a7eef6a35d3b45204d93f10ef0500bddfa348b88 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:14:17 +0300 Subject: [PATCH 1740/2705] Test --- iguana/exchanges/LP_network.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index b1b3d83e7..f261a58ff 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -304,15 +304,15 @@ char *LP_psock(char *myipaddr,int32_t ispaired) retjson = cJSON_CreateObject(); pushport = Psockport++; subport = Psockport++; - for (i=0; i<100; i++) + for (i=0; i<100; i++,pushport += 2,subport += 2) { if ( pushport < 10000 ) pushport = 10001; if ( subport <= pushport ) subport = pushport + 1; pullsock = pubsock = -1; - nanomsg_transportname(1,pushaddr,myipaddr,pushport), pushport += 2; - nanomsg_transportname(1,subaddr,myipaddr,subport), subport += 2; + nanomsg_transportname(1,pushaddr,myipaddr,pushport); + nanomsg_transportname(1,subaddr,myipaddr,subport); if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PUB)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) From a4ccad7d1f3d1f6928f896bb39fa4914c3120e50 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:17:08 +0300 Subject: [PATCH 1741/2705] Test --- iguana/exchanges/LP_network.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index f261a58ff..9ed659003 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -313,7 +313,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,pushport); nanomsg_transportname(1,subaddr,myipaddr,subport); - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PUB)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -402,7 +402,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_SUB; + else nntype = NN_PAIR;//NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) @@ -430,14 +430,6 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); exit(-1); } else printf("nntype.%d NN_SUB.%d connect to %s pullsock.%d\n",nntype,NN_SUB,connectaddr,pullsock); - while ( 0 ) - { - int32_t size; void *buf; - if ( (size= nn_recv(pullsock,&buf,NN_MSG,0)) > 0 ) - printf("SUBPULL.(%s)\n",(char *)buf); - else printf("size.%d\n",size); - sleep(10); - } } else { @@ -456,7 +448,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); } - if ( 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,LP_COMMAND_SENDSOCK) < 0 ) + if ( ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PAIR) < 0 ) { printf("command socket didnt work\n"); exit(-1); From 3a6f7734f1af22aa735c3b5f5424e93debdff3be Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:18:12 +0300 Subject: [PATCH 1742/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 9ed659003..412eec997 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -448,7 +448,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); } - if ( ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PAIR) < 0 ) + if ( 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PAIR) < 0 ) { printf("command socket didnt work\n"); exit(-1); From 285642625f8866dfb3182a196ac673dea063e65b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:22:44 +0300 Subject: [PATCH 1743/2705] Test --- iguana/exchanges/LP_network.c | 41 +++++++---------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 412eec997..b75c8cbc1 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -18,7 +18,8 @@ // marketmaker // -#define PSOCK_IDLETIMEOUT (2 * INSTANTDEX_LOCKTIME + 600) +#define PSOCK_KEEPALIVE 6 + struct psock { uint32_t lasttime,lastping; @@ -99,7 +100,7 @@ uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbit void LP_psockloop(void *_ptr) { - int32_t i,n,nonz,iter,retval,size=0,sentbytes,sendsock = -1; uint32_t now; struct psock *ptr=0; void *buf=0; struct nn_pollfd pfd,*pfds; char keepalive[512];//,*myipaddr = _ptr; + int32_t i,n,nonz,iter,retval,size=0,sentbytes,sendsock = -1; uint32_t now; struct psock *ptr=0; void *buf=0; struct nn_pollfd *pfds; char keepalive[512];//,*myipaddr = _ptr; while ( 1 ) { now = (uint32_t)time(NULL); @@ -120,24 +121,6 @@ void LP_psockloop(void *_ptr) sendsock = -1; } } - /* pfd.fd = ptr->sendsock; - pfd.events = NN_POLLOUT; - if ( nn_poll(&pfd,1,1) > 0 ) - { - if ( (sentbytes= nn_send(sendsock,buf,size,0)) > 0 ) - { - printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->recvsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); - } else printf("send error to %s\n",ptr->sendaddr); - if ( buf != 0 ) - { - if ( buf != keepalive ) - nn_freemsg(buf); - buf = 0; - size = 0; - ptr = 0; - sendsock = -1; - } - }*/ } else if ( Numpsocks > 0 ) { @@ -165,7 +148,6 @@ void LP_psockloop(void *_ptr) printf("%s has pollin\n",ptr->sendaddr); if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) { - ptr->lasttime = now; sendsock = ptr->sendsock; printf("[%s]\n",(char *)buf); break; @@ -173,7 +155,7 @@ void LP_psockloop(void *_ptr) } } n++; - if ( ptr->ispaired != 0 ) + //if ( ptr->ispaired != 0 ) { if ( iter == 0 ) { @@ -220,14 +202,7 @@ void LP_psockloop(void *_ptr) if ( i < Numpsocks ) { ptr = &PSOCKS[i]; - /*if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) - { - printf("got %d bytes for %s\n",size,ptr->sendaddr); - ptr->lasttime = now; - sendsock = ptr->sendsock; - break; - } - else*/ if ( now > ptr->lasttime+PSOCK_IDLETIMEOUT ) + if ( now > ptr->lasttime+PSOCK_KEEPALIVE ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->recvport,ptr->sendport,now - ptr->lasttime); if ( ptr->recvsock >= 0 ) @@ -243,11 +218,11 @@ void LP_psockloop(void *_ptr) portable_mutex_unlock(&LP_psockmutex); break; } - else if ( now > ptr->lastping+6 ) + else if ( now > ptr->lastping+PSOCK_KEEPALIVE ) { ptr->lastping = now; sendsock = ptr->sendsock; - printf("keep %s alive\n",ptr->sendaddr); + //printf("keep %s alive\n",ptr->sendaddr); sprintf(keepalive,"{\"method\":\"keepalive\",\"endpoint\":\"%s\"}",ptr->sendaddr); size = (int32_t)strlen(keepalive) + 1; buf = keepalive; @@ -304,7 +279,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) retjson = cJSON_CreateObject(); pushport = Psockport++; subport = Psockport++; - for (i=0; i<100; i++,pushport += 2,subport += 2) + for (i=0; i<100; i++,pushport+=2,subport+=2) { if ( pushport < 10000 ) pushport = 10001; From 655f7f359d602cbb286f9e7c0b7d6578f831441a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:28:37 +0300 Subject: [PATCH 1744/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 60065b77b..77df59431 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -162,11 +162,9 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t { if ( (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { - if ( IAMLP == 0 ) - printf("pullsock.%d recv.%d (%s)\n",pullsock,recvlen,(char *)ptr); nonz++; *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); - } //else printf("pullsock.%d recvlen.%d\n",pullsock,recvlen); + } } return(nonz); } @@ -369,7 +367,7 @@ void LP_initpeers(int32_t pubsock,struct LP_peerinfo *mypeer,char *myipaddr,uint void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; + char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128],keepalive[128]; IAMLP = !amclient; #ifndef __linux__ if ( IAMLP != 0 ) @@ -458,14 +456,22 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit printf("mainloop\n"); if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin) == 0 ) usleep(100000); - if ( LP_canbind == 0 && LP_deadman_switch < time(NULL)-777 ) + if ( LP_canbind == 0 ) { - printf("DEAD man's switch activated, register forwarding again\n"); - if ( pullsock >= 0 ) - nn_close(pullsock); - pullsock = LP_initpublicaddr(&mypullport,pushaddr,myipaddr,mypullport,0); - LP_deadman_switch = (uint32_t)time(NULL); - LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,100000); + if ( LP_deadman_switch < time(NULL)-PSOCK_KEEPALIVE ) + { + printf("DEAD man's switch activated, register forwarding again\n"); + if ( pullsock >= 0 ) + nn_close(pullsock); + pullsock = LP_initpublicaddr(&mypullport,pushaddr,myipaddr,mypullport,0); + LP_deadman_switch = (uint32_t)time(NULL); + LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,100000); + } + else + { + sprintf(keepalive,"{\"method\":\"keepalive\"}"); + LP_send(pullsock,keepalive,0); + } } } } From 1f29a7562cc0b2347ee094fbaa2bf674cde60a6b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:30:04 +0300 Subject: [PATCH 1745/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 77df59431..ef3c1660b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -471,6 +471,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { sprintf(keepalive,"{\"method\":\"keepalive\"}"); LP_send(pullsock,keepalive,0); + printf("send keepalive\n"); } } } From dff29527c388d614b88cfeebab159e76819bb99e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:31:10 +0300 Subject: [PATCH 1746/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ef3c1660b..ed52707eb 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -467,7 +467,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit LP_deadman_switch = (uint32_t)time(NULL); LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,100000); } - else + else if ( LP_deadman_switch < time(NULL)-PSOCK_KEEPALIVE/2 ) { sprintf(keepalive,"{\"method\":\"keepalive\"}"); LP_send(pullsock,keepalive,0); From 2cc4fdb7dce6cd25b4b91f30b30b77c648f328b4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:37:04 +0300 Subject: [PATCH 1747/2705] Test --- iguana/exchanges/LP_network.c | 41 ++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index b75c8cbc1..03066b98a 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -155,29 +155,35 @@ void LP_psockloop(void *_ptr) } } n++; - //if ( ptr->ispaired != 0 ) + if ( iter == 0 ) { - if ( iter == 0 ) + pfds[n].fd = ptr->sendsock; + pfds[n].events = POLLIN; + } + else + { + if ( pfds[n].fd != ptr->sendsock ) { - pfds[n].fd = ptr->sendsock; - pfds[n].events = POLLIN; + printf("unexpected fd.%d mismatched sendsock.%d\n",pfds[n].fd,ptr->sendsock); + break; } - else + else if ( (pfds[n].revents & POLLIN) != 0 ) { - if ( pfds[n].fd != ptr->sendsock ) + printf("%s paired has pollin\n",ptr->sendaddr); + if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) { - printf("unexpected fd.%d mismatched sendsock.%d\n",pfds[n].fd,ptr->sendsock); - break; - } - else if ( (pfds[n].revents & POLLIN) != 0 ) - { - printf("%s paired has pollin\n",ptr->sendaddr); - if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) + ptr->lasttime = now; + if ( ptr->ispaired != 0 ) { - ptr->lasttime = now; sendsock = ptr->recvsock; break; } + else + { + nn_freemsg(buf); + buf = 0; + size = 0; + } } } n++; @@ -292,13 +298,13 @@ char *LP_psock(char *myipaddr,int32_t ispaired) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { - timeout = 10; + timeout = 1; nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); maxsize = 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - if ( ispaired != 0 ) + //if ( ispaired != 0 ) { nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); @@ -378,8 +384,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; else nntype = NN_PAIR;//NN_SUB; - } - else nntype = NN_PAIR; + } else nntype = NN_PAIR; if ( LP_canbind != 0 ) { nanomsg_transportname(0,publicaddr,myipaddr,mypullport); From 2dddc8f54b1baaa41bc96d1530d847a64a63f291 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:38:25 +0300 Subject: [PATCH 1748/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 03066b98a..d676b1a8d 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -18,7 +18,7 @@ // marketmaker // -#define PSOCK_KEEPALIVE 6 +#define PSOCK_KEEPALIVE 60 struct psock { From d458b327d43452dc8718f5cd62b05b560a16cb79 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:41:09 +0300 Subject: [PATCH 1749/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ed52707eb..18f44c125 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -298,6 +298,13 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso free(retstr); if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); + if ( LP_canbind == 0 && (counter % 60) == 13 ) + { + char keepalive[128]; + sprintf(keepalive,"{\"method\":\"keepalive\"}"); + LP_send(pullsock,keepalive,0); + printf("send keepalive\n"); + } counter++; return(nonz); } @@ -367,7 +374,7 @@ void LP_initpeers(int32_t pubsock,struct LP_peerinfo *mypeer,char *myipaddr,uint void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128],keepalive[128]; + char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; IAMLP = !amclient; #ifndef __linux__ if ( IAMLP != 0 ) @@ -467,12 +474,6 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit LP_deadman_switch = (uint32_t)time(NULL); LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,100000); } - else if ( LP_deadman_switch < time(NULL)-PSOCK_KEEPALIVE/2 ) - { - sprintf(keepalive,"{\"method\":\"keepalive\"}"); - LP_send(pullsock,keepalive,0); - printf("send keepalive\n"); - } } } } From 2fe97816afb32f5e0ffd6112c9f61aadc63359c0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:47:08 +0300 Subject: [PATCH 1750/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 18f44c125..723d5c96b 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -235,6 +235,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso origipaddr = "127.0.0.1"; if ( mypeer == 0 ) myipaddr = "127.0.0.1"; + if ( LP_canbind == 0 ) printf("counter.%d canbind.%d peers\n",counter,LP_canbind); numpeers = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -263,6 +264,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } nonz += LP_subsock_check(origipaddr,pubsock,peer->subsock,profitmargin); } + if ( LP_canbind == 0 ) printf("counter.%d canbind.%d forwarding\n",counter,LP_canbind); if ( (counter % 600) == 60 ) { LP_myutxo_updates(pubsock,passphrase,profitmargin); @@ -272,6 +274,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso lastforward = now; } } + if ( LP_canbind == 0 ) printf("counter.%d canbind.%d utxos\n",counter,LP_canbind); if ( (counter % 600) == 0 ) { HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) @@ -285,6 +288,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_utxo_clientpublish(utxo); } } + if ( LP_canbind == 0 ) printf("counter.%d canbind.%d swapentry\n",counter,LP_canbind); if ( (counter % 600) == 599 ) { if ( (retstr= basilisk_swapentry(0,0)) != 0 ) @@ -293,11 +297,13 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso free(retstr); } } + if ( LP_canbind == 0 ) printf("counter.%d canbind.%d\n",counter,LP_canbind); nonz += LP_pullsock_check(&retstr,myipaddr,pubsock,pullsock,profitmargin); if ( retstr != 0 ) free(retstr); if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); + if ( LP_canbind == 0 ) printf("counter.%d canbind.%d\n",counter,LP_canbind); if ( LP_canbind == 0 && (counter % 60) == 13 ) { char keepalive[128]; From 6fdbe4ceb9d2e1a2dc596b15ccd24cb7fb7828d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:52:14 +0300 Subject: [PATCH 1751/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 723d5c96b..4ef2345be 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -465,12 +465,13 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } while ( 1 ) { - if ( 0 && (rand() % 100) == 0 ) + if ( LP_canbind == 0 ) printf("mainloop\n"); if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin) == 0 ) usleep(100000); if ( LP_canbind == 0 ) { + printf("check deadman %u vs %u\n",LP_deadman_switch,(uint32_t)time(NULL)); if ( LP_deadman_switch < time(NULL)-PSOCK_KEEPALIVE ) { printf("DEAD man's switch activated, register forwarding again\n"); From e517a65086efaca9ae73f469d6fbdde413cd272a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:53:12 +0300 Subject: [PATCH 1752/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 2a1880b42..09a329480 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -215,7 +215,7 @@ forwardhex(pubkey,hex)\n\ { printf("got keepalive lag.%d\n",(int32_t)time(NULL) - LP_deadman_switch); LP_deadman_switch = (uint32_t)time(NULL); - return(0); + return(clonestr("{\"result\":\"success\"}")); } else if ( strcmp(method,"getpeers") == 0 ) return(LP_peers()); From bd061c313583221661ccf58c4509554afed1f231 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:55:35 +0300 Subject: [PATCH 1753/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4ef2345be..d94acdc26 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -164,6 +164,7 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t { nonz++; *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); + printf("got retstr.%p\n",*retstrp); } } return(nonz); @@ -297,10 +298,11 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso free(retstr); } } - if ( LP_canbind == 0 ) printf("counter.%d canbind.%d\n",counter,LP_canbind); + if ( LP_canbind == 0 ) printf("counter.%d canbind.%d pullsock check\n",counter,LP_canbind); nonz += LP_pullsock_check(&retstr,myipaddr,pubsock,pullsock,profitmargin); if ( retstr != 0 ) free(retstr); + if ( LP_canbind == 0 ) printf("counter.%d canbind.%d hellos\n",counter,LP_canbind); if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); if ( LP_canbind == 0 ) printf("counter.%d canbind.%d\n",counter,LP_canbind); @@ -308,8 +310,9 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); - LP_send(pullsock,keepalive,0); printf("send keepalive\n"); + LP_send(pullsock,keepalive,0); + printf("sent keepalive\n"); } counter++; return(nonz); From ced6fd608a13a574f180ff1e675ed628e0a9d4ae Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 12:57:42 +0300 Subject: [PATCH 1754/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d94acdc26..7e2ed4b87 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -301,7 +301,11 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso if ( LP_canbind == 0 ) printf("counter.%d canbind.%d pullsock check\n",counter,LP_canbind); nonz += LP_pullsock_check(&retstr,myipaddr,pubsock,pullsock,profitmargin); if ( retstr != 0 ) + { + printf("free (%s)\n",retstr); free(retstr); + printf("Freed\n"); + } if ( LP_canbind == 0 ) printf("counter.%d canbind.%d hellos\n",counter,LP_canbind); if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); From c58b04ab12fdcb56048458c7f9f03cb1fa1ec599 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:00:31 +0300 Subject: [PATCH 1755/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7e2ed4b87..1afb731f5 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -158,9 +158,9 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t { void *ptr; int32_t recvlen=-1,nonz = 0; *retstrp = 0; - while ( pullsock >= 0 ) + if ( pullsock >= 0 ) { - if ( (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + while ( (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) { nonz++; *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); @@ -173,11 +173,14 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double profitmargin) { int32_t recvlen,nonz = 0; void *ptr; char *retstr; - while ( sock >= 0 && (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) + if ( sock >= 0 ) { - nonz++; - if ( (retstr= LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock)) != 0 ) - free(retstr); + while ( (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) + { + nonz++; + if ( (retstr= LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock)) != 0 ) + free(retstr); + } } return(nonz); } From db86f30637bdbcdd21464d31b53807f79d92c9ec Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:02:07 +0300 Subject: [PATCH 1756/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1afb731f5..958408524 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -164,7 +164,6 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t { nonz++; *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); - printf("got retstr.%p\n",*retstrp); } } return(nonz); @@ -239,7 +238,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso origipaddr = "127.0.0.1"; if ( mypeer == 0 ) myipaddr = "127.0.0.1"; - if ( LP_canbind == 0 ) printf("counter.%d canbind.%d peers\n",counter,LP_canbind); + //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d peers\n",counter,LP_canbind); numpeers = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { @@ -268,7 +267,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } nonz += LP_subsock_check(origipaddr,pubsock,peer->subsock,profitmargin); } - if ( LP_canbind == 0 ) printf("counter.%d canbind.%d forwarding\n",counter,LP_canbind); + //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d forwarding\n",counter,LP_canbind); if ( (counter % 600) == 60 ) { LP_myutxo_updates(pubsock,passphrase,profitmargin); @@ -278,7 +277,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso lastforward = now; } } - if ( LP_canbind == 0 ) printf("counter.%d canbind.%d utxos\n",counter,LP_canbind); + //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d utxos\n",counter,LP_canbind); if ( (counter % 600) == 0 ) { HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) @@ -292,7 +291,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_utxo_clientpublish(utxo); } } - if ( LP_canbind == 0 ) printf("counter.%d canbind.%d swapentry\n",counter,LP_canbind); + //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d swapentry\n",counter,LP_canbind); if ( (counter % 600) == 599 ) { if ( (retstr= basilisk_swapentry(0,0)) != 0 ) @@ -301,25 +300,20 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso free(retstr); } } - if ( LP_canbind == 0 ) printf("counter.%d canbind.%d pullsock check\n",counter,LP_canbind); + //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d pullsock check\n",counter,LP_canbind); nonz += LP_pullsock_check(&retstr,myipaddr,pubsock,pullsock,profitmargin); if ( retstr != 0 ) - { - printf("free (%s)\n",retstr); free(retstr); - printf("Freed\n"); - } - if ( LP_canbind == 0 ) printf("counter.%d canbind.%d hellos\n",counter,LP_canbind); + //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d hellos\n",counter,LP_canbind); if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); - if ( LP_canbind == 0 ) printf("counter.%d canbind.%d\n",counter,LP_canbind); + //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d\n",counter,LP_canbind); if ( LP_canbind == 0 && (counter % 60) == 13 ) { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); printf("send keepalive\n"); LP_send(pullsock,keepalive,0); - printf("sent keepalive\n"); } counter++; return(nonz); @@ -475,13 +469,11 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } while ( 1 ) { - if ( LP_canbind == 0 ) - printf("mainloop\n"); if ( LP_mainloop_iter(myipaddr,mypeer,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin) == 0 ) usleep(100000); if ( LP_canbind == 0 ) { - printf("check deadman %u vs %u\n",LP_deadman_switch,(uint32_t)time(NULL)); + //printf("check deadman %u vs %u\n",LP_deadman_switch,(uint32_t)time(NULL)); if ( LP_deadman_switch < time(NULL)-PSOCK_KEEPALIVE ) { printf("DEAD man's switch activated, register forwarding again\n"); From 0b51b6b26d3a849e8013cd14769013a42f343091 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:14:41 +0300 Subject: [PATCH 1757/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 958408524..503e1904a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -312,7 +312,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); - printf("send keepalive\n"); + //printf("send keepalive\n"); LP_send(pullsock,keepalive,0); } counter++; diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index d676b1a8d..2ade33b1e 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -145,11 +145,11 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - printf("%s has pollin\n",ptr->sendaddr); + //printf("%s has pollin\n",ptr->sendaddr); if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) { sendsock = ptr->sendsock; - printf("[%s]\n",(char *)buf); + //printf("[%s]\n",(char *)buf); break; } } @@ -169,7 +169,7 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - printf("%s paired has pollin\n",ptr->sendaddr); + //printf("%s paired has pollin\n",ptr->sendaddr); if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) { ptr->lasttime = now; From 515b8a75ec930dc0caa334bf7d772739484cc14a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:24:30 +0300 Subject: [PATCH 1758/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 09a329480..4cc96c755 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -213,7 +213,7 @@ forwardhex(pubkey,hex)\n\ } else if ( strcmp(method,"keepalive") == 0 ) { - printf("got keepalive lag.%d\n",(int32_t)time(NULL) - LP_deadman_switch); + printf("got keepalive lag.%d switch.%u\n",(int32_t)time(NULL) - LP_deadman_switch,LP_deadman_switch); LP_deadman_switch = (uint32_t)time(NULL); return(clonestr("{\"result\":\"success\"}")); } diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 503e1904a..1f7b74932 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -476,7 +476,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit //printf("check deadman %u vs %u\n",LP_deadman_switch,(uint32_t)time(NULL)); if ( LP_deadman_switch < time(NULL)-PSOCK_KEEPALIVE ) { - printf("DEAD man's switch activated, register forwarding again\n"); + printf("DEAD man's switch %u activated at %u lag.%d, register forwarding again\n",LP_deadman_switch,(uint32_t)time(NULL),(uint32_t)(time(NULL) - LP_deadman_switch)); if ( pullsock >= 0 ) nn_close(pullsock); pullsock = LP_initpublicaddr(&mypullport,pushaddr,myipaddr,mypullport,0); From 14f9769cb827796eef6b14f97d5d7120c59109f5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:27:46 +0300 Subject: [PATCH 1759/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 2ade33b1e..5394c2d05 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -224,7 +224,7 @@ void LP_psockloop(void *_ptr) portable_mutex_unlock(&LP_psockmutex); break; } - else if ( now > ptr->lastping+PSOCK_KEEPALIVE ) + else if ( now > ptr->lastping+PSOCK_KEEPALIVE/2 ) { ptr->lastping = now; sendsock = ptr->sendsock; From 2d071816ef9a8ad9dc319d02aa126bf0dcf6d209 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:31:35 +0300 Subject: [PATCH 1760/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 5394c2d05..303459fe4 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -169,9 +169,9 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - //printf("%s paired has pollin\n",ptr->sendaddr); if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) { + printf("%s paired has pollin (%s)\n",ptr->sendaddr,(char *)buf); ptr->lasttime = now; if ( ptr->ispaired != 0 ) { @@ -208,7 +208,7 @@ void LP_psockloop(void *_ptr) if ( i < Numpsocks ) { ptr = &PSOCKS[i]; - if ( now > ptr->lasttime+PSOCK_KEEPALIVE ) + if ( now > ptr->lasttime+PSOCK_KEEPALIVE*2 ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->recvport,ptr->sendport,now - ptr->lasttime); if ( ptr->recvsock >= 0 ) From b7d882ad9649c6d3bba72951620dec557c318818 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:34:31 +0300 Subject: [PATCH 1761/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1f7b74932..33aff2988 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -312,7 +312,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); - //printf("send keepalive\n"); + printf("send keepalive\n"); LP_send(pullsock,keepalive,0); } counter++; From 3f254b0b7ea9c2803a93d8d3a8aebc26b64af40b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:35:08 +0300 Subject: [PATCH 1762/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 33aff2988..49ef0ac3e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -312,7 +312,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); - printf("send keepalive\n"); + printf("send keepalive to %s\n",pushaddr); LP_send(pullsock,keepalive,0); } counter++; From 39797f0e8f7fc405f284ead61fba892daa56c912 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:40:37 +0300 Subject: [PATCH 1763/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 49ef0ac3e..4e3f5da47 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -312,8 +312,9 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); - printf("send keepalive to %s\n",pushaddr); - LP_send(pullsock,keepalive,0); + printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); + if ( LP_send(pullsock,keepalive,0) < 0 ) + LP_deadman_switch = 0; } counter++; return(nonz); From 8cc3141fb9eb4205750a6052c15a658c649e5625 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:46:09 +0300 Subject: [PATCH 1764/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 4e3f5da47..58c082160 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -160,7 +160,7 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t *retstrp = 0; if ( pullsock >= 0 ) { - while ( (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) >= 0 ) + while ( (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) > 0 ) { nonz++; *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); @@ -174,7 +174,7 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof int32_t recvlen,nonz = 0; void *ptr; char *retstr; if ( sock >= 0 ) { - while ( (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) >= 0 ) + while ( (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) > 0 ) { nonz++; if ( (retstr= LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock)) != 0 ) From ea6fc93be45024d5d5fd5034d5928183f4c93005 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:49:49 +0300 Subject: [PATCH 1765/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 303459fe4..5ad630bfd 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -294,7 +294,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,pushport); nanomsg_transportname(1,subaddr,myipaddr,subport); - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -383,7 +383,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_PAIR;//NN_SUB; + else nntype = NN_BUS;//NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) { From 597f270d601239f8ddc121f07ab9e214654715c0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:52:53 +0300 Subject: [PATCH 1766/2705] Test --- iguana/exchanges/LP_network.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 5ad630bfd..70260f95f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -421,8 +421,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, } timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - if ( nntype == NN_PAIR ) - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); if ( nntype == NN_SUB ) From e4068f3b7577dde9413bc5474a17542d7b3f4646 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 13:59:42 +0300 Subject: [PATCH 1767/2705] Test --- iguana/exchanges/LP_network.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 70260f95f..371e8a6de 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -228,7 +228,6 @@ void LP_psockloop(void *_ptr) { ptr->lastping = now; sendsock = ptr->sendsock; - //printf("keep %s alive\n",ptr->sendaddr); sprintf(keepalive,"{\"method\":\"keepalive\",\"endpoint\":\"%s\"}",ptr->sendaddr); size = (int32_t)strlen(keepalive) + 1; buf = keepalive; @@ -294,7 +293,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,pushport); nanomsg_transportname(1,subaddr,myipaddr,subport); - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -383,7 +382,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_BUS;//NN_SUB; + else nntype = NN_PAIR;//NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) { From 98b42d635ab55b2354ff6264a7e1f6c93d3b654f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:05:49 +0300 Subject: [PATCH 1768/2705] Test --- iguana/exchanges/LP_network.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 371e8a6de..f0e64735f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -191,7 +191,7 @@ void LP_psockloop(void *_ptr) } if ( iter == 0 ) { - if ( (retval= nn_poll(pfds,n,10)) <= 0 ) + if ( (retval= nn_poll(pfds,n,1)) <= 0 ) { if ( retval != 0 ) printf("nn_poll retval.%d\n",retval); @@ -297,7 +297,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { - timeout = 1; + timeout = 10; nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); @@ -420,6 +420,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, } timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + timeout = 10; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); From 1f37eb816a5aaff0a4853a9ff7bf6c6f0ae10cee Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:16:08 +0300 Subject: [PATCH 1769/2705] Test --- iguana/exchanges/LP_network.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index f0e64735f..382fa95db 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -32,7 +32,7 @@ uint16_t Numpsocks,Psockport = 10000; char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { - sprintf(str,"tcp://%s:%u",bindflag == 0 ? ipaddr : "*",port); + sprintf(str,"ws://%s:%u",bindflag == 0 ? ipaddr : "*",port); return(str); } @@ -297,7 +297,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { - timeout = 10; + timeout = 1; nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); @@ -319,7 +319,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) jaddnum(retjson,"ispaired",ispaired); jaddstr(retjson,"publicaddr",pushaddr); jaddnum(retjson,"publicport",pushport); - printf("i.%d publicaddr.(%s) for %s, pullsock.%d pubsock.%d\n",i,pushaddr,subaddr,pullsock,pubsock); + printf("i.%d publicaddr.(%s) for subaddr.(%s), pullsock.%d pubsock.%d\n",i,pushaddr,subaddr,pullsock,pubsock); break; } else printf("bind error on %s or %s\n",pushaddr,subaddr); if ( pullsock >= 0 ) @@ -420,7 +420,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, } timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - timeout = 10; + timeout = 1; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); maxsize = 2 * 1024 * 1024; nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); From 553a16d97bbf177250e4b77e6fa091378a6508f4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:18:14 +0300 Subject: [PATCH 1770/2705] Test --- iguana/exchanges/LP_network.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 382fa95db..6e833bdb0 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -426,6 +426,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); + LP_send(pullsock,"hello init",0); } if ( 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PAIR) < 0 ) { From 06b0884f3280e6dd90397e6f00e532312d7d519b Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:20:41 +0300 Subject: [PATCH 1771/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 6e833bdb0..4e01c73e3 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -196,7 +196,7 @@ void LP_psockloop(void *_ptr) if ( retval != 0 ) printf("nn_poll retval.%d\n",retval); break; - } + } else printf("num pfds.%d\n",n); } } portable_mutex_unlock(&LP_psockmutex); From 9e62e833f2f5c3d243453b76e2eb444300d7e447 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:23:24 +0300 Subject: [PATCH 1772/2705] Test --- iguana/exchanges/LP_network.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 4e01c73e3..536a2a788 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -145,7 +145,7 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - //printf("%s has pollin\n",ptr->sendaddr); + printf("%s has pollin\n",ptr->sendaddr); if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) { sendsock = ptr->sendsock; @@ -169,9 +169,9 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { + printf("%s paired has pollin (%s)\n",ptr->sendaddr,(char *)buf); if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) { - printf("%s paired has pollin (%s)\n",ptr->sendaddr,(char *)buf); ptr->lasttime = now; if ( ptr->ispaired != 0 ) { @@ -196,7 +196,7 @@ void LP_psockloop(void *_ptr) if ( retval != 0 ) printf("nn_poll retval.%d\n",retval); break; - } else printf("num pfds.%d\n",n); + } else printf("num pfds.%d retval.%d\n",n,retval); } } portable_mutex_unlock(&LP_psockmutex); From a571558c2cb4b99a411f73a9bcb23f72c8c4d265 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:29:48 +0300 Subject: [PATCH 1773/2705] Test --- iguana/exchanges/LP_network.c | 56 +++++++++++++++++------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 536a2a788..86987340f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -23,8 +23,8 @@ struct psock { uint32_t lasttime,lastping; - int32_t recvsock,sendsock,ispaired; - uint16_t recvport,sendport; + int32_t publicsock,sendsock,ispaired; + uint16_t publicport,sendport; char sendaddr[128],publicaddr[128]; } *PSOCKS; @@ -109,7 +109,7 @@ void LP_psockloop(void *_ptr) if ( size > 0 ) { if ( (sentbytes= LP_send(sendsock,buf,0)) > 0 ) - printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->recvsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); + printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); else printf("send error to %s\n",ptr->sendaddr); if ( buf != 0 ) { @@ -133,23 +133,23 @@ void LP_psockloop(void *_ptr) ptr = &PSOCKS[i]; if ( iter == 0 ) { - pfds[n].fd = ptr->recvsock; + pfds[n].fd = ptr->publicsock; pfds[n].events = POLLIN; } else { - if ( pfds[n].fd != ptr->recvsock ) + if ( pfds[n].fd != ptr->publicsock ) { - printf("unexpected fd.%d mismatched recvsock.%d\n",pfds[n].fd,ptr->recvsock); + printf("unexpected fd.%d mismatched publicsock.%d\n",pfds[n].fd,ptr->publicsock); break; } else if ( (pfds[n].revents & POLLIN) != 0 ) { - printf("%s has pollin\n",ptr->sendaddr); - if ( (size= nn_recv(ptr->recvsock,&buf,NN_MSG,0)) > 0 ) + printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); + if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { sendsock = ptr->sendsock; - //printf("[%s]\n",(char *)buf); + printf("[%s] -> sendsock.%d\n",(char *)buf,sendsock); break; } } @@ -175,7 +175,7 @@ void LP_psockloop(void *_ptr) ptr->lasttime = now; if ( ptr->ispaired != 0 ) { - sendsock = ptr->recvsock; + sendsock = ptr->publicsock; break; } else @@ -196,7 +196,7 @@ void LP_psockloop(void *_ptr) if ( retval != 0 ) printf("nn_poll retval.%d\n",retval); break; - } else printf("num pfds.%d retval.%d\n",n,retval); + } // else printf("num pfds.%d retval.%d\n",n,retval); } } portable_mutex_unlock(&LP_psockmutex); @@ -210,9 +210,9 @@ void LP_psockloop(void *_ptr) ptr = &PSOCKS[i]; if ( now > ptr->lasttime+PSOCK_KEEPALIVE*2 ) { - printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->recvport,ptr->sendport,now - ptr->lasttime); - if ( ptr->recvsock >= 0 ) - nn_close(ptr->recvsock); + printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->publicport,ptr->sendport,now - ptr->lasttime); + if ( ptr->publicsock >= 0 ) + nn_close(ptr->publicsock); if ( ptr->sendsock >= 0 ) nn_close(ptr->sendsock); portable_mutex_lock(&LP_psockmutex); @@ -242,15 +242,15 @@ void LP_psockloop(void *_ptr) } } -void LP_psockadd(int32_t ispaired,int32_t recvsock,uint16_t recvport,int32_t sendsock,uint16_t sendport,char *subaddr,char *publicaddr) +void LP_psockadd(int32_t ispaired,int32_t publicsock,uint16_t recvport,int32_t sendsock,uint16_t sendport,char *subaddr,char *publicaddr) { struct psock *ptr; portable_mutex_lock(&LP_psockmutex); PSOCKS = realloc(PSOCKS,sizeof(*PSOCKS) * (Numpsocks + 1)); ptr = &PSOCKS[Numpsocks++]; ptr->ispaired = ispaired; - ptr->recvsock = recvsock; - ptr->recvport = recvport; + ptr->publicsock = publicsock; + ptr->publicport = recvport; ptr->sendsock = sendsock; ptr->sendport = sendport; safecopy(ptr->sendaddr,subaddr,sizeof(ptr->sendaddr)); @@ -280,18 +280,18 @@ int32_t LP_psockmark(char *publicaddr) char *LP_psock(char *myipaddr,int32_t ispaired) { - char pushaddr[128],subaddr[128]; uint16_t i,pushport,subport; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; cJSON *retjson=0; + char pushaddr[128],subaddr[128]; uint16_t i,publicport,subport; int32_t timeout,maxsize,pullsock=-1,pubsock=-1; cJSON *retjson=0; retjson = cJSON_CreateObject(); - pushport = Psockport++; + publicport = Psockport++; subport = Psockport++; - for (i=0; i<100; i++,pushport+=2,subport+=2) + for (i=0; i<100; i++,publicport+=2,subport+=2) { - if ( pushport < 10000 ) - pushport = 10001; - if ( subport <= pushport ) - subport = pushport + 1; + if ( publicport < 10000 ) + publicport = 10001; + if ( subport <= publicport ) + subport = publicport + 1; pullsock = pubsock = -1; - nanomsg_transportname(1,pushaddr,myipaddr,pushport); + nanomsg_transportname(1,pushaddr,myipaddr,publicport); nanomsg_transportname(1,subaddr,myipaddr,subport); if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) { @@ -309,16 +309,16 @@ char *LP_psock(char *myipaddr,int32_t ispaired) nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); nn_setsockopt(pubsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); } - nanomsg_transportname(0,pushaddr,myipaddr,pushport); + nanomsg_transportname(0,pushaddr,myipaddr,publicport); nanomsg_transportname(0,subaddr,myipaddr,subport); - LP_psockadd(ispaired,pullsock,pushport,pubsock,subport,subaddr,pushaddr); + LP_psockadd(ispaired,pullsock,publicport,pubsock,subport,subaddr,pushaddr); jaddstr(retjson,"result","success"); jaddstr(retjson,"LPipaddr",myipaddr); jaddstr(retjson,"connectaddr",subaddr); jaddnum(retjson,"connectport",subport); jaddnum(retjson,"ispaired",ispaired); jaddstr(retjson,"publicaddr",pushaddr); - jaddnum(retjson,"publicport",pushport); + jaddnum(retjson,"publicport",publicport); printf("i.%d publicaddr.(%s) for subaddr.(%s), pullsock.%d pubsock.%d\n",i,pushaddr,subaddr,pullsock,pubsock); break; } else printf("bind error on %s or %s\n",pushaddr,subaddr); From a8a3db008c00cdefb7e952a0a33d4a0db5771b81 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:41:27 +0300 Subject: [PATCH 1774/2705] Test --- iguana/exchanges/LP_network.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 86987340f..ff468217c 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -32,7 +32,7 @@ uint16_t Numpsocks,Psockport = 10000; char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { - sprintf(str,"ws://%s:%u",bindflag == 0 ? ipaddr : "*",port); + sprintf(str,"tcp://%s:%u",bindflag == 0 ? ipaddr : "*",port); return(str); } @@ -249,10 +249,10 @@ void LP_psockadd(int32_t ispaired,int32_t publicsock,uint16_t recvport,int32_t s PSOCKS = realloc(PSOCKS,sizeof(*PSOCKS) * (Numpsocks + 1)); ptr = &PSOCKS[Numpsocks++]; ptr->ispaired = ispaired; - ptr->publicsock = publicsock; - ptr->publicport = recvport; - ptr->sendsock = sendsock; - ptr->sendport = sendport; + ptr->publicsock = sendsock;//publicsock; + ptr->publicport = sendport;//recvport; + ptr->sendsock = publicsock;//sendsock; + ptr->sendport = recvport;//sendport; safecopy(ptr->sendaddr,subaddr,sizeof(ptr->sendaddr)); safecopy(ptr->publicaddr,publicaddr,sizeof(ptr->publicaddr)); ptr->lasttime = (uint32_t)time(NULL); @@ -408,7 +408,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); exit(-1); - } else printf("nntype.%d NN_SUB.%d connect to %s pullsock.%d\n",nntype,NN_SUB,connectaddr,pullsock); + } else printf("nntype.%d NN_PAIR.%d connect to %s pullsock.%d\n",nntype,NN_PAIR,connectaddr,pullsock); } else { From 2fa7ad229c98d4ca5d812d5133274470ed3f3538 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:47:09 +0300 Subject: [PATCH 1775/2705] Test --- iguana/exchanges/LP_network.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index ff468217c..553bf7597 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -249,10 +249,10 @@ void LP_psockadd(int32_t ispaired,int32_t publicsock,uint16_t recvport,int32_t s PSOCKS = realloc(PSOCKS,sizeof(*PSOCKS) * (Numpsocks + 1)); ptr = &PSOCKS[Numpsocks++]; ptr->ispaired = ispaired; - ptr->publicsock = sendsock;//publicsock; - ptr->publicport = sendport;//recvport; - ptr->sendsock = publicsock;//sendsock; - ptr->sendport = recvport;//sendport; + ptr->publicsock = publicsock; + ptr->publicport = recvport; + ptr->sendsock = sendsock; + ptr->sendport = sendport; safecopy(ptr->sendaddr,subaddr,sizeof(ptr->sendaddr)); safecopy(ptr->publicaddr,publicaddr,sizeof(ptr->publicaddr)); ptr->lasttime = (uint32_t)time(NULL); From c4ab07bbef92b913fc697264d96aadfff9da1161 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:48:50 +0300 Subject: [PATCH 1776/2705] Test --- iguana/exchanges/LP_network.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 553bf7597..58ae1c8e1 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -148,6 +148,7 @@ void LP_psockloop(void *_ptr) printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { + ptr->lasttime = now; sendsock = ptr->sendsock; printf("[%s] -> sendsock.%d\n",(char *)buf,sendsock); break; From 78fe51f6c494f977be8dce6bc1c972ba0690c101 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:52:44 +0300 Subject: [PATCH 1777/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 58ae1c8e1..7be68096f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -145,7 +145,7 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); + //printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { ptr->lasttime = now; From 5064fc08aae751aa58f1479629a028849db517cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 14:56:59 +0300 Subject: [PATCH 1778/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 58c082160..82dbcfc35 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -312,7 +312,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); - printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); + //printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); if ( LP_send(pullsock,keepalive,0) < 0 ) LP_deadman_switch = 0; } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 7be68096f..5eaf5a71f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -109,8 +109,9 @@ void LP_psockloop(void *_ptr) if ( size > 0 ) { if ( (sentbytes= LP_send(sendsock,buf,0)) > 0 ) - printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); - else printf("send error to %s\n",ptr->sendaddr); + { + //printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); + } else printf("send error to %s\n",ptr->sendaddr); if ( buf != 0 ) { if ( buf != keepalive ) @@ -150,7 +151,7 @@ void LP_psockloop(void *_ptr) { ptr->lasttime = now; sendsock = ptr->sendsock; - printf("[%s] -> sendsock.%d\n",(char *)buf,sendsock); + printf("keepalive.%u [%s] -> sendsock.%d\n",now,(char *)buf,sendsock); break; } } From fb86481cbccabefd187ede41d870a6a6944d8db4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 15:01:25 +0300 Subject: [PATCH 1779/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 82dbcfc35..58c082160 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -312,7 +312,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); - //printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); + printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); if ( LP_send(pullsock,keepalive,0) < 0 ) LP_deadman_switch = 0; } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 5eaf5a71f..c65f9e24d 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -146,7 +146,7 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - //printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); + printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { ptr->lasttime = now; From a6b6387069745ac057c88d194cbf265b46b376cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 15:03:54 +0300 Subject: [PATCH 1780/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index c65f9e24d..b931fbb7f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -210,7 +210,7 @@ void LP_psockloop(void *_ptr) if ( i < Numpsocks ) { ptr = &PSOCKS[i]; - if ( now > ptr->lasttime+PSOCK_KEEPALIVE*2 ) + if ( now > ptr->lasttime+PSOCK_KEEPALIVE*10 ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->publicport,ptr->sendport,now - ptr->lasttime); if ( ptr->publicsock >= 0 ) From 87a22745f1f2642bfaccfc079d5ed02c9f6449e2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 15:09:15 +0300 Subject: [PATCH 1781/2705] Test --- iguana/exchanges/LP_network.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index b931fbb7f..5ea3a1a1c 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -149,8 +149,13 @@ void LP_psockloop(void *_ptr) printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { - ptr->lasttime = now; - sendsock = ptr->sendsock; + cJSON *retjson; + if ( (retjson= cJSON_Parse((char *)buf)) != 0 ) + { + //ptr->lasttime = now; + //sendsock = ptr->sendsock; + free_json(retjson); + } printf("keepalive.%u [%s] -> sendsock.%d\n",now,(char *)buf,sendsock); break; } From edfb24f00016ac4a16933b31ae86d8770c89b681 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 15:11:59 +0300 Subject: [PATCH 1782/2705] Test --- iguana/exchanges/LP_network.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 5ea3a1a1c..deae086a6 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -149,15 +149,15 @@ void LP_psockloop(void *_ptr) printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { + printf("keepalive.%u [%s] -> sendsock.%d\n",now,(char *)buf,sendsock); cJSON *retjson; if ( (retjson= cJSON_Parse((char *)buf)) != 0 ) { - //ptr->lasttime = now; - //sendsock = ptr->sendsock; free_json(retjson); + ptr->lasttime = now; + sendsock = ptr->sendsock; + break; } - printf("keepalive.%u [%s] -> sendsock.%d\n",now,(char *)buf,sendsock); - break; } } } From 506bb45b480fcbff0ed1756ed79c5b2fae508cb7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 15:15:06 +0300 Subject: [PATCH 1783/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index deae086a6..28e9d3382 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -300,7 +300,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,publicport); nanomsg_transportname(1,subaddr,myipaddr,subport); - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -389,7 +389,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_PAIR;//NN_SUB; + else nntype = NN_BUS;//NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) { From 29b1141a334cae80588b9f7a9d716efa11f69aa7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 15:20:04 +0300 Subject: [PATCH 1784/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 28e9d3382..deae086a6 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -300,7 +300,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,publicport); nanomsg_transportname(1,subaddr,myipaddr,subport); - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -389,7 +389,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_BUS;//NN_SUB; + else nntype = NN_PAIR;//NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) { diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 5f3007957..c4e4a00af 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -132,7 +132,6 @@ uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired) { if ( (retstr= issue_LP_psock(peer->ipaddr,peer->port,ispaired)) != 0 ) { - //printf("got.(%s)\n",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (addr= jstr(retjson,"publicaddr")) != 0 ) @@ -143,6 +142,7 @@ uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired) publicport = juint(retjson,"publicport"); free_json(retjson); } + printf("got.(%s) connect.%s public.%s\n",retstr,connectaddr,publicaddr); free(retstr); } if ( publicport != 0 ) From 5d223a5c6a430d8b273df269f14cc80d6bb2c24d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 18:02:23 +0300 Subject: [PATCH 1785/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 58c082160..7e23ae448 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -129,7 +129,7 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro { } portable_mutex_unlock(&LP_commandmutex); - if ( LP_COMMAND_RECVSOCK == NN_REP ) + //if ( LP_COMMAND_RECVSOCK == NN_REP ) { if ( retstr != 0 ) { From 58926a9ceabfa5a6fd4e0da15f09c03cf2061dc0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 18:22:24 +0300 Subject: [PATCH 1786/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7e23ae448..58c082160 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -129,7 +129,7 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro { } portable_mutex_unlock(&LP_commandmutex); - //if ( LP_COMMAND_RECVSOCK == NN_REP ) + if ( LP_COMMAND_RECVSOCK == NN_REP ) { if ( retstr != 0 ) { diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index deae086a6..2866cb9fc 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -300,7 +300,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,publicport); nanomsg_transportname(1,subaddr,myipaddr,subport); - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -389,7 +389,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_PAIR;//NN_SUB; + else nntype = NN_BUS;//NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) { From bc2f4a32fc362bb8c1d582b2fd69255551d87e36 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 18:24:38 +0300 Subject: [PATCH 1787/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 58c082160..7e23ae448 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -129,7 +129,7 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro { } portable_mutex_unlock(&LP_commandmutex); - if ( LP_COMMAND_RECVSOCK == NN_REP ) + //if ( LP_COMMAND_RECVSOCK == NN_REP ) { if ( retstr != 0 ) { From f114af135dd89e41f7031f4b349a6f98b34e941e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 18:33:23 +0300 Subject: [PATCH 1788/2705] Test --- iguana/exchanges/LP_network.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 2866cb9fc..42c89c49f 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -123,7 +123,7 @@ void LP_psockloop(void *_ptr) } } } - else if ( Numpsocks > 0 ) + else if ( 0 && Numpsocks > 0 ) { pfds = calloc(Numpsocks,sizeof(*pfds) * 2); portable_mutex_lock(&LP_psockmutex); @@ -215,7 +215,19 @@ void LP_psockloop(void *_ptr) if ( i < Numpsocks ) { ptr = &PSOCKS[i]; - if ( now > ptr->lasttime+PSOCK_KEEPALIVE*10 ) + if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) + { + printf("publicsock got (%s)\n",(char *)buf); + sendsock = ptr->sendsock; + break; + } + else if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) + { + printf("sendsock got (%s)\n",(char *)buf); + sendsock = ptr->publicsock; + break; + } + else if ( 0 && now > ptr->lasttime+PSOCK_KEEPALIVE*10 ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->publicport,ptr->sendport,now - ptr->lasttime); if ( ptr->publicsock >= 0 ) @@ -300,7 +312,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) pullsock = pubsock = -1; nanomsg_transportname(1,pushaddr,myipaddr,publicport); nanomsg_transportname(1,subaddr,myipaddr,subport); - if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_BUS)) >= 0 ) + if ( (pullsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PULL)) >= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 0 ) { if ( nn_bind(pullsock,pushaddr) >= 0 && nn_bind(pubsock,subaddr) >= 0 ) { @@ -389,7 +401,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { if ( LP_canbind != 0 ) nntype = LP_COMMAND_RECVSOCK; - else nntype = NN_BUS;//NN_SUB; + else nntype = NN_PAIR;//NN_SUB; } else nntype = NN_PAIR; if ( LP_canbind != 0 ) { From d24bc16098b94a70af1eec10cf89870ee30d4796 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 18:37:40 +0300 Subject: [PATCH 1789/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 42c89c49f..54ef4a071 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -427,7 +427,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, { printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); exit(-1); - } else printf("nntype.%d NN_PAIR.%d connect to %s pullsock.%d\n",nntype,NN_PAIR,connectaddr,pullsock); + } else printf("nntype.%d NN_PAIR.%d connect to %s connectsock.%d\n",nntype,NN_PAIR,connectaddr,pullsock); } else { @@ -445,7 +445,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); if ( nntype == NN_SUB ) nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - LP_send(pullsock,"hello init",0); + //LP_send(pullsock,"hello init",0); } if ( 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PAIR) < 0 ) { From c8fe81585dd3a414eba9e60d6096970340d8b4ce Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 18:40:38 +0300 Subject: [PATCH 1790/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7e23ae448..58c082160 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -129,7 +129,7 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro { } portable_mutex_unlock(&LP_commandmutex); - //if ( LP_COMMAND_RECVSOCK == NN_REP ) + if ( LP_COMMAND_RECVSOCK == NN_REP ) { if ( retstr != 0 ) { From f3a5dbdfc15e1b0aeaaafe361c44cc9284f40397 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:04:46 +0300 Subject: [PATCH 1791/2705] Test --- iguana/exchanges/LP_network.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 54ef4a071..fa0035d4d 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -367,7 +367,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) { - int32_t sock,n,timeout,retval = -1; char msg[512],*retstr; + int32_t sock,n,m,timeout,retval = -1; char msg[512],*retstr; printf("nn_tests.(%s)\n",pushaddr); if ( (sock= nn_socket(AF_SP,nnother)) >= 0 ) { @@ -380,8 +380,10 @@ int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); n = LP_send(sock,msg,0); + sprintf(msg,"{\"method\":\"nn_tests2\",\"ipaddr\":\"%s\"}",pushaddr); + m = LP_send(pullsock,msg,0); LP_pullsock_check(&retstr,"127.0.0.1",-1,pullsock,0.); - printf(">>>>>>>>>>>>>>>>>>>>>> sent %d bytes -> %d (%s)\n",n,pullsock,retstr!=0?retstr:""); + printf(">>>>>>>>>>>>>>>>>>>>>> sent %d+%d bytes -> %d (%s)\n",n,m,pullsock,retstr!=0?retstr:""); if ( retstr != 0 ) { free(retstr); @@ -447,7 +449,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); //LP_send(pullsock,"hello init",0); } - if ( 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PAIR) < 0 ) + if ( 1 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PAIR) < 0 ) { printf("command socket didnt work\n"); exit(-1); From 71cc8d23ae8b8732f5241e342029e40902019b2a Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:08:50 +0300 Subject: [PATCH 1792/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index fa0035d4d..3daa21b28 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -380,10 +380,10 @@ int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); n = LP_send(sock,msg,0); + LP_pullsock_check(&retstr,"127.0.0.1",-1,pullsock,0.); sprintf(msg,"{\"method\":\"nn_tests2\",\"ipaddr\":\"%s\"}",pushaddr); m = LP_send(pullsock,msg,0); - LP_pullsock_check(&retstr,"127.0.0.1",-1,pullsock,0.); - printf(">>>>>>>>>>>>>>>>>>>>>> sent %d+%d bytes -> %d (%s)\n",n,m,pullsock,retstr!=0?retstr:""); + printf(">>>>>>>>>>>>>>>>>>>>>> sent %d+%d bytes -> pullsock.%d (%s)\n",n,m,pullsock,retstr!=0?retstr:""); if ( retstr != 0 ) { free(retstr); From 6f3b411e2e9ce9099fca12f66a39bda4139b793f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:10:33 +0300 Subject: [PATCH 1793/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 3daa21b28..49aed9d2d 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -449,7 +449,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); //LP_send(pullsock,"hello init",0); } - if ( 1 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PAIR) < 0 ) + if ( 1 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PUSH) < 0 ) { printf("command socket didnt work\n"); exit(-1); From d7d9ea20f40527b6617714a8c0dc57e82b4831c1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:14:23 +0300 Subject: [PATCH 1794/2705] Test --- iguana/exchanges/LP_network.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 49aed9d2d..bdcbe3e28 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -206,8 +206,8 @@ void LP_psockloop(void *_ptr) } // else printf("num pfds.%d retval.%d\n",n,retval); } } - portable_mutex_unlock(&LP_psockmutex); free(pfds); + printf("sendsock.%d Numpsocks.%d\n",sendsock,Numpsocks); if ( sendsock < 0 ) { for (i=nonz=0; ipublicsock); if ( ptr->sendsock >= 0 ) nn_close(ptr->sendsock); - portable_mutex_lock(&LP_psockmutex); + //portable_mutex_lock(&LP_psockmutex); if ( Numpsocks > 1 ) { PSOCKS[i] = PSOCKS[--Numpsocks]; memset(&PSOCKS[Numpsocks],0,sizeof(*ptr)); } else Numpsocks = 0; - portable_mutex_unlock(&LP_psockmutex); + //portable_mutex_unlock(&LP_psockmutex); break; } else if ( now > ptr->lastping+PSOCK_KEEPALIVE/2 ) @@ -254,6 +254,7 @@ void LP_psockloop(void *_ptr) } } } + portable_mutex_unlock(&LP_psockmutex); if ( nonz == 0 && i == Numpsocks ) usleep(100000); } From 9d7f33e2679477d4bdf4ad4429af900ae8015779 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:18:14 +0300 Subject: [PATCH 1795/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index bdcbe3e28..60689277b 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -123,7 +123,7 @@ void LP_psockloop(void *_ptr) } } } - else if ( 0 && Numpsocks > 0 ) + else if ( Numpsocks > 0 ) { pfds = calloc(Numpsocks,sizeof(*pfds) * 2); portable_mutex_lock(&LP_psockmutex); From 21a7743592aaa2850e8bc9044369915579e53c7f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:19:29 +0300 Subject: [PATCH 1796/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 60689277b..dd207786c 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -450,7 +450,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); //LP_send(pullsock,"hello init",0); } - if ( 1 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PUSH) < 0 ) + if ( LP_canbind == 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PUSH) < 0 ) { printf("command socket didnt work\n"); exit(-1); From a3e0286d96c517c2af4665ca3eccc937079c3df5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:24:20 +0300 Subject: [PATCH 1797/2705] Test --- iguana/exchanges/LP_network.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index dd207786c..eac4dcad7 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -110,7 +110,7 @@ void LP_psockloop(void *_ptr) { if ( (sentbytes= LP_send(sendsock,buf,0)) > 0 ) { - //printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); + printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); } else printf("send error to %s\n",ptr->sendaddr); if ( buf != 0 ) { @@ -149,7 +149,7 @@ void LP_psockloop(void *_ptr) printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { - printf("keepalive.%u [%s] -> sendsock.%d\n",now,(char *)buf,sendsock); + printf("keepalive.%u [%s] -> sendsock.%d\n",now,(char *)buf,ptr->sendsock); cJSON *retjson; if ( (retjson= cJSON_Parse((char *)buf)) != 0 ) { @@ -254,10 +254,10 @@ void LP_psockloop(void *_ptr) } } } - portable_mutex_unlock(&LP_psockmutex); if ( nonz == 0 && i == Numpsocks ) usleep(100000); } + portable_mutex_unlock(&LP_psockmutex); } else usleep(100000); } } From 1b2eec844676d16f311f41c2bfe94bda2ee71031 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:26:22 +0300 Subject: [PATCH 1798/2705] Test --- iguana/exchanges/LP_network.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index eac4dcad7..80eeb624b 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -207,7 +207,7 @@ void LP_psockloop(void *_ptr) } } free(pfds); - printf("sendsock.%d Numpsocks.%d\n",sendsock,Numpsocks); + //printf("sendsock.%d Numpsocks.%d\n",sendsock,Numpsocks); if ( sendsock < 0 ) { for (i=nonz=0; ipublicsock,&buf,NN_MSG,0)) > 0 ) - { - printf("publicsock got (%s)\n",(char *)buf); - sendsock = ptr->sendsock; - break; - } - else if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) - { - printf("sendsock got (%s)\n",(char *)buf); - sendsock = ptr->publicsock; - break; - } - else if ( 0 && now > ptr->lasttime+PSOCK_KEEPALIVE*10 ) + if ( 0 && now > ptr->lasttime+PSOCK_KEEPALIVE*10 ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->publicport,ptr->sendport,now - ptr->lasttime); if ( ptr->publicsock >= 0 ) From d4ff09bca3c6fb0f4ad3a3370ba8ffac1c81000e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:28:37 +0300 Subject: [PATCH 1799/2705] Test --- iguana/exchanges/LP_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 80eeb624b..d6ab12de7 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -193,8 +193,8 @@ void LP_psockloop(void *_ptr) } } } - n++; } + n++; } if ( iter == 0 ) { From 5820f03d76f5b0ec8e3887ba860ca98ac424b8e5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:32:38 +0300 Subject: [PATCH 1800/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index d6ab12de7..eaf6ef689 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -176,9 +176,9 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - printf("%s paired has pollin (%s)\n",ptr->sendaddr,(char *)buf); if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) { + printf("%s paired has pollin (%s)\n",ptr->sendaddr,(char *)buf); ptr->lasttime = now; if ( ptr->ispaired != 0 ) { @@ -212,7 +212,7 @@ void LP_psockloop(void *_ptr) { for (i=nonz=0; i ptr->lasttime+PSOCK_KEEPALIVE*10 ) From 30a23bd7e778ea732335373cee41fcfce2a3830e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:35:18 +0300 Subject: [PATCH 1801/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index eaf6ef689..22021f72d 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -364,15 +364,15 @@ int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) printf("connect error %s\n",nn_strerror(nn_errno())); else { - sleep(1); timeout = 1; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); n = LP_send(sock,msg,0); + sleep(3); LP_pullsock_check(&retstr,"127.0.0.1",-1,pullsock,0.); sprintf(msg,"{\"method\":\"nn_tests2\",\"ipaddr\":\"%s\"}",pushaddr); m = LP_send(pullsock,msg,0); - printf(">>>>>>>>>>>>>>>>>>>>>> sent %d+%d bytes -> pullsock.%d (%s)\n",n,m,pullsock,retstr!=0?retstr:""); + printf(">>>>>>>>>>>>>>>>>>>>>> sent %d+%d bytes -> pullsock.%d retstr.(%s)\n",n,m,pullsock,retstr!=0?retstr:""); if ( retstr != 0 ) { free(retstr); From 86c03de6075ced53cb865290dfa9fdeb8b69e872 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:36:43 +0300 Subject: [PATCH 1802/2705] Test --- iguana/exchanges/LP_network.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 22021f72d..0faab537b 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -364,6 +364,7 @@ int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) printf("connect error %s\n",nn_strerror(nn_errno())); else { + sleep(3); timeout = 1; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); From 164bffeca9e1071c839d198d945ddb4cdf0fa56f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:38:31 +0300 Subject: [PATCH 1803/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 0faab537b..c9ce77790 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -212,10 +212,10 @@ void LP_psockloop(void *_ptr) { for (i=nonz=0; i ptr->lasttime+PSOCK_KEEPALIVE*10 ) + if ( now > ptr->lasttime+PSOCK_KEEPALIVE*10 ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->publicport,ptr->sendport,now - ptr->lasttime); if ( ptr->publicsock >= 0 ) From 52f0034182f525475f4a7b3dbb26bfa1c53e82df Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 21:52:10 +0300 Subject: [PATCH 1804/2705] Test --- iguana/exchanges/LP_network.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index c9ce77790..4a6c8ddf0 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -22,7 +22,7 @@ struct psock { - uint32_t lasttime,lastping; + uint32_t lasttime,lastping,errors; int32_t publicsock,sendsock,ispaired; uint16_t publicport,sendport; char sendaddr[128],publicaddr[128]; @@ -111,7 +111,12 @@ void LP_psockloop(void *_ptr) if ( (sentbytes= LP_send(sendsock,buf,0)) > 0 ) { printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); - } else printf("send error to %s\n",ptr->sendaddr); + } + else + { + ptr->errors++; + printf("send error.%d to %s\n",ptr->errors,ptr->sendaddr); + } if ( buf != 0 ) { if ( buf != keepalive ) @@ -215,7 +220,7 @@ void LP_psockloop(void *_ptr) if ( i < Numpsocks ) { ptr = &PSOCKS[i]; - if ( now > ptr->lasttime+PSOCK_KEEPALIVE*10 ) + if ( now > ptr->lasttime+PSOCK_KEEPALIVE ) { printf("PSOCKS[%d] of %d (%u %u) lag.%d IDLETIMEOUT\n",i,Numpsocks,ptr->publicport,ptr->sendport,now - ptr->lasttime); if ( ptr->publicsock >= 0 ) @@ -231,7 +236,7 @@ void LP_psockloop(void *_ptr) //portable_mutex_unlock(&LP_psockmutex); break; } - else if ( now > ptr->lastping+PSOCK_KEEPALIVE/2 ) + else if ( now > ptr->lastping+PSOCK_KEEPALIVE/2 && ptr->errors < 3 ) { ptr->lastping = now; sendsock = ptr->sendsock; From 107b953b381177f796d44a13ff2047d6f359c788 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 22:08:45 +0300 Subject: [PATCH 1805/2705] Test --- iguana/exchanges/LP_ordermatch.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index f03da6a7e..4e660f225 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -343,6 +343,16 @@ int32_t LP_nanobind(char *pairstr,char *myipaddr) int32_t i,timeout,r,pairsock = -1; uint16_t mypullport; char bindaddr[128]; if ( LP_canbind != 0 ) { + if ( strcmp(myipaddr,"127.0.0.1") == 0 ) + { + if ( LP_mypeer != 0 ) + myipaddr = LP_mypeer->ipaddr; + } + if ( strcmp(myipaddr,"127.0.0.1") == 0 ) + { + printf("cant nanobind to localhost\n"); + return(-1); + } if ( (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) printf("error creating utxo->pair\n"); else From a891433d308e76ba20cdf8925f7ae9bd3bc42189 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 22:36:07 +0300 Subject: [PATCH 1806/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/LP_swap.c | 6 ++++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index e706d124c..de84ed0c5 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -212,7 +212,7 @@ struct basilisk_swap struct basilisk_swapinfo I; struct basilisk_rawtx bobdeposit,bobpayment,alicepayment,myfee,otherfee,aliceclaim,alicespend,bobreclaim,bobspend,bobrefund,alicereclaim; bits256 privkeys[INSTANTDEX_DECKSIZE]; - struct basilisk_swapmessage *messages; int32_t nummessages; + struct basilisk_swapmessage *messages; int32_t nummessages,sentflag; char Bdeposit[64],Bpayment[64]; uint64_t otherdeck[INSTANTDEX_DECKSIZE][2],deck[INSTANTDEX_DECKSIZE][2]; uint8_t persistent_pubkey33[33],changermd160[20],pad[15],verifybuf[65536]; diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 58c082160..432bc4ce0 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -103,7 +103,7 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro decode_hex((void *)jsonstr,datalen,(char *)ptr); jsonstr[datalen] = 0; } else jsonstr = (char *)ptr; - if ( 1 && IAMLP == 0 ) + if ( 0 && IAMLP == 0 ) printf("%s %d, datalen.%d (%s)\n",typestr,recvlen,datalen,jsonstr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { @@ -312,7 +312,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); - printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); + //printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); if ( LP_send(pullsock,keepalive,0) < 0 ) LP_deadman_switch = 0; } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 4a6c8ddf0..9c6321b86 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -18,7 +18,7 @@ // marketmaker // -#define PSOCK_KEEPALIVE 60 +#define PSOCK_KEEPALIVE 600 struct psock { diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index b45181822..3bed48c10 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -120,6 +120,8 @@ void basilisk_rawtx_purge(struct basilisk_rawtx *rawtx) void basilisk_swap_finished(struct basilisk_swap *swap) { int32_t i; + if ( swap->utxo != 0 && swap->sentflag == 0 ) + LP_availableset(swap->utxo); swap->I.finished = (uint32_t)time(NULL); // save to permanent storage basilisk_rawtx_purge(&swap->bobdeposit); @@ -140,8 +142,6 @@ void basilisk_swap_finished(struct basilisk_swap *swap) swap->nummessages = 0; if ( swap->N.pair >= 0 ) nn_close(swap->N.pair), swap->N.pair = -1; - if ( swap->utxo != 0 ) - LP_availableset(swap->utxo); } uint32_t basilisk_quoteid(struct basilisk_request *rp) @@ -696,6 +696,7 @@ void LP_bobloop(void *_swap) } if ( LP_swapdata_rawtxsend(swap->N.pair,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0) == 0 ) printf("error sending bobpayment\n"); + swap->sentflag = 1; swap->bobreclaim.utxovout = 0; swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); @@ -741,6 +742,7 @@ void LP_aliceloop(void *_swap) char str[65];printf("%d waiting for alicepayment to be confirmed.%d %s %s\n",n,1,swap->alicecoin.symbol,bits256_str(str,swap->alicepayment.I.signedtxid)); sleep(LP_SWAPSTEP_TIMEOUT); } + swap->sentflag = 1; if ( LP_waitfor(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT,LP_verify_bobpayment) < 0 ) printf("error waiting for bobpayment\n"); else From 43a6a971afeada1f5ade4d3ae32e9cb550e3fe29 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 22:43:02 +0300 Subject: [PATCH 1807/2705] Test --- iguana/exchanges/LP_network.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 9c6321b86..29a4313f1 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -110,7 +110,7 @@ void LP_psockloop(void *_ptr) { if ( (sentbytes= LP_send(sendsock,buf,0)) > 0 ) { - printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); + //printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); } else { @@ -151,7 +151,7 @@ void LP_psockloop(void *_ptr) } else if ( (pfds[n].revents & POLLIN) != 0 ) { - printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); + //printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { printf("keepalive.%u [%s] -> sendsock.%d\n",now,(char *)buf,ptr->sendsock); @@ -183,7 +183,7 @@ void LP_psockloop(void *_ptr) { if ( (size= nn_recv(ptr->sendsock,&buf,NN_MSG,0)) > 0 ) { - printf("%s paired has pollin (%s)\n",ptr->sendaddr,(char *)buf); + //printf("%s paired has pollin (%s)\n",ptr->sendaddr,(char *)buf); ptr->lasttime = now; if ( ptr->ispaired != 0 ) { From 82c04f740e6a84654e89ccccde302faec14bd3eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 22:46:19 +0300 Subject: [PATCH 1808/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 432bc4ce0..9dde8e1cd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -32,7 +32,7 @@ char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; -char *default_LPnodes[] = { "5.9.253.195", };//"5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // +char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // uint32_t LP_deadman_switch; int32_t LP_mypubsock = -1; From 8ef3dbe88f1c8626ff633e80cf82a6c9f5ff84cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 23:22:24 +0300 Subject: [PATCH 1809/2705] Test --- iguana/exchanges/LP_bitcoin.c | 125 ++++++++++++++++-------------- iguana/exchanges/LP_coins.c | 7 +- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_ordermatch.c | 17 +++- iguana/exchanges/LP_remember.c | 24 +++--- iguana/exchanges/LP_swap.c | 12 +-- iguana/exchanges/LP_transaction.c | 98 +++++++++++------------ iguana/exchanges/LP_utxos.c | 2 +- iguana/exchanges/client | 1 + iguana/exchanges/run | 1 + 11 files changed, 155 insertions(+), 136 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 12b975c02..9f07c094b 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2028,19 +2028,20 @@ char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *meth return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params,0)); } -int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr) +int32_t bitcoin_addr2rmd160(uint8_t taddr,uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr) { - bits256 hash; uint8_t *buf,_buf[25]; int32_t len; + bits256 hash; uint8_t *buf,_buf[26]; int32_t len,offset; + offset = 1 + (taddr != 0); memset(rmd160,0,20); *addrtypep = 0; buf = _buf; if ( (len= bitcoin_base58decode(buf,coinaddr)) >= 4 ) { // validate with trailing hash, then remove hash - hash = bits256_doublesha256(0,buf,21); + hash = bits256_doublesha256(0,buf,20+offset); *addrtypep = *buf; - memcpy(rmd160,buf+1,20); - if ( (buf[21]&0xff) == hash.bytes[31] && (buf[22]&0xff) == hash.bytes[30] &&(buf[23]&0xff) == hash.bytes[29] && (buf[24]&0xff) == hash.bytes[28] ) + memcpy(rmd160,buf+offset,20); + if ( (buf[20+offset]&0xff) == hash.bytes[31] && (buf[21+offset]&0xff) == hash.bytes[30] &&(buf[22+offset]&0xff) == hash.bytes[29] && (buf[23+offset]&0xff) == hash.bytes[28] ) { //printf("coinaddr.(%s) valid checksum addrtype.%02x\n",coinaddr,*addrtypep); return(20); @@ -2060,18 +2061,21 @@ int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr return(0); } -char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len) +char *bitcoin_address(char *coinaddr,uint8_t taddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len) { - int32_t i; uint8_t data[25]; bits256 hash;// char checkaddr[65]; + int32_t offset,i; uint8_t data[26]; bits256 hash;// char checkaddr[65]; + offset = 1 + (taddr != 0); if ( len != 20 ) - calc_rmd160_sha256(data+1,pubkey_or_rmd160,len); - else memcpy(data+1,pubkey_or_rmd160,20); + calc_rmd160_sha256(data+offset,pubkey_or_rmd160,len); + else memcpy(data+offset,pubkey_or_rmd160,20); //btc_convrmd160(checkaddr,addrtype,data+1); data[0] = addrtype; - hash = bits256_doublesha256(0,data,21); + if ( taddr != 0 ) + data[1] = taddr; + hash = bits256_doublesha256(0,data,20+offset); for (i=0; i<4; i++) - data[21+i] = hash.bytes[31-i]; - if ( (coinaddr= bitcoin_base58encode(coinaddr,data,25)) != 0 ) + data[20+offset+i] = hash.bytes[31-i]; + if ( (coinaddr= bitcoin_base58encode(coinaddr,data,24+offset)) != 0 ) { //uint8_t checktype,rmd160[20]; //bitcoin_addr2rmd160(&checktype,rmd160,coinaddr); @@ -2081,34 +2085,37 @@ char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160, return(coinaddr); } -int32_t bitcoin_validaddress(uint8_t pubtype,uint8_t p2shtype,char *coinaddr) +int32_t bitcoin_validaddress(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,char *coinaddr) { uint8_t rmd160[20],addrtype; char checkaddr[128]; if ( coinaddr == 0 || coinaddr[0] == 0 ) return(-1); - else if ( bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr) < 0 ) + else if ( bitcoin_addr2rmd160(taddr,&addrtype,rmd160,coinaddr) < 0 ) return(-1); else if ( addrtype != pubtype && addrtype != p2shtype ) return(-1); - else if ( bitcoin_address(checkaddr,addrtype,rmd160,sizeof(rmd160)) != checkaddr || strcmp(checkaddr,coinaddr) != 0 ) + else if ( bitcoin_address(checkaddr,addrtype,taddr,rmd160,sizeof(rmd160)) != checkaddr || strcmp(checkaddr,coinaddr) != 0 ) return(-1); return(0); } -int32_t base58encode_checkbuf(uint8_t addrtype,uint8_t *data,int32_t data_len) +int32_t base58encode_checkbuf(uint8_t taddr,uint8_t addrtype,uint8_t *data,int32_t data_len) { - uint8_t i; bits256 hash; + uint8_t i,offset; bits256 hash; + offset = 1 + (taddr != 0); data[0] = addrtype; + if ( taddr != 0 ) + data[1] = taddr; //for (i=0; i "); - hash = bits256_doublesha256(0,data,(int32_t)data_len+1); + hash = bits256_doublesha256(0,data,(int32_t)data_len+offset); //for (i=0; i<32; i++) // printf("%02x",hash.bytes[i]); //printf(" checkhash\n"); for (i=0; i<4; i++) - data[data_len+i+1] = hash.bytes[31-i]; - return(data_len + 5); + data[data_len+i+offset] = hash.bytes[31-i]; + return(data_len + 4 + offset); } int32_t bitcoin_wif2priv(uint8_t *addrtypep,bits256 *privkeyp,char *wifstr) @@ -2146,7 +2153,7 @@ int32_t bitcoin_priv2wif(char *wifstr,bits256 privkey,uint8_t addrtype) uint8_t data[128]; int32_t len = 32; memcpy(data+1,privkey.bytes,sizeof(privkey)); data[1 + len++] = 1; - len = base58encode_checkbuf(addrtype,data,len); + len = base58encode_checkbuf(0,addrtype,data,len); if ( bitcoin_base58encode(wifstr,data,len) == 0 ) return(-1); if ( 1 ) @@ -2165,7 +2172,7 @@ int32_t bitcoin_priv2wiflong(char *wifstr,bits256 privkey,uint8_t addrtype) { uint8_t data[128]; int32_t len = 32; memcpy(data+1,privkey.bytes,sizeof(privkey)); - len = base58encode_checkbuf(addrtype,data,len); + len = base58encode_checkbuf(0,addrtype,data,len); if ( bitcoin_base58encode(wifstr,data,len) == 0 ) return(-1); if ( 1 ) @@ -2180,10 +2187,10 @@ int32_t bitcoin_priv2wiflong(char *wifstr,bits256 privkey,uint8_t addrtype) return((int32_t)strlen(wifstr)); } -bits256 LP_privkey(char *coinaddr) +bits256 LP_privkey(char *coinaddr,uint8_t taddr) { bits256 privkey; uint8_t addrtype,rmd160[20]; - bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); + bitcoin_addr2rmd160(taddr,&addrtype,rmd160,coinaddr); privkey = LP_privkeyfind(rmd160); return(privkey); } @@ -2216,7 +2223,7 @@ uint8_t iguana_addrtype(uint8_t pubtype,uint8_t p2shtype,uint8_t script_type) } } -int32_t iguana_scriptgen(uint8_t pubtype,uint8_t p2shtype,int32_t *Mp,int32_t *nump,char *coinaddr,uint8_t *script,char *asmstr,uint8_t rmd160[20],uint8_t type,const struct vin_info *vp,int32_t txi) +int32_t iguana_scriptgen(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,int32_t *Mp,int32_t *nump,char *coinaddr,uint8_t *script,char *asmstr,uint8_t rmd160[20],uint8_t type,const struct vin_info *vp,int32_t txi) { uint8_t addrtype; char rmd160str[41],pubkeystr[256]; int32_t plen,i,m,n,flag = 0,scriptlen = 0; m = n = 0; @@ -2226,7 +2233,7 @@ int32_t iguana_scriptgen(uint8_t pubtype,uint8_t p2shtype,int32_t *Mp,int32_t *n if ( type == IGUANA_SCRIPT_76A988AC || type == IGUANA_SCRIPT_AC || type == IGUANA_SCRIPT_76AC || type == IGUANA_SCRIPT_P2SH ) { init_hexbytes_noT(rmd160str,rmd160,20); - bitcoin_address(coinaddr,addrtype,rmd160,20); + bitcoin_address(coinaddr,taddr,addrtype,rmd160,20); } switch ( type ) { @@ -2265,7 +2272,7 @@ int32_t iguana_scriptgen(uint8_t pubtype,uint8_t p2shtype,int32_t *Mp,int32_t *n case IGUANA_SCRIPT_OPRETURN: if ( asmstr != 0 ) strcpy(asmstr,"OP_RETURN "); - bitcoin_address(coinaddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); + bitcoin_address(coinaddr,taddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); flag++; break; case IGUANA_SCRIPT_3of3: m = 3, n = 3; break; @@ -2278,13 +2285,13 @@ int32_t iguana_scriptgen(uint8_t pubtype,uint8_t p2shtype,int32_t *Mp,int32_t *n case IGUANA_SCRIPT_DATA: if ( asmstr != 0 ) strcpy(asmstr,"DATA ONLY"); - bitcoin_address(coinaddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); + bitcoin_address(coinaddr,taddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); flag++; break; case IGUANA_SCRIPT_STRANGE: if ( asmstr != 0 ) strcpy(asmstr,"STRANGE SCRIPT "); - bitcoin_address(coinaddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); + bitcoin_address(coinaddr,taddr,addrtype,(uint8_t *)&vp->spendscript[0],vp->spendlen); flag++; break; default: break;//printf("unexpected script type.%d\n",type); break; @@ -2292,7 +2299,7 @@ int32_t iguana_scriptgen(uint8_t pubtype,uint8_t p2shtype,int32_t *Mp,int32_t *n if ( n > 0 ) { scriptlen = bitcoin_MofNspendscript(rmd160,script,0,vp); - bitcoin_address(coinaddr,p2shtype,script,scriptlen); + bitcoin_address(coinaddr,taddr,p2shtype,script,scriptlen); if ( asmstr != 0 ) { sprintf(asmstr,"%d ",m); @@ -2319,7 +2326,7 @@ int32_t iguana_scriptgen(uint8_t pubtype,uint8_t p2shtype,int32_t *Mp,int32_t *n return(scriptlen); } -int32_t bitcoin_scriptget(uint8_t pubtype,uint8_t p2shtype,int32_t *hashtypep,uint32_t *sigsizep,uint32_t *pubkeysizep,uint8_t **userdatap,uint32_t *userdatalenp,struct vin_info *vp,uint8_t *scriptsig,int32_t len,int32_t spendtype) +int32_t bitcoin_scriptget(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,int32_t *hashtypep,uint32_t *sigsizep,uint32_t *pubkeysizep,uint8_t **userdatap,uint32_t *userdatalenp,struct vin_info *vp,uint8_t *scriptsig,int32_t len,int32_t spendtype) { int32_t j,n,siglen,plen; uint8_t *p2shscript; j = n = 0; @@ -2393,12 +2400,12 @@ int32_t bitcoin_scriptget(uint8_t pubtype,uint8_t p2shtype,int32_t *hashtypep,ui decode_hex(vp->rmd160,20,"010966776006953d5567439e5e39f86a0d273bee");//3564a74f9ddb4372301c49154605573d7d1a88fe"); vp->type = IGUANA_SCRIPT_76A988AC; }*/ - vp->spendlen = iguana_scriptgen(pubtype,p2shtype,&vp->M,&vp->N,vp->coinaddr,vp->spendscript,0,vp->rmd160,vp->type,(const struct vin_info *)vp,vp->vin.prev_vout); + vp->spendlen = iguana_scriptgen(taddr,pubtype,p2shtype,&vp->M,&vp->N,vp->coinaddr,vp->spendscript,0,vp->rmd160,vp->type,(const struct vin_info *)vp,vp->vin.prev_vout); //printf("type.%d asmstr.(%s) spendlen.%d\n",vp->type,asmstr,vp->spendlen); return(vp->spendlen); } -int32_t _iguana_calcrmd160(uint8_t pubtype,uint8_t p2shtype,struct vin_info *vp) +int32_t _iguana_calcrmd160(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,struct vin_info *vp) { static uint8_t zero_rmd160[20]; char hexstr[8192]; uint8_t *script,type; int32_t i,n,m,plen; @@ -2473,7 +2480,7 @@ int32_t _iguana_calcrmd160(uint8_t pubtype,uint8_t p2shtype,struct vin_info *vp) } memcpy(vp->signers[i].pubkey,script,plen); calc_rmd160_sha256(vp->signers[i].rmd160,vp->signers[i].pubkey,plen); - bitcoin_address(vp->signers[i].coinaddr,pubtype,vp->signers[i].pubkey,plen); + bitcoin_address(vp->signers[i].coinaddr,taddr,pubtype,vp->signers[i].pubkey,plen); } if ( (int32_t)((long)script - (long)vp->spendscript) == vp->spendlen-2 ) { @@ -2526,7 +2533,7 @@ int32_t _iguana_calcrmd160(uint8_t pubtype,uint8_t p2shtype,struct vin_info *vp) return(type); } -int32_t iguana_calcrmd160(uint8_t pubtype,uint8_t p2shtype,char *asmstr,struct vin_info *vp,uint8_t *pk_script,int32_t pk_scriptlen,bits256 debugtxid,int32_t vout,uint32_t sequence) +int32_t iguana_calcrmd160(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,char *asmstr,struct vin_info *vp,uint8_t *pk_script,int32_t pk_scriptlen,bits256 debugtxid,int32_t vout,uint32_t sequence) { int32_t scriptlen; uint8_t script[IGUANA_MAXSCRIPTSIZE]; memset(vp,0,sizeof(*vp)); @@ -2534,9 +2541,9 @@ int32_t iguana_calcrmd160(uint8_t pubtype,uint8_t p2shtype,char *asmstr,struct v vp->spendlen = pk_scriptlen; vp->vin.sequence = sequence; memcpy(vp->spendscript,pk_script,pk_scriptlen); - if ( (vp->type= _iguana_calcrmd160(pubtype,p2shtype,vp)) >= 0 ) + if ( (vp->type= _iguana_calcrmd160(taddr,pubtype,p2shtype,vp)) >= 0 ) { - scriptlen = iguana_scriptgen(pubtype,p2shtype,&vp->M,&vp->N,vp->coinaddr,script,asmstr,vp->rmd160,vp->type,(const struct vin_info *)vp,vout); + scriptlen = iguana_scriptgen(taddr,pubtype,p2shtype,&vp->M,&vp->N,vp->coinaddr,script,asmstr,vp->rmd160,vp->type,(const struct vin_info *)vp,vout); if ( vp->M == 0 && vp->N == 0 ) { vp->M = vp->N = 1; @@ -2578,11 +2585,11 @@ cJSON *bitcoin_txscript(char *asmstr,char **vardata,int32_t numvars) return(scriptjson); } -cJSON *iguana_scriptpubkeys(uint8_t pubtype,uint8_t p2shtype,uint8_t *script,int32_t scriptlen,bits256 txid,int16_t vout,uint32_t sequenceid) +cJSON *iguana_scriptpubkeys(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t *script,int32_t scriptlen,bits256 txid,int16_t vout,uint32_t sequenceid) { int32_t type,i,n,plen; struct vin_info V; cJSON *pubkeys; char pubkeystr[256]; pubkeys = cJSON_CreateArray(); - if ( (type= iguana_calcrmd160(pubtype,p2shtype,0,&V,script,scriptlen,txid,vout,sequenceid)) >= 0 ) + if ( (type= iguana_calcrmd160(taddr,pubtype,p2shtype,0,&V,script,scriptlen,txid,vout,sequenceid)) >= 0 ) { if ( (n= V.N) == 0 ) n = 1; @@ -2634,7 +2641,7 @@ cJSON *iguana_pubkeysjson(uint8_t *pubkeyptrs[],int32_t numpubkeys) return(pubkeysjson); } -cJSON *bitcoin_txinput(uint8_t pubtype,uint8_t p2shtype,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequenceid,uint8_t *spendscript,int32_t spendlen,uint8_t *redeemscript,int32_t p2shlen,uint8_t *pubkeys[],int32_t numpubkeys,uint8_t *sig,int32_t siglen) +cJSON *bitcoin_txinput(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequenceid,uint8_t *spendscript,int32_t spendlen,uint8_t *redeemscript,int32_t p2shlen,uint8_t *pubkeys[],int32_t numpubkeys,uint8_t *sig,int32_t siglen) { cJSON *item,*vins; char p2shscriptstr[IGUANA_MAXSCRIPTSIZE*2+1]; uint8_t *script,len=0; vins = jduplicate(jobj(txobj,"vin")); @@ -2654,7 +2661,7 @@ cJSON *bitcoin_txinput(uint8_t pubtype,uint8_t p2shtype,cJSON *txobj,bits256 txi script = redeemscript, len = p2shlen; } else script = 0; if ( script != 0 && numpubkeys == 0 ) - jadd(item,"pubkeys",iguana_scriptpubkeys(pubtype,p2shtype,script,len,txid,vout,sequenceid)); + jadd(item,"pubkeys",iguana_scriptpubkeys(taddr,pubtype,p2shtype,script,len,txid,vout,sequenceid)); else if ( pubkeys != 0 && numpubkeys > 0 ) jadd(item,"pubkeys",iguana_pubkeysjson(pubkeys,numpubkeys)); jaddbits256(item,"txid",txid); @@ -2698,12 +2705,12 @@ cJSON *bitcoin_txoutput(cJSON *txobj,uint8_t *paymentscript,int32_t len,uint64_t return(txobj); } -int32_t bitcoin_txaddspend(uint8_t pubtype,uint8_t p2shtype,cJSON *txobj,char *destaddress,uint64_t satoshis) +int32_t bitcoin_txaddspend(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,cJSON *txobj,char *destaddress,uint64_t satoshis) { uint8_t outputscript[128],addrtype,rmd160[20]; int32_t scriptlen; - if ( bitcoin_validaddress(pubtype,p2shtype,destaddress) == 0 && satoshis != 0 ) + if ( bitcoin_validaddress(taddr,pubtype,p2shtype,destaddress) == 0 && satoshis != 0 ) { - bitcoin_addr2rmd160(&addrtype,rmd160,destaddress); + bitcoin_addr2rmd160(taddr,&addrtype,rmd160,destaddress); scriptlen = bitcoin_standardspend(outputscript,0,rmd160); bitcoin_txoutput(txobj,outputscript,scriptlen,satoshis); return(0); @@ -3130,7 +3137,7 @@ int32_t iguana_parsevoutobj(uint8_t *serialized,int32_t maxsize,struct iguana_ms return(len); } -cJSON *iguana_voutjson(uint8_t pubtype,uint8_t p2shtype,struct iguana_msgvout *vout,int32_t txi,bits256 txid) +cJSON *iguana_voutjson(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,struct iguana_msgvout *vout,int32_t txi,bits256 txid) { // 035f1321ed17d387e4433b2fa229c53616057964af065f98bfcae2233c5108055e OP_CHECKSIG char scriptstr[IGUANA_MAXSCRIPTSIZE+1],asmstr[2*IGUANA_MAXSCRIPTSIZE+1]; int32_t i,m,n,scriptlen,asmtype; struct vin_info *vp; @@ -3143,10 +3150,10 @@ cJSON *iguana_voutjson(uint8_t pubtype,uint8_t p2shtype,struct iguana_msgvout *v if ( vout->pk_script != 0 && vout->pk_scriptlen*2+1 < sizeof(scriptstr) ) { memset(vp,0,sizeof(*vp)); - if ( (asmtype= iguana_calcrmd160(pubtype,p2shtype,asmstr,vp,vout->pk_script,vout->pk_scriptlen,txid,txi,0xffffffff)) >= 0 ) + if ( (asmtype= iguana_calcrmd160(taddr,pubtype,p2shtype,asmstr,vp,vout->pk_script,vout->pk_scriptlen,txid,txi,0xffffffff)) >= 0 ) { skey = cJSON_CreateObject(); - scriptlen = iguana_scriptgen(pubtype,p2shtype,&m,&n,vp->coinaddr,space,asmstr,vp->rmd160,asmtype,vp,txi); + scriptlen = iguana_scriptgen(taddr,pubtype,p2shtype,&m,&n,vp->coinaddr,space,asmstr,vp->rmd160,asmtype,vp,txi); if ( asmstr[0] != 0 ) jaddstr(skey,"asm",asmstr); addrs = cJSON_CreateArray(); @@ -3223,9 +3230,9 @@ int32_t iguana_vinarray_check(cJSON *vinarray,bits256 txid,int32_t vout) return(-1); } -int32_t iguana_rwmsgtx(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,int32_t rwflag,cJSON *json,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,bits256 *txidp,char *vpnstr,uint8_t *extraspace,int32_t extralen,cJSON *vins,int32_t suppress_pubkeys); +int32_t iguana_rwmsgtx(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,int32_t rwflag,cJSON *json,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,bits256 *txidp,char *vpnstr,uint8_t *extraspace,int32_t extralen,cJSON *vins,int32_t suppress_pubkeys); -bits256 bitcoin_sigtxid(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,int32_t vini,uint8_t *spendscript,int32_t spendlen,int32_t hashtype,char *vpnstr,int32_t suppress_pubkeys) +bits256 bitcoin_sigtxid(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,int32_t vini,uint8_t *spendscript,int32_t spendlen,int32_t hashtype,char *vpnstr,int32_t suppress_pubkeys) { int32_t i,len; bits256 sigtxid,txid,revsigtxid; struct iguana_msgtx dest; dest = *msgtx; @@ -3259,7 +3266,7 @@ bits256 bitcoin_sigtxid(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t h dest.vins[i].userdata = 0; dest.vins[i].userdatalen = 0; } - len = iguana_rwmsgtx(pubtype,p2shtype,isPoS,height,1,0,serialized,maxlen,&dest,&txid,vpnstr,0,0,0,suppress_pubkeys); + len = iguana_rwmsgtx(taddr,pubtype,p2shtype,isPoS,height,1,0,serialized,maxlen,&dest,&txid,vpnstr,0,0,0,suppress_pubkeys); //for (i=0; iversion),&msg->version); @@ -3366,7 +3373,7 @@ int32_t iguana_rwmsgtx(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t he return(-1); } if ( voutarray != 0 ) - jaddi(voutarray,iguana_voutjson(pubtype,p2shtype,&msg->vouts[i],i,*txidp)); + jaddi(voutarray,iguana_voutjson(taddr,pubtype,p2shtype,&msg->vouts[i],i,*txidp)); } len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->lock_time),&msg->lock_time); //printf("lock_time.%08x len.%d\n",msg->lock_time,len); @@ -3398,7 +3405,7 @@ int32_t iguana_rwmsgtx(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t he if ( vins != 0 && jitem(vins,i) != 0 ) { iguana_vinobjset(&msg->vins[i],jitem(vins,i),spendscript,sizeof(spendscript)); - sigtxid = bitcoin_sigtxid(pubtype,p2shtype,isPoS,height,sigser,maxsize*2,msg,i,msg->vins[i].spendscript,msg->vins[i].spendlen,SIGHASH_ALL,vpnstr,suppress_pubkeys); + sigtxid = bitcoin_sigtxid(taddr,pubtype,p2shtype,isPoS,height,sigser,maxsize*2,msg,i,msg->vins[i].spendscript,msg->vins[i].spendlen,SIGHASH_ALL,vpnstr,suppress_pubkeys); //printf("after vini.%d vinscript.%p spendscript.%p spendlen.%d (%s)\n",i,msg->vins[i].vinscript,msg->vins[i].spendscript,msg->vins[i].spendlen,jprint(jitem(vins,i),0)); if ( iguana_vinarray_check(vinarray,msg->vins[i].prev_hash,msg->vins[i].prev_vout) < 0 ) jaddi(vinarray,iguana_vinjson(&msg->vins[i],sigtxid)); @@ -3495,13 +3502,13 @@ bits256 iguana_parsetxobj(uint8_t isPoS,int32_t *txstartp,uint8_t *serialized,in return(txid); } -char *iguana_rawtxbytes(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,cJSON *json,struct iguana_msgtx *msgtx,int32_t suppress_pubkeys) +char *iguana_rawtxbytes(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,cJSON *json,struct iguana_msgtx *msgtx,int32_t suppress_pubkeys) { int32_t n; char *txbytes = 0,vpnstr[64]; uint8_t *serialized; serialized = malloc(IGUANA_MAXPACKETSIZE); vpnstr[0] = 0; //char str[65]; printf("%d of %d: %s\n",i,msg.txn_count,bits256_str(str,tx.txid)); - if ( (n= iguana_rwmsgtx(pubtype,p2shtype,isPoS,height,1,json,serialized,IGUANA_MAXPACKETSIZE,msgtx,&msgtx->txid,vpnstr,0,0,0,suppress_pubkeys)) > 0 ) + if ( (n= iguana_rwmsgtx(taddr,pubtype,p2shtype,isPoS,height,1,json,serialized,IGUANA_MAXPACKETSIZE,msgtx,&msgtx->txid,vpnstr,0,0,0,suppress_pubkeys)) > 0 ) { txbytes = malloc(n*2+1); init_hexbytes_noT(txbytes,serialized,n); @@ -3529,7 +3536,7 @@ char *bitcoin_json2hex(uint8_t isPoS,bits256 *txidp,cJSON *txjson,struct vin_inf return(txbytes); } -cJSON *bitcoin_data2json(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *txidp,struct iguana_msgtx *msgtx,uint8_t *extraspace,int32_t extralen,uint8_t *serialized,int32_t len,cJSON *vins,int32_t suppress_pubkeys) +cJSON *bitcoin_data2json(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *txidp,struct iguana_msgtx *msgtx,uint8_t *extraspace,int32_t extralen,uint8_t *serialized,int32_t len,cJSON *vins,int32_t suppress_pubkeys) { int32_t n; char vpnstr[64]; struct iguana_msgtx M; cJSON *txobj; if ( serialized == 0 ) @@ -3540,7 +3547,7 @@ cJSON *bitcoin_data2json(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t memset(msgtx,0,sizeof(M)); vpnstr[0] = 0; memset(txidp,0,sizeof(*txidp)); - if ( (n= iguana_rwmsgtx(pubtype,p2shtype,isPoS,height,0,txobj,serialized,len,msgtx,txidp,vpnstr,extraspace,extralen,vins,suppress_pubkeys)) <= 0 ) + if ( (n= iguana_rwmsgtx(taddr,pubtype,p2shtype,isPoS,height,0,txobj,serialized,len,msgtx,txidp,vpnstr,extraspace,extralen,vins,suppress_pubkeys)) <= 0 ) { printf("errortxobj.(%s)\n",jprint(txobj,0)); free_json(txobj); @@ -3558,7 +3565,7 @@ cJSON *bitcoin_data2json(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t return(txobj); } -cJSON *bitcoin_hex2json(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *txidp,struct iguana_msgtx *msgtx,char *txbytes,uint8_t *extraspace,int32_t extralen,uint8_t *origserialized,cJSON *vins,int32_t suppress_pubkeys) +cJSON *bitcoin_hex2json(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *txidp,struct iguana_msgtx *msgtx,char *txbytes,uint8_t *extraspace,int32_t extralen,uint8_t *origserialized,cJSON *vins,int32_t suppress_pubkeys) { int32_t len; uint8_t *serialized; cJSON *txobj; if ( txbytes == 0 ) @@ -3567,7 +3574,7 @@ cJSON *bitcoin_hex2json(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t h if ( (serialized= origserialized) == 0 ) serialized = calloc(1,len+4096); decode_hex(serialized,len,txbytes); - txobj = bitcoin_data2json(pubtype,p2shtype,isPoS,height,txidp,msgtx,extraspace,extralen,serialized,len,vins,suppress_pubkeys); + txobj = bitcoin_data2json(taddr,pubtype,p2shtype,isPoS,height,txidp,msgtx,extraspace,extralen,serialized,len,vins,suppress_pubkeys); if ( serialized != origserialized ) free(serialized); return(txobj); diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 06ea91849..65ba8bc43 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -173,12 +173,13 @@ cJSON *LP_coinsjson() return(array); } -void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain) +void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain,uint8_t taddr) { memset(coin,0,sizeof(*coin)); safecopy(coin->symbol,symbol,sizeof(coin->symbol)); sprintf(coin->serverport,"127.0.0.1:%u",port); coin->isPoS = isPoS; + coin->taddr = taddr; coin->longestchain = longestchain; coin->txfee = txfee; coin->estimatedrate = estimatedrate; @@ -249,7 +250,7 @@ struct iguana_info *LP_coinfind(char *symbol) name = symbol; assetname = symbol; } - LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); + LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,0); if ( (coin= LP_coinadd(&cdata)) != 0 && strcmp(symbol,"KMD") == 0 ) coin->inactive = 0; return(coin); @@ -278,7 +279,7 @@ struct iguana_info *LP_coincreate(cJSON *item) name = assetname; else if ( (name= jstr(item,"name")) == 0 ) name = symbol; - LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain); + LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,jint(item,"taddr")); coin = LP_coinadd(&cdata); } if ( coin != 0 && item != 0 ) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 4cc96c755..dde474f84 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -52,7 +52,7 @@ char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjs } if ( strcmp(method,"hello") == 0 ) { - printf("got hello from %s:%u\n",ipaddr!=0?ipaddr:"",argport); + //printf("got hello from %s:%u\n",ipaddr!=0?ipaddr:"",argport); return(0); } else if ( strcmp(method,"nn_tests") == 0 ) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index de84ed0c5..79127306d 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -151,7 +151,7 @@ struct iguana_info { uint64_t txfee; double estimatedrate,profitmargin; int32_t longestchain; uint32_t counter,inactive; - uint8_t pubtype,p2shtype,isPoS,wiftype; + uint8_t pubtype,p2shtype,isPoS,wiftype,taddr; char symbol[16],smartaddr[64],userpass[1024],serverport[128]; }; diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 4e660f225..c67c105bb 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -378,10 +378,15 @@ int32_t LP_nanobind(char *pairstr,char *myipaddr) int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin,double price,struct LP_quoteinfo *qp) { - char pairstr[512]; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; + char pairstr[512]; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; struct iguana_info *coin; printf("LP_connectstartbob.(%s) with.(%s)\n",myipaddr,jprint(argjson,0)); qp->quotetime = (uint32_t)time(NULL); - privkey = LP_privkey(utxo->coinaddr); + if ( (coin= LP_coinfind(utxo->coin)) == 0 ) + { + printf("cant find coin.%s\n",utxo->coin); + return(-1); + } + privkey = LP_privkey(utxo->coinaddr,coin->taddr); if ( bits256_nonz(privkey) != 0 && qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending && bits256_cmp(LP_mypubkey,qp->srchash) == 0 ) { if ( (pair= LP_nanobind(pairstr,myipaddr)) >= 0 ) @@ -424,7 +429,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs char *LP_connectedalice(cJSON *argjson) // alice { - cJSON *retjson; double bid,ask,price,qprice; int32_t timeout,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *autxo,*butxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; + cJSON *retjson; double bid,ask,price,qprice; int32_t timeout,pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *autxo,*butxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; struct iguana_info *coin; if ( LP_quoteparse(&Q,argjson) < 0 ) clonestr("{\"error\":\"cant parse quote\"}"); if ( bits256_cmp(Q.desthash,LP_mypubkey) != 0 ) @@ -449,7 +454,11 @@ char *LP_connectedalice(cJSON *argjson) // alice LP_availableset(autxo); return(clonestr("{\"error\":\"quote price too expensive\"}")); } - Q.privkey = LP_privkey(Q.destaddr); + if ( (coin= LP_coinfind(Q.destcoin)) == 0 ) + { + return(clonestr("{\"error\":\"cant get alicecoin\"}")); + } + Q.privkey = LP_privkey(Q.destaddr,coin->taddr); if ( bits256_nonz(Q.privkey) != 0 && Q.quotetime >= Q.timestamp-3 ) { retjson = cJSON_CreateObject(); diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index d2a06d19f..78ce4a783 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -71,7 +71,7 @@ void basilisk_dontforget(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid)); if ( bits256_nonz(swap->I.pubAm) != 0 && bits256_nonz(swap->I.pubBn) != 0 ) { - basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin.p2shtype,swap->I.pubAm,swap->I.pubBn); + basilisk_alicescript(redeemscript,&len,script,0,coinaddr,swap->alicecoin.taddr,swap->alicecoin.p2shtype,swap->I.pubAm,swap->I.pubBn); LP_importaddress(swap->alicecoin.symbol,coinaddr); fprintf(fp,",\"Apayment\":\"%s\"",coinaddr); } @@ -568,12 +568,12 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti { if ( (alice= LP_coinfind(alicecoin)) != 0 ) { - bitcoin_address(Adestaddr,alice->pubtype,pubkey33,33); + bitcoin_address(Adestaddr,alice->taddr,alice->pubtype,pubkey33,33); AAdest = Adestaddr; } if ( (bob= LP_coinfind(bobcoin)) != 0 ) { - bitcoin_address(destaddr,bob->pubtype,pubkey33,33); + bitcoin_address(destaddr,bob->taddr,bob->pubtype,pubkey33,33); Adest = destaddr; } } @@ -581,12 +581,12 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti { if ( (bob= LP_coinfind(bobcoin)) != 0 ) { - bitcoin_address(destaddr,bob->pubtype,pubkey33,33); + bitcoin_address(destaddr,bob->taddr,bob->pubtype,pubkey33,33); Bdest = destaddr; } if ( (alice= LP_coinfind(alicecoin)) != 0 ) { - bitcoin_address(Adestaddr,alice->pubtype,pubkey33,33); + bitcoin_address(Adestaddr,alice->taddr,alice->pubtype,pubkey33,33); ABdest = Adestaddr; } } @@ -625,12 +625,12 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti { char privaddr[64]; uint8_t privpub33[33]; bitcoin_pubkey33(ctx,privpub33,myprivs[0]); - bitcoin_address(privaddr,60,privpub33,33); + bitcoin_address(privaddr,0,60,privpub33,33); printf("alicespend len.%d redeemlen.%d priv0addr.(%s) priv0.(%s)\n",len,redeemlen,privaddr,bits256_str(str,myprivs[0])); } for (j=0; j<32; j++) rev.bytes[j] = myprivs[0].bytes[31 - j]; - if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr,1)) != 0 ) + if ( (txbytes[BASILISK_ALICESPEND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"alicespend",bobcoin,bob->taddr,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,1,expiration,&values[BASILISK_ALICESPEND],0,0,bobpaymentaddr,1)) != 0 ) printf("alicespend.(%s)\n",txbytes[BASILISK_ALICESPEND]); } } @@ -655,7 +655,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0,bobdepositaddr,1)) != 0 ) + if ( (txbytes[BASILISK_ALICECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"aliceclaim",bobcoin,bob->taddr,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,0,expiration,&values[BASILISK_ALICECLAIM],0,0,bobdepositaddr,1)) != 0 ) printf("privBn.(%s) aliceclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICECLAIM]); } } @@ -677,7 +677,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti privBn = basilisk_swap_privBn_extract(&txids[BASILISK_BOBREFUND],bobcoin,txids[BASILISK_BOBDEPOSIT],privBn); if ( bits256_nonz(txids[BASILISK_ALICEPAYMENT]) != 0 && bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",alicecoin,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM],alicepaymentaddr)) != 0 ) + if ( (txbytes[BASILISK_ALICERECLAIM]= basilisk_swap_Aspend("alicereclaim",alicecoin,alice->taddr,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_ALICERECLAIM],alicepaymentaddr)) != 0 ) printf("privBn.(%s) alicereclaim.(%s)\n",bits256_str(str,privBn),txbytes[BASILISK_ALICERECLAIM]); } } @@ -707,7 +707,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) { - if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",alicecoin,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND],alicepaymentaddr)) != 0 ) + if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",alicecoin,alice->taddr,alice->pubtype,alice->p2shtype,alice->isPoS,alice->wiftype,ctx,privAm,privBn,txids[BASILISK_ALICEPAYMENT],0,pubkey33,expiration,&values[BASILISK_BOBSPEND],alicepaymentaddr)) != 0 ) printf("bobspend.(%s)\n",txbytes[BASILISK_BOBSPEND]); } } @@ -731,7 +731,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti if ( redeemlen > 0 ) { len = basilisk_swapuserdata(userdata,zero,1,myprivs[1],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0,bobpaymentaddr,1)) != 0 ) + if ( (txbytes[BASILISK_BOBRECLAIM]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->taddr,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[1],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBPAYMENT],0,0,pubkey33,0,expiration,&values[BASILISK_BOBRECLAIM],0,0,bobpaymentaddr,1)) != 0 ) { int32_t z; for (z=0; z<20; z++) @@ -761,7 +761,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti vcalc_sha256(0,secretBn256,privBn.bytes,sizeof(privBn)); redeemlen = basilisk_swap_bobredeemscript(1,&secretstart,redeemscript,dlocktime,pubA0,pubB0,pubB1,privAm,privBn,secretAm,secretAm256,secretBn,secretBn256); len = basilisk_swapuserdata(userdata,privBn,0,myprivs[0],redeemscript,redeemlen); - if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0,bobdepositaddr,1)) != 0 ) + if ( (txbytes[BASILISK_BOBREFUND]= basilisk_swap_bobtxspend(&signedtxid,txfee,"bobrefund",bobcoin,bob->taddr,bob->pubtype,bob->p2shtype,bob->isPoS,bob->wiftype,ctx,myprivs[0],0,redeemscript,redeemlen,userdata,len,txids[BASILISK_BOBDEPOSIT],0,0,pubkey33,1,expiration,&values[BASILISK_BOBREFUND],0,0,bobdepositaddr,1)) != 0 ) printf("pubB1.(%s) bobrefund.(%s)\n",bits256_str(str,pubB1),txbytes[BASILISK_BOBREFUND]); } if ( txbytes[BASILISK_BOBREFUND] != 0 ) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 3bed48c10..158ccf323 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -510,7 +510,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); //for (i=0; iI.redeemlen; i++) // printf("%02x",rawtx->redeemscript[i]); - bitcoin_address(redeemaddr,rawtx->coin->p2shtype,rawtx->redeemscript,rawtx->I.redeemlen); + bitcoin_address(redeemaddr,rawtx->coin->taddr,rawtx->coin->p2shtype,rawtx->redeemscript,rawtx->I.redeemlen); //printf(" received redeemscript.(%s)\n",redeemaddr); LP_swap_coinaddr(swap,rawtx->coin,checkaddr,data,datalen); if ( strcmp(redeemaddr,checkaddr) != 0 ) @@ -542,7 +542,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba //char str[65]; printf("rawtx.%s txid %s\n",rawtx->name,bits256_str(str,txid)); if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 ) rawtx->I.actualtxid = txid; - if ( (txobj= bitcoin_data2json(rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + if ( (txobj= bitcoin_data2json(rawtx->coin->taddr,rawtx->coin->pubtype,rawtx->coin->p2shtype,rawtx->coin->isPoS,height,&rawtx->I.signedtxid,&rawtx->msgtx,rawtx->extraspace,sizeof(rawtx->extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { rawtx->I.actualtxid = rawtx->I.signedtxid; //char str[65]; printf("got %s txid.%s (%s)\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),jprint(txobj,0)); @@ -556,7 +556,7 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba { decode_hex(rawtx->spendscript,hexlen,hexstr); rawtx->I.spendlen = hexlen; - bitcoin_address(rawtx->p2shaddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); + bitcoin_address(rawtx->p2shaddr,rawtx->coin->taddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen); //if ( swap != 0 ) // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment retval = 0; @@ -866,13 +866,13 @@ void basilisk_rawtx_setparms(char *name,uint32_t quoteid,struct basilisk_rawtx * if ( strcmp(coin->symbol,"BTC") == 0 && (quoteid % 10) == 0 ) decode_hex(rawtx->I.rmd160,20,TIERNOLAN_RMD160); else decode_hex(rawtx->I.rmd160,20,INSTANTDEX_RMD160); - bitcoin_address(rawtx->I.destaddr,rawtx->coin->pubtype,rawtx->I.rmd160,20); + bitcoin_address(rawtx->I.destaddr,rawtx->coin->taddr,rawtx->coin->pubtype,rawtx->I.rmd160,20); } if ( pubkey33 != 0 ) { memcpy(rawtx->I.pubkey33,pubkey33,33); - bitcoin_address(rawtx->I.destaddr,rawtx->coin->pubtype,rawtx->I.pubkey33,33); - bitcoin_addr2rmd160(&rawtx->I.addrtype,rawtx->I.rmd160,rawtx->I.destaddr); + bitcoin_address(rawtx->I.destaddr,rawtx->coin->taddr,rawtx->coin->pubtype,rawtx->I.pubkey33,33); + bitcoin_addr2rmd160(rawtx->coin->taddr,&rawtx->I.addrtype,rawtx->I.rmd160,rawtx->I.destaddr); } if ( rawtx->I.vouttype <= 1 && rawtx->I.destaddr[0] != 0 ) { diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 28f3b6aa4..81cc74a93 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -454,7 +454,7 @@ bits256 iguana_str2priv(char *str) return(privkey); } -int32_t iguana_vininfo_create(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msgtx,cJSON *vins,int32_t numinputs,struct vin_info *V) +int32_t iguana_vininfo_create(uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msgtx,cJSON *vins,int32_t numinputs,struct vin_info *V) { int32_t i,plen,finalized = 1,len = 0; struct vin_info *vp; //struct iguana_waccount *wacct; struct iguana_waddress *waddr; uint32_t sigsize,pubkeysize,p2shsize,userdatalen; msgtx->tx_in = numinputs; @@ -486,9 +486,9 @@ int32_t iguana_vininfo_create(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uin { memcpy(vp->spendscript,msgtx->vins[i].spendscript,msgtx->vins[i].spendlen); vp->spendlen = msgtx->vins[i].spendlen; - _iguana_calcrmd160(pubtype,p2shtype,vp); + _iguana_calcrmd160(taddr,pubtype,p2shtype,vp); if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) > 0 ) - bitcoin_address(vp->coinaddr,pubtype,vp->signers[0].pubkey,plen); + bitcoin_address(vp->coinaddr,taddr,pubtype,vp->signers[0].pubkey,plen); } if ( vp->M == 0 && vp->N == 0 ) vp->M = vp->N = 1; @@ -506,7 +506,7 @@ int32_t iguana_vininfo_create(uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uin return(finalized); } -int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxlen,struct vin_info *V,uint32_t sighash,int32_t signtx,int32_t suppress_pubkeys) +int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxlen,struct vin_info *V,uint32_t sighash,int32_t signtx,int32_t suppress_pubkeys) { bits256 sigtxid; uint8_t *sig,*script; struct vin_info *vp; char vpnstr[64]; int32_t scriptlen,complete=0,j,vini=0,flag=0,siglen,numvouts,numsigs; numvouts = msgtx->tx_out; @@ -528,7 +528,7 @@ int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shty script = msgtx->vins[vini].spendscript; scriptlen = msgtx->vins[vini].spendlen; } - sigtxid = bitcoin_sigtxid(pubtype,p2shtype,isPoS,height,serialized,maxlen,msgtx,vini,script,scriptlen,sighash,vpnstr,suppress_pubkeys); + sigtxid = bitcoin_sigtxid(taddr,pubtype,p2shtype,isPoS,height,serialized,maxlen,msgtx,vini,script,scriptlen,sighash,vpnstr,suppress_pubkeys); if ( bits256_nonz(sigtxid) != 0 ) { vp = &V[vini]; @@ -584,7 +584,7 @@ int32_t bitcoin_verifyvins(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shty } iguana_msgtx_Vset(serialized,maxlen,msgtx,V); cJSON *txobj = cJSON_CreateObject(); - *signedtx = iguana_rawtxbytes(pubtype,p2shtype,isPoS,height,txobj,msgtx,suppress_pubkeys); + *signedtx = iguana_rawtxbytes(taddr,pubtype,p2shtype,isPoS,height,txobj,msgtx,suppress_pubkeys); //printf("SIGNEDTX.(%s)\n",jprint(txobj,1)); *signedtxidp = msgtx->txid; return(complete); @@ -598,7 +598,7 @@ int64_t iguana_lockval(int32_t finalized,int64_t locktime) return(lockval); } -int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,struct iguana_msgtx *msgtx,char **signedtxp,bits256 *signedtxidp,struct vin_info *V,int32_t numinputs,char *rawtx,cJSON *vins,cJSON *privkeysjson) +int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,struct iguana_msgtx *msgtx,char **signedtxp,bits256 *signedtxidp,struct vin_info *V,int32_t numinputs,char *rawtx,cJSON *vins,cJSON *privkeysjson) { uint8_t *serialized,*serialized2,*serialized3,*serialized4,*extraspace,pubkeys[64][33]; int32_t finalized,i,len,n,z,plen,maxsize,complete = 0,extralen = 65536; char *privkeystr,*signedtx = 0; bits256 privkeys[64],privkey,txid; cJSON *item; cJSON *txobj = 0; maxsize = 1000000; @@ -613,7 +613,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t memset(msgtx,0,sizeof(*msgtx)); decode_hex(serialized,len,rawtx); // printf("call hex2json.(%s) vins.(%s)\n",rawtx,jprint(vins,0)); - if ( (txobj= bitcoin_hex2json(pubtype,p2shtype,isPoS,height,&txid,msgtx,rawtx,extraspace,extralen,serialized4,vins,V->suppress_pubkeys)) != 0 ) + if ( (txobj= bitcoin_hex2json(taddr,pubtype,p2shtype,isPoS,height,&txid,msgtx,rawtx,extraspace,extralen,serialized4,vins,V->suppress_pubkeys)) != 0 ) { //printf("back from bitcoin_hex2json (%s)\n",jprint(vins,0)); } else fprintf(stderr,"no txobj from bitcoin_hex2json\n"); @@ -621,7 +621,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t { //printf("numinputs.%d msgtx.%d\n",numinputs,msgtx->tx_in); memset(msgtx,0,sizeof(*msgtx)); - if ( iguana_rwmsgtx(pubtype,p2shtype,isPoS,height,0,0,serialized,maxsize,msgtx,&txid,"",extraspace,65536,vins,V->suppress_pubkeys) > 0 && numinputs == msgtx->tx_in ) + if ( iguana_rwmsgtx(taddr,pubtype,p2shtype,isPoS,height,0,0,serialized,maxsize,msgtx,&txid,"",extraspace,65536,vins,V->suppress_pubkeys) > 0 && numinputs == msgtx->tx_in ) { memset(pubkeys,0,sizeof(pubkeys)); memset(privkeys,0,sizeof(privkeys)); @@ -649,14 +649,14 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t coinaddr[0] = 0; sigsize = 0; flag = (msgtx->vins[i].vinscript[0] == 0); - type = bitcoin_scriptget(pubtype,p2shtype,&hashtype,&sigsize,&pubkeysize,&userdata,&userdatalen,&mainvin,msgtx->vins[i].vinscript+flag,msgtx->vins[i].scriptlen-flag,0); + type = bitcoin_scriptget(taddr,pubtype,p2shtype,&hashtype,&sigsize,&pubkeysize,&userdata,&userdatalen,&mainvin,msgtx->vins[i].vinscript+flag,msgtx->vins[i].scriptlen-flag,0); //printf("i.%d flag.%d type.%d scriptlen.%d\n",i,flag,type,msgtx->vins[i].scriptlen); if ( msgtx->vins[i].redeemscript != 0 ) { //for (j=0; jvins[i].p2shlen; j++) // printf("%02x",msgtx->vins[i].redeemscript[j]); - bitcoin_address(coinaddr,p2shtype,msgtx->vins[i].redeemscript,msgtx->vins[i].p2shlen); - type = iguana_calcrmd160(pubtype,p2shtype,0,&mvin,msgtx->vins[i].redeemscript,msgtx->vins[i].p2shlen,zero,0,0); + bitcoin_address(coinaddr,taddr,p2shtype,msgtx->vins[i].redeemscript,msgtx->vins[i].p2shlen); + type = iguana_calcrmd160(taddr,pubtype,p2shtype,0,&mvin,msgtx->vins[i].redeemscript,msgtx->vins[i].p2shlen,zero,0,0); for (j=0; jsuppress_pubkeys == 0 ) @@ -706,9 +706,9 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t } } } - finalized = iguana_vininfo_create(pubtype,p2shtype,isPoS,serialized2,maxsize,msgtx,vins,numinputs,V); + finalized = iguana_vininfo_create(taddr,pubtype,p2shtype,isPoS,serialized2,maxsize,msgtx,vins,numinputs,V); //printf("finalized.%d ignore_cltverr.%d suppress.%d\n",finalized,V[0].ignore_cltverr,V[0].suppress_pubkeys); - if ( (complete= bitcoin_verifyvins(ctx,symbol,pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) + if ( (complete= bitcoin_verifyvins(ctx,symbol,taddr,pubtype,p2shtype,isPoS,height,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1,V->suppress_pubkeys)) > 0 && signedtx != 0 ) { /*int32_t tmp; //char str[65]; if ( (tmp= iguana_interpreter(ctx,cJSON_CreateArray(),iguana_lockval(finalized,jint(txobj,"locktime")),V,numinputs)) < 0 ) @@ -728,7 +728,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t pubtype,uint8_t return(complete); } -char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr,int32_t suppress_pubkeys) +char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t vout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr,int32_t suppress_pubkeys) { char *rawtxbytes=0,*signedtx=0,tmpaddr[64],hexstr[999],wifstr[128],txdestaddr[64],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*item,*privkeys; int32_t completed,spendlen,ignore_cltverr=1; struct vin_info V[2]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value,change = 0; struct iguana_msgtx msgtx; *destamountp = 0; @@ -789,14 +789,14 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch } jaddbits256(item,"txid",utxotxid); jaddnum(item,"vout",vout); - bitcoin_address(tmpaddr,pubtype,pubkey33,33); - bitcoin_addr2rmd160(&addrtype,rmd160,tmpaddr); + bitcoin_address(tmpaddr,taddr,pubtype,pubkey33,33); + bitcoin_addr2rmd160(taddr,&addrtype,rmd160,tmpaddr); if ( redeemlen != 0 ) { init_hexbytes_noT(hexstr,redeemscript,redeemlen); jaddstr(item,"redeemScript",hexstr); if ( vinaddr != 0 ) - bitcoin_addr2rmd160(&addrtype,rmd160,vinaddr); + bitcoin_addr2rmd160(taddr,&addrtype,rmd160,vinaddr); spendlen = bitcoin_p2shspend(spendscript,0,rmd160); //printf("P2SH path.%s\n",vinaddr!=0?vinaddr:0); } else spendlen = bitcoin_standardspend(spendscript,0,rmd160); @@ -810,9 +810,9 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch if ( destaddr == 0 ) { destaddr = _destaddr; - bitcoin_address(destaddr,pubtype,pubkey33,33); + bitcoin_address(destaddr,taddr,pubtype,pubkey33,33); } - bitcoin_addr2rmd160(&addrtype,rmd160,destaddr); + bitcoin_addr2rmd160(taddr,&addrtype,rmd160,destaddr); if ( addrtype == p2shtype ) spendlen = bitcoin_p2shspend(spendscript,0,rmd160); else spendlen = bitcoin_standardspend(spendscript,0,rmd160); @@ -826,7 +826,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch if ( change != 0 ) { int32_t changelen; uint8_t changescript[1024],changetype,changermd160[20]; - bitcoin_addr2rmd160(&changetype,changermd160,changeaddr); + bitcoin_addr2rmd160(taddr,&changetype,changermd160,changeaddr); changelen = bitcoin_standardspend(changescript,0,changermd160); txobj = bitcoin_txoutput(txobj,changescript,changelen,change); } @@ -836,7 +836,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch completed = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); //printf("locktime.%u sequenceid.%x rawtx.(%s) vins.(%s)\n",locktime,sequenceid,rawtxbytes,jprint(vins,0)); - if ( (completed= iguana_signrawtransaction(ctx,symbol,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) + if ( (completed= iguana_signrawtransaction(ctx,symbol,taddr,pubtype,p2shtype,isPoS,1000000,&msgtx,&signedtx,signedtxidp,V,1,rawtxbytes,vins,privkeys)) < 0 ) //if ( (signedtx= LP_signrawtx(symbol,signedtxidp,&completed,vins,rawtxbytes,privkeys,V)) == 0 ) printf("couldnt sign transaction.%s %s\n",name,bits256_str(str,*signedtxidp)); else if ( completed == 0 ) @@ -862,12 +862,12 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub if ( changermd160 != 0 ) { changeaddr = _changeaddr; - bitcoin_address(changeaddr,coin->pubtype,changermd160,20); + bitcoin_address(changeaddr,coin->taddr,coin->pubtype,changermd160,20); //printf("changeaddr.(%s) vs destaddr.(%s)\n",changeaddr,rawtx->I.destaddr); } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&rawtx->I.signedtxid,iter == 0 ? txfee : newtxfee,str,coin->symbol,coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->wiftype,ctx,privkey,0,0,0,0,0,rawtx->utxotxid,rawtx->utxovout,rawtx->I.destaddr,pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,rawtx->I.suppress_pubkeys)) != 0 ) { rawtx->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( rawtx->I.datalen <= sizeof(rawtx->txbytes) ) @@ -891,7 +891,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub return(retval); } -int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160,char *vinaddr) +int32_t basilisk_rawtx_sign(char *symbol,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160,char *vinaddr) { char *signedtx,*changeaddr = 0,_changeaddr[64]; int64_t txfee,newtxfee=0,destamount; uint32_t timestamp,locktime=0,sequenceid = 0xffffffff; int32_t iter,retval = -1; double estimatedrate; //char str2[65]; printf("%s rawtxsign.(%s/v%d)\n",dest->name,bits256_str(str2,dest->utxotxid),dest->utxovout); @@ -904,12 +904,12 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ if ( changermd160 != 0 ) { changeaddr = _changeaddr; - bitcoin_address(changeaddr,pubtype,changermd160,20); + bitcoin_address(changeaddr,taddr,pubtype,changermd160,20); //printf("changeaddr.(%s)\n",changeaddr); } for (iter=0; iter<2; iter++) { - if ( (signedtx= basilisk_swap_bobtxspend(&dest->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,dest->utxotxid,dest->utxovout,dest->I.destaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) + if ( (signedtx= basilisk_swap_bobtxspend(&dest->I.signedtxid,iter == 0 ? txfee : newtxfee,rawtx->name,symbol,taddr,pubtype,p2shtype,isPoS,wiftype,swap->ctx,privkey,privkey2,rawtx->redeemscript,rawtx->I.redeemlen,userdata,userdatalen,dest->utxotxid,dest->utxovout,dest->I.destaddr,rawtx->I.pubkey33,1,0,&destamount,rawtx->I.amount,changeaddr,vinaddr,dest->I.suppress_pubkeys)) != 0 ) { dest->I.datalen = (int32_t)strlen(signedtx) >> 1; if ( dest->I.datalen <= sizeof(dest->txbytes) ) @@ -929,7 +929,7 @@ int32_t basilisk_rawtx_sign(char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_ //return(_basilisk_rawtx_sign(symbol,pubtype,p2shtype,isPoS,wiftype,swap,timestamp,locktime,sequenceid,dest,rawtx,privkey,privkey2,userdata,userdatalen,ignore_cltverr)); } -int32_t basilisk_alicescript(uint8_t *redeemscript,int32_t *redeemlenp,uint8_t *script,int32_t n,char *msigaddr,uint8_t altps2h,bits256 pubAm,bits256 pubBn) +int32_t basilisk_alicescript(uint8_t *redeemscript,int32_t *redeemlenp,uint8_t *script,int32_t n,char *msigaddr,uint8_t taddr,uint8_t altps2h,bits256 pubAm,bits256 pubBn) { uint8_t p2sh160[20]; struct vin_info V; memset(&V,0,sizeof(V)); @@ -937,7 +937,7 @@ int32_t basilisk_alicescript(uint8_t *redeemscript,int32_t *redeemlenp,uint8_t * memcpy(&V.signers[1].pubkey[1],pubBn.bytes,sizeof(pubBn)), V.signers[1].pubkey[0] = 0x03; V.M = V.N = 2; *redeemlenp = bitcoin_MofNspendscript(p2sh160,redeemscript,n,&V); - bitcoin_address(msigaddr,altps2h,p2sh160,sizeof(p2sh160)); + bitcoin_address(msigaddr,taddr,altps2h,p2sh160,sizeof(p2sh160)); n = bitcoin_p2shspend(script,0,p2sh160); //for (i=0; i<*redeemlenp; i++) // printf("%02x",redeemscript[i]); @@ -945,7 +945,7 @@ int32_t basilisk_alicescript(uint8_t *redeemscript,int32_t *redeemlenp,uint8_t * return(n); } -char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp,char *vinaddr) +char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privAm,bits256 privBn,bits256 utxotxid,int32_t vout,uint8_t pubkey33[33],uint32_t expiration,int64_t *destamountp,char *vinaddr) { char msigaddr[64],*signedtx = 0; int32_t spendlen,redeemlen; uint8_t tmp33[33],redeemscript[512],spendscript[128]; bits256 pubAm,pubBn,signedtxid; uint64_t txfee; if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 ) @@ -955,7 +955,7 @@ char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2sht //char str[65]; //printf("pubAm.(%s)\n",bits256_str(str,pubAm)); //printf("pubBn.(%s)\n",bits256_str(str,pubBn)); - spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,p2shtype,pubAm,pubBn); + spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,taddr,p2shtype,pubAm,pubBn); //char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen); /*rev = privAm; for (i=0; i<32; i++) @@ -964,7 +964,7 @@ char *basilisk_swap_Aspend(char *name,char *symbol,uint8_t pubtype,uint8_t p2sht for (i=0; i<32; i++) privBn.bytes[i] = rev.bytes[31 - i];*/ txfee = LP_txfee(symbol); - signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr,1); + signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,taddr,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,vout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr,1); } return(signedtx); } @@ -1322,7 +1322,7 @@ int32_t basilisk_bobpayment_reclaim(struct basilisk_swap *swap,int32_t delay) len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[1],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); memcpy(swap->I.userdata_bobreclaim,userdata,len); swap->I.userdata_bobreclaimlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1,swap->changermd160,swap->bobpayment.I.destaddr)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.taddr,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobreclaim,&swap->bobpayment,swap->I.myprivs[1],0,userdata,len,1,swap->changermd160,swap->bobpayment.I.destaddr)) == 0 ) { //for (i=0; ibobreclaim.I.datalen; i++) // printf("%02x",swap->bobreclaim.txbytes[i]); @@ -1339,7 +1339,7 @@ int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) len = basilisk_swapuserdata(userdata,swap->I.privBn,0,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_bobrefund,userdata,len); swap->I.userdata_bobrefundlen = len; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.taddr,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->bobrefund,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,0,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) { for (i=0; ibobrefund.I.datalen; i++) printf("%02x",swap->bobrefund.txbytes[i]); @@ -1353,13 +1353,13 @@ int32_t basilisk_bobdeposit_refund(struct basilisk_swap *swap,int32_t delay) int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) { int32_t j; char coinaddr[64]; - bitcoin_address(coinaddr,swap->bobcoin.pubtype,swap->changermd160,20); + bitcoin_address(coinaddr,swap->bobcoin.taddr,swap->bobcoin.pubtype,swap->changermd160,20); if ( genflag != 0 && swap->I.iambob == 0 ) printf("basilisk_bobscripts_set WARNING: alice generating BOB tx\n"); if ( depositflag == 0 ) { swap->bobpayment.I.spendlen = basilisk_bobscript(swap->bobpayment.I.rmd160,swap->bobpayment.redeemscript,&swap->bobpayment.I.redeemlen,swap->bobpayment.spendscript,0,&swap->bobpayment.I.locktime,&swap->bobpayment.I.secretstart,&swap->I,0); - bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.taddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); //LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); //int32_t i; for (i=0; ibobpayment.I.redeemlen; i++) @@ -1391,7 +1391,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i else { swap->bobdeposit.I.spendlen = basilisk_bobscript(swap->bobdeposit.I.rmd160,swap->bobdeposit.redeemscript,&swap->bobdeposit.I.redeemlen,swap->bobdeposit.spendscript,0,&swap->bobdeposit.I.locktime,&swap->bobdeposit.I.secretstart,&swap->I,1); - bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.taddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); //LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); //int32_t i; for (i=0; ibobdeposit.I.redeemlen; i++) @@ -1424,7 +1424,7 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i void LP_swap_coinaddr(struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) { cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; - if ( (txobj= bitcoin_data2json(coin->pubtype,coin->p2shtype,coin->isPoS,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + if ( (txobj= bitcoin_data2json(coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) { //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) @@ -1480,14 +1480,14 @@ int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_r void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,struct basilisk_rawtx *alicepayment,bits256 pubAm,bits256 pubBn) { char coinaddr[64]; - alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->p2shtype,pubAm,pubBn); + alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->taddr,coin->p2shtype,pubAm,pubBn); /*for (i=0; i<33; i++) printf("%02x",swap->persistent_pubkey33[i]); printf(" pubkey33, "); for (i=0; i<20; i++) printf("%02x",swap->changermd160[i]); printf(" rmd160, ");*/ - bitcoin_address(coinaddr,coin->pubtype,swap->changermd160,20); + bitcoin_address(coinaddr,coin->taddr,coin->pubtype,swap->changermd160,20); //printf("%s suppress.%d fee.%d\n",coinaddr,alicepayment->I.suppress_pubkeys,swap->myfee.I.suppress_pubkeys); basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); } @@ -1501,7 +1501,7 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d printf("error alice generating payment.%d\n",swap->alicepayment.I.spendlen); else { - bitcoin_address(swap->alicepayment.I.destaddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); + bitcoin_address(swap->alicepayment.I.destaddr,swap->alicecoin.taddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); //LP_importaddress(swap->alicecoin.symbol,swap->alicepayment.I.destaddr); strcpy(swap->alicepayment.p2shaddr,swap->alicepayment.I.destaddr); retval = 0; @@ -1515,7 +1515,7 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d if ( swap->myfee.I.datalen == 0 ) { printf("generate fee\n"); - bitcoin_address(coinaddr,swap->alicecoin.pubtype,swap->changermd160,20); + bitcoin_address(coinaddr,swap->alicecoin.taddr,swap->alicecoin.pubtype,swap->changermd160,20); if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr) == 0 ) { printf("rawtxsend\n"); @@ -1567,7 +1567,7 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da len = basilisk_swapuserdata(userdata,zero,1,swap->I.myprivs[0],swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); memcpy(swap->I.userdata_aliceclaim,userdata,len); swap->I.userdata_aliceclaimlen = len; - bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); + bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.taddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); //LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); /*for (i=0; ibobdeposit.I.datalen; i++) @@ -1579,9 +1579,9 @@ int32_t LP_verify_bobdeposit(struct basilisk_swap *swap,uint8_t *data,int32_t da memcpy(swap->aliceclaim.redeemscript,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); swap->aliceclaim.I.redeemlen = swap->bobdeposit.I.redeemlen; memcpy(swap->aliceclaim.I.pubkey33,swap->persistent_pubkey33,33); - bitcoin_address(swap->aliceclaim.I.destaddr,swap->alicecoin.pubtype,swap->persistent_pubkey33,33); + bitcoin_address(swap->aliceclaim.I.destaddr,swap->alicecoin.taddr,swap->alicecoin.pubtype,swap->persistent_pubkey33,33); retval = 0; - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.taddr,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->aliceclaim,&swap->bobdeposit,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->bobdeposit.I.destaddr)) == 0 ) { /*for (i=0; ibobdeposit.I.datalen; i++) printf("%02x",swap->bobdeposit.txbytes[i]); @@ -1603,7 +1603,7 @@ int32_t LP_verify_alicepayment(struct basilisk_swap *swap,uint8_t *data,int32_t { swap->bobspend.utxovout = 0; swap->bobspend.utxotxid = swap->alicepayment.I.signedtxid = LP_broadcast_tx(swap->alicepayment.name,swap->alicecoin.symbol,swap->alicepayment.txbytes,swap->alicepayment.I.datalen); - bitcoin_address(swap->alicepayment.p2shaddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); + bitcoin_address(swap->alicepayment.p2shaddr,swap->alicecoin.taddr,swap->alicecoin.p2shtype,swap->alicepayment.redeemscript,swap->alicepayment.I.redeemlen); strcpy(swap->alicepayment.I.destaddr,swap->alicepayment.p2shaddr); if ( bits256_nonz(swap->alicepayment.I.signedtxid) != 0 ) swap->aliceunconf = 1; @@ -1631,7 +1631,7 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da for (i=0; i<32; i++) revAm.bytes[i] = swap->I.privAm.bytes[31-i]; len = basilisk_swapuserdata(userdata,revAm,0,swap->I.myprivs[0],swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); - bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); + bitcoin_address(swap->bobpayment.p2shaddr,swap->bobcoin.taddr,swap->bobcoin.p2shtype,swap->bobpayment.redeemscript,swap->bobpayment.I.redeemlen); strcpy(swap->bobpayment.I.destaddr,swap->bobpayment.p2shaddr); //LP_importaddress(swap->bobcoin.symbol,swap->bobpayment.I.destaddr); /*for (i=0; ibobpayment.I.datalen; i++) @@ -1644,9 +1644,9 @@ int32_t LP_verify_bobpayment(struct basilisk_swap *swap,uint8_t *data,int32_t da swap->I.userdata_alicespendlen = len; retval = 0; memcpy(swap->alicespend.I.pubkey33,swap->persistent_pubkey33,33); - bitcoin_address(swap->alicespend.I.destaddr,swap->bobcoin.pubtype,swap->persistent_pubkey33,33); + bitcoin_address(swap->alicespend.I.destaddr,swap->bobcoin.taddr,swap->bobcoin.pubtype,swap->persistent_pubkey33,33); //char str[65],str2[65]; printf("bobpaid privAm.(%s) myprivs[0].(%s)\n",bits256_str(str,swap->I.privAm),bits256_str(str2,swap->I.myprivs[0])); - if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->alicepayment.I.destaddr)) == 0 ) + if ( (retval= basilisk_rawtx_sign(swap->bobcoin.symbol,swap->bobcoin.taddr,swap->bobcoin.pubtype,swap->bobcoin.p2shtype,swap->bobcoin.isPoS,swap->bobcoin.wiftype,swap,&swap->alicespend,&swap->bobpayment,swap->I.myprivs[0],0,userdata,len,1,swap->changermd160,swap->alicepayment.I.destaddr)) == 0 ) { /*for (i=0; ibobpayment.I.datalen; i++) printf("%02x",swap->bobpayment.txbytes[i]); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e84276fb0..80f6de979 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -738,7 +738,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co { coin->counter++; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - bitcoin_addr2rmd160(&tmptype,rmd160,coin->smartaddr); + bitcoin_addr2rmd160(coin->taddr,&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 0f89a0f95..2cb11e60c 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -5,6 +5,7 @@ git pull; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, +{\"active\":1,\"coin\":\"HUSH\",\"name\":\"hushcoin\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, diff --git a/iguana/exchanges/run b/iguana/exchanges/run index ff014cfd2..858fe930d 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -1,6 +1,7 @@ source randval pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, +{\"coin\":\"HUSH\",\"name\":\"hushcoin\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, From 470f22f01529a49bfda8bb5e31a608b11e408c28 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 23:25:49 +0300 Subject: [PATCH 1810/2705] test --- iguana/exchanges/LP_bitcoin.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 9f07c094b..a766566b6 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2069,9 +2069,11 @@ char *bitcoin_address(char *coinaddr,uint8_t taddr,uint8_t addrtype,uint8_t *pub calc_rmd160_sha256(data+offset,pubkey_or_rmd160,len); else memcpy(data+offset,pubkey_or_rmd160,20); //btc_convrmd160(checkaddr,addrtype,data+1); - data[0] = addrtype; if ( taddr != 0 ) - data[1] = taddr; + { + data[0] = taddr; + data[1] = addrtype; + } else data[0] = addrtype; hash = bits256_doublesha256(0,data,20+offset); for (i=0; i<4; i++) data[20+offset+i] = hash.bytes[31-i]; @@ -2103,9 +2105,11 @@ int32_t base58encode_checkbuf(uint8_t taddr,uint8_t addrtype,uint8_t *data,int32 { uint8_t i,offset; bits256 hash; offset = 1 + (taddr != 0); - data[0] = addrtype; if ( taddr != 0 ) - data[1] = taddr; + { + data[0] = taddr; + data[1] = addrtype; + } else data[0] = addrtype; //for (i=0; i "); From 32b780f3e4ad9303b82cf3a3063482abcc421768 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 23:28:25 +0300 Subject: [PATCH 1811/2705] Test --- iguana/exchanges/LP_bitcoin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index a766566b6..e1e0c5b2a 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2079,10 +2079,10 @@ char *bitcoin_address(char *coinaddr,uint8_t taddr,uint8_t addrtype,uint8_t *pub data[20+offset+i] = hash.bytes[31-i]; if ( (coinaddr= bitcoin_base58encode(coinaddr,data,24+offset)) != 0 ) { - //uint8_t checktype,rmd160[20]; - //bitcoin_addr2rmd160(&checktype,rmd160,coinaddr); - //if ( strcmp(checkaddr,coinaddr) != 0 ) - // printf("checkaddr.(%s) vs coinaddr.(%s) %02x vs [%02x] memcmp.%d\n",checkaddr,coinaddr,addrtype,checktype,memcmp(rmd160,data+1,20)); + uint8_t checktype,rmd160[20]; char checkaddr[65]; + bitcoin_addr2rmd160(taddr,&checktype,rmd160,coinaddr); + if ( strcmp(checkaddr,coinaddr) != 0 ) + printf("taddr.%02x checkaddr.(%s) vs coinaddr.(%s) %02x vs [%02x] memcmp.%d\n",taddr,checkaddr,coinaddr,addrtype,checktype,memcmp(rmd160,data+1,20)); } return(coinaddr); } From a25708698f881ce4b75553a8e9d5de15a38ad964 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 23:31:16 +0300 Subject: [PATCH 1812/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index e1e0c5b2a..9c2492c7e 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2083,7 +2083,7 @@ char *bitcoin_address(char *coinaddr,uint8_t taddr,uint8_t addrtype,uint8_t *pub bitcoin_addr2rmd160(taddr,&checktype,rmd160,coinaddr); if ( strcmp(checkaddr,coinaddr) != 0 ) printf("taddr.%02x checkaddr.(%s) vs coinaddr.(%s) %02x vs [%02x] memcmp.%d\n",taddr,checkaddr,coinaddr,addrtype,checktype,memcmp(rmd160,data+1,20)); - } + } else printf("null coinaddr taddr.%02x\n",taddr); return(coinaddr); } From 47ec0d31a9e228fcb037b98ff998df73e0db9b25 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 20 Jun 2017 23:55:47 +0300 Subject: [PATCH 1813/2705] Test --- iguana/exchanges/LP_bitcoin.c | 29 +++++++++++++++++++- iguana/exchanges/LP_commands.c | 12 ++++----- iguana/exchanges/LP_forwarding.c | 8 +++--- iguana/exchanges/LP_include.h | 6 ++--- iguana/exchanges/LP_nativeDEX.c | 46 ++++++++++++++++---------------- iguana/exchanges/LP_network.c | 8 +++--- iguana/exchanges/LP_ordermatch.c | 30 ++++++++++----------- iguana/exchanges/LP_utxos.c | 8 +++--- iguana/exchanges/mm.c | 24 +---------------- iguana/exchanges/stats.c | 9 +++++-- 10 files changed, 95 insertions(+), 85 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 9c2492c7e..3185da0f0 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2055,7 +2055,7 @@ int32_t bitcoin_addr2rmd160(uint8_t taddr,uint8_t *addrtypep,uint8_t rmd160[20], } for (i=0; i 0 ) + if ( LP_forward(ctx,myipaddr,pubsock,profitmargin,jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) retstr = clonestr("{\"result\":\"success\"}"); else retstr = clonestr("{\"error\":\"error forwarding\"}"); } else retstr = clonestr("{\"error\":\"cant recurse forwards\"}"); @@ -237,7 +237,7 @@ forwardhex(pubkey,hex)\n\ else if ( strcmp(method,"lookup") == 0 ) return(LP_lookup(jbits256(argjson,"client"))); else if ( strcmp(method,"forwardhex") == 0 ) - retstr = LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex")); + retstr = LP_forwardhex(ctx,pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex")); else if ( strcmp(method,"psock") == 0 ) { if ( myipaddr == 0 || myipaddr[0] == 0 || strcmp(myipaddr,"127.0.0.1") == 0 ) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 505ae8a33..cb368afe2 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -190,7 +190,7 @@ cJSON *LP_dereference(cJSON *argjson,char *excludemethod) return(reqjson); } -char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) +char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) { struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *retstr=0; cJSON *retjson=0,*argjson=0,*reqjson=0; if ( hexstr == 0 || hexstr[0] == 0 ) @@ -204,7 +204,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) { if ( reqjson != 0 ) { - retstr = LP_command_process(LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); + retstr = LP_command_process(ctx,LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); //printf("LP_forwardhex.(%s) -> (%s)\n",jprint(reqjson,0),retstr!=0?retstr:""); if ( pubsock >= 0 ) LP_send(pubsock,jprint(reqjson,0),0); @@ -248,7 +248,7 @@ char *LP_forwardhex(int32_t pubsock,bits256 pubkey,char *hexstr) return(retstr); } -int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pubkey,char *jsonstr,int32_t freeflag) +int32_t LP_forward(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin,bits256 pubkey,char *jsonstr,int32_t freeflag) { struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson,*reqjson,*argjson; if ( jsonstr == 0 || jsonstr[0] == 0 ) @@ -260,7 +260,7 @@ int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pu printf("GOT FORWARDED.(%s)\n",myipaddr); if ( (argjson= cJSON_Parse(jsonstr)) != 0 ) { - if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,0,0,profitmargin)) != 0 ) + if ( (retstr= LP_command_process(ctx,myipaddr,pubsock,argjson,0,0,profitmargin)) != 0 ) free(retstr); free_json(argjson); } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 79127306d..b00ef444f 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -228,14 +228,14 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 //double LP_query(char *method,struct LP_quoteinfo *qp,char *base,char *rel,bits256 mypub); int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys); void LP_quotesinit(char *base,char *rel); -int32_t LP_forward(char *myipaddr,int32_t pubsock,double profitmargin,bits256 pubkey,char *jsonstr,int32_t freeflag); +int32_t LP_forward(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin,bits256 pubkey,char *jsonstr,int32_t freeflag); int32_t LP_ismine(struct LP_utxoinfo *utxo); int32_t LP_isavailable(struct LP_utxoinfo *utxo); struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port); -char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin); +char *LP_command_process(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin); void LP_availableset(struct LP_utxoinfo *utxo); int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2,bits256 pubkey); -int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin); +int32_t LP_pullsock_check(void *ctx,char **retstrp,char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin); uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 9dde8e1cd..a1dadda84 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -76,14 +76,14 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_forwarding.c" #include "LP_commands.c" -char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) +char *LP_command_process(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *retstr=0; if ( jobj(argjson,"result") != 0 || jobj(argjson,"error") != 0 ) return(0); - if ( LP_tradecommand(myipaddr,pubsock,argjson,data,datalen,profitmargin) <= 0 ) + if ( LP_tradecommand(ctx,myipaddr,pubsock,argjson,data,datalen,profitmargin) <= 0 ) { - if ( (retstr= stats_JSON(myipaddr,pubsock,profitmargin,argjson,"127.0.0.1",0)) != 0 ) + if ( (retstr= stats_JSON(ctx,myipaddr,pubsock,profitmargin,argjson,"127.0.0.1",0)) != 0 ) { //printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); if ( pubsock >= 0 ) //strncmp("{\"error\":",retstr,strlen("{\"error\":")) != 0 && @@ -93,7 +93,7 @@ char *LP_command_process(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t * return(retstr); } -char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen,int32_t recvsock) +char *LP_process_message(void *ctx,char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen,int32_t recvsock) { int32_t len,datalen=0; char *retstr=0,*jsonstr=0; cJSON *argjson,*reqjson; if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) @@ -112,7 +112,7 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro if ( jstr(argjson,"method") != 0 && strcmp(jstr(argjson,"method"),"forwardhex") == 0 ) { //printf("got forwardhex\n"); - if ( (retstr= LP_forwardhex(pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) + if ( (retstr= LP_forwardhex(ctx,pubsock,jbits256(argjson,"pubkey"),jstr(argjson,"hex"))) != 0 ) { } } @@ -125,7 +125,7 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) LP_send(pubsock,jprint(reqjson,1),1); } - else if ( (retstr= LP_command_process(myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvlen - len,profitmargin)) != 0 ) + else if ( (retstr= LP_command_process(ctx,myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvlen - len,profitmargin)) != 0 ) { } portable_mutex_unlock(&LP_commandmutex); @@ -154,7 +154,7 @@ char *LP_process_message(char *typestr,char *myipaddr,int32_t pubsock,double pro return(retstr); } -int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) +int32_t LP_pullsock_check(void *ctx,char **retstrp,char *myipaddr,int32_t pubsock,int32_t pullsock,double profitmargin) { void *ptr; int32_t recvlen=-1,nonz = 0; *retstrp = 0; @@ -163,13 +163,13 @@ int32_t LP_pullsock_check(char **retstrp,char *myipaddr,int32_t pubsock,int32_t while ( (recvlen= nn_recv(pullsock,&ptr,NN_MSG,0)) > 0 ) { nonz++; - *retstrp = LP_process_message("PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); + *retstrp = LP_process_message(ctx,"PULL",myipaddr,pubsock,profitmargin,ptr,recvlen,pullsock); } } return(nonz); } -int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double profitmargin) +int32_t LP_subsock_check(void *ctx,char *myipaddr,int32_t pubsock,int32_t sock,double profitmargin) { int32_t recvlen,nonz = 0; void *ptr; char *retstr; if ( sock >= 0 ) @@ -177,7 +177,7 @@ int32_t LP_subsock_check(char *myipaddr,int32_t pubsock,int32_t sock,double prof while ( (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) > 0 ) { nonz++; - if ( (retstr= LP_process_message("SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock)) != 0 ) + if ( (retstr= LP_process_message(ctx,"SUB",myipaddr,pubsock,profitmargin,ptr,recvlen,sock)) != 0 ) free(retstr); } } @@ -205,10 +205,10 @@ void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitma } } -void LP_myutxo_updates(int32_t pubsock,char *passphrase,double profitmargin) +void LP_myutxo_updates(void *ctx,int32_t pubsock,char *passphrase,double profitmargin) { //LP_utxopurge(0); not good to disrupt existing pointers - LP_privkey_updates(pubsock,passphrase,0); + LP_privkey_updates(ctx,pubsock,passphrase,0); } int32_t LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pubsock,struct LP_peerinfo *peer,uint32_t now,double profitmargin,int32_t interval) @@ -229,7 +229,7 @@ int32_t LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pu return(n); } -int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,uint16_t pushport,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) +int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,uint16_t pushport,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) { static uint32_t counter,lastforward,numpeers; struct LP_utxoinfo *utxo,*utmp; char *retstr,*origipaddr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0,n=0,lastn=-1; @@ -265,12 +265,12 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso LP_peer_pricesquery(peer->ipaddr,peer->port); peer->diduquery = now; } - nonz += LP_subsock_check(origipaddr,pubsock,peer->subsock,profitmargin); + nonz += LP_subsock_check(ctx,origipaddr,pubsock,peer->subsock,profitmargin); } //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d forwarding\n",counter,LP_canbind); if ( (counter % 600) == 60 ) { - LP_myutxo_updates(pubsock,passphrase,profitmargin); + LP_myutxo_updates(ctx,pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) { LP_forwarding_register(LP_mypubkey,pushaddr,pushport,10); @@ -301,7 +301,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso } } //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d pullsock check\n",counter,LP_canbind); - nonz += LP_pullsock_check(&retstr,myipaddr,pubsock,pullsock,profitmargin); + nonz += LP_pullsock_check(ctx,&retstr,myipaddr,pubsock,pullsock,profitmargin); if ( retstr != 0 ) free(retstr); //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d hellos\n",counter,LP_canbind); @@ -320,7 +320,7 @@ int32_t LP_mainloop_iter(char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubso return(nonz); } -void LP_initcoins(int32_t pubsock,cJSON *coins,char *passphrase) +void LP_initcoins(void *ctx,int32_t pubsock,cJSON *coins,char *passphrase) { int32_t i,n; cJSON *item; for (i=0; i= 0 ) nn_close(pullsock); - pullsock = LP_initpublicaddr(&mypullport,pushaddr,myipaddr,mypullport,0); + pullsock = LP_initpublicaddr(ctx,&mypullport,pushaddr,myipaddr,mypullport,0); LP_deadman_switch = (uint32_t)time(NULL); LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,100000); } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 29a4313f1..1d669009a 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -359,7 +359,7 @@ char *LP_psock(char *myipaddr,int32_t ispaired) */ -int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) +int32_t nn_tests(void *ctx,int32_t pullsock,char *pushaddr,int32_t nnother) { int32_t sock,n,m,timeout,retval = -1; char msg[512],*retstr; printf("nn_tests.(%s)\n",pushaddr); @@ -375,7 +375,7 @@ int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); n = LP_send(sock,msg,0); sleep(3); - LP_pullsock_check(&retstr,"127.0.0.1",-1,pullsock,0.); + LP_pullsock_check(ctx,&retstr,"127.0.0.1",-1,pullsock,0.); sprintf(msg,"{\"method\":\"nn_tests2\",\"ipaddr\":\"%s\"}",pushaddr); m = LP_send(pullsock,msg,0); printf(">>>>>>>>>>>>>>>>>>>>>> sent %d+%d bytes -> pullsock.%d retstr.(%s)\n",n,m,pullsock,retstr!=0?retstr:""); @@ -390,7 +390,7 @@ int32_t nn_tests(int32_t pullsock,char *pushaddr,int32_t nnother) return(retval); } -int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr,uint16_t mypullport,int32_t ispaired) +int32_t LP_initpublicaddr(void *ctx,uint16_t *mypullportp,char *publicaddr,char *myipaddr,uint16_t mypullport,int32_t ispaired) { int32_t nntype,pullsock,timeout,maxsize; char bindaddr[128],connectaddr[128]; *mypullportp = mypullport; @@ -444,7 +444,7 @@ int32_t LP_initpublicaddr(uint16_t *mypullportp,char *publicaddr,char *myipaddr, nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); //LP_send(pullsock,"hello init",0); } - if ( LP_canbind == 0 && ispaired == 0 && nn_tests(pullsock,publicaddr,NN_PUSH) < 0 ) + if ( LP_canbind == 0 && ispaired == 0 && nn_tests(ctx,pullsock,publicaddr,NN_PUSH) < 0 ) { printf("command socket didnt work\n"); exit(-1); diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index c67c105bb..8416d8ad9 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -176,7 +176,7 @@ char *LP_quotereceived(cJSON *argjson) } else return(clonestr("{\"error\":\"nullptr\"}")); } -char *LP_pricepings(char *myipaddr,int32_t pubsock,double profitmargin,char *base,char *rel,double price) +char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin,char *base,char *rel,double price) { bits256 zero; cJSON *reqjson = cJSON_CreateObject(); jaddbits256(reqjson,"pubkey",LP_mypubkey); @@ -194,7 +194,7 @@ char *LP_pricepings(char *myipaddr,int32_t pubsock,double profitmargin,char *bas jaddstr(reqjson,"method","forward"); jaddstr(reqjson,"method2","postprice"); memset(zero.bytes,0,sizeof(zero)); - LP_forward(myipaddr,pubsock,profitmargin,zero,jprint(reqjson,1),1); + LP_forward(ctx,myipaddr,pubsock,profitmargin,zero,jprint(reqjson,1),1); } return(clonestr("{\"result\":\"success\"}")); } @@ -294,7 +294,7 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) return(-1); } -double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *method,struct LP_quoteinfo *qp) +double LP_query(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargin,char *method,struct LP_quoteinfo *qp) { cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; if ( strcmp(method,"request") == 0 ) @@ -321,7 +321,7 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho jaddstr(reqjson,"method2",method); jaddstr(reqjson,"method","forward"); jaddbits256(reqjson,"pubkey",qp->srchash); - LP_forward(myipaddr,mypubsock,profitmargin,qp->srchash,jprint(reqjson,1),1); + LP_forward(ctx,myipaddr,mypubsock,profitmargin,qp->srchash,jprint(reqjson,1),1); } for (i=0; i<30; i++) { @@ -338,7 +338,7 @@ double LP_query(char *myipaddr,int32_t mypubsock,double profitmargin,char *metho return(price); } -int32_t LP_nanobind(char *pairstr,char *myipaddr) +int32_t LP_nanobind(void *ctx,char *pairstr,char *myipaddr) { int32_t i,timeout,r,pairsock = -1; uint16_t mypullport; char bindaddr[128]; if ( LP_canbind != 0 ) @@ -372,11 +372,11 @@ int32_t LP_nanobind(char *pairstr,char *myipaddr) } else printf("error binding to %s for %s\n",bindaddr,pairstr); } } - } else pairsock = LP_initpublicaddr(&mypullport,pairstr,myipaddr,0,0); + } else pairsock = LP_initpublicaddr(ctx,&mypullport,pairstr,myipaddr,0,0); return(pairsock); } -int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin,double price,struct LP_quoteinfo *qp) +int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin,double price,struct LP_quoteinfo *qp) { char pairstr[512]; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; struct iguana_info *coin; printf("LP_connectstartbob.(%s) with.(%s)\n",myipaddr,jprint(argjson,0)); @@ -389,7 +389,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs privkey = LP_privkey(utxo->coinaddr,coin->taddr); if ( bits256_nonz(privkey) != 0 && qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending && bits256_cmp(LP_mypubkey,qp->srchash) == 0 ) { - if ( (pair= LP_nanobind(pairstr,myipaddr)) >= 0 ) + if ( (pair= LP_nanobind(ctx,pairstr,myipaddr)) >= 0 ) { LP_requestinit(&qp->R,qp->srchash,qp->desthash,base,qp->satoshis,rel,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); swap = LP_swapinit(1,0,privkey,&qp->R,qp); @@ -409,7 +409,7 @@ int32_t LP_connectstartbob(int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjs jdelete(retjson,"method"); jaddstr(retjson,"method2","connected"); jaddstr(retjson,"method","forward"); - LP_forward(myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,jprint(retjson,1),1); + LP_forward(ctx,myipaddr,pubsock,profitmargin,utxo->S.otherpubkey,jprint(retjson,1),1); retval = 0; } else printf("error launching swaploop\n"); } else printf("couldnt bind to any port %s\n",pairstr); @@ -496,7 +496,7 @@ char *LP_connectedalice(cJSON *argjson) // alice } } -int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) +int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { char *method; cJSON *retjson; double qprice,price,bid,ask; struct LP_utxoinfo *autxo,*butxo; int32_t retval = -1; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) @@ -541,7 +541,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d jdelete(retjson,"method"); jaddstr(retjson,"method2","reserved"); jaddstr(retjson,"method","forward"); - LP_forward(myipaddr,pubsock,profitmargin,butxo->S.otherpubkey,jprint(retjson,1),1); + LP_forward(ctx,myipaddr,pubsock,profitmargin,butxo->S.otherpubkey,jprint(retjson,1),1); butxo->T.lasttime = (uint32_t)time(NULL); printf("set swappending.%u accept qprice %.8f, min %.8f\n",butxo->T.swappending,qprice,price); } else printf("warning swappending.%u swap.%p\n",butxo->T.swappending,butxo->S.swap); @@ -550,7 +550,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d { retval = 4; if ( butxo->T.swappending != 0 && butxo->S.swap == 0 ) - LP_connectstartbob(pubsock,butxo,argjson,myipaddr,Q.srccoin,Q.destcoin,profitmargin,qprice,&Q); + LP_connectstartbob(ctx,pubsock,butxo,argjson,myipaddr,Q.srccoin,Q.destcoin,profitmargin,qprice,&Q); else printf("pend.%u swap %p when connect came in (%s)\n",butxo->T.swappending,butxo->S.swap,jprint(argjson,0)); } } @@ -558,7 +558,7 @@ int32_t LP_tradecommand(char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *d return(retval); } -char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume,int32_t timeout) +char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume,int32_t timeout) { int64_t satoshis,destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) @@ -636,13 +636,13 @@ char *LP_autotrade(char *myipaddr,int32_t mypubsock,double profitmargin,char *ba return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); - price = LP_query(myipaddr,mypubsock,profitmargin,"request",&Q); + price = LP_query(ctx,myipaddr,mypubsock,profitmargin,"request",&Q); bestitem = LP_quotejson(&Q); if ( price > SMALLVAL ) { if ( price <= maxprice ) { - price = LP_query(myipaddr,mypubsock,profitmargin,"connect",&Q); + price = LP_query(ctx,myipaddr,mypubsock,profitmargin,"connect",&Q); LP_requestinit(&Q.R,Q.srchash,Q.desthash,base,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); expiration = (uint32_t)time(NULL) + timeout; while ( time(NULL) < expiration ) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 80f6de979..66f239e59 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -722,7 +722,7 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr return(total); } -bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *coin,char *passphrase,char *wifstr) +bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *coin,char *passphrase,char *wifstr) { static uint32_t counter; bits256 privkey,userpub,userpass; char tmpstr[128]; cJSON *retjson; uint8_t tmptype,rmd160[20]; @@ -733,7 +733,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co privkey = iguana_wif2privkey(wifstr); //printf("WIF.(%s) -> %s\n",wifstr,bits256_str(str,privkey)); } - iguana_priv2pub(pubkey33,coin->smartaddr,privkey,coin->pubtype); + iguana_priv2pub(ctx,pubkey33,coin->smartaddr,privkey,coin->taddr,coin->pubtype); if ( coin->counter == 0 ) { coin->counter++; @@ -757,7 +757,7 @@ bits256 LP_privkeycalc(uint8_t *pubkey33,bits256 *pubkeyp,struct iguana_info *co return(privkey); } -void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t initonly) +void LP_privkey_updates(void *ctx,int32_t pubsock,char *passphrase,int32_t initonly) { int32_t i; struct iguana_info *coin; bits256 pubkey,privkey; uint8_t pubkey33[33]; memset(privkey.bytes,0,sizeof(privkey)); @@ -768,7 +768,7 @@ void LP_privkey_updates(int32_t pubsock,char *passphrase,int32_t initonly) if ( (coin= LP_coinfind(LP_coins[i].symbol)) != 0 ) { if ( bits256_nonz(privkey) == 0 || coin->smartaddr[0] == 0 ) - privkey = LP_privkeycalc(pubkey33,&pubkey,coin,passphrase,""); + privkey = LP_privkeycalc(ctx,pubkey33,&pubkey,coin,passphrase,""); if ( coin->inactive == 0 && initonly == 0 ) LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33); } diff --git a/iguana/exchanges/mm.c b/iguana/exchanges/mm.c index a80982185..1babc9d76 100644 --- a/iguana/exchanges/mm.c +++ b/iguana/exchanges/mm.c @@ -24,7 +24,7 @@ #include #include "OS_portable.h" #define MAX(a,b) ((a) > (b) ? (a) : (b)) -char *stats_JSON(char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjson,char *remoteaddr,uint16_t port); +char *stats_JSON(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjson,char *remoteaddr,uint16_t port); #include "stats.c" void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32]); @@ -220,28 +220,6 @@ bits256 iguana_wif2privkey(char *wifstr) return(privkey); } -void iguana_priv2pub(uint8_t *pubkey33,char *coinaddr,bits256 privkey,uint8_t addrtype) -{ - char privstr[65],url[512],postdata[1024],*retstr,*pubstr,*addr; cJSON *retjson; - memset(pubkey33,0,33); - coinaddr[0] = 0; - bits256_str(privstr,privkey); - sprintf(url,"%s/?",IGUANA_URL); - sprintf(postdata,"{\"agent\":\"SuperNET\",\"method\":\"priv2pub\",\"privkey\":\"%s\",\"addrtype\":%u}",privstr,addrtype); - if ( (retstr= bitcoind_RPC(0,"SuperNET",url,0,"priv2pub",postdata,0)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (pubstr= jstr(retjson,"secp256k1")) != 0 && strlen(pubstr) == 66 ) - decode_hex(pubkey33,33,pubstr); - if ( (addr= jstr(retjson,"result")) != 0 && strlen(addr) < 64 ) - strcpy(coinaddr,addr); - free_json(retjson); - } - free(retstr); - } -} - double bittrex_balance(char *base,char *coinaddr) { char *retstr; cJSON *retjson; double balance = 0.; diff --git a/iguana/exchanges/stats.c b/iguana/exchanges/stats.c index b0b4b11d8..64e4f985e 100644 --- a/iguana/exchanges/stats.c +++ b/iguana/exchanges/stats.c @@ -302,10 +302,15 @@ cJSON *SuperNET_urlconv(char *value,int32_t bufsize,char *urlstr) return(json); } +extern void *bitcoin_ctx(); + char *stats_rpcparse(char *retbuf,int32_t bufsize,int32_t *jsonflagp,int32_t *postflagp,char *urlstr,char *remoteaddr,char *filetype,uint16_t port) { + static void *ctx; cJSON *tokens,*argjson,*origargjson,*tmpjson=0,*json = 0; long filesize; double profitmargin = 0.; char *myipaddr="127.0.0.1",symbol[64],buf[4096],*userpass=0,urlmethod[16],*data,url[8192],furl[8192],*retstr,*filestr,*token = 0; int32_t i,j,n,num=0; //printf("rpcparse.(%s)\n",urlstr); + if ( ctx == 0 ) + ctx = bitcoin_ctx(); for (i=0; i Date: Tue, 20 Jun 2017 23:57:01 +0300 Subject: [PATCH 1814/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 3185da0f0..3e8667445 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2080,7 +2080,7 @@ char *bitcoin_address(char *coinaddr,uint8_t taddr,uint8_t addrtype,uint8_t *pub if ( (coinaddr= bitcoin_base58encode(coinaddr,data,24+offset)) != 0 ) { uint8_t checktype,rmd160[20]; char checkaddr[65]; - bitcoin_addr2rmd160(taddr,&checktype,rmd160,coinaddr); + bitcoin_addr2rmd160(taddr,&checktype,rmd160,checkaddr); if ( strcmp(checkaddr,coinaddr) != 0 ) printf("taddr.%02x checkaddr.(%s) vs coinaddr.(%s) %02x vs [%02x] memcmp.%d\n",taddr,checkaddr,coinaddr,addrtype,checktype,memcmp(rmd160,data+1,20)); } else printf("null coinaddr taddr.%02x\n",taddr); From 87190c0b091d4bf43ffd78d8ea7323b396853c19 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 00:00:06 +0300 Subject: [PATCH 1815/2705] Test --- iguana/exchanges/LP_bitcoin.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 3e8667445..9f3fae745 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2079,10 +2079,6 @@ char *bitcoin_address(char *coinaddr,uint8_t taddr,uint8_t addrtype,uint8_t *pub data[20+offset+i] = hash.bytes[31-i]; if ( (coinaddr= bitcoin_base58encode(coinaddr,data,24+offset)) != 0 ) { - uint8_t checktype,rmd160[20]; char checkaddr[65]; - bitcoin_addr2rmd160(taddr,&checktype,rmd160,checkaddr); - if ( strcmp(checkaddr,coinaddr) != 0 ) - printf("taddr.%02x checkaddr.(%s) vs coinaddr.(%s) %02x vs [%02x] memcmp.%d\n",taddr,checkaddr,coinaddr,addrtype,checktype,memcmp(rmd160,data+1,20)); } else printf("null coinaddr taddr.%02x\n",taddr); return(coinaddr); } From ae155c5577d11102cded747634185a55985f89c0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 00:40:56 +0300 Subject: [PATCH 1816/2705] Test --- iguana/exchanges/LP_coins.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 65ba8bc43..4a8c4ed81 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -245,6 +245,8 @@ struct iguana_info *LP_coinfind(char *symbol) } else if ( strcmp(symbol,"KMD") == 0 ) name = "komodo"; + else if ( strcmp(symbol,"HUSH") == 0 ) + name = "hush"; else { name = symbol; From 304b6cf3c91c2b137167191d0684798b3c3d4d70 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 09:32:16 +0300 Subject: [PATCH 1817/2705] Test --- iguana/exchanges/LP_prices.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 598d0d3ad..50a147ecd 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -52,6 +52,8 @@ struct LP_pubkeyinfo struct LP_priceinfo *LP_priceinfofind(char *symbol) { int32_t i; struct LP_priceinfo *pp; uint64_t coinbits; + if ( symbol == 0 || symbol[0] == 0 ) + return(0); if ( LP_numpriceinfos > 0 ) { coinbits = stringbits(symbol); @@ -93,6 +95,8 @@ int32_t LP_cachekey(uint8_t *key,char *base,char *rel,bits256 txid,int32_t vout) struct LP_cacheinfo *LP_cachefind(char *base,char *rel,bits256 txid,int32_t vout) { struct LP_cacheinfo *ptr=0; uint8_t key[sizeof(bits256)+sizeof(uint64_t)*2+sizeof(vout)]; + if ( base == 0 || rel == 0 ) + return(0); if ( LP_cachekey(key,base,rel,txid,vout) == sizeof(key) ) { portable_mutex_lock(&LP_cachemutex); @@ -265,32 +269,6 @@ void LP_priceinfoupdate(char *base,char *rel,double price) } } -/*double LP_myprice(double *bidp,double *askp,char *base,char *rel) -{ - struct LP_priceinfo *basepp,*relpp; double val; - *bidp = *askp = 0.; - if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) - { - if ( (*askp= basepp->myprices[relpp->ind]) > SMALLVAL ) - { - if ( (val= relpp->myprices[basepp->ind]) > SMALLVAL ) - { - *bidp = 1. / val; - } else *bidp = *askp * 0.99; - return((*askp + *bidp) * 0.5); - } - else - { - if ( (val= relpp->myprices[basepp->ind]) > SMALLVAL ) - { - *bidp = 1. / val; - *askp = *bidp / 0.99; - } - } - } - return(0.); -}*/ - double LP_myprice(double *bidp,double *askp,char *base,char *rel) { struct LP_priceinfo *basepp,*relpp; double val; From 369f2e0f2b356ae6e9c974a47919e8b4a3168be7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 10:14:25 +0300 Subject: [PATCH 1818/2705] Test --- iguana/exchanges/LP_network.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 1d669009a..b482dee2b 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -100,7 +100,8 @@ uint32_t LP_swapsend(int32_t pairsock,struct basilisk_swap *swap,uint32_t msgbit void LP_psockloop(void *_ptr) { - int32_t i,n,nonz,iter,retval,size=0,sentbytes,sendsock = -1; uint32_t now; struct psock *ptr=0; void *buf=0; struct nn_pollfd *pfds; char keepalive[512];//,*myipaddr = _ptr; + static struct nn_pollfd *pfds; + int32_t i,n,nonz,iter,retval,size=0,sentbytes,sendsock = -1; uint32_t now; struct psock *ptr=0; void *buf=0; char keepalive[512];//,*myipaddr = _ptr; while ( 1 ) { now = (uint32_t)time(NULL); @@ -130,8 +131,10 @@ void LP_psockloop(void *_ptr) } else if ( Numpsocks > 0 ) { - pfds = calloc(Numpsocks,sizeof(*pfds) * 2); + if ( pfds == 0 ) + pfds = calloc(60000,sizeof(*pfds)); portable_mutex_lock(&LP_psockmutex); + memset(pfds,0,sizeof(*pfds) * ((Numpsocks < 30000) ? Numpsocks*2 : 60000)); for (iter=0; iter<2; iter++) { for (i=n=0; i Date: Wed, 21 Jun 2017 10:28:51 +0300 Subject: [PATCH 1819/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 4a8c4ed81..2634b914e 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -119,7 +119,6 @@ void LP_statefname(char *fname,char *symbol,char *assetname,char *str) strcat(fname,"/"); #endif strcat(fname,str); - //printf("LP_statefname.(%s) <- %s %s %s\n",fname,symbol,assetname,str); } int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) @@ -140,6 +139,7 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) LP_userpassfp(symbol,username,password,fp); sprintf(userpass,"%s:%s",username,password); fclose(fp); + printf("LP_statefname.(%s) <- %s %s (%s)\n",fname,symbol,assetname,userpass); return((int32_t)strlen(userpass)); } else printf("cant open.(%s)\n",fname); return(-1); From 388f1e8de66b10e0208844c33bba8a334767ac07 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 10:36:36 +0300 Subject: [PATCH 1820/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_network.c | 89 +++++++++++++++++---------------- 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a1dadda84..798cda041 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -482,7 +482,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_close(pullsock); pullsock = LP_initpublicaddr(ctx,&mypullport,pushaddr,myipaddr,mypullport,0); LP_deadman_switch = (uint32_t)time(NULL); - LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,100000); + LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,MAX_PSOCK_PORT); } } } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index b482dee2b..cf95fc9db 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -19,6 +19,8 @@ // #define PSOCK_KEEPALIVE 600 +#define MAX_PSOCK_PORT 60000 +#define MIN_PSOCK_PORT 10000 struct psock { @@ -28,7 +30,7 @@ struct psock char sendaddr[128],publicaddr[128]; } *PSOCKS; -uint16_t Numpsocks,Psockport = 10000; +uint16_t Numpsocks,Psockport = MIN_PSOCK_PORT; char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port) { @@ -47,7 +49,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) return(-1); } len = (int32_t)strlen(msg) + 1; - for (i=0; i<1000; i++) + for (i=0; i<1000; i++) // 1000 * (1 ms + 1000 us) = 2 seconds { pfd.fd = sock; pfd.events = NN_POLLOUT; @@ -66,8 +68,6 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) usleep(1000); } printf("error LP_send sock.%d, i.%d timeout.(%s) %s\n",sock,i,msg,nn_strerror(nn_errno())); - //if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) - // printf("LP_send sent %d instead of %d\n",sentbytes,len); if ( freeflag != 0 ) free(msg); return(-1); @@ -132,9 +132,9 @@ void LP_psockloop(void *_ptr) else if ( Numpsocks > 0 ) { if ( pfds == 0 ) - pfds = calloc(60000,sizeof(*pfds)); + pfds = calloc(MAX_PSOCK_PORT,sizeof(*pfds)); portable_mutex_lock(&LP_psockmutex); - memset(pfds,0,sizeof(*pfds) * ((Numpsocks < 30000) ? Numpsocks*2 : 60000)); + memset(pfds,0,sizeof(*pfds) * ((Numpsocks*2 <= MAX_PSOCK_PORT) ? Numpsocks*2 : MAX_PSOCK_PORT)); for (iter=0; iter<2; iter++) { for (i=n=0; i 60000 ) - Psockport = 10000; - if ( i == 100 ) + if ( Psockport > MAX_PSOCK_PORT ) + Psockport = MIN_PSOCK_PORT; + if ( i == maxiters ) jaddstr(retjson,"error","cant find psock ports"); return(jprint(retjson,1)); } @@ -419,38 +421,41 @@ int32_t LP_initpublicaddr(void *ctx,uint16_t *mypullportp,char *publicaddr,char printf("try to get publicaddr again\n"); } } - if ( (pullsock= nn_socket(AF_SP,nntype)) >= 0 ) + while ( 1 ) { - if ( LP_canbind == 0 ) + if ( (pullsock= nn_socket(AF_SP,nntype)) >= 0 ) { - if ( nn_connect(pullsock,connectaddr) < 0 ) + if ( LP_canbind == 0 ) { - printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); - exit(-1); - } else printf("nntype.%d NN_PAIR.%d connect to %s connectsock.%d\n",nntype,NN_PAIR,connectaddr,pullsock); - } - else - { - if ( nn_bind(pullsock,bindaddr) < 0 ) + if ( nn_connect(pullsock,connectaddr) < 0 ) + { + printf("bind to %s error for %s: %s\n",connectaddr,publicaddr,nn_strerror(nn_errno())); + exit(-1); + } else printf("nntype.%d NN_PAIR.%d connect to %s connectsock.%d\n",nntype,NN_PAIR,connectaddr,pullsock); + } + else { - printf("bind to %s error for %s: %s\n",bindaddr,publicaddr,nn_strerror(nn_errno())); - exit(-1); + if ( nn_bind(pullsock,bindaddr) < 0 ) + { + printf("bind to %s error for %s: %s\n",bindaddr,publicaddr,nn_strerror(nn_errno())); + exit(-1); + } } + timeout = 1; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + timeout = 1; + nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + //maxsize = 2 * 1024 * 1024; + //nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); + if ( nntype == NN_SUB ) + nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); } - timeout = 1; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); - timeout = 1; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - maxsize = 2 * 1024 * 1024; - nn_setsockopt(pullsock,NN_SOL_SOCKET,NN_RCVBUF,&maxsize,sizeof(maxsize)); - if ( nntype == NN_SUB ) - nn_setsockopt(pullsock,NN_SUB,NN_SUB_SUBSCRIBE,"",0); - //LP_send(pullsock,"hello init",0); - } - if ( LP_canbind == 0 && ispaired == 0 && nn_tests(ctx,pullsock,publicaddr,NN_PUSH) < 0 ) - { - printf("command socket didnt work\n"); - exit(-1); + if ( LP_canbind != 0 || ispaired != 0 || nn_tests(ctx,pullsock,publicaddr,NN_PUSH) >= 0 ) + break; + printf("nn_tests failed, try again\n"); + sleep(3); + if ( pullsock >= 0 ) + nn_close(pullsock); } return(pullsock); } From 27c1f19942249b1721b325c1e7287c135c302edc Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 10:40:08 +0300 Subject: [PATCH 1821/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 798cda041..ab690eabd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -470,6 +470,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } while ( 1 ) { + fprintf(stderr,"."); if ( LP_mainloop_iter(ctx,myipaddr,mypeer,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin) == 0 ) usleep(100000); if ( LP_canbind == 0 ) From 94514cd68739ea3eb50817aec3127b8bdbd3b7ba Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 10:55:39 +0300 Subject: [PATCH 1822/2705] Test --- iguana/exchanges/LP_forwarding.c | 8 +++++--- iguana/exchanges/LP_nativeDEX.c | 8 +++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index cb368afe2..ad1207901 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -60,7 +60,7 @@ int32_t LP_hello(struct LP_forwardinfo *ptr) if ( nn_poll(&pfd,1,1) > 0 ) { sprintf(msg,"{\"method\":\"hello\",\"from\":\"%s\"}",LP_mypeer != 0 ? LP_mypeer->ipaddr : ""); - printf("HELLO sent.%d bytes to %s on i.%d\n",LP_send(ptr->pushsock,msg,0),ptr->pushaddr,i); + //printf("HELLO sent.%d bytes to %s on i.%d\n",LP_send(ptr->pushsock,msg,0),ptr->pushaddr,i); ptr->hello = (uint32_t)time(NULL); return(i); } @@ -120,8 +120,10 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) { nn_close(ptr->pushsock); if ( LP_psockmark(ptr->pushaddr) < 0 ) - printf("cant mark (%s)\n",ptr->pushaddr); - printf("recreate pushsock for %s\n",pushaddr); + { + //printf("cant mark (%s)\n",ptr->pushaddr); + } + char str[65]; printf("%u recreate pushsock for %s <- %s\n",(uint32_t)time(NULL),pushaddr,bits256_str(str,pubkey)); strcpy(ptr->pushaddr,pushaddr); if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 ) return(clonestr("{\"error\":\"couldnt recreate pushsock\",\"registered\":0}")); diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index ab690eabd..d2615f54e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -397,7 +397,13 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); if ( jobj(argjson,"canbind") == 0 ) + { +#ifndef __linux__ + LP_canbind = 1; +#else LP_canbind = IAMLP; +#endif + } else LP_canbind = jint(argjson,"canbind"); srand((int32_t)n); if ( userhome != 0 && userhome[0] != 0 ) @@ -470,7 +476,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } while ( 1 ) { - fprintf(stderr,"."); + //fprintf(stderr,"."); if ( LP_mainloop_iter(ctx,myipaddr,mypeer,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin) == 0 ) usleep(100000); if ( LP_canbind == 0 ) From c72f737e9a09b6024213081fcbc4a08428089e54 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 10:58:42 +0300 Subject: [PATCH 1823/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d2615f54e..06b90943f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -314,7 +314,9 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int sprintf(keepalive,"{\"method\":\"keepalive\"}"); //printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); if ( LP_send(pullsock,keepalive,0) < 0 ) - LP_deadman_switch = 0; + { + //LP_deadman_switch = 0; + } } counter++; return(nonz); From bb55ff4095b6cf8f383e9332c0025c2538e3c549 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 10:58:58 +0300 Subject: [PATCH 1824/2705] test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 06b90943f..0a4aa8d08 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -401,7 +401,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit if ( jobj(argjson,"canbind") == 0 ) { #ifndef __linux__ - LP_canbind = 1; + LP_canbind = IAMLP; #else LP_canbind = IAMLP; #endif From f0e2b7122f761397c018be411cdc75b2570044c4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 11:02:00 +0300 Subject: [PATCH 1825/2705] Test --- iguana/exchanges/LP_include.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index b00ef444f..f28054ab2 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -24,7 +24,7 @@ #define LP_COMMAND_SENDSOCK NN_PUSH #define LP_COMMAND_RECVSOCK NN_PULL -#define LP_HTTP_TIMEOUT 1 +#define LP_HTTP_TIMEOUT 3 #define LP_MAXPEER_ERRORS 3 #define LP_SWAPSTEP_TIMEOUT 3 #define LP_AUTOTRADE_TIMEOUT 3 From 76b05f86e65dda7bb82a3991eaf3fe105b12422f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 11:05:12 +0300 Subject: [PATCH 1826/2705] Test --- iguana/exchanges/LP_include.h | 6 ++++++ iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_network.c | 4 ---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index f28054ab2..1e797b2e7 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -24,6 +24,12 @@ #define LP_COMMAND_SENDSOCK NN_PUSH #define LP_COMMAND_RECVSOCK NN_PULL + +#define PSOCK_KEEPALIVE 600 +#define MAINLOOP_PERSEC 10 +#define MAX_PSOCK_PORT 60000 +#define MIN_PSOCK_PORT 10000 + #define LP_HTTP_TIMEOUT 3 #define LP_MAXPEER_ERRORS 3 #define LP_SWAPSTEP_TIMEOUT 3 diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0a4aa8d08..1432c4537 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -308,7 +308,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int if ( IAMLP != 0 && (counter % 600) == 42 ) LP_hellos(); //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d\n",counter,LP_canbind); - if ( LP_canbind == 0 && (counter % 60) == 13 ) + if ( LP_canbind == 0 && (counter % (PSOCK_KEEPALIVE*MAINLOOP_PERSEC/2)) == 13 ) { char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); @@ -480,7 +480,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit { //fprintf(stderr,"."); if ( LP_mainloop_iter(ctx,myipaddr,mypeer,pubsock,pushaddr,mypullport,pullsock,myport,passphrase,profitmargin) == 0 ) - usleep(100000); + usleep(1000000 / MAINLOOP_PERSEC); if ( LP_canbind == 0 ) { //printf("check deadman %u vs %u\n",LP_deadman_switch,(uint32_t)time(NULL)); diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index cf95fc9db..b69385cb2 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -18,10 +18,6 @@ // marketmaker // -#define PSOCK_KEEPALIVE 600 -#define MAX_PSOCK_PORT 60000 -#define MIN_PSOCK_PORT 10000 - struct psock { uint32_t lasttime,lastping,errors; From 8205b9e4583075861c3a5619282725fbb59f292a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 11:17:42 +0300 Subject: [PATCH 1827/2705] Test --- iguana/exchanges/LP_coins.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 2634b914e..83d01b2c8 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -245,13 +245,7 @@ struct iguana_info *LP_coinfind(char *symbol) } else if ( strcmp(symbol,"KMD") == 0 ) name = "komodo"; - else if ( strcmp(symbol,"HUSH") == 0 ) - name = "hush"; - else - { - name = symbol; - assetname = symbol; - } + else return(0); LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,0); if ( (coin= LP_coinadd(&cdata)) != 0 && strcmp(symbol,"KMD") == 0 ) coin->inactive = 0; @@ -281,6 +275,8 @@ struct iguana_info *LP_coincreate(cJSON *item) name = assetname; else if ( (name= jstr(item,"name")) == 0 ) name = symbol; + if ( strcmp(symbol,"HUSH") == 0 ) + printf("init HUSH %s %s %s\n",symbol,name,assetname); LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,jint(item,"taddr")); coin = LP_coinadd(&cdata); } From 1ac4b90ff107d1e63940cf4951fdb511f65c345a Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 11:28:49 +0300 Subject: [PATCH 1828/2705] Test --- iguana/exchanges/LP_coins.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 83d01b2c8..c00c6008d 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -72,7 +72,7 @@ void LP_userpassfp(char *symbol,char *username,char *password,FILE *fp) free(rpcpassword); } -void LP_statefname(char *fname,char *symbol,char *assetname,char *str) +void LP_statefname(char *fname,char *symbol,char *assetname,char *str,char *name) { sprintf(fname,"%s",LP_getdatadir()); #ifdef WIN32 @@ -88,13 +88,9 @@ void LP_statefname(char *fname,char *symbol,char *assetname,char *str) strcat(fname,".bitcoin"); #endif } - else if ( strcmp(symbol,"LTC") == 0 ) + else if ( name != 0 ) { -#ifdef __APPLE__ - strcat(fname,"Litecoin"); -#else - strcat(fname,".litecoin"); -#endif + strcat(fname,name); } else { @@ -121,7 +117,7 @@ void LP_statefname(char *fname,char *symbol,char *assetname,char *str) strcat(fname,str); } -int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) +int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot,char *name) { FILE *fp; char fname[512],username[512],password[512],confname[16]; userpass[0] = 0; @@ -133,13 +129,13 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot) if ( strcmp(&confname[len-4],"coin") == 0 ) confname[len - 4] = 'C'; #endif - LP_statefname(fname,symbol,assetname,confname); + LP_statefname(fname,symbol,assetname,confname,name); if ( (fp= fopen(fname,"rb")) != 0 ) { LP_userpassfp(symbol,username,password,fp); sprintf(userpass,"%s:%s",username,password); fclose(fp); - printf("LP_statefname.(%s) <- %s %s (%s)\n",fname,symbol,assetname,userpass); + printf("LP_statefname.(%s) <- %s %s %s (%s)\n",fname,name,symbol,assetname,userpass); return((int32_t)strlen(userpass)); } else printf("cant open.(%s)\n",fname); return(-1); @@ -175,6 +171,7 @@ cJSON *LP_coinsjson() void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain,uint8_t taddr) { + char *name2; memset(coin,0,sizeof(*coin)); safecopy(coin->symbol,symbol,sizeof(coin->symbol)); sprintf(coin->serverport,"127.0.0.1:%u",port); @@ -187,7 +184,10 @@ void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetnam coin->p2shtype = p2shtype; coin->wiftype = wiftype; coin->inactive = (uint32_t)time(NULL); - LP_userpass(coin->userpass,symbol,assetname,name); + if ( strcmp(symbol,"KMD") == 0 || (assetname != 0 && assetname[0] != 0) ) + name2 = 0; + else name2 = name; + LP_userpass(coin->userpass,symbol,assetname,name,name2); } struct iguana_info *LP_coinadd(struct iguana_info *cdata) From 110a2a786bdc9919f5e995b2461f52128d714c2f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 11:36:02 +0300 Subject: [PATCH 1829/2705] Test --- iguana/exchanges/LP_coins.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index c00c6008d..103fa1ea2 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -90,7 +90,19 @@ void LP_statefname(char *fname,char *symbol,char *assetname,char *str,char *name } else if ( name != 0 ) { - strcat(fname,name); + char name2[64]; +#ifdef __APPLE__ + int32_t len; + strcpy(name2,name); + name2[0] = toupper(name2[0]); + len = (int32_t)strlen(name2); + if ( strcmp(&name2[len-4],"coin") == 0 ) + name2[len - 4] = 'C'; +#else + name2[0] = '.'; + strcpy(name2+1,name); +#endif + strcat(fname,name2); } else { From df686624483655098f4f1e86a4a81c7273fad84f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 11:41:19 +0300 Subject: [PATCH 1830/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 103fa1ea2..4e4d22bc3 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -147,7 +147,7 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot,c LP_userpassfp(symbol,username,password,fp); sprintf(userpass,"%s:%s",username,password); fclose(fp); - printf("LP_statefname.(%s) <- %s %s %s (%s)\n",fname,name,symbol,assetname,userpass); + //printf("LP_statefname.(%s) <- %s %s %s (%s)\n",fname,name,symbol,assetname,userpass); return((int32_t)strlen(userpass)); } else printf("cant open.(%s)\n",fname); return(-1); From 502ef895999f66d512cc013c1afeb54a6c6a8a34 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 11:41:32 +0300 Subject: [PATCH 1831/2705] Test --- iguana/exchanges/LP_coins.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 4e4d22bc3..f636594d0 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -287,8 +287,6 @@ struct iguana_info *LP_coincreate(cJSON *item) name = assetname; else if ( (name= jstr(item,"name")) == 0 ) name = symbol; - if ( strcmp(symbol,"HUSH") == 0 ) - printf("init HUSH %s %s %s\n",symbol,name,assetname); LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,jint(item,"taddr")); coin = LP_coinadd(&cdata); } From 1f80f3f3ab5128872ece5c66feb7ce714f2437fc Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 12:10:49 +0300 Subject: [PATCH 1832/2705] Test --- iguana/exchanges/LP_network.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index b69385cb2..dc387a2fe 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -242,6 +242,7 @@ void LP_psockloop(void *_ptr) sprintf(keepalive,"{\"method\":\"keepalive\",\"endpoint\":\"%s\"}",ptr->sendaddr); size = (int32_t)strlen(keepalive) + 1; buf = keepalive; + printf("send keepalive.(%s)\n",keepalive); break; } } From 12105fa3334c1363af38c8ac5efbbf18976a37f7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 12:20:24 +0300 Subject: [PATCH 1833/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 1432c4537..7e2e2d8cd 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -32,7 +32,7 @@ char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; -char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", "5.9.253.204" }; // +char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", };//"5.9.253.204" }; // uint32_t LP_deadman_switch; int32_t LP_mypubsock = -1; From fb05a798c0cdbf98176214a520d81f9de0903524 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 13:07:30 +0300 Subject: [PATCH 1834/2705] Test --- iguana/exchanges/LP_coins.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index f636594d0..fcabe7c27 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -147,7 +147,8 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot,c LP_userpassfp(symbol,username,password,fp); sprintf(userpass,"%s:%s",username,password); fclose(fp); - //printf("LP_statefname.(%s) <- %s %s %s (%s)\n",fname,name,symbol,assetname,userpass); + if ( strcmp(symbol,"HUSH") == 0 ) + printf("LP_statefname.(%s) <- %s %s %s (%s)\n",fname,name,symbol,assetname,userpass); return((int32_t)strlen(userpass)); } else printf("cant open.(%s)\n",fname); return(-1); From fc17778de1319b040ccca70ca4235d2663cb0e37 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 13:22:21 +0300 Subject: [PATCH 1835/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- iguana/exchanges/client | 2 +- iguana/exchanges/run | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index fcabe7c27..e8e35f882 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -147,7 +147,7 @@ int32_t LP_userpass(char *userpass,char *symbol,char *assetname,char *confroot,c LP_userpassfp(symbol,username,password,fp); sprintf(userpass,"%s:%s",username,password); fclose(fp); - if ( strcmp(symbol,"HUSH") == 0 ) + if ( 0 && strcmp(symbol,"HUSH") == 0 ) printf("LP_statefname.(%s) <- %s %s %s (%s)\n",fname,name,symbol,assetname,userpass); return((int32_t)strlen(userpass)); } else printf("cant open.(%s)\n",fname); diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 2cb11e60c..494e686c6 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -5,7 +5,7 @@ git pull; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, -{\"active\":1,\"coin\":\"HUSH\",\"name\":\"hushcoin\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, +{\"active\":1,\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, diff --git a/iguana/exchanges/run b/iguana/exchanges/run index 858fe930d..d0e1e557f 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -1,7 +1,7 @@ source randval pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, -{\"coin\":\"HUSH\",\"name\":\"hushcoin\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, +{\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, From 002e0fdcf45a22c578a25632e3dbc45b67c09604 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 16:07:54 +0300 Subject: [PATCH 1836/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7e2e2d8cd..d63b7ca89 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -248,9 +248,10 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int { if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) { - printf("numpeers.%d updatepeer.%s lag.%d\n",numpeers,peer->ipaddr,now-peer->lastpeers); + if ( IAMLP != 0 ) + printf("numpeers.%d updatepeer.%s lag.%d\n",numpeers,peer->ipaddr,now-peer->lastpeers); peer->lastpeers = now; - if ( peer->numpeers != numpeers ) + if ( IAMLP != 0 && peer->numpeers != numpeers ) printf("%s num.%d vs %d\n",peer->ipaddr,peer->numpeers,numpeers); if ( strcmp(peer->ipaddr,myipaddr) != 0 ) LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport,profitmargin); From f16d4e83af2399d8d14ed2541be2b36743d967f1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 16:39:12 +0300 Subject: [PATCH 1837/2705] Test --- iguana/exchanges/LP_network.c | 2 +- iguana/exchanges/LP_ordermatch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index dc387a2fe..f63fc2438 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -394,7 +394,7 @@ int32_t nn_tests(void *ctx,int32_t pullsock,char *pushaddr,int32_t nnother) int32_t LP_initpublicaddr(void *ctx,uint16_t *mypullportp,char *publicaddr,char *myipaddr,uint16_t mypullport,int32_t ispaired) { - int32_t nntype,pullsock,timeout,maxsize; char bindaddr[128],connectaddr[128]; + int32_t nntype,pullsock,timeout; char bindaddr[128],connectaddr[128]; *mypullportp = mypullport; if ( ispaired == 0 ) { diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 8416d8ad9..929d0aac5 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -372,7 +372,7 @@ int32_t LP_nanobind(void *ctx,char *pairstr,char *myipaddr) } else printf("error binding to %s for %s\n",bindaddr,pairstr); } } - } else pairsock = LP_initpublicaddr(ctx,&mypullport,pairstr,myipaddr,0,0); + } else pairsock = LP_initpublicaddr(ctx,&mypullport,pairstr,myipaddr,0,1); return(pairsock); } From 7476c49052f6efc7d3d56b1be0b54976fd88ca7d Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 19:53:23 +0300 Subject: [PATCH 1838/2705] Test --- iguana/exchanges/LP_utxos.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 66f239e59..8310ff735 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -28,6 +28,8 @@ int32_t LP_ismine(struct LP_utxoinfo *utxo) int32_t LP_isavailable(struct LP_utxoinfo *utxo) { + if ( time(NULL) > utxo->T.swappending ) + utxo->T.swappending = 0; if ( utxo != 0 && utxo->T.swappending == 0 && utxo->S.swap == 0 ) return(1); else return(0); From 82d883aa276afb8f26b0b53203f63decd183698b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 20:30:04 +0300 Subject: [PATCH 1839/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- iguana/exchanges/LP_ordermatch.c | 18 ++++-------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index d63b7ca89..2681d5dad 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -30,7 +30,7 @@ struct LP_forwardinfo *LP_forwardinfos; char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; -char USERPASS[65],USERPASS_WIFSTR[64],USERHOME[512] = { "/root" }; +char USERPASS[65],USERPASS_WIFSTR[64],LP_myipaddr[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", };//"5.9.253.204" }; // @@ -438,6 +438,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit n = strlen(myipaddr); if ( myipaddr[n-1] == '\n' ) myipaddr[--n] = 0; + strcpy(LP_myipaddr,myipaddr); } else printf("error getting myipaddr\n"); } else printf("error issuing curl\n"); if ( IAMLP != 0 ) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 929d0aac5..a59f825d0 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -338,21 +338,11 @@ double LP_query(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargin,c return(price); } -int32_t LP_nanobind(void *ctx,char *pairstr,char *myipaddr) +int32_t LP_nanobind(void *ctx,char *pairstr) { int32_t i,timeout,r,pairsock = -1; uint16_t mypullport; char bindaddr[128]; if ( LP_canbind != 0 ) { - if ( strcmp(myipaddr,"127.0.0.1") == 0 ) - { - if ( LP_mypeer != 0 ) - myipaddr = LP_mypeer->ipaddr; - } - if ( strcmp(myipaddr,"127.0.0.1") == 0 ) - { - printf("cant nanobind to localhost\n"); - return(-1); - } if ( (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) printf("error creating utxo->pair\n"); else @@ -360,8 +350,8 @@ int32_t LP_nanobind(void *ctx,char *pairstr,char *myipaddr) for (i=0; i<10; i++) { r = (10000 + (rand() % 50000)) & 0xffff; - nanomsg_transportname(0,pairstr,myipaddr,r); - nanomsg_transportname(1,bindaddr,myipaddr,r); + nanomsg_transportname(0,pairstr,LP_myipaddr,r); + nanomsg_transportname(1,bindaddr,LP_myipaddr,r); if ( nn_bind(pairsock,bindaddr) >= 0 ) { timeout = 100; @@ -372,7 +362,7 @@ int32_t LP_nanobind(void *ctx,char *pairstr,char *myipaddr) } else printf("error binding to %s for %s\n",bindaddr,pairstr); } } - } else pairsock = LP_initpublicaddr(ctx,&mypullport,pairstr,myipaddr,0,1); + } else pairsock = LP_initpublicaddr(ctx,&mypullport,pairstr,"127.0.0.1",0,1); return(pairsock); } From cca4176eb17c4e64bb8a209424089d6958e8346f Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 20:33:19 +0300 Subject: [PATCH 1840/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index a59f825d0..723105cec 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -369,7 +369,7 @@ int32_t LP_nanobind(void *ctx,char *pairstr) int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin,double price,struct LP_quoteinfo *qp) { char pairstr[512]; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; struct iguana_info *coin; - printf("LP_connectstartbob.(%s) with.(%s)\n",myipaddr,jprint(argjson,0)); + printf("LP_connectstartbob.(%s) with.(%s) %s\n",myipaddr,jprint(argjson,0),LP_myipaddr); qp->quotetime = (uint32_t)time(NULL); if ( (coin= LP_coinfind(utxo->coin)) == 0 ) { From 988028e79ead5d23bf8395a98f53343e27beb6e9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 21 Jun 2017 20:34:53 +0300 Subject: [PATCH 1841/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 723105cec..01d43690b 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -379,7 +379,7 @@ int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJ privkey = LP_privkey(utxo->coinaddr,coin->taddr); if ( bits256_nonz(privkey) != 0 && qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending && bits256_cmp(LP_mypubkey,qp->srchash) == 0 ) { - if ( (pair= LP_nanobind(ctx,pairstr,myipaddr)) >= 0 ) + if ( (pair= LP_nanobind(ctx,pairstr)) >= 0 ) { LP_requestinit(&qp->R,qp->srchash,qp->desthash,base,qp->satoshis,rel,qp->destsatoshis,qp->timestamp,qp->quotetime,DEXselector); swap = LP_swapinit(1,0,privkey,&qp->R,qp); From 23da4a615add7e54a79cb46030f8097f83bd7c79 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 16:33:44 +0300 Subject: [PATCH 1842/2705] test --- iguana/exchanges/LP_forwarding.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index ad1207901..9e9e4b320 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -207,7 +207,7 @@ char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) if ( reqjson != 0 ) { retstr = LP_command_process(ctx,LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); - //printf("LP_forwardhex.(%s) -> (%s)\n",jprint(reqjson,0),retstr!=0?retstr:""); + printf("LP_forwardhex.(%s) -> (%s)\n",jprint(reqjson,0),retstr!=0?retstr:""); if ( pubsock >= 0 ) LP_send(pubsock,jprint(reqjson,0),0); } else printf("LP_forwardhex couldnt parse (%s)\n",(char *)data); @@ -216,7 +216,7 @@ char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) { if ( ptr->pushsock >= 0 )//&& ptr->hello != 0 ) { - //printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data); + printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data); sentbytes = LP_send(ptr->pushsock,(char *)data,0); } retjson = cJSON_CreateObject(); @@ -293,7 +293,7 @@ int32_t LP_forward(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin, } else retval = 0; if ( retval >= 0 && peer->pushsock >= 0 ) { - //printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); + printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,jsonstr); len = (int32_t)strlen(jsonstr) + 1; hexstr = malloc(len*2 + 1); init_hexbytes_noT(hexstr,(uint8_t *)jsonstr,len); From fb8451e888e1ca700419a7239b0a35f8ca1cb3eb Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 19:22:22 +0300 Subject: [PATCH 1843/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 158ccf323..55e2b2832 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -662,7 +662,7 @@ void LP_bobloop(void *_swap) expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",5*LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); else if ( LP_waitsend("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); @@ -718,7 +718,7 @@ void LP_aliceloop(void *_swap) if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); - if ( LP_sendwait("pubkeys",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_sendwait("pubkeys",5*LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); else if ( LP_sendwait("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); From 6757d89640386ee9f7f068d1e57204dfd8def482 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 19:30:31 +0300 Subject: [PATCH 1844/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_swap.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 1e797b2e7..0036bb5fc 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -30,7 +30,7 @@ #define MAX_PSOCK_PORT 60000 #define MIN_PSOCK_PORT 10000 -#define LP_HTTP_TIMEOUT 3 +#define LP_HTTP_TIMEOUT 1 #define LP_MAXPEER_ERRORS 3 #define LP_SWAPSTEP_TIMEOUT 3 #define LP_AUTOTRADE_TIMEOUT 3 diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 55e2b2832..bd832e817 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -662,7 +662,7 @@ void LP_bobloop(void *_swap) expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",5*LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",15*LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); else if ( LP_waitsend("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); @@ -718,7 +718,7 @@ void LP_aliceloop(void *_swap) if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); - if ( LP_sendwait("pubkeys",5*LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_sendwait("pubkeys",15*LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); else if ( LP_sendwait("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); From c421a6ca493483561baad1530abc572b51dc1231 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 19:32:45 +0300 Subject: [PATCH 1845/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index bd832e817..8ef6167d1 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -662,7 +662,7 @@ void LP_bobloop(void *_swap) expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",15*LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",60,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); else if ( LP_waitsend("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); @@ -718,7 +718,7 @@ void LP_aliceloop(void *_swap) if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); - if ( LP_sendwait("pubkeys",15*LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_sendwait("pubkeys",60,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); else if ( LP_sendwait("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); From f440fdd68b10f2f62657b6b996c678e193c02b21 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 19:36:38 +0300 Subject: [PATCH 1846/2705] Test --- iguana/exchanges/LP_swap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 8ef6167d1..4c94d6365 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -718,6 +718,7 @@ void LP_aliceloop(void *_swap) if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); + sleep(10); if ( LP_sendwait("pubkeys",60,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); else if ( LP_sendwait("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) From 63afa00559777cc384cc3c78d8f4587e1a831b80 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 19:42:26 +0300 Subject: [PATCH 1847/2705] Test --- iguana/exchanges/LP_rpc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index c4e4a00af..71362afed 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -20,9 +20,12 @@ char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) { - char *retstr = 0; struct LP_peerinfo *peer = 0; + char *retstr = 0; int32_t maxerrs; struct LP_peerinfo *peer = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destip),port); - if ( peer == 0 || peer->errors < LP_MAXPEER_ERRORS ) + if ( strncmp("5.9.253",destip,strlen("5.9.253")) == 0 ) + maxerrs = LP_MAXPEER_ERRORS; + else maxerrs = 1; + if ( peer == 0 || peer->errors < maxerrs ) { if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 ) { From fee18da6da632c4682f8d00d6d9deb0055c3cc30 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 19:48:54 +0300 Subject: [PATCH 1848/2705] Test --- iguana/exchanges/LP_ordermatch.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 01d43690b..4a61874ac 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -355,8 +355,8 @@ int32_t LP_nanobind(void *ctx,char *pairstr) if ( nn_bind(pairsock,bindaddr) >= 0 ) { timeout = 100; - nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); printf("nanobind %s to %d\n",pairstr,pairsock); return(pairsock); } else printf("error binding to %s for %s\n",bindaddr,pairstr); @@ -456,9 +456,9 @@ char *LP_connectedalice(cJSON *argjson) // alice jaddstr(retjson,"error","couldnt create pairsock"); else if ( nn_connect(pairsock,pairstr) >= 0 ) { - timeout = 100; - nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + //timeout = 100; + //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q); swap->N.pair = pairsock; @@ -472,7 +472,7 @@ char *LP_connectedalice(cJSON *argjson) // alice jaddnum(retjson,"requestid",Q.R.requestid); jaddnum(retjson,"quoteid",Q.R.quoteid); } else jaddstr(retjson,"error","couldnt aliceloop"); - } + } else printf("connect error %s\n",nn_strerror(nn_errno())); printf("connected result.(%s)\n",jprint(retjson,0)); if ( jobj(retjson,"error") != 0 ) LP_availableset(autxo); From 6f0edcf7c7554ca57021c4afe9f63457ac9df449 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 19:53:13 +0300 Subject: [PATCH 1849/2705] Test --- iguana/exchanges/LP_ordermatch.c | 10 +++++----- iguana/exchanges/LP_swap.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 4a61874ac..3bc28c3b7 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -355,8 +355,8 @@ int32_t LP_nanobind(void *ctx,char *pairstr) if ( nn_bind(pairsock,bindaddr) >= 0 ) { timeout = 100; - //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); printf("nanobind %s to %d\n",pairstr,pairsock); return(pairsock); } else printf("error binding to %s for %s\n",bindaddr,pairstr); @@ -456,9 +456,9 @@ char *LP_connectedalice(cJSON *argjson) // alice jaddstr(retjson,"error","couldnt create pairsock"); else if ( nn_connect(pairsock,pairstr) >= 0 ) { - //timeout = 100; - //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); - //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); + timeout = 100; + nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); + nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis,Q.destcoin,Q.destsatoshis,Q.timestamp,Q.quotetime,DEXselector); swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q); swap->N.pair = pairsock; diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 4c94d6365..d3a5ac463 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -662,7 +662,7 @@ void LP_bobloop(void *_swap) expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",60,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",LP_SWAPSTEP_TIMEOUT*3,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); else if ( LP_waitsend("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); @@ -718,8 +718,8 @@ void LP_aliceloop(void *_swap) if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); - sleep(10); - if ( LP_sendwait("pubkeys",60,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + sleep(1); + if ( LP_sendwait("pubkeys",LP_SWAPSTEP_TIMEOUT*3,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); else if ( LP_sendwait("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); From 9fbb13ab5b7c95cd88db160b99631964ba037436 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 19:57:29 +0300 Subject: [PATCH 1850/2705] Test --- iguana/exchanges/LP_swap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index d3a5ac463..7b24fbcf1 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -420,15 +420,15 @@ int32_t LP_waitfor(int32_t pairsock,struct basilisk_swap *swap,int32_t timeout,i int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,int32_t (*verify)(struct basilisk_swap *swap,uint8_t *data,int32_t datalen),int32_t (*datagen)(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen)) { int32_t datalen,sendlen,retval = -1; - //printf("waitsend.%s\n",statename); + printf("waitsend.%s\n",statename); if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 ) { - //printf("waited for %s\n",statename); + printf("waited for %s\n",statename); if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 ) { if ( (sendlen= nn_send(pairsock,data,datalen,0)) == datalen ) { - //printf("sent.%d after waitfor.%s\n",sendlen,statename); + printf("sent.%d after waitfor.%s\n",sendlen,statename); retval = 0; } else printf("send %s error\n",statename); } else printf("%s datagen no data\n",statename); From 5bfc7f7c5b61b5231134878dcdf0ae3a0e5a419c Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 20:04:47 +0300 Subject: [PATCH 1851/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 7b24fbcf1..5f6eabfbd 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -432,7 +432,7 @@ int32_t LP_waitsend(char *statename,int32_t timeout,int32_t pairsock,struct basi retval = 0; } else printf("send %s error\n",statename); } else printf("%s datagen no data\n",statename); - } else printf("didnt get valid data\n"); + } else printf("didnt get valid data after %d\n",timeout); return(retval); } @@ -662,7 +662,7 @@ void LP_bobloop(void *_swap) expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",LP_SWAPSTEP_TIMEOUT*3,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",LP_SWAPSTEP_TIMEOUT*30,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); else if ( LP_waitsend("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); From 55920f142279c7a26f6626da771cf88d310df354 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 22 Jun 2017 20:06:24 +0300 Subject: [PATCH 1852/2705] Test --- iguana/exchanges/LP_swap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 5f6eabfbd..c819e80ad 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -718,8 +718,8 @@ void LP_aliceloop(void *_swap) if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); - sleep(1); - if ( LP_sendwait("pubkeys",LP_SWAPSTEP_TIMEOUT*3,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + sleep(10); + if ( LP_sendwait("pubkeys",60,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); else if ( LP_sendwait("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); From b3db01b63ee031159b65e28410ac9e282ccf0986 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 09:15:52 +0300 Subject: [PATCH 1853/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 10 +++++++--- iguana/exchanges/LP_ordermatch.c | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 2681d5dad..7f61ccc17 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -35,6 +35,7 @@ char USERPASS[65],USERPASS_WIFSTR[64],LP_myipaddr[64],USERHOME[512] = { "/root" char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", };//"5.9.253.204" }; // uint32_t LP_deadman_switch; +uint16_t LP_fixed_pairport; int32_t LP_mypubsock = -1; int32_t USERPASS_COUNTER,IAMLP = 0; double LP_profitratio = 1.; @@ -402,12 +403,15 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit if ( jobj(argjson,"canbind") == 0 ) { #ifndef __linux__ - LP_canbind = IAMLP; + LP_canbind = 1; #else LP_canbind = IAMLP; #endif - } - else LP_canbind = jint(argjson,"canbind"); + } else LP_canbind = jint(argjson,"canbind"); + if ( LP_canbind > 1000 && LP_canbind < 65536 ) + LP_fixed_pairport = LP_canbind; + if ( LP_canbind != 0 ) + LP_canbind = 1; srand((int32_t)n); if ( userhome != 0 && userhome[0] != 0 ) { diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 3bc28c3b7..7d16f4b6b 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -350,6 +350,8 @@ int32_t LP_nanobind(void *ctx,char *pairstr) for (i=0; i<10; i++) { r = (10000 + (rand() % 50000)) & 0xffff; + if ( LP_fixed_pairport != 0 ) + r = LP_fixed_pairport; nanomsg_transportname(0,pairstr,LP_myipaddr,r); nanomsg_transportname(1,bindaddr,LP_myipaddr,r); if ( nn_bind(pairsock,bindaddr) >= 0 ) @@ -360,6 +362,8 @@ int32_t LP_nanobind(void *ctx,char *pairstr) printf("nanobind %s to %d\n",pairstr,pairsock); return(pairsock); } else printf("error binding to %s for %s\n",bindaddr,pairstr); + if ( LP_fixed_pairport != 0 ) + break; } } } else pairsock = LP_initpublicaddr(ctx,&mypullport,pairstr,"127.0.0.1",0,1); From 533361a6032b122eb8a3e40cac44d4105cd45681 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 09:17:09 +0300 Subject: [PATCH 1854/2705] Test --- iguana/exchanges/LP_swap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index c819e80ad..6d6b22d28 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -662,7 +662,7 @@ void LP_bobloop(void *_swap) expiration = (uint32_t)time(NULL) + LP_SWAPSTEP_TIMEOUT; if ( swap != 0 ) { - if ( LP_waitsend("pubkeys",LP_SWAPSTEP_TIMEOUT*30,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_waitsend("pubkeys",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error waitsend pubkeys\n"); else if ( LP_waitsend("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error waitsend choosei\n"); @@ -718,8 +718,7 @@ void LP_aliceloop(void *_swap) if ( swap != 0 ) { fprintf(stderr,"start swap iamalice pair.%d\n",swap->N.pair); - sleep(10); - if ( LP_sendwait("pubkeys",60,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) + if ( LP_sendwait("pubkeys",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_pubkeys_verify,LP_pubkeys_data) < 0 ) printf("error LP_sendwait pubkeys\n"); else if ( LP_sendwait("choosei",LP_SWAPSTEP_TIMEOUT,swap->N.pair,swap,data,maxlen,LP_choosei_verify,LP_choosei_data) < 0 ) printf("error LP_sendwait choosei\n"); From 167537db2f0d8234267d13fe800c4a5daba70fff Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 10:09:39 +0300 Subject: [PATCH 1855/2705] Test --- iguana/exchanges/LP_swap.c | 18 ++++--- iguana/exchanges/LP_transaction.c | 78 ++++++++++++++++++------------- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 6d6b22d28..0079c1d35 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -508,10 +508,10 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba if ( rawtx->I.redeemlen > 0 && rawtx->I.redeemlen < 0x100 ) { memcpy(rawtx->redeemscript,&data[datalen],rawtx->I.redeemlen); - //for (i=0; iI.redeemlen; i++) - // printf("%02x",rawtx->redeemscript[i]); + for (i=0; iI.redeemlen; i++) + printf("%02x",rawtx->redeemscript[i]); bitcoin_address(redeemaddr,rawtx->coin->taddr,rawtx->coin->p2shtype,rawtx->redeemscript,rawtx->I.redeemlen); - //printf(" received redeemscript.(%s)\n",redeemaddr); + printf(" received redeemscript.(%s) %s taddr.%d\n",redeemaddr,rawtx->coin->symbol,rawtx->coin->taddr); LP_swap_coinaddr(swap,rawtx->coin,checkaddr,data,datalen); if ( strcmp(redeemaddr,checkaddr) != 0 ) { @@ -624,9 +624,9 @@ int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t { char *retstr; cJSON *retjson=0; uint32_t expiration = (uint32_t)(time(NULL) + duration); printf("wait %d:%d for SWAP.(r%u/q%u) to complete\n",duration,sleeptime,requestid,quoteid); + sleep(10); while ( time(NULL) < expiration ) { - sleep(3); if ( (retstr= basilisk_swapentry(requestid,quoteid)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) @@ -700,7 +700,9 @@ void LP_bobloop(void *_swap) swap->bobreclaim.utxovout = 0; swap->bobreclaim.utxotxid = swap->bobpayment.I.signedtxid; basilisk_bobpayment_reclaim(swap,swap->I.callduration); - LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); + if ( swap->N.pair >= 0 ) + nn_close(swap->N.pair), swap->N.pair = -1; + LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,300); } } } @@ -759,7 +761,9 @@ void LP_aliceloop(void *_swap) char str[65];printf("%d waiting for alicespend to be confirmed.%d %s %s\n",n,swap->I.aliceconfirms,swap->bobcoin.symbol,bits256_str(str,swap->alicespend.I.signedtxid)); sleep(LP_SWAPSTEP_TIMEOUT); } - LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,60); + if ( swap->N.pair >= 0 ) + nn_close(swap->N.pair), swap->N.pair = -1; + LP_swapwait(swap->I.req.requestid,swap->I.req.quoteid,4*3600,300); } } } @@ -958,7 +962,7 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256 } swap->I.bobconfirms *= !bobistrusted; swap->I.aliceconfirms *= !aliceistrusted; - printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms); + printf(">>>>>>>>>> jumblrflag.%d <<<<<<<<< use smart address, %.8f bobconfs.%d, %.8f aliceconfs.%d taddr.%d %d\n",jumblrflag,dstr(swap->I.bobsatoshis),swap->I.bobconfirms,dstr(swap->I.alicesatoshis),swap->I.aliceconfirms,swap->bobcoin.taddr,swap->alicecoin.taddr); if ( swap->I.iambob != 0 ) { basilisk_rawtx_setparms("myfee",swap->I.req.quoteid,&swap->myfee,&swap->bobcoin,0,0,LP_DEXFEE(swap->I.bobsatoshis),0,0,jumblrflag); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 81cc74a93..9a3d73225 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -1283,9 +1283,9 @@ int32_t basilisk_bobscript(uint8_t *rmd160,uint8_t *redeemscript,int32_t *redeem { calc_rmd160_sha256(rmd160,redeemscript,n); n = bitcoin_p2shspend(script,0,rmd160); - //for (i=0; itaddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) + { + //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); + if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) + { + vout = jitem(vouts,0); + //printf("VOUT.(%s)\n",jprint(vout,0)); + if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) + { + item = jitem(addresses,0); + //printf("item.(%s)\n",jprint(item,0)); + if ( (addr= jstr(item,0)) != 0 ) + { + safecopy(coinaddr,addr,64); + //printf("extracted.(%s)\n",coinaddr); + } + } + } + free_json(txobj); + } +} + int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,int32_t genflag) { - int32_t j; char coinaddr[64]; + int32_t j; char coinaddr[64],checkaddr[64]; bitcoin_address(coinaddr,swap->bobcoin.taddr,swap->bobcoin.pubtype,swap->changermd160,20); if ( genflag != 0 && swap->I.iambob == 0 ) printf("basilisk_bobscripts_set WARNING: alice generating BOB tx\n"); @@ -1382,6 +1407,12 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i printf("%02x",swap->bobpayment.redeemscript[j]); printf(" <- redeem.%d\n",swap->bobpayment.I.redeemlen); printf(" <- GENERATED BOB PAYMENT.%d destaddr.(%s)\n",swap->bobpayment.I.datalen,swap->bobpayment.I.destaddr); + LP_swap_coinaddr(swap,&swap->bobcoin,checkaddr,swap->bobpayment.txbytes,swap->bobpayment.I.datalen); + if ( strcmp(swap->bobpayment.I.destaddr,checkaddr) != 0 ) + { + printf("BOBPAYMENT REDEEMADDR MISMATCH??? %s != %s\n",swap->bobpayment.I.destaddr,checkaddr); + return(-1); + } LP_unspents_mark(swap->bobcoin.symbol,swap->bobpayment.vins); //printf("bobscripts set completed\n"); return(0); @@ -1394,9 +1425,9 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i bitcoin_address(swap->bobdeposit.p2shaddr,swap->bobcoin.taddr,swap->bobcoin.p2shtype,swap->bobdeposit.redeemscript,swap->bobdeposit.I.redeemlen); strcpy(swap->bobdeposit.I.destaddr,swap->bobdeposit.p2shaddr); //LP_importaddress(swap->bobcoin.symbol,swap->bobdeposit.I.destaddr); - //int32_t i; for (i=0; ibobdeposit.I.redeemlen; i++) - // printf("%02x",swap->bobdeposit.redeemscript[i]); - //printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); + int32_t i; for (i=0; ibobdeposit.I.redeemlen; i++) + printf("%02x",swap->bobdeposit.redeemscript[i]); + printf(" <- bobdeposit redeem %d %s\n",i,swap->bobdeposit.I.destaddr); if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) ) { basilisk_rawtx_gen(swap->ctx,"deposit",swap->I.started,swap->persistent_pubkey33,1,1,&swap->bobdeposit,swap->bobdeposit.I.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.I.spendlen,swap->bobdeposit.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); @@ -1409,7 +1440,13 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i { for (j=0; jbobdeposit.I.datalen; j++) printf("%02x",swap->bobdeposit.txbytes[j]); - printf(" <- GENERATED BOB DEPOSIT.%d\n",swap->bobdeposit.I.datalen); + printf(" <- GENERATED BOB DEPOSIT.%d (%s)\n",swap->bobdeposit.I.datalen,swap->bobdeposit.I.destaddr); + LP_swap_coinaddr(swap,&swap->bobcoin,checkaddr,swap->bobdeposit.txbytes,swap->bobdeposit.I.datalen); + if ( strcmp(swap->bobdeposit.I.destaddr,checkaddr) != 0 ) + { + printf("BOBDEPOSIT REDEEMADDR MISMATCH??? %s != %s\n",swap->bobdeposit.I.destaddr,checkaddr); + return(-1); + } LP_unspents_mark(swap->bobcoin.symbol,swap->bobdeposit.vins); printf("bobscripts set completed\n"); return(0); @@ -1421,31 +1458,6 @@ int32_t basilisk_bobscripts_set(struct basilisk_swap *swap,int32_t depositflag,i /**/ -void LP_swap_coinaddr(struct basilisk_swap *swap,struct iguana_info *coin,char *coinaddr,uint8_t *data,int32_t datalen) -{ - cJSON *txobj,*vouts,*vout,*addresses,*item,*skey; uint8_t extraspace[8192]; bits256 signedtxid; struct iguana_msgtx msgtx; char *addr; int32_t n,m,suppress_pubkeys = 0; - if ( (txobj= bitcoin_data2json(coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->longestchain,&signedtxid,&msgtx,extraspace,sizeof(extraspace),data,datalen,0,suppress_pubkeys)) != 0 ) - { - //char str[65]; printf("got txid.%s (%s)\n",bits256_str(str,signedtxid),jprint(txobj,0)); - if ( (vouts= jarray(&n,txobj,"vout")) != 0 && n > 0 ) - { - vout = jitem(vouts,0); - //printf("VOUT.(%s)\n",jprint(vout,0)); - if ( (skey= jobj(vout,"scriptPubKey")) != 0 && (addresses= jarray(&m,skey,"addresses")) != 0 ) - { - item = jitem(addresses,0); - //printf("item.(%s)\n",jprint(item,0)); - if ( (addr= jstr(item,0)) != 0 ) - { - safecopy(coinaddr,addr,64); - //printf("extracted.(%s)\n",coinaddr); - } - } - } - free_json(txobj); - } -} - #ifdef old int32_t basilisk_alicepayment_spend(struct basilisk_swap *swap,struct basilisk_rawtx *dest) { From cdb81bcb62e777446228db4f8049a4d4f848c9d1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 10:20:44 +0300 Subject: [PATCH 1856/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7f61ccc17..967a43bdb 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -270,7 +270,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int nonz += LP_subsock_check(ctx,origipaddr,pubsock,peer->subsock,profitmargin); } //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d forwarding\n",counter,LP_canbind); - if ( (counter % 600) == 60 ) + if ( (counter % 600) == 20 ) { LP_myutxo_updates(ctx,pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) @@ -280,7 +280,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int } } //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d utxos\n",counter,LP_canbind); - if ( (counter % 600) == 0 ) + if ( (counter % 600) == 60 ) { HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp) { @@ -288,9 +288,11 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int } HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp) { + char str[65]; LP_utxo_spentcheck(pubsock,utxo,profitmargin); if ( utxo->T.lasttime == 0 ) LP_utxo_clientpublish(utxo); + else printf("lasttime set %s\n",bits256_str(str,utxo->payment.txid)); } } //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d swapentry\n",counter,LP_canbind); From 6cfcb572ec9d0358c86a2c77c14aaefe4641709a Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 10:22:01 +0300 Subject: [PATCH 1857/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 967a43bdb..de858f992 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -292,11 +292,12 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int LP_utxo_spentcheck(pubsock,utxo,profitmargin); if ( utxo->T.lasttime == 0 ) LP_utxo_clientpublish(utxo); - else printf("lasttime set %s\n",bits256_str(str,utxo->payment.txid)); + else if ( strcmp(utxo->coin,"HUSH") == 0 ) + printf("lasttime set %s\n",bits256_str(str,utxo->payment.txid)); } } //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d swapentry\n",counter,LP_canbind); - if ( (counter % 600) == 599 ) + if ( (counter % 6000) == 5999 ) { if ( (retstr= basilisk_swapentry(0,0)) != 0 ) { From 9f9243777fa9ac84146d41c210cca44db4604385 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 10:24:43 +0300 Subject: [PATCH 1858/2705] Test --- iguana/exchanges/LP_utxos.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 8310ff735..79fdbb394 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -543,7 +543,11 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n txid = jbits256(item,"txid"); //printf("parse.(%s)\n",jprint(item,0)); if ( (utxo= LP_utxoaddjson(1,-1,item)) != 0 ) + { + if ( strcmp(utxo->coin,"HUSH") == 0 ) + printf("%s set lasttime (%s)\n",destipaddr,jprint(item,0)); utxo->T.lasttime = now; + } } } if ( (destpeer= LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport)) != 0 ) From f82c946b96b020a235afadc16f0b527f1e36f14f Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 10:27:24 +0300 Subject: [PATCH 1859/2705] Test --- iguana/exchanges/LP_prices.c | 4 ++++ iguana/exchanges/LP_utxos.c | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 50a147ecd..e0771709a 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -521,7 +521,11 @@ int32_t LP_utxo_clientpublish(struct LP_utxoinfo *utxo) if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( jobj(retjson,"error") == 0 ) + { + if ( strcmp("HUSH",utxo->coin) == 0 ) + printf("clientpublish %s (%s)\n",peer->ipaddr,retstr); utxo->T.lasttime = (uint32_t)time(NULL); + } free_json(retjson); } free(retstr); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 79fdbb394..d2879210a 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -494,8 +494,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit { if ( mypubsock >= 0 ) LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - else - LP_utxo_clientpublish(utxo); + else LP_utxo_clientpublish(utxo); if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) LP_mypeer->numutxos++; } From 22a8120d0fa898b8dbe08ab6754fbfd832b066e5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 11:09:51 +0300 Subject: [PATCH 1860/2705] Test --- iguana/exchanges/LP_commands.c | 5 +- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_rpc.c | 40 ++++++++------- iguana/exchanges/LP_utxos.c | 86 ++++++++++++++++---------------- 4 files changed, 70 insertions(+), 63 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 5e45829a5..dda9c8d1d 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -223,8 +223,9 @@ forwardhex(pubkey,hex)\n\ return(LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn"))); else if ( strcmp(method,"notified") == 0 ) { - LP_utxoaddjson(1,LP_mypubsock,argjson); - return(clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}")); + if ( LP_utxoaddjson(1,LP_mypubsock,argjson) != 0 ) + return(clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}")); + else return(clonestr("{\"error\":\"couldnt add utxo\"}")); } else if ( IAMLP != 0 ) { diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 9e9e4b320..e7b733505 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -127,7 +127,7 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) strcpy(ptr->pushaddr,pushaddr); if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 ) return(clonestr("{\"error\":\"couldnt recreate pushsock\",\"registered\":0}")); - } else printf("no need to create identical endpoint\n"); + } //else printf("no need to create identical endpoint\n"); } return(clonestr("{\"error\":\"already registered\",\"registered\":1}")); } diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 71362afed..242f0fcf5 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -22,9 +22,7 @@ char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) { char *retstr = 0; int32_t maxerrs; struct LP_peerinfo *peer = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destip),port); - if ( strncmp("5.9.253",destip,strlen("5.9.253")) == 0 ) - maxerrs = LP_MAXPEER_ERRORS; - else maxerrs = 1; + maxerrs = LP_MAXPEER_ERRORS; if ( peer == 0 || peer->errors < maxerrs ) { if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 ) @@ -57,16 +55,18 @@ char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn, { char url[512]; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curlt(url,LP_HTTP_TIMEOUT)); + return(LP_issue_curl("getutxos",destip,destport,url)); + //return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_clientgetutxos(char *destip,uint16_t destport,char *coin,int32_t lastn) { - char url[512],*retstr; + char url[512];//,*retstr; sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn); - retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + return(LP_issue_curl("clientgetutxos",destip,destport,url)); + //retstr = issue_curlt(url,LP_HTTP_TIMEOUT); //printf("%s clientgetutxos.(%s)\n",url,retstr); - return(retstr); + //return(retstr); } char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,double profitmargin,int32_t numpeers,int32_t numutxos) @@ -78,7 +78,8 @@ char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port, return(0); } sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&profit=%.6f&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,profitmargin,numpeers,numutxos); - return(issue_curlt(url,LP_HTTP_TIMEOUT)); + return(LP_issue_curl("notify",destip,destport,url)); + //return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) @@ -100,7 +101,8 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx sprintf(url,"http://%s:%u/api/stats/notified?iambob=%d&pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,utxo->iambob,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); - return(issue_curlt(url,LP_HTTP_TIMEOUT)); + return(LP_issue_curl("notifyutxo",destip,destport,url)); + //return(issue_curlt(url,LP_HTTP_TIMEOUT)); } else { @@ -111,20 +113,22 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *ipaddr,uint16_t pushport) { - char url[512],str[65],*retstr; + char url[512],str[65];//*retstr; sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s&pushport=%u",destip,destport,bits256_str(str,pubkey),ipaddr,pushport); - retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + return(LP_issue_curl("register",destip,destport,url)); + //retstr = issue_curlt(url,LP_HTTP_TIMEOUT); //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); - return(retstr); + //return(retstr); } char *issue_LP_psock(char *destip,uint16_t destport,int32_t ispaired) { - char url[512],*retstr; + char url[512]; sprintf(url,"http://%s:%u/api/stats/psock?ispaired=%d",destip,destport,ispaired); - retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + return(LP_issue_curl("psock",destip,destport,url)); + //retstr = issue_curlt(url,LP_HTTP_TIMEOUT); //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); - return(retstr); + //return(retstr); } uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired) @@ -159,7 +163,8 @@ char *issue_LP_lookup(char *destip,uint16_t destport,bits256 pubkey) char url[512],str[65]; sprintf(url,"http://%s:%u/api/stats/lookup?client=%s",destip,destport,bits256_str(str,pubkey)); //printf("getutxo.(%s)\n",url); - return(issue_curlt(url,LP_HTTP_TIMEOUT)); + return(LP_issue_curl("lookup",destip,destport,url)); + //return(issue_curlt(url,LP_HTTP_TIMEOUT)); } char *issue_LP_getprices(char *destip,uint16_t destport) @@ -167,7 +172,8 @@ char *issue_LP_getprices(char *destip,uint16_t destport) char url[512]; sprintf(url,"http://%s:%u/api/stats/getprices",destip,destport); //printf("getutxo.(%s)\n",url); - return(issue_curlt(url,LP_HTTP_TIMEOUT)); + return(LP_issue_curl("getprices",destip,destport,url)); + //return(issue_curlt(url,LP_HTTP_TIMEOUT)); } cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index d2879210a..b64e8dfc8 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -17,7 +17,6 @@ // LP_utxos.c // marketmaker // -// jl777: invalidate utxo when either part is spent. if not expected spend, mark as bad and generate new utxopair using other half int32_t LP_ismine(struct LP_utxoinfo *utxo) { @@ -450,54 +449,55 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit char str[65],str2[65],str3[65],str4[65],str5[65],str6[65]; if ( dispflag != 0 ) printf("error on subsequent utxo iambob.%d %.8f %.8f add.(%s %s) when.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",iambob,dstr(val),dstr(val2),bits256_str(str,txid),bits256_str(str2,txid2),bits256_str(str3,utxo->payment.txid),bits256_str(str4,utxo->deposit.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str5,pubkey),bits256_str(str6,utxo->pubkey)); + if ( utxo->T.spentflag != 0 || LP_txvalue(utxo->coinaddr,utxo->coin,utxo->payment.txid,utxo->payment.vout) < utxo->payment.value || LP_txvalue(utxo->coinaddr,utxo->coin,u.txid,u.vout) < u.value ) + { + if ( utxo->T.spentflag == 0 ) + utxo->T.spentflag = (uint32_t)time(NULL); + printf("original utxo pair not valid\n"); + utxo = 0; + } } else if ( profitmargin > SMALLVAL ) utxo->S.profitmargin = profitmargin; + if ( utxo != 0 ) + return(utxo); + } + utxo = calloc(1,sizeof(*utxo)); + utxo->S.profitmargin = profitmargin; + utxo->pubkey = pubkey; + safecopy(utxo->coin,symbol,sizeof(utxo->coin)); + safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); + safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); + utxo->payment.txid = txid; + utxo->payment.vout = vout; + utxo->payment.value = value; + utxo->S.satoshis = tmpsatoshis; + if ( (utxo->iambob= iambob) != 0 ) + { + utxo->deposit.txid = txid2; + utxo->deposit.vout = vout2; + utxo->deposit.value = value2; } else { - /*if ( (val= LP_txvalue(destaddr,symbol,txid,vout)) != value || (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) != value2 || strcmp(destaddr,destaddr2) != 0 || strcmp(coinaddr,destaddr) != 0 ) - { - printf("utxoadd mismatch %s/v%d (%s %.8f) + %s/v%d (%s %.8f) != %s %.8f %.8f\n",bits256_str(str,txid),vout,destaddr,dstr(val),bits256_str(str2,txid2),vout2,destaddr2,dstr(val2),coinaddr,dstr(value),dstr(value2)); - return(0); - }*/ - utxo = calloc(1,sizeof(*utxo)); - utxo->S.profitmargin = profitmargin; - utxo->pubkey = pubkey; - safecopy(utxo->coin,symbol,sizeof(utxo->coin)); - safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); - safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); - utxo->payment.txid = txid; - utxo->payment.vout = vout; - utxo->payment.value = value; - utxo->S.satoshis = tmpsatoshis; - if ( (utxo->iambob= iambob) != 0 ) - { - utxo->deposit.txid = txid2; - utxo->deposit.vout = vout2; - utxo->deposit.value = value2; - } - else - { - utxo->fee.txid = txid2; - utxo->fee.vout = vout2; - utxo->fee.value = value2; - } - LP_utxosetkey(utxo->key,txid,vout); - LP_utxosetkey(utxo->key2,txid2,vout2); - portable_mutex_lock(&LP_utxomutex); - HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); - if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) - HASH_ADD_KEYPTR(hh2,LP_utxoinfos2[iambob],utxo->key2,sizeof(utxo->key2),utxo); - portable_mutex_unlock(&LP_utxomutex); - if ( iambob != 0 ) - { - if ( mypubsock >= 0 ) - LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - else LP_utxo_clientpublish(utxo); - if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) - LP_mypeer->numutxos++; - } + utxo->fee.txid = txid2; + utxo->fee.vout = vout2; + utxo->fee.value = value2; + } + LP_utxosetkey(utxo->key,txid,vout); + LP_utxosetkey(utxo->key2,txid2,vout2); + portable_mutex_lock(&LP_utxomutex); + HASH_ADD_KEYPTR(hh,LP_utxoinfos[iambob],utxo->key,sizeof(utxo->key),utxo); + if ( _LP_utxo2find(iambob,txid2,vout2) == 0 ) + HASH_ADD_KEYPTR(hh2,LP_utxoinfos2[iambob],utxo->key2,sizeof(utxo->key2),utxo); + portable_mutex_unlock(&LP_utxomutex); + if ( iambob != 0 ) + { + if ( mypubsock >= 0 ) + LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); + else LP_utxo_clientpublish(utxo); + if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) + LP_mypeer->numutxos++; } return(utxo); } From 94a28caa02456c92bc44d929b8fe22d13ec870d2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 11:19:24 +0300 Subject: [PATCH 1861/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 9f3fae745..168b728ec 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2039,7 +2039,7 @@ int32_t bitcoin_addr2rmd160(uint8_t taddr,uint8_t *addrtypep,uint8_t rmd160[20], { // validate with trailing hash, then remove hash hash = bits256_doublesha256(0,buf,20+offset); - *addrtypep = *buf; + *addrtypep = (taddr == 0) ? *buf : buf[1]; memcpy(rmd160,buf+offset,20); if ( (buf[20+offset]&0xff) == hash.bytes[31] && (buf[21+offset]&0xff) == hash.bytes[30] &&(buf[22+offset]&0xff) == hash.bytes[29] && (buf[23+offset]&0xff) == hash.bytes[28] ) { From a4784cf4f0cf6e7333a19cb6faa25bab5f554c24 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 11:51:02 +0300 Subject: [PATCH 1862/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- iguana/exchanges/LP_prices.c | 4 ++-- iguana/exchanges/LP_utxos.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index de858f992..bc5a1ac9e 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -292,8 +292,8 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int LP_utxo_spentcheck(pubsock,utxo,profitmargin); if ( utxo->T.lasttime == 0 ) LP_utxo_clientpublish(utxo); - else if ( strcmp(utxo->coin,"HUSH") == 0 ) - printf("lasttime set %s\n",bits256_str(str,utxo->payment.txid)); + //else if ( strcmp(utxo->coin,"HUSH") == 0 ) + // printf("lasttime set %s\n",bits256_str(str,utxo->payment.txid)); } } //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d swapentry\n",counter,LP_canbind); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index e0771709a..6ca36fd5d 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -522,8 +522,8 @@ int32_t LP_utxo_clientpublish(struct LP_utxoinfo *utxo) { if ( jobj(retjson,"error") == 0 ) { - if ( strcmp("HUSH",utxo->coin) == 0 ) - printf("clientpublish %s (%s)\n",peer->ipaddr,retstr); + //if ( strcmp("HUSH",utxo->coin) == 0 ) + // printf("clientpublish %s (%s)\n",peer->ipaddr,retstr); utxo->T.lasttime = (uint32_t)time(NULL); } free_json(retjson); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b64e8dfc8..b8c30c953 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -543,8 +543,8 @@ int32_t LP_utxosparse(char *destipaddr,uint16_t destport,char *retstr,uint32_t n //printf("parse.(%s)\n",jprint(item,0)); if ( (utxo= LP_utxoaddjson(1,-1,item)) != 0 ) { - if ( strcmp(utxo->coin,"HUSH") == 0 ) - printf("%s set lasttime (%s)\n",destipaddr,jprint(item,0)); + //if ( strcmp(utxo->coin,"HUSH") == 0 ) + // printf("%s set lasttime (%s)\n",destipaddr,jprint(item,0)); utxo->T.lasttime = now; } } From f90dbc3e4a2d412f483c11c164512fa6fd55f365 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 23 Jun 2017 12:24:23 +0300 Subject: [PATCH 1863/2705] Test --- iguana/exchanges/LP_swap.c | 8 ++++++-- iguana/exchanges/LP_utxos.c | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_swap.c b/iguana/exchanges/LP_swap.c index 0079c1d35..6f0c8aa34 100644 --- a/iguana/exchanges/LP_swap.c +++ b/iguana/exchanges/LP_swap.c @@ -622,9 +622,11 @@ uint32_t LP_swapdata_rawtxsend(int32_t pairsock,struct basilisk_swap *swap,uint3 int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t sleeptime) { - char *retstr; cJSON *retjson=0; uint32_t expiration = (uint32_t)(time(NULL) + duration); + char *retstr; cJSON *retjson=0; uint32_t divisor=8,expiration = (uint32_t)(time(NULL) + duration); printf("wait %d:%d for SWAP.(r%u/q%u) to complete\n",duration,sleeptime,requestid,quoteid); sleep(10); + if ( sleeptime < divisor*60 ) + sleeptime = divisor * 60; while ( time(NULL) < expiration ) { if ( (retstr= basilisk_swapentry(requestid,quoteid)) != 0 ) @@ -638,7 +640,9 @@ int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t } free(retstr); } - sleep(sleeptime); + sleep(sleeptime/divisor); + if ( divisor > 1 ) + divisor--; } if ( retjson != 0 ) { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index b8c30c953..f86cbb0b0 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -689,6 +689,8 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr targetval = (depositval / 776) + 100000; else targetval = (depositval / 9) * 8 + 100000; //printf("i.%d %.8f target %.8f\n",i,dstr(depositval),dstr(targetval)); + if ( (i= LP_nearestvalue(values,n,targetval)) < 0 && iambob != 0 ) + targetval /= 4; if ( (i= LP_nearestvalue(values,n,targetval)) >= 0 ) { item = jitem(array,i); From 074dffaa72538d23b59dcaad12b6a7ae968846a1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 24 Jun 2017 20:24:51 +0300 Subject: [PATCH 1864/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- iguana/exchanges/LP_utxos.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index e8e35f882..73a77a3df 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -266,7 +266,7 @@ struct iguana_info *LP_coinfind(char *symbol) } // "coins":[{"coin":"", "rpcport":pppp}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }] -// {"coin":"HUSH", "name":"hushcoin", "rpcport":8822, "taddr":28, "pubtype":184, "p2shtype":189, "wiftype":128, "txfee":10000 } +// {"coin":"HUSH", "name":"hush", "rpcport":8822, "taddr":28, "pubtype":184, "p2shtype":189, "wiftype":128, "txfee":10000 } struct iguana_info *LP_coincreate(cJSON *item) { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index f86cbb0b0..de5ab7d29 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -745,6 +745,7 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan { coin->counter++; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); + LP_importprivkey(coin->symbol,tmpstr,"",0); bitcoin_addr2rmd160(coin->taddr,&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) From 58bbd9396b18ca04831c41e7600fc9b729118e4b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 24 Jun 2017 22:09:41 +0300 Subject: [PATCH 1865/2705] Test --- iguana/exchanges/LP_utxos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index de5ab7d29..e5c438677 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -745,7 +745,8 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan { coin->counter++; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - LP_importprivkey(coin->symbol,tmpstr,"",0); + if ( coin->inactive == 0 ) + LP_importprivkey(coin->symbol,tmpstr,"",0); bitcoin_addr2rmd160(coin->taddr,&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) From 25978c585495efac7e64c250df1ce77f5ae00400 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 25 Jun 2017 16:49:01 +0300 Subject: [PATCH 1866/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_utxos.c | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index bc5a1ac9e..38ea5550c 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -288,7 +288,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int } HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp) { - char str[65]; + //char str[65]; LP_utxo_spentcheck(pubsock,utxo,profitmargin); if ( utxo->T.lasttime == 0 ) LP_utxo_clientpublish(utxo); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index e5c438677..5f0506b26 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -407,15 +407,18 @@ char *LP_spentcheck(cJSON *argjson) struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - uint64_t val,val2=0,tmpsatoshis; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + uint64_t val,val2=0,tmpsatoshis,bigtxfee = 100000; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } - if ( iambob != 0 && value2 < 9 * (value >> 3) + 100000 ) // big txfee padding - tmpsatoshis = (((value2 - 100000) / 9) << 3); - else tmpsatoshis = value; + if ( iambob != 0 && value2 < 9 * (value >> 3) + bigtxfee ) // big txfee padding + { + if ( value2 > bigtxfee+20000 ) + tmpsatoshis = (((value2 - bigtxfee) / 9) << 3); + else return(0); + } else tmpsatoshis = value; char str[65],str2[65],dispflag = (iambob == 0); if ( iambob == 0 && bits256_cmp(pubkey,LP_mypubkey) != 0 ) { @@ -745,12 +748,12 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan { coin->counter++; bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); - if ( coin->inactive == 0 ) - LP_importprivkey(coin->symbol,tmpstr,"",0); bitcoin_addr2rmd160(coin->taddr,&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); - if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) + //if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); + if ( coin->inactive == 0 ) + printf("importprivkey: %s\n",jprint(LP_importprivkey(coin->symbol,tmpstr,"",0),1)); if ( counter++ == 0 ) { bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); From d159adcca1140e5a0b461fefe65a78ebec778e96 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 25 Jun 2017 16:50:06 +0300 Subject: [PATCH 1867/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 5f0506b26..1673a5964 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -753,7 +753,7 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan //if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( coin->inactive == 0 ) - printf("importprivkey: %s\n",jprint(LP_importprivkey(coin->symbol,tmpstr,"",0),1)); + printf("importprivkey: %s\n",jprint(LP_importprivkey(coin->symbol,tmpstr,"",-1),1)); if ( counter++ == 0 ) { bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); From 51dcc6a2e1f31b6d012d5728539a4111b64ba94c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 25 Jun 2017 17:52:59 +0300 Subject: [PATCH 1868/2705] Test --- iguana/exchanges/LP_include.h | 1 + iguana/exchanges/LP_ordermatch.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 0036bb5fc..e521aad1b 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -36,6 +36,7 @@ #define LP_AUTOTRADE_TIMEOUT 3 #define LP_MIN_TXFEE 10000 #define LP_MINVOL 3 +#define LP_MINCLIENTVOL 6 #define LP_DEXFEE(destsatoshis) ((destsatoshis) / INSTANTDEX_INSURANCEDIV) #define LP_DEPOSITSATOSHIS(satoshis) ((satoshis) + (satoshis >> 3)) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 7d16f4b6b..390374762 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -273,7 +273,7 @@ double LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxop printf("utxo payment %.8f is less than half covered by Q %.8f\n",dstr(srcvalue),dstr(qp->satoshis)); return(-12); } - if ( qp->destsatoshis < (destvalue >> LP_MINVOL) ) + if ( qp->destsatoshis < (destvalue >> LP_MINCLIENTVOL) ) { printf("destsatoshis %.8f is less than half of value %.8f\n",dstr(qp->destsatoshis),dstr(destvalue)); return(-13); @@ -596,7 +596,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi if ( destsatoshis > autxo->payment.value-desttxfee-1 ) destsatoshis = autxo->payment.value-desttxfee-1; satoshis = destsatoshis / price; - if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> LP_MINVOL) && satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL) && satoshis < butxo->payment.value-txfee ) + if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> LP_MINCLIENTVOL) && satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL) && satoshis < butxo->payment.value-txfee ) { printf("value %.8f price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",dstr(autxo->payment.value),price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; @@ -608,7 +608,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi bestmetric = metric; printf("set best!\n"); } - } else printf("skip.(%d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> LP_MINVOL),destsatoshis/price > (butxo->S.satoshis >> LP_MINVOL),metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); + } else printf("skip.(%d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> LP_MINCLIENTVOL),destsatoshis/price > (butxo->S.satoshis >> LP_MINVOL),metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); } else { From b30266ba04386db1a8e96d14e03285da6896776a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 25 Jun 2017 17:57:33 +0300 Subject: [PATCH 1869/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 390374762..c66ab3565 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -608,7 +608,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi bestmetric = metric; printf("set best!\n"); } - } else printf("skip.(%d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",destsatoshis > (autxo->payment.value >> LP_MINCLIENTVOL),destsatoshis/price > (butxo->S.satoshis >> LP_MINVOL),metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); + } else printf("skip.(%d %d %d %d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",metric < 1.2,destsatoshis > desttxfee,destsatoshis-desttxfee > (autxo->payment.value >> LP_MINCLIENTVOL),satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL),satoshis < butxo->payment.value-txfee,metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); } else { From 27b1c568a8b24fb9d3dad01bd1af8679a4b4327a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 25 Jun 2017 17:59:53 +0300 Subject: [PATCH 1870/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index c66ab3565..c97754351 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -608,7 +608,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi bestmetric = metric; printf("set best!\n"); } - } else printf("skip.(%d %d %d %d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f\n",metric < 1.2,destsatoshis > desttxfee,destsatoshis-desttxfee > (autxo->payment.value >> LP_MINCLIENTVOL),satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL),satoshis < butxo->payment.value-txfee,metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee)); + } else printf("skip.(%d %d %d %d %d) metric %f destsatoshis %.8f value %.8f destvalue %.8f txfees %.8f %.8f sats %.8f\n",metric < 1.2,destsatoshis > desttxfee,destsatoshis-desttxfee > (autxo->payment.value >> LP_MINCLIENTVOL),satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL),satoshis < butxo->payment.value-txfee,metric,dstr(destsatoshis),dstr(butxo->S.satoshis),dstr(autxo->payment.value),dstr(txfee),dstr(desttxfee),dstr(satoshis)); } else { diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 1673a5964..37160a1b8 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -750,7 +750,7 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan bitcoin_priv2wif(tmpstr,privkey,coin->wiftype); bitcoin_addr2rmd160(coin->taddr,&tmptype,rmd160,coin->smartaddr); LP_privkeyadd(privkey,rmd160); - //if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) + if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); if ( coin->inactive == 0 ) printf("importprivkey: %s\n",jprint(LP_importprivkey(coin->symbol,tmpstr,"",-1),1)); From c9977816bfbf6fb9ebecfe279c4dbca1b551a627 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 25 Jun 2017 18:01:36 +0300 Subject: [PATCH 1871/2705] Test --- iguana/exchanges/LP_ordermatch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index c97754351..f6f54b8c5 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -595,8 +595,8 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi destsatoshis = (butxo->S.satoshis * price); if ( destsatoshis > autxo->payment.value-desttxfee-1 ) destsatoshis = autxo->payment.value-desttxfee-1; - satoshis = destsatoshis / price; - if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> LP_MINCLIENTVOL) && satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL) && satoshis < butxo->payment.value-txfee ) + satoshis = destsatoshis / price + 0.0000000049; + if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> LP_MINCLIENTVOL) && satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL) && satoshis <= butxo->payment.value-txfee ) { printf("value %.8f price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",dstr(autxo->payment.value),price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); metric = dstr(destsatoshis) * metric * metric * metric; From db91e5ff20c96dcc6f44aec6961c2070d9008272 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 25 Jun 2017 18:09:50 +0300 Subject: [PATCH 1872/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index f6f54b8c5..d8e108841 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -595,7 +595,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi destsatoshis = (butxo->S.satoshis * price); if ( destsatoshis > autxo->payment.value-desttxfee-1 ) destsatoshis = autxo->payment.value-desttxfee-1; - satoshis = destsatoshis / price + 0.0000000049; + satoshis = (destsatoshis / price + 0.0000000049) - txfee; if ( metric < 1.2 && destsatoshis > desttxfee && destsatoshis-desttxfee > (autxo->payment.value >> LP_MINCLIENTVOL) && satoshis-txfee > (butxo->S.satoshis >> LP_MINVOL) && satoshis <= butxo->payment.value-txfee ) { printf("value %.8f price %.8f/%.8f best %.8f destsatoshis %.8f * metric %.8f -> (%f)\n",dstr(autxo->payment.value),price,bestprice,bestmetric,dstr(destsatoshis),metric,dstr(destsatoshis) * metric * metric * metric); From 4286403f6803c02863956f8a4429ce25b1d1b3b9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 25 Jun 2017 18:26:49 +0300 Subject: [PATCH 1873/2705] Test --- iguana/exchanges/LP_ordermatch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index d8e108841..d2df17e54 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -592,7 +592,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi metric = price / bestprice; if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && (long long)(vol*SATOSHIDEN) == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) { - destsatoshis = (butxo->S.satoshis * price); + destsatoshis = ((butxo->S.satoshis - txfee) * price); if ( destsatoshis > autxo->payment.value-desttxfee-1 ) destsatoshis = autxo->payment.value-desttxfee-1; satoshis = (destsatoshis / price + 0.0000000049) - txfee; From 7cd19bb1c503603c819cf2c094f45d41526ce4ae Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 27 Jun 2017 13:27:21 +0300 Subject: [PATCH 1874/2705] Test --- iguana/exchanges/client | 3 ++- iguana/exchanges/run | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 494e686c6..9c3f3cdfa 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -5,7 +5,8 @@ git pull; ./m_mm; ./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, -{\"active\":1,\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, +{\"active\":0,\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, +{\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, diff --git a/iguana/exchanges/run b/iguana/exchanges/run index d0e1e557f..e02aa5e4a 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -2,6 +2,7 @@ source randval pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, +{\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, From 23903882df5f51744bbc51f8c1244678fc002d53 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 10:40:43 +0300 Subject: [PATCH 1875/2705] Blacklisting --- iguana/exchanges/LP_include.h | 4 ++-- iguana/exchanges/LP_ordermatch.c | 12 ++++++++---- iguana/exchanges/LP_prices.c | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index e521aad1b..43e9a9508 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -24,7 +24,7 @@ #define LP_COMMAND_SENDSOCK NN_PUSH #define LP_COMMAND_RECVSOCK NN_PULL - +#define LP_MAXPUBKEY_ERRORS 3 #define PSOCK_KEEPALIVE 600 #define MAINLOOP_PERSEC 10 #define MAX_PSOCK_PORT 60000 @@ -164,7 +164,7 @@ struct iguana_info struct _LP_utxoinfo { bits256 txid; uint64_t value; int32_t vout; }; -struct LP_utxostats { uint32_t lasttime,errors,swappending,spentflag,lastspentcheck; }; +struct LP_utxostats { uint32_t lasttime,errors,swappending,spentflag,lastspentcheck,bestflag; }; struct LP_utxobob { struct _LP_utxoinfo utxo,deposit; }; diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index d2df17e54..d5d4ca042 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -554,7 +554,7 @@ int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson, char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume,int32_t timeout) { - int64_t satoshis,destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; + int64_t satoshis,destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; struct LP_pubkeyinfo *pubp; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) return(clonestr("{\"error\":\"invalid parameter\"}")); if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * volume)) == 0 ) @@ -581,7 +581,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi if ( price > maxprice ) price = maxprice; pubkey = jbits256(item,"pubkey"); - if ( bits256_cmp(pubkey,LP_mypubkey) != 0 ) + if ( bits256_cmp(pubkey,LP_mypubkey) != 0 && (pubp= LP_pubkeyadd(pubkey)) != 0 && pubp->numerrors < LP_MAXPUBKEY_ERRORS ) { if ( bestprice == 0. ) // assumes price ordered asks bestprice = price; @@ -590,7 +590,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi vout = jint(item,"vout"); vol = jdouble(item,"volume"); metric = price / bestprice; - if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && (long long)(vol*SATOSHIDEN) == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 ) + if ( (butxo= LP_utxofind(1,txid,vout)) != 0 && (long long)(vol*SATOSHIDEN) == butxo->S.satoshis && LP_isavailable(butxo) > 0 && LP_ismine(butxo) == 0 && butxo->T.bestflag == 0 ) { destsatoshis = ((butxo->S.satoshis - txfee) * price); if ( destsatoshis > autxo->payment.value-desttxfee-1 ) @@ -630,6 +630,7 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi return(clonestr("{\"error\":\"cant set ordermatch quote\"}")); if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); + bestutxo->T.bestflag = (uint32_t)time(NULL); price = LP_query(ctx,myipaddr,mypubsock,profitmargin,"request",&Q); bestitem = LP_quotejson(&Q); if ( price > SMALLVAL ) @@ -646,8 +647,11 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi sleep(1); } if ( autxo->S.swap == 0 ) + { + if ( (pubp= LP_pubkeyadd(bestutxo->pubkey)) != 0 ) + pubp->numerrors++; jaddstr(bestitem,"status","couldnt establish connection"); - else jaddstr(bestitem,"status","connected"); + } else jaddstr(bestitem,"status","connected"); jaddnum(bestitem,"quotedprice",price); jaddnum(bestitem,"maxprice",maxprice); jaddnum(bestitem,"requestid",Q.R.requestid); diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 6ca36fd5d..46d15fcda 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -46,7 +46,7 @@ struct LP_pubkeyinfo UT_hash_handle hh; bits256 pubkey; double matrix[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS]; - uint32_t timestamp,istrusted; + uint32_t timestamp,istrusted,numerrors; } *LP_pubkeyinfos; struct LP_priceinfo *LP_priceinfofind(char *symbol) From e2f1248ea3f64f63052055432dea8e1cec1f76d6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 10:45:23 +0300 Subject: [PATCH 1876/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_rpc.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 43e9a9508..5050388a3 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -25,7 +25,7 @@ #define LP_COMMAND_RECVSOCK NN_PULL #define LP_MAXPUBKEY_ERRORS 3 -#define PSOCK_KEEPALIVE 600 +#define PSOCK_KEEPALIVE 3600 #define MAINLOOP_PERSEC 10 #define MAX_PSOCK_PORT 60000 #define MIN_PSOCK_PORT 10000 diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 242f0fcf5..d71800242 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -134,10 +134,10 @@ char *issue_LP_psock(char *destip,uint16_t destport,int32_t ispaired) uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired) { uint16_t publicport = 0; char *retstr,*addr; cJSON *retjson; struct LP_peerinfo *peer,*tmp; - connectaddr[0] = publicaddr[0] = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { - if ( (retstr= issue_LP_psock(peer->ipaddr,peer->port,ispaired)) != 0 ) + connectaddr[0] = publicaddr[0] = 0; + if ( peer->errors < LP_MAXPEER_ERRORS && (retstr= issue_LP_psock(peer->ipaddr,peer->port,ispaired)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { From 97580c9ea596768ad0b10979cf2988c071945561 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 10:49:14 +0300 Subject: [PATCH 1877/2705] Test --- iguana/exchanges/LP_prices.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 46d15fcda..27751556a 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -546,6 +546,8 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * { if ( pubp == 0 || bits256_cmp(pubp->pubkey,utxo->pubkey) != 0 ) pubp = LP_pubkeyfind(utxo->pubkey); + if ( pubp->numerrors >= LP_MAXPUBKEY_ERRORS ) + continue; //char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); if ( strcmp(base,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && pubp != 0 && (price= pubp->matrix[baseid][relid]) > SMALLVAL ) { From 134840f1dba0d9efaf691ae9d0f7156afd722978 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 11:04:04 +0300 Subject: [PATCH 1878/2705] Test --- iguana/exchanges/LP_prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 27751556a..1633b2d7c 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -546,7 +546,7 @@ int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char * { if ( pubp == 0 || bits256_cmp(pubp->pubkey,utxo->pubkey) != 0 ) pubp = LP_pubkeyfind(utxo->pubkey); - if ( pubp->numerrors >= LP_MAXPUBKEY_ERRORS ) + if ( pubp != 0 && pubp->numerrors >= LP_MAXPUBKEY_ERRORS ) continue; //char str[65],str2[65]; printf("check utxo.%s/v%d from %s\n",bits256_str(str,utxo->payment.txid),utxo->payment.vout,bits256_str(str2,utxo->pubkey)); if ( strcmp(base,utxo->coin) == 0 && LP_isavailable(utxo) > 0 && pubp != 0 && (price= pubp->matrix[baseid][relid]) > SMALLVAL ) From 898227421e5c69c278972037c7eb30f4ab71bcf8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 11:37:29 +0300 Subject: [PATCH 1879/2705] Test --- iguana/exchanges/LP_commands.c | 3 +++ iguana/exchanges/LP_forwarding.c | 23 +++++++++++++++++++++-- iguana/exchanges/LP_nativeDEX.c | 18 +++++++++--------- iguana/exchanges/LP_ordermatch.c | 4 +++- iguana/exchanges/LP_peers.c | 10 ++++++++++ 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index dda9c8d1d..a07054c5c 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -77,6 +77,7 @@ orderbook(base, rel)\n\ getprices(base, rel)\n\ trust(pubkey, trust)\n\ register(pubkey,pushaddr)\n\ +registerall(numnodes)\n\ lookup(pubkey)\n\ forward(pubkey,method2,)\n\ forward(pubkey,method2=publish,)\n\ @@ -199,6 +200,8 @@ forwardhex(pubkey,hex)\n\ return(LP_prices()); else if ( strcmp(method,"orderbook") == 0 ) return(LP_orderbook(base,rel)); + else if ( strcmp(method,"registerall") == 0 ) + return(LP_registerall(jint(argjson,"numnodes"))); else if ( strcmp(method,"forward") == 0 ) { cJSON *reqjson; diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index e7b733505..c56170d67 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -149,13 +149,13 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) } } -void LP_forwarding_register(bits256 pubkey,char *pushaddr,uint16_t pushport,int32_t max) +int32_t LP_forwarding_register(bits256 pubkey,char *pushaddr,uint16_t pushport,int32_t max) { char *retstr,ipaddr[64]; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t j,n=0,retval = -1; if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) { printf("LP_forwarding_register illegal pushaddr or null pubkey\n"); - return; + return(0); } for (j=0; pushaddr[j]!=0; j++) if ( pushaddr[j] >= '0' && pushaddr[j] <= '9' ) @@ -178,6 +178,25 @@ void LP_forwarding_register(bits256 pubkey,char *pushaddr,uint16_t pushport,int3 if ( retval == 0 ) break; } + return(n); +} + +char *LP_registerall(int32_t numnodes) +{ + int32_t i,maxnodes,n=0; cJSON *retjson; + if ( numnodes < sizeof(default_LPnodes)/sizeof(*default_LPnodes) ) + numnodes = (int32_t)(sizeof(default_LPnodes)/sizeof(*default_LPnodes)); + if ( (maxnodes= LP_numpeers()) < numnodes ) + numnodes = maxnodes; + for (i=0; i= numnodes ) + break; + retjson = cJSON_CreateObject(); + if ( i < numnodes ) + jaddstr(retjson,"error","not enough nodes"); + jaddnum(retjson,"numnodes",numnodes); + jaddnum(retjson,"registered",n); + return(jprint(retjson,1)); } cJSON *LP_dereference(cJSON *argjson,char *excludemethod) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 38ea5550c..16156cd19 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -30,12 +30,12 @@ struct LP_forwardinfo *LP_forwardinfos; char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; -char USERPASS[65],USERPASS_WIFSTR[64],LP_myipaddr[64],USERHOME[512] = { "/root" }; +char USERPASS[65],USERPASS_WIFSTR[64],LP_myipaddr[64],LP_publicaddr[64],USERHOME[512] = { "/root" }; char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", };//"5.9.253.204" }; // uint32_t LP_deadman_switch; -uint16_t LP_fixed_pairport; +uint16_t LP_fixed_pairport,LP_publicport; int32_t LP_mypubsock = -1; int32_t USERPASS_COUNTER,IAMLP = 0; double LP_profitratio = 1.; @@ -73,8 +73,8 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_swap.c" #include "LP_peers.c" #include "LP_utxos.c" -#include "LP_ordermatch.c" #include "LP_forwarding.c" +#include "LP_ordermatch.c" #include "LP_commands.c" char *LP_command_process(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) @@ -240,11 +240,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int if ( mypeer == 0 ) myipaddr = "127.0.0.1"; //if ( LP_canbind == 0 ) printf("counter.%d canbind.%d peers\n",counter,LP_canbind); - numpeers = 0; - HASH_ITER(hh,LP_peerinfos,peer,tmp) - { - numpeers++; - } + numpeers = LP_numpeers(); HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) @@ -275,7 +271,9 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int LP_myutxo_updates(ctx,pubsock,passphrase,profitmargin); if ( lastforward < now-3600 ) { - LP_forwarding_register(LP_mypubkey,pushaddr,pushport,10); + if ( (retstr= LP_registerall(0)) != 0 ) + free(retstr); + //LP_forwarding_register(LP_mypubkey,pushaddr,pushport,10); lastforward = now; } } @@ -500,6 +498,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit nn_close(pullsock); pullsock = LP_initpublicaddr(ctx,&mypullport,pushaddr,myipaddr,mypullport,0); LP_deadman_switch = (uint32_t)time(NULL); + strcpy(LP_publicaddr,pushaddr); + LP_publicport = mypullport; LP_forwarding_register(LP_mypubkey,pushaddr,mypullport,MAX_PSOCK_PORT); } } diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index d5d4ca042..6a2415236 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -554,7 +554,7 @@ int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson, char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargin,char *base,char *rel,double maxprice,double volume,int32_t timeout) { - int64_t satoshis,destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; struct LP_pubkeyinfo *pubp; + int64_t satoshis,destsatoshis,desttxfee,txfee,bestdestsatoshis=0; bits256 txid,pubkey; char *obookstr,*retstr; cJSON *orderbook,*asks,*item,*bestitem=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; int32_t i,vout,numasks,DEXselector=0; uint32_t expiration; double ordermatchprice,bestmetric,metric,bestprice=0.,vol,price; struct LP_quoteinfo Q; struct LP_pubkeyinfo *pubp; if ( maxprice <= 0. || volume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 ) return(clonestr("{\"error\":\"invalid parameter\"}")); if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * volume)) == 0 ) @@ -631,6 +631,8 @@ char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargi if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypubkey,autxo->coinaddr) < 0 ) return(clonestr("{\"error\":\"cant set ordermatch quote info\"}")); bestutxo->T.bestflag = (uint32_t)time(NULL); + if ( (retstr= LP_registerall(0)) != 0 ) + free(retstr); price = LP_query(ctx,myipaddr,mypubsock,profitmargin,"request",&Q); bestitem = LP_quotejson(&Q); if ( price > SMALLVAL ) diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 7207e53a7..7193a522c 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -182,3 +182,13 @@ void LP_peersquery(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr } } } + +int32_t LP_numpeers() +{ + struct LP_peerinfo *peer,*tmp; int32_t numpeers = 0; + HASH_ITER(hh,LP_peerinfos,peer,tmp) + { + numpeers++; + } + return(numpeers); +} From c9e7ec42a3907d1239f49a195ebdb556ca11aa2b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 11:38:36 +0300 Subject: [PATCH 1880/2705] Test --- iguana/exchanges/registerall | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 iguana/exchanges/registerall diff --git a/iguana/exchanges/registerall b/iguana/exchanges/registerall new file mode 100755 index 000000000..9024b8230 --- /dev/null +++ b/iguana/exchanges/registerall @@ -0,0 +1,3 @@ + +source userpass +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"registerall\",\"numnodes\":10}" From eac8a5aefb5c3d590f7af92f6e49ac5c6f787ddb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 11:39:42 +0300 Subject: [PATCH 1881/2705] Test --- iguana/exchanges/LP_include.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 5050388a3..7774a0070 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -30,7 +30,7 @@ #define MAX_PSOCK_PORT 60000 #define MIN_PSOCK_PORT 10000 -#define LP_HTTP_TIMEOUT 1 +#define LP_HTTP_TIMEOUT 2 // 1 is too small due to edge cases of time(NULL) #define LP_MAXPEER_ERRORS 3 #define LP_SWAPSTEP_TIMEOUT 3 #define LP_AUTOTRADE_TIMEOUT 3 From ba412011d20ceccbafd56e69a4939586c3564011 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 11:42:57 +0300 Subject: [PATCH 1882/2705] Test --- iguana/exchanges/LP_forwarding.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index c56170d67..dc33c3ea6 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -149,24 +149,24 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) } } -int32_t LP_forwarding_register(bits256 pubkey,char *pushaddr,uint16_t pushport,int32_t max) +int32_t LP_forwarding_register(bits256 pubkey,char *publicaddr,uint16_t publicport,int32_t max) { char *retstr,ipaddr[64]; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t j,n=0,retval = -1; - if ( pushaddr == 0 || pushaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) + if ( publicaddr == 0 || publicaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) { - printf("LP_forwarding_register illegal pushaddr or null pubkey\n"); + char str[65]; printf("LP_forwarding_register illegal publicaddr.(%s) or null pubkey (%s)\n",publicaddr,bits256_str(str,pubkey)); return(0); } - for (j=0; pushaddr[j]!=0; j++) - if ( pushaddr[j] >= '0' && pushaddr[j] <= '9' ) + for (j=0; publicaddr[j]!=0; j++) + if ( publicaddr[j] >= '0' && publicaddr[j] <= '9' ) break; - parse_ipaddr(ipaddr,pushaddr+j); + parse_ipaddr(ipaddr,publicaddr+j); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("register.(%s) %s %u with (%s)\n",pushaddr,ipaddr,pushport,peer->ipaddr); - if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,ipaddr,pushport)) != 0 ) + printf("register.(%s) %s %u with (%s)\n",publicaddr,ipaddr,publicport,peer->ipaddr); + if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,ipaddr,publicport)) != 0 ) { - //printf("[%s] LP_register.(%s) returned.(%s)\n",pushaddr,peer->ipaddr,retstr); + //printf("[%s] LP_register.(%s) returned.(%s)\n",publicaddr,peer->ipaddr,retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { if ( jint(retjson,"registered") != 0 && ++n >= max ) From e91ca453e31ea9654a78dafcaa569d6fdd846b75 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 11:44:57 +0300 Subject: [PATCH 1883/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_nativeDEX.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index dc33c3ea6..3c506c826 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -154,7 +154,7 @@ int32_t LP_forwarding_register(bits256 pubkey,char *publicaddr,uint16_t publicpo char *retstr,ipaddr[64]; cJSON *retjson; struct LP_peerinfo *peer,*tmp; int32_t j,n=0,retval = -1; if ( publicaddr == 0 || publicaddr[0] == 0 || bits256_nonz(pubkey) == 0 ) { - char str[65]; printf("LP_forwarding_register illegal publicaddr.(%s) or null pubkey (%s)\n",publicaddr,bits256_str(str,pubkey)); + char str[65]; printf("LP_forwarding_register illegal publicaddr.(%s):%u or null pubkey (%s)\n",publicaddr,publicport,bits256_str(str,pubkey)); return(0); } for (j=0; publicaddr[j]!=0; j++) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 16156cd19..7e748a743 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -470,6 +470,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit } LP_initpeers(pubsock,mypeer,myipaddr,myport,jstr(argjson,"seednode"),profitmargin); pullsock = LP_initpublicaddr(ctx,&mypullport,pushaddr,myipaddr,mypullport,0); + strcpy(LP_publicaddr,pushaddr); + LP_publicport = mypullport; LP_deadman_switch = (uint32_t)time(NULL); printf("my command address is (%s) pullsock.%d pullport.%u\n",pushaddr,pullsock,mypullport); LP_initcoins(ctx,pubsock,jobj(argjson,"coins"),passphrase); From 72d1f7daaf6e77341acbdfd41be966eb98a687b2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 11:48:14 +0300 Subject: [PATCH 1884/2705] Test --- iguana/exchanges/LP_forwarding.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 3c506c826..cf655535c 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -192,10 +192,11 @@ char *LP_registerall(int32_t numnodes) if ( (n= LP_forwarding_register(LP_mypubkey,LP_publicaddr,LP_publicport,numnodes)) >= numnodes ) break; retjson = cJSON_CreateObject(); - if ( i < numnodes ) + if ( i == numnodes ) jaddstr(retjson,"error","not enough nodes"); jaddnum(retjson,"numnodes",numnodes); jaddnum(retjson,"registered",n); + jaddnum(retjson,"iters",i); return(jprint(retjson,1)); } From ac0e1ea593169edd41e914ae9570ad99526a4a18 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 11:58:59 +0300 Subject: [PATCH 1885/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- iguana/exchanges/LP_include.h | 5 ++++- iguana/exchanges/LP_rpc.c | 8 +++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index cf655535c..588d2ea12 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -174,7 +174,7 @@ int32_t LP_forwarding_register(bits256 pubkey,char *publicaddr,uint16_t publicpo free_json(retjson); } free(retstr); - } else printf("error registering with %s\n",peer->ipaddr); + } else printf("timeout registering with %s errs.%d good.%d\n",peer->ipaddr,peer->errors,peer->good); if ( retval == 0 ) break; } diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 7774a0070..207f67afa 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -32,6 +32,9 @@ #define LP_HTTP_TIMEOUT 2 // 1 is too small due to edge cases of time(NULL) #define LP_MAXPEER_ERRORS 3 +#define LP_MINPEER_GOOD 100 +#define LP_PEERGOOD_ERRORDECAY 0.9 + #define LP_SWAPSTEP_TIMEOUT 3 #define LP_AUTOTRADE_TIMEOUT 3 #define LP_MIN_TXFEE 10000 @@ -191,7 +194,7 @@ struct LP_peerinfo UT_hash_handle hh; uint64_t ip_port; double profitmargin; - uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected,lastutxos,lastpeers,diduquery; + uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected,lastutxos,lastpeers,diduquery,good; int32_t pushsock,subsock; uint16_t port; char ipaddr[64]; diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index d71800242..547a05be2 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -23,14 +23,16 @@ char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) char *retstr = 0; int32_t maxerrs; struct LP_peerinfo *peer = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destip),port); maxerrs = LP_MAXPEER_ERRORS; - if ( peer == 0 || peer->errors < maxerrs ) + if ( peer == 0 || (peer->errors < maxerrs && peer->good < LP_MINPEER_GOOD) ) { if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 ) { if ( peer != 0 ) + { peer->errors++; - else printf("%s error on (%s:%u) without peer\n",debugstr,destip,port); - } + peer->good *= LP_PEERGOOD_ERRORDECAY; + } else printf("%s error on (%s:%u) without peer\n",debugstr,destip,port); + } else peer->good++; } return(retstr); } From 2851ea07edcde596b0ee8d2b9e01b4a743d0b9ee Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 12:08:30 +0300 Subject: [PATCH 1886/2705] Test --- iguana/exchanges/LP_rpc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 547a05be2..ec45c7fd1 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -32,7 +32,9 @@ char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) peer->errors++; peer->good *= LP_PEERGOOD_ERRORDECAY; } else printf("%s error on (%s:%u) without peer\n",debugstr,destip,port); - } else peer->good++; + } + else if ( peer != 0 ) + peer->good++; } return(retstr); } From 4d30edaaeb239b6fbcb87bcffe21811e243ac816 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 12:16:36 +0300 Subject: [PATCH 1887/2705] Test --- iguana/exchanges/LP_include.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 207f67afa..62da124fb 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -32,7 +32,7 @@ #define LP_HTTP_TIMEOUT 2 // 1 is too small due to edge cases of time(NULL) #define LP_MAXPEER_ERRORS 3 -#define LP_MINPEER_GOOD 100 +#define LP_MINPEER_GOOD 20 #define LP_PEERGOOD_ERRORDECAY 0.9 #define LP_SWAPSTEP_TIMEOUT 3 From fe2a204b6e8fe1918cf1afbb6e11030783cff312 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 12:18:26 +0300 Subject: [PATCH 1888/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 7e748a743..b2fd99459 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -243,6 +243,12 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int numpeers = LP_numpeers(); HASH_ITER(hh,LP_peerinfos,peer,tmp) { + if ( peer->errors >= LP_MAXPEER_ERRORS ) + { + if ( (rand() % 10000) == 0 ) + peer->errors--; + else continue; + } if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) ) { if ( IAMLP != 0 ) From 90ec75f6565c07faa16dc7aac5c32a2c5058c473 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 12:27:42 +0300 Subject: [PATCH 1889/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index ec45c7fd1..dfd48bcda 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -23,7 +23,7 @@ char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) char *retstr = 0; int32_t maxerrs; struct LP_peerinfo *peer = 0; peer = LP_peerfind((uint32_t)calc_ipbits(destip),port); maxerrs = LP_MAXPEER_ERRORS; - if ( peer == 0 || (peer->errors < maxerrs && peer->good < LP_MINPEER_GOOD) ) + if ( peer == 0 || (peer->errors < maxerrs || peer->good >= LP_MINPEER_GOOD) ) { if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 ) { From 7d2b7a113b6978a37543ad5d3279d61dc58a052e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 13:57:03 +0300 Subject: [PATCH 1890/2705] Test --- iguana/exchanges/LP_forwarding.c | 21 ++++++++++++++------- iguana/exchanges/LP_nativeDEX.c | 15 +++++++++------ iguana/exchanges/LP_network.c | 28 +++++++++++----------------- iguana/exchanges/LP_ordermatch.c | 24 ++++++++++++++++-------- iguana/exchanges/LP_peers.c | 5 ++++- iguana/exchanges/LP_utxos.c | 13 ++++++++----- 6 files changed, 62 insertions(+), 44 deletions(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 588d2ea12..98a6df18c 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -214,7 +214,7 @@ cJSON *LP_dereference(cJSON *argjson,char *excludemethod) char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) { - struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *retstr=0; cJSON *retjson=0,*argjson=0,*reqjson=0; + struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *msg,*retstr=0; cJSON *retjson=0,*argjson=0,*reqjson=0; if ( hexstr == 0 || hexstr[0] == 0 ) return(clonestr("{\"error\":\"nohex\"}")); datalen = (int32_t)strlen(hexstr) >> 1; @@ -229,7 +229,10 @@ char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) retstr = LP_command_process(ctx,LP_mypeer != 0 ? LP_mypeer->ipaddr : "127.0.0.1",LP_mypubsock,reqjson,0,0,LP_profitratio - 1.); printf("LP_forwardhex.(%s) -> (%s)\n",jprint(reqjson,0),retstr!=0?retstr:""); if ( pubsock >= 0 ) - LP_send(pubsock,jprint(reqjson,0),0); + { + msg = jprint(reqjson,0); + LP_send(pubsock,msg,(int32_t)strlen(msg)+1,0); + } } else printf("LP_forwardhex couldnt parse (%s)\n",(char *)data); } else if ( (ptr= LP_forwardfind(pubkey)) != 0 ) @@ -237,7 +240,7 @@ char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) if ( ptr->pushsock >= 0 )//&& ptr->hello != 0 ) { printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data); - sentbytes = LP_send(ptr->pushsock,(char *)data,0); + sentbytes = LP_send(ptr->pushsock,(char *)data,datalen,0); } retjson = cJSON_CreateObject(); if ( sentbytes == datalen ) @@ -259,7 +262,10 @@ char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) { char str[65]; printf("couldnt find %s to forward to\n",bits256_str(str,pubkey)); if ( pubsock >= 0 ) - LP_send(pubsock,jprint(reqjson,0),0); + { + msg = jprint(reqjson,0); + LP_send(pubsock,msg,(int32_t)strlen(msg)+1,1); + } retstr = clonestr("{\"error\":\"notfound\"}"); } free(data); @@ -272,7 +278,7 @@ char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) int32_t LP_forward(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin,bits256 pubkey,char *jsonstr,int32_t freeflag) { - struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson,*reqjson,*argjson; + struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *msg,*hexstr,*retstr; int32_t len,retval = -1; cJSON *retjson,*reqjson,*argjson; if ( jsonstr == 0 || jsonstr[0] == 0 ) return(-1); if ( bits256_nonz(pubkey) != 0 ) @@ -292,7 +298,7 @@ int32_t LP_forward(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin, { printf("GOT FORWARDED.(%s) -> pushsock.%d\n",jsonstr,ptr->pushsock); len = (int32_t)strlen(jsonstr); - if ( LP_send(ptr->pushsock,jsonstr,0) == len+1 ) + if ( LP_send(ptr->pushsock,jsonstr,(int32_t)strlen(jsonstr)+1,0) == len+1 ) return(1); } } @@ -324,7 +330,8 @@ int32_t LP_forward(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin, jaddstr(reqjson,"hex",hexstr); jaddbits256(reqjson,"pubkey",pubkey); free(hexstr); - return(LP_send(peer->pushsock,jprint(reqjson,1),1)); + msg = jprint(reqjson,1); + return(LP_send(peer->pushsock,msg,(int32_t)strlen(msg)+1,1)); } else retval = -1; } if ( freeflag != 0 ) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index b2fd99459..c5d00e332 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -88,7 +88,7 @@ char *LP_command_process(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson { //printf("%s PULL.[%d]-> (%s)\n",myipaddr != 0 ? myipaddr : "127.0.0.1",datalen,retstr); if ( pubsock >= 0 ) //strncmp("{\"error\":",retstr,strlen("{\"error\":")) != 0 && - LP_send(pubsock,retstr,0); + LP_send(pubsock,retstr,(int32_t)strlen(retstr)+1,0); } } return(retstr); @@ -96,7 +96,7 @@ char *LP_command_process(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson char *LP_process_message(void *ctx,char *typestr,char *myipaddr,int32_t pubsock,double profitmargin,void *ptr,int32_t recvlen,int32_t recvsock) { - int32_t len,datalen=0; char *retstr=0,*jsonstr=0; cJSON *argjson,*reqjson; + int32_t len,datalen=0; char *msg,*retstr=0,*jsonstr=0; cJSON *argjson,*reqjson; if ( (datalen= is_hexstr((char *)ptr,0)) > 0 ) { datalen >>= 1; @@ -124,7 +124,10 @@ char *LP_process_message(void *ctx,char *typestr,char *myipaddr,int32_t pubsock, jdelete(argjson,"method2"); jaddstr(argjson,"method2","broadcast"); if ( pubsock >= 0 && (reqjson= LP_dereference(argjson,"publish")) != 0 ) - LP_send(pubsock,jprint(reqjson,1),1); + { + msg = jprint(reqjson,1); + LP_send(pubsock,msg,(int32_t)strlen(msg)+1,1); + } } else if ( (retstr= LP_command_process(ctx,myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvlen - len,profitmargin)) != 0 ) { @@ -137,13 +140,13 @@ char *LP_process_message(void *ctx,char *typestr,char *myipaddr,int32_t pubsock, if ( strcmp("PULL",typestr) == 0 ) { printf("%d got REQ.(%s) -> (%s)\n",recvsock,jprint(argjson,0),retstr); - LP_send(recvsock,retstr,0); + LP_send(recvsock,retstr,(int32_t)strlen(retstr)+1,0); } } else if ( strcmp("PULL",typestr) == 0 ) { printf("%d got REQ.(%s) -> null\n",recvsock,jprint(argjson,0)); - LP_send(recvsock,"{\"result\":null}",0); + LP_send(recvsock,"{\"result\":null}",(int32_t)strlen("{\"result\":null}")+1,0); } } free_json(argjson); @@ -322,7 +325,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int char keepalive[128]; sprintf(keepalive,"{\"method\":\"keepalive\"}"); //printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock); - if ( LP_send(pullsock,keepalive,0) < 0 ) + if ( LP_send(pullsock,keepalive,(int32_t)strlen(keepalive)+1,0) < 0 ) { //LP_deadman_switch = 0; } diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index f63fc2438..7713c380b 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -34,9 +34,9 @@ char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t por return(str); } -int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) +int32_t LP_send(int32_t sock,void *msg,int32_t sendlen,int32_t freeflag) { - int32_t sentbytes,len,i; struct nn_pollfd pfd; + int32_t sentbytes,i; struct nn_pollfd pfd; if ( sock < 0 ) { printf("LP_send.(%s) to illegal socket\n",msg); @@ -44,7 +44,7 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) free(msg); return(-1); } - len = (int32_t)strlen(msg) + 1; + //len = (int32_t)strlen(msg) + 1; for (i=0; i<1000; i++) // 1000 * (1 ms + 1000 us) = 2 seconds { pfd.fd = sock; @@ -52,8 +52,8 @@ int32_t LP_send(int32_t sock,char *msg,int32_t freeflag) //portable_mutex_lock(&LP_networkmutex); if ( nn_poll(&pfd,1,1) > 0 ) { - if ( (sentbytes= nn_send(sock,msg,len,0)) != len ) - printf("LP_send sent %d instead of %d\n",sentbytes,len); + if ( (sentbytes= nn_send(sock,msg,sendlen,0)) != sendlen ) + printf("LP_send sent %d instead of %d\n",sentbytes,sendlen); //else printf("SENT.(%s)\n",msg); if ( freeflag != 0 ) free(msg); @@ -105,7 +105,7 @@ void LP_psockloop(void *_ptr) { if ( size > 0 ) { - if ( (sentbytes= LP_send(sendsock,buf,0)) > 0 ) + if ( (sentbytes= LP_send(sendsock,buf,size,0)) > 0 ) { //printf("PSOCKS (%d %d %d) (%s) -> %d/%d bytes %s\n",ptr->publicsock,ptr->sendsock,sendsock,(char *)buf,size,sentbytes,ptr->sendaddr); } @@ -153,15 +153,9 @@ void LP_psockloop(void *_ptr) //printf("publicsock.%d %s has pollin\n",ptr->publicsock,ptr->publicaddr); if ( (size= nn_recv(ptr->publicsock,&buf,NN_MSG,0)) > 0 ) { - printf("keepalive.%u [%s] -> sendsock.%d\n",now,(char *)buf,ptr->sendsock); - cJSON *retjson; - if ( (retjson= cJSON_Parse((char *)buf)) != 0 ) - { - free_json(retjson); - ptr->lasttime = now; - sendsock = ptr->sendsock; - break; - } + ptr->lasttime = now; + sendsock = ptr->sendsock; + break; } } } @@ -375,11 +369,11 @@ int32_t nn_tests(void *ctx,int32_t pullsock,char *pushaddr,int32_t nnother) timeout = 1; nn_setsockopt(sock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); sprintf(msg,"{\"method\":\"nn_tests\",\"ipaddr\":\"%s\"}",pushaddr); - n = LP_send(sock,msg,0); + n = LP_send(sock,msg,(int32_t)strlen(msg)+1,0); sleep(3); LP_pullsock_check(ctx,&retstr,"127.0.0.1",-1,pullsock,0.); sprintf(msg,"{\"method\":\"nn_tests2\",\"ipaddr\":\"%s\"}",pushaddr); - m = LP_send(pullsock,msg,0); + m = LP_send(pullsock,msg,(int32_t)strlen(msg)+1,0); printf(">>>>>>>>>>>>>>>>>>>>>> sent %d+%d bytes -> pullsock.%d retstr.(%s)\n",n,m,pullsock,retstr!=0?retstr:""); if ( retstr != 0 ) { diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c index 6a2415236..9153fb449 100644 --- a/iguana/exchanges/LP_ordermatch.c +++ b/iguana/exchanges/LP_ordermatch.c @@ -178,7 +178,7 @@ char *LP_quotereceived(cJSON *argjson) char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin,char *base,char *rel,double price) { - bits256 zero; cJSON *reqjson = cJSON_CreateObject(); + bits256 zero; char *msg; cJSON *reqjson = cJSON_CreateObject(); jaddbits256(reqjson,"pubkey",LP_mypubkey); jaddstr(reqjson,"base",base); jaddstr(reqjson,"rel",rel); @@ -187,7 +187,8 @@ char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin { jaddstr(reqjson,"method","postprice"); //printf("%d pricepings.(%s)\n",pubsock,jprint(reqjson,0)); - LP_send(pubsock,jprint(reqjson,1),1); + msg = jprint(reqjson,1); + LP_send(pubsock,msg,(int32_t)strlen(msg)+1,1); } else { @@ -296,7 +297,7 @@ int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout) double LP_query(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargin,char *method,struct LP_quoteinfo *qp) { - cJSON *reqjson; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; + cJSON *reqjson; char *msg; int32_t i,flag = 0; double price = 0.; struct LP_utxoinfo *utxo; if ( strcmp(method,"request") == 0 ) { if ( (utxo= LP_utxofind(0,qp->desttxid,qp->destvout)) != 0 && LP_ismine(utxo) > 0 && LP_isavailable(utxo) > 0 ) @@ -314,7 +315,8 @@ double LP_query(void *ctx,char *myipaddr,int32_t mypubsock,double profitmargin,c if ( IAMLP != 0 ) { jaddstr(reqjson,"method",method); - LP_send(LP_mypubsock,jprint(reqjson,1),1); + msg = jprint(reqjson,1); + LP_send(LP_mypubsock,msg,(int32_t)strlen(msg)+1,1); } else { @@ -372,7 +374,7 @@ int32_t LP_nanobind(void *ctx,char *pairstr) int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *myipaddr,char *base,char *rel,double profitmargin,double price,struct LP_quoteinfo *qp) { - char pairstr[512]; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; struct iguana_info *coin; + char pairstr[512],*msg; cJSON *retjson; bits256 privkey; int32_t pair=-1,retval = -1,DEXselector = 0; struct basilisk_swap *swap; struct iguana_info *coin; printf("LP_connectstartbob.(%s) with.(%s) %s\n",myipaddr,jprint(argjson,0),LP_myipaddr); qp->quotetime = (uint32_t)time(NULL); if ( (coin= LP_coinfind(utxo->coin)) == 0 ) @@ -399,7 +401,10 @@ int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJ jaddnum(retjson,"quoteid",qp->R.quoteid); char str[65]; printf("BOB pubsock.%d sends to (%s)\n",pubsock,bits256_str(str,utxo->S.otherpubkey)); if ( pubsock >= 0 ) - LP_send(pubsock,jprint(retjson,0),1); + { + msg = jprint(retjson,0); + LP_send(pubsock,msg,(int32_t)strlen(msg)+1,1); + } jdelete(retjson,"method"); jaddstr(retjson,"method2","connected"); jaddstr(retjson,"method","forward"); @@ -492,7 +497,7 @@ char *LP_connectedalice(cJSON *argjson) // alice int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen,double profitmargin) { - char *method; cJSON *retjson; double qprice,price,bid,ask; struct LP_utxoinfo *autxo,*butxo; int32_t retval = -1; struct LP_quoteinfo Q; + char *method,*msg; cJSON *retjson; double qprice,price,bid,ask; struct LP_utxoinfo *autxo,*butxo; int32_t retval = -1; struct LP_quoteinfo Q; if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"request") == 0 ||strcmp(method,"connect") == 0) ) { //printf("TRADECOMMAND.(%s)\n",jprint(argjson,0)); @@ -531,7 +536,10 @@ int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson, jaddbits256(retjson,"pubkey",butxo->S.otherpubkey); jaddstr(retjson,"method","reserved"); if ( pubsock >= 0 ) - LP_send(pubsock,jprint(retjson,0),1); + { + msg = jprint(retjson,0); + LP_send(pubsock,msg,(int32_t)strlen(msg)+1,1); + } jdelete(retjson,"method"); jaddstr(retjson,"method2","reserved"); jaddstr(retjson,"method","forward"); diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c index 7193a522c..95c708348 100644 --- a/iguana/exchanges/LP_peers.c +++ b/iguana/exchanges/LP_peers.c @@ -114,7 +114,10 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char } else peer->numpeers = 1; // will become mypeer portable_mutex_unlock(&LP_peermutex); if ( mypubsock >= 0 ) - LP_send(mypubsock,jprint(LP_peerjson(peer),1),1); + { + char *msg = jprint(LP_peerjson(peer),1); + LP_send(mypubsock,msg,(int32_t)strlen(msg)+1,1); + } } } else printf("LP_addpeer: checkip.(%s) vs (%s)\n",checkip,ipaddr); return(peer); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 37160a1b8..0eeecbc5f 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -352,7 +352,7 @@ struct LP_utxoinfo *LP_utxo_bestfit(char *symbol,uint64_t destsatoshis) void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) { - cJSON *argjson; struct _LP_utxoinfo u; + cJSON *argjson; struct _LP_utxoinfo u; char *msg; utxo->T.spentflag = (uint32_t)time(NULL); if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) LP_mypeer->numutxos--; @@ -370,7 +370,8 @@ void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) jaddbits256(argjson,"checktxid",u.txid); jaddnum(argjson,"checkvout",u.vout); } - LP_send(LP_mypubsock,jprint(argjson,1),1); + msg = jprint(argjson,1); + LP_send(LP_mypubsock,msg,(int32_t)strlen(msg)+1,1); } } @@ -407,7 +408,7 @@ char *LP_spentcheck(cJSON *argjson) struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) { - uint64_t val,val2=0,tmpsatoshis,bigtxfee = 100000; int32_t spendvini,selector; bits256 spendtxid; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + uint64_t val,val2=0,tmpsatoshis,bigtxfee = 100000; int32_t spendvini,selector; bits256 spendtxid; char *msg; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); @@ -497,8 +498,10 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( iambob != 0 ) { if ( mypubsock >= 0 ) - LP_send(mypubsock,jprint(LP_utxojson(utxo),1),1); - else LP_utxo_clientpublish(utxo); + { + msg = jprint(LP_utxojson(utxo),1); + LP_send(mypubsock,msg,(int32_t)strlen(msg)+1,1); + } else LP_utxo_clientpublish(utxo); if ( LP_mypeer != 0 && LP_ismine(utxo) > 0 ) LP_mypeer->numutxos++; } From 61d4f04155c8542e69af95c1f7b17ed4d1f21088 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 14:00:16 +0300 Subject: [PATCH 1891/2705] Test --- iguana/exchanges/LP_network.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c index 7713c380b..b25dc824a 100644 --- a/iguana/exchanges/LP_network.c +++ b/iguana/exchanges/LP_network.c @@ -39,7 +39,7 @@ int32_t LP_send(int32_t sock,void *msg,int32_t sendlen,int32_t freeflag) int32_t sentbytes,i; struct nn_pollfd pfd; if ( sock < 0 ) { - printf("LP_send.(%s) to illegal socket\n",msg); + printf("LP_send.(%s) to illegal socket\n",(char *)msg); if ( freeflag != 0 ) free(msg); return(-1); @@ -63,7 +63,7 @@ int32_t LP_send(int32_t sock,void *msg,int32_t sendlen,int32_t freeflag) //portable_mutex_unlock(&LP_networkmutex); usleep(1000); } - printf("error LP_send sock.%d, i.%d timeout.(%s) %s\n",sock,i,msg,nn_strerror(nn_errno())); + printf("error LP_send sock.%d, i.%d timeout.(%s) %s\n",sock,i,(char *)msg,nn_strerror(nn_errno())); if ( freeflag != 0 ) free(msg); return(-1); From 91f5543d6c684796a142efc4534516c0e511c4c5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 14:13:11 +0300 Subject: [PATCH 1892/2705] Test --- iguana/exchanges/LP_prices.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index 1633b2d7c..d124af247 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -513,7 +513,7 @@ int32_t LP_orderbookfind(struct LP_orderbookentry **array,int32_t num,bits256 tx int32_t LP_utxo_clientpublish(struct LP_utxoinfo *utxo) { - struct LP_peerinfo *peer,*tmp; cJSON *retjson; char *retstr; + struct LP_peerinfo *peer,*tmp; cJSON *retjson; char *retstr; int32_t n = 0; HASH_ITER(hh,LP_peerinfos,peer,tmp) { if ( (retstr= issue_LP_notifyutxo(peer->ipaddr,peer->port,utxo)) != 0 ) @@ -525,15 +525,16 @@ int32_t LP_utxo_clientpublish(struct LP_utxoinfo *utxo) //if ( strcmp("HUSH",utxo->coin) == 0 ) // printf("clientpublish %s (%s)\n",peer->ipaddr,retstr); utxo->T.lasttime = (uint32_t)time(NULL); + n++; } free_json(retjson); } free(retstr); } - if ( utxo->T.lasttime != 0 ) - return(0); + //if ( utxo->T.lasttime != 0 ) + // return(0); } - return(-1); + return(n); } int32_t LP_orderbook_utxoentries(uint32_t now,int32_t polarity,char *base,char *rel,struct LP_orderbookentry *(**arrayp),int32_t num,int32_t cachednum) From 46cc1644bf6436ef338a4ca6308eefa6e988afdb Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 15:22:35 +0300 Subject: [PATCH 1893/2705] Test --- iguana/exchanges/LP_include.h | 2 +- iguana/exchanges/LP_nativeDEX.c | 3 +++ iguana/exchanges/LP_utxos.c | 11 +++++++---- iguana/exchanges/client | 2 +- iguana/exchanges/run | 2 +- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_include.h b/iguana/exchanges/LP_include.h index 62da124fb..41c5286c8 100644 --- a/iguana/exchanges/LP_include.h +++ b/iguana/exchanges/LP_include.h @@ -186,7 +186,7 @@ struct LP_utxoinfo int32_t iambob,iamlp; uint8_t key[sizeof(bits256) + sizeof(int32_t)]; uint8_t key2[sizeof(bits256) + sizeof(int32_t)]; - char coin[16],coinaddr[64],spendscript[256]; + char coin[16],coinaddr[64],spendscript[256],gui[16]; }; struct LP_peerinfo diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c5d00e332..78903fd2a 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -31,6 +31,7 @@ struct LP_forwardinfo *LP_forwardinfos; char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; char USERPASS[65],USERPASS_WIFSTR[64],LP_myipaddr[64],LP_publicaddr[64],USERHOME[512] = { "/root" }; +char LP_gui[16] = { "cli" }; char *default_LPnodes[] = { "5.9.253.195", "5.9.253.196", "5.9.253.197", "5.9.253.198", "5.9.253.199", "5.9.253.200", "5.9.253.201", "5.9.253.202", "5.9.253.203", };//"5.9.253.204" }; // @@ -410,6 +411,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit #endif LP_profitratio += profitmargin; OS_randombytes((void *)&n,sizeof(n)); + if ( jobj(argjson,"gui") != 0 ) + safecopy(LP_gui,jstr(argjson,"gui"),sizeof(LP_gui)); if ( jobj(argjson,"canbind") == 0 ) { #ifndef __linux__ diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0eeecbc5f..87e0117ba 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -217,6 +217,8 @@ cJSON *LP_inventoryjson(cJSON *item,struct LP_utxoinfo *utxo) { struct _LP_utxoinfo u; jaddstr(item,"method","notified"); + if ( utxo->gui[0] != 0 ) + jaddstr(item,"gui",utxo->gui); jaddstr(item,"coin",utxo->coin); jaddnum(item,"now",time(NULL)); jaddnum(item,"iambob",utxo->iambob); @@ -406,7 +408,7 @@ char *LP_spentcheck(cJSON *argjson) return(clonestr("{\"error\":\"cant find txid to check spent status\"}")); } -struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin) +struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin,char *gui) { uint64_t val,val2=0,tmpsatoshis,bigtxfee = 100000; int32_t spendvini,selector; bits256 spendtxid; char *msg; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) @@ -469,6 +471,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit utxo = calloc(1,sizeof(*utxo)); utxo->S.profitmargin = profitmargin; utxo->pubkey = pubkey; + safecopy(utxo->gui,gui,sizeof(utxo->gui)); safecopy(utxo->coin,symbol,sizeof(utxo->coin)); safecopy(utxo->coinaddr,coinaddr,sizeof(utxo->coinaddr)); safecopy(utxo->spendscript,spendscript,sizeof(utxo->spendscript)); @@ -517,7 +520,7 @@ struct LP_utxoinfo *LP_utxoaddjson(int32_t iambob,int32_t pubsock,cJSON *argjson return(0); } portable_mutex_lock(&LP_UTXOmutex); - utxo = LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit")); + utxo = LP_utxoadd(iambob,pubsock,jstr(argjson,"coin"),jbits256(argjson,"txid"),jint(argjson,"vout"),j64bits(argjson,"value"),jbits256(argjson,"txid2"),jint(argjson,"vout2"),j64bits(argjson,"value2"),jstr(argjson,"script"),jstr(argjson,"address"),jbits256(argjson,"pubkey"),jdouble(argjson,"profit"),jstr(argjson,"gui")); portable_mutex_unlock(&LP_UTXOmutex); return(utxo); } @@ -709,13 +712,13 @@ uint64_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypr portable_mutex_lock(&LP_UTXOmutex); if ( iambob != 0 ) { - if ( (utxo= LP_utxoadd(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_mypeer != 0 ? LP_mypeer->profitmargin : 0.01)) != 0 ) + if ( (utxo= LP_utxoadd(1,mypubsock,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,script,coin->smartaddr,mypub,LP_mypeer != 0 ? LP_mypeer->profitmargin : 0.01,LP_gui)) != 0 ) { } } else { - if ( (utxo= LP_utxoadd(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0.)) != 0 ) + if ( (utxo= LP_utxoadd(0,mypubsock,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,script,coin->smartaddr,mypub,0.,LP_gui)) != 0 ) { } } diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 9c3f3cdfa..f4c37a458 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -3,7 +3,7 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; -./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, +./marketmaker "{\"gui\":\"nogui\",\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"active\":0,\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, diff --git a/iguana/exchanges/run b/iguana/exchanges/run index e02aa5e4a..8238af326 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -1,5 +1,5 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, +pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"gui\":\"nogui\",\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, From 6216a160dfc165e21caf3ca14b9f5624bf97ca99 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 28 Jun 2017 15:26:38 +0300 Subject: [PATCH 1894/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index dfd48bcda..4b4a3e4c2 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -102,7 +102,7 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,u.txid,u.vout,utxo->pubkey) > 0 ) { - sprintf(url,"http://%s:%u/api/stats/notified?iambob=%d&pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u",destip,destport,utxo->iambob,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL)); + sprintf(url,"http://%s:%u/api/stats/notified?iambob=%d&pubkey=%s&profit=%.6f&coin=%s&txid=%s&vout=%d&value=%llu&txid2=%s&vout2=%d&value2=%llu&script=%s&address=%s×tamp=%u&gui=%s",destip,destport,utxo->iambob,bits256_str(str3,utxo->pubkey),utxo->S.profitmargin,utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,(long long)utxo->payment.value,bits256_str(str2,utxo->deposit.txid),utxo->deposit.vout,(long long)utxo->deposit.value,utxo->spendscript,utxo->coinaddr,(uint32_t)time(NULL),utxo->gui); if ( strlen(url) > 1024 ) printf("WARNING long url.(%s)\n",url); return(LP_issue_curl("notifyutxo",destip,destport,url)); From debc63cd93d3f5d77033c84c58c83e5417812388 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 11:26:21 +0300 Subject: [PATCH 1895/2705] Test --- iguana/exchanges/enable | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/enable b/iguana/exchanges/enable index a5edfdb35..a974c1860 100755 --- a/iguana/exchanges/enable +++ b/iguana/exchanges/enable @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"REVS\"}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"BTC\"}" From cdd2e07213951e375d5c92d3920c206a8de0abee Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 11:28:59 +0300 Subject: [PATCH 1896/2705] Test --- iguana/exchanges/LP_forwarding.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index 98a6df18c..cbde40d71 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -163,7 +163,7 @@ int32_t LP_forwarding_register(bits256 pubkey,char *publicaddr,uint16_t publicpo parse_ipaddr(ipaddr,publicaddr+j); HASH_ITER(hh,LP_peerinfos,peer,tmp) { - printf("register.(%s) %s %u with (%s)\n",publicaddr,ipaddr,publicport,peer->ipaddr); + //printf("register.(%s) %s %u with (%s)\n",publicaddr,ipaddr,publicport,peer->ipaddr); if ( (retstr= issue_LP_register(peer->ipaddr,peer->port,pubkey,ipaddr,publicport)) != 0 ) { //printf("[%s] LP_register.(%s) returned.(%s)\n",publicaddr,peer->ipaddr,retstr); From 5aa58faa5c3bd1b85c25bc144e9457044a5543ab Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 11:31:44 +0300 Subject: [PATCH 1897/2705] Test --- iguana/exchanges/inv | 2 +- iguana/exchanges/orderbook | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/inv b/iguana/exchanges/inv index 0009b7af4..3d6669329 100755 --- a/iguana/exchanges/inv +++ b/iguana/exchanges/inv @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"inventory\",\"coin\":\"REVS\"}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"inventory\",\"coin\":\"BTC\"}" diff --git a/iguana/exchanges/orderbook b/iguana/exchanges/orderbook index 4d2367a42..a2110f07b 100755 --- a/iguana/exchanges/orderbook +++ b/iguana/exchanges/orderbook @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"orderbook\",\"base\":\"REVS\",\"rel\":\"KMD\"}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"orderbook\",\"base\":\"KMD\",\"rel\":\"BTC\"}" From 068533aa7848fe02f333fe84b3c9c5a363b00194 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 14:29:20 +0300 Subject: [PATCH 1898/2705] Test --- iguana/exchanges/LP_commands.c | 2 ++ iguana/exchanges/LP_transaction.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index a07054c5c..6ea87069f 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -162,6 +162,8 @@ forwardhex(pubkey,hex)\n\ LP_privkey_init(-1,ptr,privkey,pubkey,pubkey33); retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); + jaddstr(retjson,"coin",coin); + jaddnum(retjson,"timestamp",time(NULL)); jadd(retjson,"alice",LP_inventory(coin,0)); jadd(retjson,"bob",LP_inventory(coin,1)); return(jprint(retjson,1)); diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 9a3d73225..2e3d57a89 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -136,7 +136,8 @@ int32_t LP_vinscan(bits256 *spendtxidp,int32_t *spendvinip,char *symbol,bits256 { if ( bits256_cmp(txid,jbits256(txobj,"txid")) != 0 ) { - printf("txid mismatch error\n"); + char str[65]; printf("txid mismatch error %s vs %s\n",bits256_str(str,txid),jprint(txobj,0)); + free_json(txobj); return(-2); } vins = jarray(&numvins,txobj,"vin"); From 2044cd286d624994795c79e6b69cca7245a62361 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 14:30:12 +0300 Subject: [PATCH 1899/2705] Test --- iguana/exchanges/LP_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 6ea87069f..f8b55823b 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -22,6 +22,7 @@ char *stats_JSON(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport=0,pushport,subport; int32_t otherpeers,othernumutxos,flag = 0; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; + printf("stats_JSON(%s)\n",jprint(argjson,0)); if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { if ( strcmp(ipaddr,"127.0.0.1") != 0 && argport >= 1000 ) From 2eca9f6ba56df5e67240b26a8104773435d22218 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 15:23:22 +0300 Subject: [PATCH 1900/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 4b4a3e4c2..db72f04d4 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -219,7 +219,7 @@ cJSON *LP_getmempool(char *symbol) cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout) { char buf[128],str[65]; struct iguana_info *coin = LP_coinfind(symbol); - sprintf(buf,"\"%s\", %d",bits256_str(str,txid),vout); + sprintf(buf,"\"%s\", %d, 1",bits256_str(str,txid),vout); return(bitcoin_json(coin,"gettxout",buf)); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 87e0117ba..7cb030d60 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -436,7 +436,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( dispflag != 0 ) printf("%.8f %.8f %s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",dstr(val),dstr(val2),coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); dispflag = 1; - if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) + if ( 0 && (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) { printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); return(0); From 6f62d98798300f41a6a229fd20961423cbfe6a4b Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 15:25:14 +0300 Subject: [PATCH 1901/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index f8b55823b..5d9dfb80a 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -22,7 +22,7 @@ char *stats_JSON(void *ctx,char *myipaddr,int32_t pubsock,double profitmargin,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port { char *method,*ipaddr,*userpass,*base,*rel,*coin,*retstr = 0; uint16_t argport=0,pushport,subport; int32_t otherpeers,othernumutxos,flag = 0; struct LP_peerinfo *peer; cJSON *retjson; struct iguana_info *ptr; - printf("stats_JSON(%s)\n",jprint(argjson,0)); + //printf("stats_JSON(%s)\n",jprint(argjson,0)); if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 ) { if ( strcmp(ipaddr,"127.0.0.1") != 0 && argport >= 1000 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index db72f04d4..adcbdd420 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -219,7 +219,7 @@ cJSON *LP_getmempool(char *symbol) cJSON *LP_gettxout(char *symbol,bits256 txid,int32_t vout) { char buf[128],str[65]; struct iguana_info *coin = LP_coinfind(symbol); - sprintf(buf,"\"%s\", %d, 1",bits256_str(str,txid),vout); + sprintf(buf,"\"%s\", %d, true",bits256_str(str,txid),vout); return(bitcoin_json(coin,"gettxout",buf)); } From c5c5f0d958b19a6ea96310034d0acb1cf28f2a31 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 18:47:56 +0300 Subject: [PATCH 1902/2705] Coqui --- basilisk/basilisk_tradebot.c | 1 - iguana/coins/basilisk/coqui | 2 ++ iguana/coins/coqui_7776 | 1 + iguana/exchanges/client | 2 +- iguana/exchanges/run | 2 +- iguana/iguana_notary.c | 2 +- iguana/m_notary | 3 ++- 7 files changed, 8 insertions(+), 5 deletions(-) create mode 100755 iguana/coins/basilisk/coqui create mode 100755 iguana/coins/coqui_7776 diff --git a/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c index e98a64509..2635cde97 100755 --- a/basilisk/basilisk_tradebot.c +++ b/basilisk/basilisk_tradebot.c @@ -316,7 +316,6 @@ double basilisk_request_listprocess(struct supernet_info *myinfo,struct basilisk } } else noquoteflag++; } - // MVP -> USD myrequest.0 pendingid.0 noquoteflag.1 havequoteflag.0 maxi.-1 0.00000000 struct iguana_info *coin; char coinaddr[64]; double retvals[4],refprice=0.,profitmargin,aveprice,destvolume; destvolume = dstr(maxamount); //printf("destvolume <- %.8f\n",dstr(destvolume)); diff --git a/iguana/coins/basilisk/coqui b/iguana/coins/basilisk/coqui new file mode 100755 index 000000000..cc86f422a --- /dev/null +++ b/iguana/coins/basilisk/coqui @@ -0,0 +1,2 @@ +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"COQUI.conf\",\"path\":\"${HOME#"/"}/.komodo/COQUI\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"COQUI\",\"name\":\"COQUI\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"dd5ce076\",\"p2p\":12455,\"rpc\":12456,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" + diff --git a/iguana/coins/coqui_7776 b/iguana/coins/coqui_7776 new file mode 100755 index 000000000..7233677cf --- /dev/null +++ b/iguana/coins/coqui_7776 @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"COQUI.conf\",\"path\":\"${HOME#"/"}/.komodo/COQUI\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"COQUI\",\"name\":\"COQUI\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fa05f107\",\"p2p\":12455,\"rpc\":12456,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/exchanges/client b/iguana/exchanges/client index f4c37a458..6582e2c82 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -19,6 +19,6 @@ git pull; {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":12456},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} ], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & diff --git a/iguana/exchanges/run b/iguana/exchanges/run index 8238af326..a81c74556 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -15,5 +15,5 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"gui\":\"nog {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":12456},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} ]}" & diff --git a/iguana/iguana_notary.c b/iguana/iguana_notary.c index e7c02acda..fe9d14c60 100755 --- a/iguana/iguana_notary.c +++ b/iguana/iguana_notary.c @@ -437,7 +437,7 @@ STRING_ARG(iguana,addnotary,ipaddr) char NOTARY_CURRENCIES[][16] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", "CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", - "REVS", "SUPERNET", "DEX", "PANGEA", "JUMBLR", "BET", "CRYPTO", "HODL", "SHARK", "BOTS", "MGW", "MVP", "WLC", "KV", "CEAL", "MESH", "LTC" }; + "REVS", "SUPERNET", "DEX", "PANGEA", "JUMBLR", "BET", "CRYPTO", "HODL", "SHARK", "BOTS", "MGW", "COQUI", "WLC", "KV", "CEAL", "MESH", "LTC" }; ZERO_ARGS(dpow,notarychains) { diff --git a/iguana/m_notary b/iguana/m_notary index 633fb4583..d2c82c7c0 100755 --- a/iguana/m_notary +++ b/iguana/m_notary @@ -35,7 +35,8 @@ coins/jumblr_7776 coins/crypto_7776 coins/pangea_7776 coins/mgw_7776 -coins/mvp_7776 +#coins/mvp_7776 +coins/coqui_7776 coins/wlc_7776 coins/kv_7776 coins/ceal_7776 From 9a28b4be4eeed3323835b1054c8073cf3ad9e22f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 29 Jun 2017 18:55:07 +0300 Subject: [PATCH 1903/2705] Test --- iguana/exchanges/LP_prices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c index d124af247..eaf3db19a 100644 --- a/iguana/exchanges/LP_prices.c +++ b/iguana/exchanges/LP_prices.c @@ -20,7 +20,7 @@ struct LP_orderbookentry { bits256 txid,txid2,pubkey; double price; uint64_t basesatoshis; int32_t vout,vout2; }; -#define LP_MAXPRICEINFOS 64 +#define LP_MAXPRICEINFOS 256 struct LP_priceinfo { char symbol[16]; From c249ab7fca4f0f6d22bd183572a884e82ac0dfa4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 12:20:26 +0300 Subject: [PATCH 1904/2705] Fix coqui port --- iguana/coins/basilisk/coqui | 2 +- iguana/coins/coqui_7776 | 2 +- iguana/exchanges/LP_nativeDEX.c | 1 + iguana/exchanges/LP_scan.c | 227 ++++++++++++++++++++++++++++++ iguana/exchanges/LP_transaction.c | 206 --------------------------- iguana/exchanges/LP_utxos.c | 2 - iguana/exchanges/client | 2 +- iguana/exchanges/run | 2 +- 8 files changed, 232 insertions(+), 212 deletions(-) create mode 100644 iguana/exchanges/LP_scan.c diff --git a/iguana/coins/basilisk/coqui b/iguana/coins/basilisk/coqui index cc86f422a..55730d486 100755 --- a/iguana/coins/basilisk/coqui +++ b/iguana/coins/basilisk/coqui @@ -1,2 +1,2 @@ -curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"COQUI.conf\",\"path\":\"${HOME#"/"}/.komodo/COQUI\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"COQUI\",\"name\":\"COQUI\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"dd5ce076\",\"p2p\":12455,\"rpc\":12456,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7778" --data "{\"conf\":\"COQUI.conf\",\"path\":\"${HOME#"/"}/.komodo/COQUI\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":0,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"COQUI\",\"name\":\"COQUI\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"dd5ce076\",\"p2p\":14275,\"rpc\":14276,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/coins/coqui_7776 b/iguana/coins/coqui_7776 index 7233677cf..6079fd06e 100755 --- a/iguana/coins/coqui_7776 +++ b/iguana/coins/coqui_7776 @@ -1 +1 @@ -curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"COQUI.conf\",\"path\":\"${HOME#"/"}/.komodo/COQUI\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"COQUI\",\"name\":\"COQUI\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fa05f107\",\"p2p\":12455,\"rpc\":12456,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" +curl --url "http://127.0.0.1:7776" --data "{\"conf\":\"COQUI.conf\",\"path\":\"${HOME#"/"}/.komodo/COQUI\",\"unitval\":\"20\",\"zcash\":1,\"RELAY\":-1,\"VALIDATE\":0,\"prefetchlag\":-1,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":8,\"newcoin\":\"COQUI\",\"name\":\"COQUI\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fa05f107\",\"p2p\":14275,\"rpc\":14276,\"pubval\":60,\"p2shval\":85,\"wifval\":188,\"txfee_satoshis\":\"10000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"027e3758c3a65b12aa1046462b486d0a63bfa1beae327897f56c5cfb7daaae71\",\"protover\":170002,\"genesisblock\":\"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000000000000000000000000000000000000000000000000000000000000029ab5f490f0f0f200b00000000000000000000000000000000000000000000000000000000000000fd4005000d5ba7cda5d473947263bf194285317179d2b0d307119c2e7cc4bd8ac456f0774bd52b0cd9249be9d40718b6397a4c7bbd8f2b3272fed2823cd2af4bd1632200ba4bf796727d6347b225f670f292343274cc35099466f5fb5f0cd1c105121b28213d15db2ed7bdba490b4cedc69742a57b7c25af24485e523aadbb77a0144fc76f79ef73bd8530d42b9f3b9bed1c135ad1fe152923fafe98f95f76f1615e64c4abb1137f4c31b218ba2782bc15534788dda2cc08a0ee2987c8b27ff41bd4e31cd5fb5643dfe862c9a02ca9f90c8c51a6671d681d04ad47e4b53b1518d4befafefe8cadfb912f3d03051b1efbf1dfe37b56e93a741d8dfd80d576ca250bee55fab1311fc7b3255977558cdda6f7d6f875306e43a14413facdaed2f46093e0ef1e8f8a963e1632dcbeebd8e49fd16b57d49b08f9762de89157c65233f60c8e38a1f503a48c555f8ec45dedecd574a37601323c27be597b956343107f8bd80f3a925afaf30811df83c402116bb9c1e5231c70fff899a7c82f73c902ba54da53cc459b7bf1113db65cc8f6914d3618560ea69abd13658fa7b6af92d374d6eca9529f8bd565166e4fcbf2a8dfb3c9b69539d4d2ee2e9321b85b331925df195915f2757637c2805e1d4131e1ad9ef9bc1bb1c732d8dba4738716d351ab30c996c8657bab39567ee3b29c6d054b711495c0d52e1cd5d8e55b4f0f0325b97369280755b46a02afd54be4ddd9f77c22272b8bbb17ff5118fedbae2564524e797bd28b5f74f7079d532ccc059807989f94d267f47e724b3f1ecfe00ec9e6541c961080d8891251b84b4480bc292f6a180bea089fef5bbda56e1e41390d7c0e85ba0ef530f7177413481a226465a36ef6afe1e2bca69d2078712b3912bba1a99b1fbff0d355d6ffe726d2bb6fbc103c4ac5756e5bee6e47e17424ebcbf1b63d8cb90ce2e40198b4f4198689daea254307e52a25562f4c1455340f0ffeb10f9d8e914775e37d0edca019fb1b9c6ef81255ed86bc51c5391e0591480f66e2d88c5f4fd7277697968656a9b113ab97f874fdd5f2465e5559533e01ba13ef4a8f7a21d02c30c8ded68e8c54603ab9c8084ef6d9eb4e92c75b078539e2ae786ebab6dab73a09e0aa9ac575bcefb29e930ae656e58bcb513f7e3c17e079dce4f05b5dbc18c2a872b22509740ebe6a3903e00ad1abc55076441862643f93606e3dc35e8d9f2caef3ee6be14d513b2e062b21d0061de3bd56881713a1a5c17f5ace05e1ec09da53f99442df175a49bd154aa96e4949decd52fed79ccf7ccbce32941419c314e374e4a396ac553e17b5340336a1a25c22f9e42a243ba5404450b650acfc826a6e432971ace776e15719515e1634ceb9a4a35061b668c74998d3dfb5827f6238ec015377e6f9c94f38108768cf6e5c8b132e0303fb5a200368f845ad9d46343035a6ff94031df8d8309415bb3f6cd5ede9c135fdabcc030599858d803c0f85be7661c88984d88faa3d26fb0e9aac0056a53f1b5d0baed713c853c4a2726869a0a124a8a5bbc0fc0ef80c8ae4cb53636aa02503b86a1eb9836fcc259823e2692d921d88e1ffc1e6cb2bde43939ceb3f32a611686f539f8f7c9f0bf00381f743607d40960f06d347d1cd8ac8a51969c25e37150efdf7aa4c2037a2fd0516fb444525ab157a0ed0a7412b2fa69b217fe397263153782c0f64351fbdf2678fa0dc8569912dcd8e3ccad38f34f23bbbce14c6a26ac24911b308b82c7e43062d180baeac4ba7153858365c72c63dcf5f6a5b08070b730adb017aeae925b7d0439979e2679f45ed2f25a7edcfd2fb77a8794630285ccb0a071f5cce410b46dbf9750b0354aae8b65574501cc69efb5b6a43444074fee116641bb29da56c2b4a7f456991fc92b2\",\"debug\":0,\"seedipaddr\":\"78.47.196.146\"}" diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 78903fd2a..60263420d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -69,6 +69,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_ #include "LP_coins.c" #include "LP_rpc.c" #include "LP_prices.c" +#include "LP_scan.c" #include "LP_transaction.c" #include "LP_remember.c" #include "LP_swap.c" diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c new file mode 100644 index 000000000..333062475 --- /dev/null +++ b/iguana/exchanges/LP_scan.c @@ -0,0 +1,227 @@ + +/****************************************************************************** + * Copyright © 2014-2017 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ +// +// LP_scan.c +// marketmaker +// + +uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) +{ + uint64_t value = 0; double interest; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; + if ( (txobj= LP_gettx(symbol,txid)) != 0 ) + { + //char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); + if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 && vout < numvouts ) + { + utxoobj = jitem(vouts,vout); + if ( (value= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) + { + char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d/%d\n",symbol,bits256_str(str,txid),jprint(utxoobj,0),vout,numvouts); + } + else if ( strcmp(symbol,"KMD") == 0 ) + { + if ( (utxoobj= LP_gettxout(symbol,txid,vout)) != 0 ) + { + if ( (interest= jdouble(utxoobj,"interest")) != 0. ) + { + //printf("add interest of %.8f to %.8f\n",interest,dstr(value)); + value += SATOSHIDEN * interest; + } + free_json(utxoobj); + } + } + } + free_json(txobj); + } + return(value); +} + +uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) +{ + uint64_t value = 0; double interest; cJSON *txobj,*sobj,*array; int32_t n; + coinaddr[0] = 0; + if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) + { + if ( (value= jdouble(txobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(txobj,"value")*SATOSHIDEN) == 0 ) + { + char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d\n",symbol,bits256_str(str,txid),jprint(txobj,0),vout); + } + else if ( strcmp(symbol,"KMD") == 0 ) + { + if ( (interest= jdouble(txobj,"interest")) != 0. ) + { + //printf("add interest of %.8f to %.8f\n",interest,dstr(value)); + value += SATOSHIDEN * interest; + } + } + if ( (sobj= jobj(txobj,"scriptPubKey")) != 0 && (array= jarray(&n,sobj,"addresses")) != 0 ) + strcpy(coinaddr,jstri(array,0)); + //char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); + free_json(txobj); + } + return(value); +} + +int32_t LP_vinscan(bits256 *spendtxidp,int32_t *spendvinip,char *symbol,bits256 txid,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) +{ + cJSON *txobj,*vins,*vin; bits256 spenttxid; int32_t j,numvins,spentvout,retval = -1; + if ( (txobj= LP_gettx(symbol,txid)) != 0 ) + { + if ( bits256_cmp(txid,jbits256(txobj,"txid")) != 0 ) + { + char str[65]; printf("txid mismatch error %s vs %s\n",bits256_str(str,txid),jprint(txobj,0)); + free_json(txobj); + return(-2); + } + vins = jarray(&numvins,txobj,"vin"); + for (j=0; j 0 ) + return(0); + if ( (txobj= LP_gettx(symbol,searchtxid)) == 0 ) + return(0); + hash = jbits256(txobj,"blockhash"); + free_json(txobj); + if ( bits256_nonz(hash) == 0 ) + return(0); + if ( (blockjson= LP_getblock(symbol,hash)) == 0 ) + return(0); + loadheight = jint(blockjson,"height"); + free_json(blockjson); + if ( loadheight <= 0 ) + return(0); + while ( errs == 0 && *indp < 0 ) + { + //printf("search %s ht.%d\n",symbol,loadheight); + if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 && h == loadheight ) + { + if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) + { + for (i=0; i= 0 ) + break; + } + } + free_json(blockjson); + } else errs++; + loadheight++; + } + char str[65]; printf("reached %s ht.%d %s/v%d\n",symbol,loadheight,bits256_str(str,*spendtxidp),*indp); + if ( bits256_nonz(*spendtxidp) != 0 && *indp >= 0 ) + return(loadheight); + else return(0); +} + +int32_t LP_mempoolscan(char *symbol,bits256 txid) +{ + int32_t i,n; cJSON *array; + if ( (array= LP_getmempool(symbol)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; icoin->symbol,rawtx->I.signedtxid)) != 0 ) + { + numconfirms = jint(txobj,"confirmations"); + free_json(txobj); + } + else if ( LP_mempoolscan(rawtx->coin->symbol,rawtx->I.signedtxid) >= 0 ) + numconfirms = 0; +//#endif + return(numconfirms); +} + +int32_t LP_waitmempool(char *symbol,bits256 txid,int32_t duration) +{ + uint32_t expiration = (uint32_t)time(NULL) + duration; + while ( time(NULL) < expiration ) + { + if ( LP_mempoolscan(symbol,txid) >= 0 ) + return(0); + usleep(250000); + } + return(-1); +} + +int32_t LP_mempool_vinscan(bits256 *spendtxidp,int32_t *spendvinp,char *symbol,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) +{ + int32_t i,n; cJSON *array; bits256 mempooltxid; + if ( symbol == 0 || symbol[0] == 0 || bits256_nonz(searchtxid) == 0 || bits256_nonz(searchtxid2) == 0 ) + return(-1); + if ( (array= LP_getmempool(symbol)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i= 0 ) + return(i); + } + free_json(array); + } + } + return(-1); +} + + diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index 2e3d57a89..d67031477 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -72,212 +72,6 @@ bits256 LP_broadcast_tx(char *name,char *symbol,uint8_t *data,int32_t datalen) return(txid); } -uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) -{ - uint64_t value = 0; double interest; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; - if ( (txobj= LP_gettx(symbol,txid)) != 0 ) - { - //char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); - if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 && vout < numvouts ) - { - utxoobj = jitem(vouts,vout); - if ( (value= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) - { - char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d/%d\n",symbol,bits256_str(str,txid),jprint(utxoobj,0),vout,numvouts); - } - else if ( strcmp(symbol,"KMD") == 0 ) - { - if ( (utxoobj= LP_gettxout(symbol,txid,vout)) != 0 ) - { - if ( (interest= jdouble(utxoobj,"interest")) != 0. ) - { - //printf("add interest of %.8f to %.8f\n",interest,dstr(value)); - value += SATOSHIDEN * interest; - } - free_json(utxoobj); - } - } - } - free_json(txobj); - } - return(value); -} - -uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) -{ - uint64_t value = 0; double interest; cJSON *txobj,*sobj,*array; int32_t n; - coinaddr[0] = 0; - if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) - { - if ( (value= jdouble(txobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(txobj,"value")*SATOSHIDEN) == 0 ) - { - char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d\n",symbol,bits256_str(str,txid),jprint(txobj,0),vout); - } - else if ( strcmp(symbol,"KMD") == 0 ) - { - if ( (interest= jdouble(txobj,"interest")) != 0. ) - { - //printf("add interest of %.8f to %.8f\n",interest,dstr(value)); - value += SATOSHIDEN * interest; - } - } - if ( (sobj= jobj(txobj,"scriptPubKey")) != 0 && (array= jarray(&n,sobj,"addresses")) != 0 ) - strcpy(coinaddr,jstri(array,0)); - //char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); - free_json(txobj); - } - return(value); -} - -int32_t LP_vinscan(bits256 *spendtxidp,int32_t *spendvinip,char *symbol,bits256 txid,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) -{ - cJSON *txobj,*vins,*vin; bits256 spenttxid; int32_t j,numvins,spentvout,retval = -1; - if ( (txobj= LP_gettx(symbol,txid)) != 0 ) - { - if ( bits256_cmp(txid,jbits256(txobj,"txid")) != 0 ) - { - char str[65]; printf("txid mismatch error %s vs %s\n",bits256_str(str,txid),jprint(txobj,0)); - free_json(txobj); - return(-2); - } - vins = jarray(&numvins,txobj,"vin"); - for (j=0; j 0 ) - return(0); - if ( (txobj= LP_gettx(symbol,searchtxid)) == 0 ) - return(0); - hash = jbits256(txobj,"blockhash"); - free_json(txobj); - if ( bits256_nonz(hash) == 0 ) - return(0); - if ( (blockjson= LP_getblock(symbol,hash)) == 0 ) - return(0); - loadheight = jint(blockjson,"height"); - free_json(blockjson); - if ( loadheight <= 0 ) - return(0); - while ( errs == 0 && *indp < 0 ) - { - //printf("search %s ht.%d\n",symbol,loadheight); - if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 && h == loadheight ) - { - if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) - { - for (i=0; i= 0 ) - break; - } - } - free_json(blockjson); - } else errs++; - loadheight++; - } - char str[65]; printf("reached %s ht.%d %s/v%d\n",symbol,loadheight,bits256_str(str,*spendtxidp),*indp); - if ( bits256_nonz(*spendtxidp) != 0 && *indp >= 0 ) - return(loadheight); - else return(0); -} - -int32_t LP_mempoolscan(char *symbol,bits256 txid) -{ - int32_t i,n; cJSON *array; - if ( (array= LP_getmempool(symbol)) != 0 ) - { - if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) - { - for (i=0; i 0 ) - { - for (i=0; i= 0 ) - return(i); - } - free_json(array); - } - } - return(-1); -} - -int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) -{ - int32_t numconfirms = 100; -//#ifndef BASILISK_DISABLEWAITTX - cJSON *txobj; - numconfirms = -1; - if ( (txobj= LP_gettx(rawtx->coin->symbol,rawtx->I.signedtxid)) != 0 ) - { - numconfirms = jint(txobj,"confirmations"); - free_json(txobj); - } - else if ( LP_mempoolscan(rawtx->coin->symbol,rawtx->I.signedtxid) >= 0 ) - numconfirms = 0; -//#endif - return(numconfirms); -} - -int32_t LP_waitmempool(char *symbol,bits256 txid,int32_t duration) -{ - uint32_t expiration = (uint32_t)time(NULL) + duration; - while ( time(NULL) < expiration ) - { - if ( LP_mempoolscan(symbol,txid) >= 0 ) - return(0); - usleep(250000); - } - return(-1); -} - int32_t iguana_msgtx_Vset(uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,struct vin_info *V) { int32_t vini,j,scriptlen,p2shlen,userdatalen,siglen,plen,need_op0=0,len = 0; uint8_t *script,*redeemscript=0,*userdata=0; struct vin_info *vp; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 7cb030d60..1e3ee862e 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -758,8 +758,6 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan LP_privkeyadd(privkey,rmd160); if ( coin->pubtype != 60 || strcmp(coin->symbol,"KMD") == 0 ) printf("%s (%s) %d wif.(%s) (%s)\n",coin->symbol,coin->smartaddr,coin->pubtype,tmpstr,passphrase); - if ( coin->inactive == 0 ) - printf("importprivkey: %s\n",jprint(LP_importprivkey(coin->symbol,tmpstr,"",-1),1)); if ( counter++ == 0 ) { bitcoin_priv2wif(USERPASS_WIFSTR,privkey,188); diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 6582e2c82..9809d229a 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -19,6 +19,6 @@ git pull; {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":12456},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} ], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & diff --git a/iguana/exchanges/run b/iguana/exchanges/run index a81c74556..870ccf3d0 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -15,5 +15,5 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"gui\":\"nog {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":12456},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} +{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} ]}" & From fd75b32410e255d7bbea55acb024d8f444c60260 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 12:55:45 +0300 Subject: [PATCH 1905/2705] Test --- iguana/exchanges/LP_coins.c | 10 ++++++++-- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 73a77a3df..c11b5aac3 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -270,7 +270,7 @@ struct iguana_info *LP_coinfind(char *symbol) struct iguana_info *LP_coincreate(cJSON *item) { - struct iguana_info cdata,*coin=0; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*symbol,*assetname; + struct iguana_info cdata,*coin=0; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name=0,*symbol,*assetname=0; if ( (symbol= jstr(item,"coin")) != 0 && symbol[0] != 0 && strlen(symbol) < 16 && LP_coinfind(symbol) == 0 && (port= juint(item,"rpcport")) != 0 ) { isPoS = jint(item,"isPoS"); @@ -292,7 +292,13 @@ struct iguana_info *LP_coincreate(cJSON *item) coin = LP_coinadd(&cdata); } if ( coin != 0 && item != 0 ) - coin->inactive = (strcmp("KMD",coin->symbol) == 0) ? 0 : !jint(item,"active"); + { + if ( strcmp("KMD",coin->symbol) != 0 ) + { + if ( IAMLP == 0 || assetname != name ) + coin->inactive = !jint(item,"active"); + } + } return(0); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 1e3ee862e..ad6cfc8b6 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -765,7 +765,7 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan userpub = curve25519(userpass,curve25519_basepoint9()); printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); } - if ( coin->inactive == 0 && (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) + if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) //coin->inactive == 0 && printf("importprivkey -> (%s)\n",jprint(retjson,1)); } LP_mypubkey = *pubkeyp = curve25519(privkey,curve25519_basepoint9()); From 5f35206102981dc8cdfa962bdce85a8df6a198a7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:00:43 +0300 Subject: [PATCH 1906/2705] Test --- iguana/exchanges/LP_coins.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index c11b5aac3..e1af730f0 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -297,6 +297,8 @@ struct iguana_info *LP_coincreate(cJSON *item) { if ( IAMLP == 0 || assetname != name ) coin->inactive = !jint(item,"active"); + if ( IAMLP != 0 && coin->inactive != 0 ) + printf("LPnode %s disabled\n",coin->symbol); } } return(0); From b268e93cc3de7e2b48f3490450f92206c21f4d0c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:01:56 +0300 Subject: [PATCH 1907/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index e1af730f0..70dbfff3b 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -298,7 +298,7 @@ struct iguana_info *LP_coincreate(cJSON *item) if ( IAMLP == 0 || assetname != name ) coin->inactive = !jint(item,"active"); if ( IAMLP != 0 && coin->inactive != 0 ) - printf("LPnode %s disabled\n",coin->symbol); + printf("LPnode %s disabled %p vs %p\n",coin->symbol,assetname,name); } } return(0); From 47a4430ae788b49ea6947622e2eaf6344f7af634 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:04:24 +0300 Subject: [PATCH 1908/2705] Test --- iguana/exchanges/LP_coins.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 70dbfff3b..d91394081 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -297,6 +297,7 @@ struct iguana_info *LP_coincreate(cJSON *item) { if ( IAMLP == 0 || assetname != name ) coin->inactive = !jint(item,"active"); + else coin->inactive = 0; if ( IAMLP != 0 && coin->inactive != 0 ) printf("LPnode %s disabled %p vs %p\n",coin->symbol,assetname,name); } From a43eb07d14c1e76fd4f4f6ccef99777ea17a20af Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:06:35 +0300 Subject: [PATCH 1909/2705] Test --- iguana/exchanges/LP_coins.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index d91394081..2230d33be 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -295,12 +295,12 @@ struct iguana_info *LP_coincreate(cJSON *item) { if ( strcmp("KMD",coin->symbol) != 0 ) { - if ( IAMLP == 0 || assetname != name ) + if ( IAMLP == 0 || assetname != name || (strcmp("ZEC",coin->symbol) != 0 && strcmp("HUSH",coin->symbol) != 0) ) coin->inactive = !jint(item,"active"); else coin->inactive = 0; if ( IAMLP != 0 && coin->inactive != 0 ) printf("LPnode %s disabled %p vs %p\n",coin->symbol,assetname,name); - } + } else coin->inactive = 0; } return(0); } From 2878afe265147f205851a6c50ac0a1dd66dd5fc0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:13:54 +0300 Subject: [PATCH 1910/2705] Test --- iguana/dexscripts/.marker | 0 iguana/exchanges/candidates | 2 -- iguana/exchanges/client | 22 +++------------------- iguana/exchanges/coins | 1 + iguana/exchanges/install | 1 + iguana/exchanges/run | 23 +++++------------------ 6 files changed, 10 insertions(+), 39 deletions(-) create mode 100644 iguana/dexscripts/.marker delete mode 100755 iguana/exchanges/candidates create mode 100644 iguana/exchanges/coins create mode 100755 iguana/exchanges/install diff --git a/iguana/dexscripts/.marker b/iguana/dexscripts/.marker new file mode 100644 index 000000000..e69de29bb diff --git a/iguana/exchanges/candidates b/iguana/exchanges/candidates deleted file mode 100755 index ec3e2c1a1..000000000 --- a/iguana/exchanges/candidates +++ /dev/null @@ -1,2 +0,0 @@ -source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"candidates\",\"txid\":\"$1\",\"vout\":$2,\"coin\":\"REVS\"}" diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 9809d229a..ae0e1f486 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -1,24 +1,8 @@ source randval +source coins pkill -15 marketmaker; git pull; - cd ..; +cd ..; ./m_mm; -./marketmaker "{\"gui\":\"nogui\",\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, -{\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, -{\"active\":0,\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, -{\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, -{\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, -{\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, -{\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, -{\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, -{\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, -{\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, -{\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, -{\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, -{\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, -{\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, -{\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, -{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} -], \"userhome\":\"/${HOME#"/"}\",\"passphrase\":\"$randval\"}" & +./marketmaker "{\"gui\":\"nogui\",\"client\":1,\"coins\":$coins}" diff --git a/iguana/exchanges/coins b/iguana/exchanges/coins new file mode 100644 index 000000000..de59ee96b --- /dev/null +++ b/iguana/exchanges/coins @@ -0,0 +1 @@ +export coins="[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196}, {\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, {\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, {\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, {\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, {\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, {\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, {\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341}, {\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167}, {\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068}, {\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890}, {\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250}, {\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516}, {\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431}, {\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114}, {\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964}, {\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386}, {\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276}, {\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747}, {\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116}, {\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455}]" diff --git a/iguana/exchanges/install b/iguana/exchanges/install new file mode 100755 index 000000000..c41f33434 --- /dev/null +++ b/iguana/exchanges/install @@ -0,0 +1 @@ +cp autotrade client run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub randval run_osx setprice status userpass utxos ../dexscripts diff --git a/iguana/exchanges/run b/iguana/exchanges/run index 870ccf3d0..2dd0b02c7 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -1,19 +1,6 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; $1 ./marketmaker "{\"gui\":\"nogui\",\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, -{\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, -{\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, -{\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, -{\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, -{\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, -{\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, -{\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, -{\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, -{\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, -{\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, -{\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, -{\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, -{\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, -{\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, -{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} -]}" & +source coins +pkill -15 marketmaker; +git pull; +cd ..; +./m_mm; $1 ./marketmaker "{\"gui\":\"nogui\",\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":$coins}" From 660d65d0867383315c3e1db846383f5306180b4f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:22:34 +0300 Subject: [PATCH 1911/2705] Test --- iguana/exchanges/LP_coins.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 2230d33be..43da95086 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -182,7 +182,7 @@ cJSON *LP_coinsjson() return(array); } -void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain,uint8_t taddr) +int32_t LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain,uint8_t taddr) { char *name2; memset(coin,0,sizeof(*coin)); @@ -200,7 +200,7 @@ void LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetnam if ( strcmp(symbol,"KMD") == 0 || (assetname != 0 && assetname[0] != 0) ) name2 = 0; else name2 = name; - LP_userpass(coin->userpass,symbol,assetname,name,name2); + return(LP_userpass(coin->userpass,symbol,assetname,name,name2)); } struct iguana_info *LP_coinadd(struct iguana_info *cdata) @@ -259,9 +259,11 @@ struct iguana_info *LP_coinfind(char *symbol) else if ( strcmp(symbol,"KMD") == 0 ) name = "komodo"; else return(0); - LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,0); - if ( (coin= LP_coinadd(&cdata)) != 0 && strcmp(symbol,"KMD") == 0 ) - coin->inactive = 0; + if ( LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,0) > 0 ) + { + if ( (coin= LP_coinadd(&cdata)) != 0 && strcmp(symbol,"KMD") == 0 ) + coin->inactive = 0; + } return(coin); } @@ -288,8 +290,8 @@ struct iguana_info *LP_coincreate(cJSON *item) name = assetname; else if ( (name= jstr(item,"name")) == 0 ) name = symbol; - LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,jint(item,"taddr")); - coin = LP_coinadd(&cdata); + if ( LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,jint(item,"taddr")) > 0 ) + coin = LP_coinadd(&cdata); } if ( coin != 0 && item != 0 ) { From 7fe7929cf432b296da86fe2bcc2ad8e4b8143faf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:24:16 +0300 Subject: [PATCH 1912/2705] Test --- iguana/exchanges/LP_bitcoin.c | 2 +- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c index 168b728ec..3aba41ed2 100644 --- a/iguana/exchanges/LP_bitcoin.c +++ b/iguana/exchanges/LP_bitcoin.c @@ -2025,7 +2025,7 @@ int32_t bitcoin_p2shscript(uint8_t *script,int32_t n,const uint8_t *p2shscript,c char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params) { - return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params,0)); + return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params,2)); } int32_t bitcoin_addr2rmd160(uint8_t taddr,uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index adcbdd420..6e38f087d 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -185,7 +185,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) char *retstr; cJSON *retjson = 0; if ( coin != 0 ) { - //printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); + printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) { From 8a49110bb63d6881ed044d7bbb4ccf8bfad81baa Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:27:22 +0300 Subject: [PATCH 1913/2705] Test --- iguana/exchanges/LP_coins.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 43da95086..28f9e59b2 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -297,11 +297,16 @@ struct iguana_info *LP_coincreate(cJSON *item) { if ( strcmp("KMD",coin->symbol) != 0 ) { - if ( IAMLP == 0 || assetname != name || (strcmp("ZEC",coin->symbol) != 0 && strcmp("HUSH",coin->symbol) != 0) ) + if ( jobj(item,"active") != 0 ) coin->inactive = !jint(item,"active"); - else coin->inactive = 0; - if ( IAMLP != 0 && coin->inactive != 0 ) - printf("LPnode %s disabled %p vs %p\n",coin->symbol,assetname,name); + else + { + if ( IAMLP == 0 || assetname != name || (strcmp("ZEC",coin->symbol) != 0 && strcmp("HUSH",coin->symbol) != 0) ) + coin->inactive = (uint32_t)time(NULL); + else coin->inactive = 0; + } + if ( coin->inactive != 0 ) + printf("LPnode.%d %s disabled %p vs %p\n",IAMLP,coin->symbol,assetname,name); } else coin->inactive = 0; } return(0); From 215eb585cccfd1a399d510aa1474a9f0c9d0e600 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:32:32 +0300 Subject: [PATCH 1914/2705] Test --- iguana/exchanges/LP_coins.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 28f9e59b2..9f5ed375e 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -263,7 +263,7 @@ struct iguana_info *LP_coinfind(char *symbol) { if ( (coin= LP_coinadd(&cdata)) != 0 && strcmp(symbol,"KMD") == 0 ) coin->inactive = 0; - } + } else coin->inactive = (uint32_t)time(NULL); return(coin); } @@ -290,8 +290,11 @@ struct iguana_info *LP_coincreate(cJSON *item) name = assetname; else if ( (name= jstr(item,"name")) == 0 ) name = symbol; - if ( LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,jint(item,"taddr")) > 0 ) + if ( LP_coininit(&cdata,symbol,name,assetname==0?"":assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,jint(item,"taddr")) < 0 ) + { coin = LP_coinadd(&cdata); + coin->inactive = (uint32_t)time(NULL); + } else coin = LP_coinadd(&cdata); } if ( coin != 0 && item != 0 ) { @@ -305,10 +308,10 @@ struct iguana_info *LP_coincreate(cJSON *item) coin->inactive = (uint32_t)time(NULL); else coin->inactive = 0; } - if ( coin->inactive != 0 ) - printf("LPnode.%d %s disabled %p vs %p\n",IAMLP,coin->symbol,assetname,name); } else coin->inactive = 0; } + if ( coin != 0 && coin->inactive != 0 ) + printf("LPnode.%d %s disabled %p vs %p\n",IAMLP,coin->symbol,assetname,name); return(0); } From 352cd7e0d63343914b38ccc3f51b4d226b7c7ea0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:37:44 +0300 Subject: [PATCH 1915/2705] Test --- iguana/exchanges/LP_rpc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 6e38f087d..45b60af67 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -185,16 +185,19 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) char *retstr; cJSON *retjson = 0; if ( coin != 0 ) { - printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); - retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); - if ( retstr != 0 && retstr[0] != 0 ) + //printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); + if ( coin->inactive == 0 ) { - //printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); - retjson = cJSON_Parse(retstr); - free(retstr); - } - //usleep(1000); - //printf("dpow_gettxout.(%s)\n",retstr); + retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); + if ( retstr != 0 && retstr[0] != 0 ) + { + //printf("%s: %s.%s -> (%s)\n",coin->symbol,method,params,retstr); + retjson = cJSON_Parse(retstr); + free(retstr); + } + //usleep(1000); + //printf("dpow_gettxout.(%s)\n",retstr); + } else retjson = cJSON_Parse("{\"error\":\"disabled\"}"); } else printf("bitcoin_json cant talk to NULL coin\n"); return(retjson); } From abb2be567ab816a0aae94371613907e06000aa6b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:38:06 +0300 Subject: [PATCH 1916/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 45b60af67..83dfb5092 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -186,7 +186,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) if ( coin != 0 ) { //printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); - if ( coin->inactive == 0 ) + if ( coin->inactive == 0 && strcmp(method,"importprivkey") != 0 ) { retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) From 443f07f60a1e9acf4336d79afe39fcbf13ec963c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:50:31 +0300 Subject: [PATCH 1917/2705] Test --- iguana/exchanges/LP_coins.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 9f5ed375e..f727c99f3 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -261,8 +261,13 @@ struct iguana_info *LP_coinfind(char *symbol) else return(0); if ( LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,0) > 0 ) { - if ( (coin= LP_coinadd(&cdata)) != 0 && strcmp(symbol,"KMD") == 0 ) - coin->inactive = 0; + if ( (coin= LP_coinadd(&cdata)) != 0 ) + { + if ( strcmp(symbol,"KMD") == 0 ) + coin->inactive = 0; + else if ( strcmp(symbol,"BTC") == 0 ) + coin->inactive = !IAMLP * (uint32_t)time(NULL); + } } else coin->inactive = (uint32_t)time(NULL); return(coin); } From a2ccc39c72f0bd20b9ac36de44b854d65de1220e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:52:48 +0300 Subject: [PATCH 1918/2705] Test --- iguana/exchanges/LP_utxos.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index ad6cfc8b6..d43ebad5b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -410,12 +410,14 @@ char *LP_spentcheck(cJSON *argjson) struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *spendscript,char *coinaddr,bits256 pubkey,double profitmargin,char *gui) { - uint64_t val,val2=0,tmpsatoshis,bigtxfee = 100000; int32_t spendvini,selector; bits256 spendtxid; char *msg; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; + uint64_t val,val2=0,tmpsatoshis,bigtxfee = 100000; int32_t spendvini,selector; bits256 spendtxid; char *msg; struct iguana_info *coin; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; if ( symbol == 0 || symbol[0] == 0 || spendscript == 0 || spendscript[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 ) { printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } + if ( (coin= LP_coinfind(symbol)) == 0 && coin->inactive != 0 ) + return(0); if ( iambob != 0 && value2 < 9 * (value >> 3) + bigtxfee ) // big txfee padding { if ( value2 > bigtxfee+20000 ) From f724120e479f5d26f2a0866a52a96e2d14eb0eec Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:57:06 +0300 Subject: [PATCH 1919/2705] Test --- iguana/exchanges/LP_rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 83dfb5092..aae5e7b93 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -186,7 +186,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) if ( coin != 0 ) { //printf("issue.(%s, %s, %s, %s, %s)\n",coin->symbol,coin->serverport,coin->userpass,method,params); - if ( coin->inactive == 0 && strcmp(method,"importprivkey") != 0 ) + if ( coin->inactive == 0 || strcmp(method,"importprivkey") == 0 ) { retstr = bitcoind_passthru(coin->symbol,coin->serverport,coin->userpass,method,params); if ( retstr != 0 && retstr[0] != 0 ) From f889ed9620a86ac49a8bbe04542b622b1a0ce7c7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 13:59:00 +0300 Subject: [PATCH 1920/2705] Test --- iguana/exchanges/LP_coins.c | 5 ++++- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index f727c99f3..3b0beab8b 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -266,9 +266,12 @@ struct iguana_info *LP_coinfind(char *symbol) if ( strcmp(symbol,"KMD") == 0 ) coin->inactive = 0; else if ( strcmp(symbol,"BTC") == 0 ) + { coin->inactive = !IAMLP * (uint32_t)time(NULL); + printf("BTC inactive.%u\n",coin->inactive); + } } - } else coin->inactive = (uint32_t)time(NULL); + } return(coin); } diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index d43ebad5b..c01f950b2 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -768,7 +768,7 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan printf("userpass.(%s)\n",bits256_str(USERPASS,userpub)); } if ( (retjson= LP_importprivkey(coin->symbol,tmpstr,coin->smartaddr,-1)) != 0 ) //coin->inactive == 0 && - printf("importprivkey -> (%s)\n",jprint(retjson,1)); + printf("importprivkey.%s -> (%s)\n",coin->symbol,jprint(retjson,1)); } LP_mypubkey = *pubkeyp = curve25519(privkey,curve25519_basepoint9()); //printf("privkey.(%s) -> LP_mypubkey.(%s)\n",bits256_str(str,privkey),bits256_str(str2,LP_mypubkey)); From c3436f63b6c7991ea82372918f2b1c578af8f354 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:15:22 +0300 Subject: [PATCH 1921/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- iguana/exchanges/LP_scan.c | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 3b0beab8b..a17e9379c 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -319,7 +319,7 @@ struct iguana_info *LP_coincreate(cJSON *item) } else coin->inactive = 0; } if ( coin != 0 && coin->inactive != 0 ) - printf("LPnode.%d %s disabled %p vs %p\n",IAMLP,coin->symbol,assetname,name); + printf("LPnode.%d %s inactive.%u %p vs %p\n",IAMLP,coin->symbol,coin->inactive,assetname,name); return(0); } diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 333062475..a9198398f 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -18,7 +18,7 @@ // marketmaker // -uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) +/*uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) { uint64_t value = 0; double interest; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; if ( (txobj= LP_gettx(symbol,txid)) != 0 ) @@ -47,11 +47,13 @@ uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) free_json(txobj); } return(value); -} +}*/ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) { - uint64_t value = 0; double interest; cJSON *txobj,*sobj,*array; int32_t n; + uint64_t value = 0; double interest; cJSON *txobj,*sobj,*array; int32_t n; struct iguana_info *coin; + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) + return(0); coinaddr[0] = 0; if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) { @@ -77,7 +79,11 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) int32_t LP_vinscan(bits256 *spendtxidp,int32_t *spendvinip,char *symbol,bits256 txid,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) { - cJSON *txobj,*vins,*vin; bits256 spenttxid; int32_t j,numvins,spentvout,retval = -1; + cJSON *txobj,*vins,*vin; bits256 spenttxid; struct iguana_info *coin; int32_t j,numvins,spentvout,retval = -1; + memset(spendtxidp,0,sizeof(*spendtxidp)); + *spendvinip = -1; + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) + return(retval); if ( (txobj= LP_gettx(symbol,txid)) != 0 ) { if ( bits256_cmp(txid,jbits256(txobj,"txid")) != 0 ) @@ -114,8 +120,10 @@ int32_t LP_vinscan(bits256 *spendtxidp,int32_t *spendvinip,char *symbol,bits256 int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 searchtxid,int32_t searchvout) { - char destaddr[64]; cJSON *blockjson,*txids,*txobj; bits256 hash,txid; int32_t h,i,j,numtxids,loadheight,errs = 0; + char destaddr[64]; struct iguana_info *coin; cJSON *blockjson,*txids,*txobj; bits256 hash,txid; int32_t h,i,j,numtxids,loadheight,errs = 0; *indp = -1; + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) + return(0); memset(spendtxidp,0,sizeof(*spendtxidp)); if ( LP_txvalue(destaddr,symbol,searchtxid,searchvout) > 0 ) return(0); @@ -157,7 +165,9 @@ int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 se int32_t LP_mempoolscan(char *symbol,bits256 txid) { - int32_t i,n; cJSON *array; + int32_t i,n; cJSON *array; struct iguana_info *coin; + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) + return(-1); if ( (array= LP_getmempool(symbol)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) @@ -176,9 +186,11 @@ int32_t LP_mempoolscan(char *symbol,bits256 txid) int32_t LP_numconfirms(struct basilisk_swap *swap,struct basilisk_rawtx *rawtx) { - int32_t numconfirms = 100; + struct iguana_info *coin; int32_t numconfirms = 100; //#ifndef BASILISK_DISABLEWAITTX cJSON *txobj; + if ( (coin= LP_coinfind(rawtx->coin->symbol)) == 0 || coin->inactive != 0 ) + return(-1); numconfirms = -1; if ( (txobj= LP_gettx(rawtx->coin->symbol,rawtx->I.signedtxid)) != 0 ) { @@ -205,9 +217,11 @@ int32_t LP_waitmempool(char *symbol,bits256 txid,int32_t duration) int32_t LP_mempool_vinscan(bits256 *spendtxidp,int32_t *spendvinp,char *symbol,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) { - int32_t i,n; cJSON *array; bits256 mempooltxid; + int32_t i,n; cJSON *array; bits256 mempooltxid; struct iguana_info *coin; if ( symbol == 0 || symbol[0] == 0 || bits256_nonz(searchtxid) == 0 || bits256_nonz(searchtxid2) == 0 ) return(-1); + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) + return(-1); if ( (array= LP_getmempool(symbol)) != 0 ) { if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) From 41c57b759e149aeb5f3a26b5e9d55c279935f8c8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:17:05 +0300 Subject: [PATCH 1922/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index c01f950b2..a70f4bd0b 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -432,7 +432,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit } if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2,pubkey) <= 0 ) { - printf("iambob.%d utxoadd got ineligible txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",iambob,dstr(value),dstr(value2),dstr(tmpsatoshis)); + printf("iambob.%d utxoadd %s inactive.%u got ineligible txid value %.8f, value2 %.8f, tmpsatoshis %.8f\n",iambob,symbol,coin->inactive,dstr(value),dstr(value2),dstr(tmpsatoshis)); return(0); } if ( dispflag != 0 ) From cc0a555a9e2aaa347450cf409fc94ecaabd3b838 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:18:18 +0300 Subject: [PATCH 1923/2705] Test --- iguana/exchanges/LP_utxos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index a70f4bd0b..c0e539aff 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -416,7 +416,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit printf("malformed addutxo %d %d %d %d %d %d %d %d %d\n", symbol == 0,spendscript == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); return(0); } - if ( (coin= LP_coinfind(symbol)) == 0 && coin->inactive != 0 ) + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) return(0); if ( iambob != 0 && value2 < 9 * (value >> 3) + bigtxfee ) // big txfee padding { From 3b1fe551cf6f67fa0019b3c51fefa6aa16bc8153 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:20:10 +0300 Subject: [PATCH 1924/2705] Test --- iguana/exchanges/client | 2 +- iguana/exchanges/run | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index ae0e1f486..51ce828ff 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -4,5 +4,5 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; -./marketmaker "{\"gui\":\"nogui\",\"client\":1,\"coins\":$coins}" +./marketmaker "{\"gui\":\"nogui\",\"client\":1,\"coins\":$coins}" & diff --git a/iguana/exchanges/run b/iguana/exchanges/run index 2dd0b02c7..a7cddca12 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -3,4 +3,4 @@ source coins pkill -15 marketmaker; git pull; cd ..; -./m_mm; $1 ./marketmaker "{\"gui\":\"nogui\",\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":$coins}" +./m_mm; $1 ./marketmaker "{\"gui\":\"nogui\",\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":$coins}" & From 53f1e8e5a9f72bf47fc71625d79917ef6e42549d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:22:17 +0300 Subject: [PATCH 1925/2705] Test --- iguana/exchanges/install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/install b/iguana/exchanges/install index c41f33434..ebec4840a 100755 --- a/iguana/exchanges/install +++ b/iguana/exchanges/install @@ -1 +1 @@ -cp autotrade client run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub randval run_osx setprice status userpass utxos ../dexscripts +cp autotrade client run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub run_osx setprice status utxos ../dexscripts From 65fde5f522e2b0758b574c81131bd858b23e3cdb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:31:07 +0300 Subject: [PATCH 1926/2705] Test --- iguana/exchanges/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 iguana/exchanges/README.md diff --git a/iguana/exchanges/README.md b/iguana/exchanges/README.md new file mode 100644 index 000000000..b648afd7d --- /dev/null +++ b/iguana/exchanges/README.md @@ -0,0 +1,21 @@ +You need to build iguana onetime from ~/SuperNET/iguana: + +./m_LP + +Then launch it to run in background ../agents/iguana & + +Now iguana should be running and providing port 7778 API: 127.0.0.1:7778 page in the browser will show the API testpage, but for marketmaker these functions are not used very much. it is port 7779 that is used and the marketmaker program is what provides those functions. + +From ~/SuperNET/iguana/exchanges: + +./install + +Now in the ~/SuperNET/iguana/dexscripts directory you will have example scripts that you can change without new git updates overwriting them. Of course, if a new update to a script is made and you dont run install again then you wont have the latest versions. All these scripts are expecting a userpass file, which contains the definition of the $userpass variable to authenticate API access. This avoids evil webpages that try to issue port 7779 calls to steal your money. The userpass variable is linked to each passphrase and that is defined in the randval file. Put your passphrase in that file. You can find templates for these two files in the iguana/exchanges dir. + +At first you wont know the value of userpass. To find out, just run any API script. The first one will return all the required data, the "userpass" field is first and you can copy that value and put it into ~/SuperNET/iguana/dexscripts/userpass file. If you dont, all subsequent API calls will get authorization errors. + +Assuming you created the userpass file properly, you can now issue barterDEX api calls using all the scripts in the dexscripts dir. Please look at these scripts, they are simple curl invocations of a couple lines. Nothing scary and should be self explanatory. + +The help script displays all the api endpoints you should need. You can customize any of the dexscripts for your desired usage, make sure you edit them with the right coins, as if you issue a script for BTC it will do it for BTC instead of the coin you wanted. These scripts wont read your mind, they just do what is in them + + From 98a4935e3835873f96f1e0561876a89e9c631782 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:39:38 +0300 Subject: [PATCH 1927/2705] Test --- iguana/exchanges/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/README.md b/iguana/exchanges/README.md index b648afd7d..b5d73ca82 100644 --- a/iguana/exchanges/README.md +++ b/iguana/exchanges/README.md @@ -12,6 +12,8 @@ From ~/SuperNET/iguana/exchanges: Now in the ~/SuperNET/iguana/dexscripts directory you will have example scripts that you can change without new git updates overwriting them. Of course, if a new update to a script is made and you dont run install again then you wont have the latest versions. All these scripts are expecting a userpass file, which contains the definition of the $userpass variable to authenticate API access. This avoids evil webpages that try to issue port 7779 calls to steal your money. The userpass variable is linked to each passphrase and that is defined in the randval file. Put your passphrase in that file. You can find templates for these two files in the iguana/exchanges dir. +Next step is to actually start the marketmaker from ~/SuperNET/iguana/dexscripts. Use ./run for LP node and ./client for client mode + At first you wont know the value of userpass. To find out, just run any API script. The first one will return all the required data, the "userpass" field is first and you can copy that value and put it into ~/SuperNET/iguana/dexscripts/userpass file. If you dont, all subsequent API calls will get authorization errors. Assuming you created the userpass file properly, you can now issue barterDEX api calls using all the scripts in the dexscripts dir. Please look at these scripts, they are simple curl invocations of a couple lines. Nothing scary and should be self explanatory. From 14ee1a31c5c9c2170bd1ff9d80805f3056e2ef8d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:50:15 +0300 Subject: [PATCH 1928/2705] Test --- iguana/exchanges/coins | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/coins b/iguana/exchanges/coins index de59ee96b..a62ad08db 100644 --- a/iguana/exchanges/coins +++ b/iguana/exchanges/coins @@ -1 +1 @@ -export coins="[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196}, {\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, {\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, {\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, {\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, {\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, {\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, {\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341}, {\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167}, {\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068}, {\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890}, {\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250}, {\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516}, {\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431}, {\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114}, {\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964}, {\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386}, {\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276}, {\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747}, {\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116}, {\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455}]" +export coins="[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196}, {\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, {\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, {\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, {\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, {\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, {\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, {\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341}, {\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167}, {\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068}, {\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890}, {\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250}, {\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516}, {\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431}, {\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114}, {\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964}, {\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386}, {\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276}, {\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":8299}, {\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116}, {\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455}]" From 06bffa09ddc1f553b284c2b77b6883eb6439dd15 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 14:58:36 +0300 Subject: [PATCH 1929/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index a17e9379c..ae6cbfe58 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -312,7 +312,7 @@ struct iguana_info *LP_coincreate(cJSON *item) coin->inactive = !jint(item,"active"); else { - if ( IAMLP == 0 || assetname != name || (strcmp("ZEC",coin->symbol) != 0 && strcmp("HUSH",coin->symbol) != 0) ) + if ( IAMLP == 0 || assetname != name ) coin->inactive = (uint32_t)time(NULL); else coin->inactive = 0; } From 98151d1efc0f48aafde01b0f647245b3980ab0d5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 15:04:10 +0300 Subject: [PATCH 1930/2705] Test --- iguana/exchanges/client | 2 +- iguana/exchanges/run | 3 ++- iguana/exchanges/run_osx | 22 ++++++---------------- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/client b/iguana/exchanges/client index 51ce828ff..4634d6fd2 100755 --- a/iguana/exchanges/client +++ b/iguana/exchanges/client @@ -4,5 +4,5 @@ pkill -15 marketmaker; git pull; cd ..; ./m_mm; -./marketmaker "{\"gui\":\"nogui\",\"client\":1,\"coins\":$coins}" & +./marketmaker "{\"gui\":\"nogui\",\"client\":1, \"userhome\":\"/${HOME#"/"}\", \"passphrase\":\"$randval\", \"coins\":$coins}" & diff --git a/iguana/exchanges/run b/iguana/exchanges/run index a7cddca12..b8242f67a 100755 --- a/iguana/exchanges/run +++ b/iguana/exchanges/run @@ -3,4 +3,5 @@ source coins pkill -15 marketmaker; git pull; cd ..; -./m_mm; $1 ./marketmaker "{\"gui\":\"nogui\",\"profitmargin\":0.01,\"passphrase\":\"$randval\",\"coins\":$coins}" & +./m_mm; + $1 ./marketmaker "{\"gui\":\"nogui\", \"profitmargin\":0.01, \"userhome\":\"/${HOME#"/"}\", \"passphrase\":\"$randval\", \"coins\":$coins}" & diff --git a/iguana/exchanges/run_osx b/iguana/exchanges/run_osx index e39934a75..5c129b0cf 100755 --- a/iguana/exchanges/run_osx +++ b/iguana/exchanges/run_osx @@ -1,17 +1,7 @@ source randval -pkill -15 marketmaker; git pull; cd ..; ./m_mm; ./marketmaker "{\"profitmargin\":0.01,\"userhome\":\"/${HOME#"/"}/Library/Application\ Support\",\"passphrase\":\"$randval\",\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, -{\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, -{\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, -{\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, -{\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, -{\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, -{\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, -{\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, -{\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, -{\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, -{\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, -{\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, -{\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, -{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} -]}" & +source coins +pkill -15 marketmaker; +git pull; +cd ..; +./m_mm; +$1 ./marketmaker "{\"gui\":\"nogui\", \"profitmargin\":0.01, \"userhome\":\"/${HOME#"/"}/Library/Application\ Support\", \"passphrase\":\"$randval\", \"coins\":$coins}" & From 1538cd377bea2eaccb75ba65b9a05cfe81f933af Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 15:07:50 +0300 Subject: [PATCH 1931/2705] Test --- iguana/exchanges/client_osx | 20 +++----------------- iguana/exchanges/install | 2 +- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/client_osx b/iguana/exchanges/client_osx index a46cbff64..2d1442a76 100755 --- a/iguana/exchanges/client_osx +++ b/iguana/exchanges/client_osx @@ -1,22 +1,8 @@ source randval +source coins pkill -15 marketmaker; git pull; - cd ..; +cd ..; ./m_mm; -./marketmaker "{\"client\":1,\"coins\":[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196},{\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, -{\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, -{\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, -{\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, -{\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, -{\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, -{\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, -{\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, -{\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, -{\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, -{\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, -{\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, -{\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, -{\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, -{\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341},{\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167},{\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068},{\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890},{\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250},{\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516},{\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431},{\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114},{\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964},{\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386},{\"coin\":\"MVP\",\"asset\":\"MVP\",\"rpcport\":8655},{\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":9747},{\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116},{\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455} -], \"userhome\":\"/${HOME#"/"}/Library/Application\ Support\", \"passphrase\":\"$randval\"}" & +./marketmaker "{\"gui\":\"nogui\",\"client\":1, \"userhome\":\"/${HOME#"/"}/Library/Application\ Support\", \"passphrase\":\"$randval\", \"coins\":$coins}" & diff --git a/iguana/exchanges/install b/iguana/exchanges/install index ebec4840a..4014e7555 100755 --- a/iguana/exchanges/install +++ b/iguana/exchanges/install @@ -1 +1 @@ -cp autotrade client run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub run_osx setprice status utxos ../dexscripts +cp autotrade client run_osx client_osx run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub run_osx setprice status utxos ../dexscripts From adf3defcb754f51ae9d761742bd4878e6dc44ed2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 15:10:46 +0300 Subject: [PATCH 1932/2705] Test --- iguana/exchanges/install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/install b/iguana/exchanges/install index 4014e7555..ad3276a7e 100755 --- a/iguana/exchanges/install +++ b/iguana/exchanges/install @@ -1 +1 @@ -cp autotrade client run_osx client_osx run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub run_osx setprice status utxos ../dexscripts +cp orderbook autotrade client run_osx client_osx run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub run_osx setprice status utxos ../dexscripts From 0297c866b725abc848bf37872ba868820ab511a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 15:12:06 +0300 Subject: [PATCH 1933/2705] Test --- iguana/exchanges/install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/install b/iguana/exchanges/install index ad3276a7e..0d635a3ee 100755 --- a/iguana/exchanges/install +++ b/iguana/exchanges/install @@ -1 +1 @@ -cp orderbook autotrade client run_osx client_osx run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub run_osx setprice status utxos ../dexscripts +cp orderbook autotrade client run_osx client_osx run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub setprice status utxos ../dexscripts From f4980b865a978c06ccda0010829ffb81e025b18c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 15:14:40 +0300 Subject: [PATCH 1934/2705] Test --- iguana/exchanges/inv | 2 +- iguana/exchanges/orderbook | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/inv b/iguana/exchanges/inv index 3d6669329..b0b5e52b1 100755 --- a/iguana/exchanges/inv +++ b/iguana/exchanges/inv @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"inventory\",\"coin\":\"BTC\"}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"inventory\",\"coin\":\"KMD\"}" diff --git a/iguana/exchanges/orderbook b/iguana/exchanges/orderbook index a2110f07b..3ec8ffbdf 100755 --- a/iguana/exchanges/orderbook +++ b/iguana/exchanges/orderbook @@ -1,2 +1,2 @@ source userpass -curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"orderbook\",\"base\":\"KMD\",\"rel\":\"BTC\"}" +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"orderbook\",\"base\":\"JUMBLR\",\"rel\":\"KMD\"}" From 3f91f883f6268e260059a1c614f2a72c3a06d6cc Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 15:25:18 +0300 Subject: [PATCH 1935/2705] Test --- iguana/exchanges/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/README.md b/iguana/exchanges/README.md index b5d73ca82..28e9fc035 100644 --- a/iguana/exchanges/README.md +++ b/iguana/exchanges/README.md @@ -20,4 +20,5 @@ Assuming you created the userpass file properly, you can now issue barterDEX api The help script displays all the api endpoints you should need. You can customize any of the dexscripts for your desired usage, make sure you edit them with the right coins, as if you issue a script for BTC it will do it for BTC instead of the coin you wanted. These scripts wont read your mind, they just do what is in them +In order to start trading, you need to fund your smartaddress (as listed on the first API call return) from the getcoins API call. To make sure you have utxo pairs for both the bob and alice usage, it is best to send utxo in triplets of X, 1.2 X and 0.01 X. So if X is 10, send 10, 12, and 0.1 coins using sendtoaddress to your smartaddress. After this, it should appear in the inventory. After you setprice, then it will appear in orderbooks with that coin in either the base or rel. From 4d1887874f12ed82c4a74fe5414ef3944005f3dc Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 17:23:32 +0300 Subject: [PATCH 1936/2705] Test --- iguana/exchanges/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iguana/exchanges/README.md b/iguana/exchanges/README.md index 28e9fc035..d66036859 100644 --- a/iguana/exchanges/README.md +++ b/iguana/exchanges/README.md @@ -10,6 +10,8 @@ From ~/SuperNET/iguana/exchanges: ./install +From ~/SuperNET/iguana/dexscripts: + Now in the ~/SuperNET/iguana/dexscripts directory you will have example scripts that you can change without new git updates overwriting them. Of course, if a new update to a script is made and you dont run install again then you wont have the latest versions. All these scripts are expecting a userpass file, which contains the definition of the $userpass variable to authenticate API access. This avoids evil webpages that try to issue port 7779 calls to steal your money. The userpass variable is linked to each passphrase and that is defined in the randval file. Put your passphrase in that file. You can find templates for these two files in the iguana/exchanges dir. Next step is to actually start the marketmaker from ~/SuperNET/iguana/dexscripts. Use ./run for LP node and ./client for client mode From 92591449c990f30eb70d503ad4763da99bf60839 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 18:22:22 +0300 Subject: [PATCH 1937/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index ae6cbfe58..de929033b 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -267,7 +267,7 @@ struct iguana_info *LP_coinfind(char *symbol) coin->inactive = 0; else if ( strcmp(symbol,"BTC") == 0 ) { - coin->inactive = !IAMLP * (uint32_t)time(NULL); + coin->inactive = (uint32_t)time(NULL); printf("BTC inactive.%u\n",coin->inactive); } } From dbfe83b716103a3c9c926d7a412c4f8482f17f08 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 1 Jul 2017 23:38:21 +0300 Subject: [PATCH 1938/2705] Pax coins --- iguana/exchanges/coins | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/coins b/iguana/exchanges/coins index a62ad08db..1e4c8de7a 100644 --- a/iguana/exchanges/coins +++ b/iguana/exchanges/coins @@ -1 +1,2 @@ -export coins="[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196}, {\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, {\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, {\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, {\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, {\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, {\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, {\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341}, {\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167}, {\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068}, {\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890}, {\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250}, {\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516}, {\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431}, {\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114}, {\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964}, {\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386}, {\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276}, {\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":8299}, {\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116}, {\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455}]" +export coins="[{\"coin\":\"REVS\",\"active\":1, \"asset\":\"REVS\",\"rpcport\":10196}, {\"coin\":\"JUMBLR\",\"active\":1, \"asset\":\"JUMBLR\",\"rpcport\":15106}, {\"coin\":\"DOGE\", \"name\":\"dogecoin\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000000}, {\"coin\":\"HUSH\",\"name\":\"hush\",\"rpcport\":8822,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"active\":0,\"coin\":\"ZEC\",\"name\":\"zcash\",\"rpcport\":8232,\"taddr\":28,\"pubtype\":184,\"p2shtype\":189,\"wiftype\":128,\"txfee\":10000 }, {\"coin\":\"DGB\", \"name\":\"digibyte\", \"pubtype\":30, \"p2shtype\":5, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"MZC\", \"name\":\"mazacoin\", \"pubtype\":50, \"p2shtype\":9, \"wiftype\":224, \"txfee\":0}, {\"coin\":\"SYS\", \"name\":\"syscoin\", \"pubtype\":0, \"p2shtype\":5, \"wiftype\":128, \"txfee\":100000}, {\"coin\":\"UNO\", \"name\":\"unobtanium\", \"pubtype\":130, \"p2shtype\":30, \"wiftype\":224, \"txfee\":1000000}, {\"coin\":\"ZET\", \"name\":\"zetacoin\", \"pubtype\":80, \"p2shtype\":9, \"wiftype\":224, \"txfee\":10000}, {\"coin\":\"ZEC\", \"name\":\"zcash\", \"pubtype\":184, \"p2shtype\":189, \"wiftype\":128, \"txfee\":10000}, {\"coin\":\"BTM\", \"name\":\"bitmark\", \"pubtype\":85, \"p2shtype\":5, \"wiftype\":213, \"txfee\":0}, {\"coin\":\"CARB\", \"name\":\"carboncoin\", \"pubtype\":47, \"p2shtype\":5, \"wiftype\":175, \"txfee\":0}, {\"coin\":\"ANC\", \"name\":\"anoncoin\", \"pubtype\":23, \"p2shtype\":5, \"wiftype\":151, \"txfee\":2000000}, {\"coin\":\"FRK\", \"name\":\"franko\", \"pubtype\":35, \"p2shtype\":5, \"wiftype\":163, \"txfee\":0}, {\"coin\":\"GAME\", \"name\":\"gamecredits\", \"pubtype\":38, \"p2shtype\":5, \"wiftype\":166, \"txfee\":100000}, {\"coin\":\"LTC\", \"name\":\"litecoin\", \"rpcport\":9332, \"pubtype\":48, \"p2shtype\":5, \"wiftype\":176, \"txfee\":100000 }, {\"coin\":\"SUPERNET\",\"asset\":\"SUPERNET\",\"rpcport\":11341}, {\"coin\":\"WLC\",\"asset\":\"WLC\",\"rpcport\":12167}, {\"coin\":\"PANGEA\",\"asset\":\"PANGEA\",\"rpcport\":14068}, {\"coin\":\"DEX\",\"asset\":\"DEX\",\"rpcport\":11890}, {\"coin\":\"BET\",\"asset\":\"BET\",\"rpcport\":14250}, {\"coin\":\"CRYPTO\",\"asset\":\"CRYPTO\",\"rpcport\":8516}, {\"coin\":\"HODL\",\"asset\":\"HODL\",\"rpcport\":14431}, {\"coin\":\"SHARK\",\"asset\":\"SHARK\",\"rpcport\":10114}, {\"coin\":\"BOTS\",\"asset\":\"BOTS\",\"rpcport\":11964}, {\"coin\":\"MGW\",\"asset\":\"MGW\",\"rpcport\":12386}, {\"coin\":\"COQUI\",\"asset\":\"COQUI\",\"rpcport\":14276}, {\"coin\":\"KV\",\"asset\":\"KV\",\"rpcport\":8299}, {\"coin\":\"CEAL\",\"asset\":\"CEAL\",\"rpcport\":11116}, {\"coin\":\"MESH\",\"asset\":\"MESH\",\"rpcport\":9455},{\"coin\":\"AUD\",\"asset\":\"AUD\",\"rpcport\":8045}, {\"coin\":\"BGN\",\"asset\":\"BGN\",\"rpcport\":9110}, {\"coin\":\"CAD\",\"asset\":\"CAD\",\"rpcport\":8720}, {\"coin\":\"CHF\",\"asset\":\"CHF\",\"rpcport\":15312}, {\"coin\":\"CNY\",\"asset\":\"CNY\",\"rpcport\":10384}, {\"coin\":\"CZK\",\"asset\":\"CZK\",\"rpcport\":9482}, {\"coin\":\"DKK\",\"asset\":\"DKK\",\"rpcport\":13830}, {\"coin\":\"EUR\",\"asset\":\"EUR\",\"rpcport\":8065}, {\"coin\":\"GBP\",\"asset\":\"GBP\",\"rpcport\":11505}, {\"coin\":\"HKD\",\"asset\":\"HKD\",\"rpcport\":15409}, {\"coin\":\"HRK\",\"asset\":\"HRK\",\"rpcport\":12617}, {\"coin\":\"HUF\",\"asset\":\"HUF\",\"rpcport\":13699}, {\"coin\":\"IDR\",\"asset\":\"IDR\",\"rpcport\":14459}, {\"coin\":\"ILS\",\"asset\":\"ILS\",\"rpcport\":14638}, {\"coin\":\"INR\",\"asset\":\"INR\",\"rpcport\":10536}, {\"coin\":\"JPY\",\"asset\":\"JPY\",\"rpcport\":13145}, {\"coin\":\"KRW\",\"asset\":\"KRW\",\"rpcport\":14020}, {\"coin\":\"MXN\",\"asset\":\"MXN\",\"rpcport\":13970}, {\"coin\":\"MYR\",\"asset\":\"MYR\",\"rpcport\":10688}, {\"coin\":\"NOK\",\"asset\":\"NOK\",\"rpcport\":11588}, {\"coin\":\"NZD\",\"asset\":\"NZD\",\"rpcport\":10915}, {\"coin\":\"PHP\",\"asset\":\"PHP\",\"rpcport\":11181}, {\"coin\":\"PLN\",\"asset\":\"PLN\",\"rpcport\":13493}, {\"coin\":\"BRL\",\"asset\":\"BRL\",\"rpcport\":9914}, {\"coin\":\"RON\",\"asset\":\"RON\",\"rpcport\":8675}, {\"coin\":\"RUB\",\"asset\":\"RUB\",\"rpcport\":8199}, {\"coin\":\"SEK\",\"asset\":\"SEK\",\"rpcport\":11447}, {\"coin\":\"SGD\",\"asset\":\"SGD\",\"rpcport\":14475}, {\"coin\":\"THB\",\"asset\":\"THB\",\"rpcport\":11847}, {\"coin\":\"TRY\",\"asset\":\"TRY\",\"rpcport\":13924}, {\"coin\":\"USD\",\"asset\":\"USD\",\"rpcport\":13967}, {\"coin\":\"ZAR\",\"asset\":\"ZAR\",\"rpcport\":15160}]" + From f1eb8884c85ff48f7d8b8902fe836f11e1bdffc1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 14:08:44 +0300 Subject: [PATCH 1939/2705] Cached tx for spend checks --- iguana/exchanges/LP_coins.c | 50 ++--- iguana/exchanges/LP_include.h | 15 +- iguana/exchanges/LP_nativeDEX.c | 57 +++++- iguana/exchanges/LP_remember.c | 6 + iguana/exchanges/LP_scan.c | 302 +++++++++++++++++++---------- iguana/exchanges/LP_statemachine.c | 47 +++++ iguana/exchanges/LP_transaction.c | 20 +- iguana/exchanges/LP_utxos.c | 23 +-- 8 files changed, 352 insertions(+), 168 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index de929033b..b29d44428 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -173,15 +173,37 @@ cJSON *LP_coinjson(struct iguana_info *coin) return(item); } -static struct iguana_info *LP_coins; static int32_t LP_numcoins; cJSON *LP_coinsjson() { - int32_t i; cJSON *array = cJSON_CreateArray(); - for (i=0; itxmutex); + portable_mutex_lock(&LP_coinmutex); + HASH_ADD_KEYPTR(hh,LP_coins,coin->symbol,strlen(coin->symbol),coin); + portable_mutex_unlock(&LP_coinmutex); + return(coin); +} + int32_t LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *assetname,int32_t isPoS,uint16_t port,uint8_t pubtype,uint8_t p2shtype,uint8_t wiftype,uint64_t txfee,double estimatedrate,int32_t longestchain,uint8_t taddr) { char *name2; @@ -203,26 +225,6 @@ int32_t LP_coininit(struct iguana_info *coin,char *symbol,char *name,char *asset return(LP_userpass(coin->userpass,symbol,assetname,name,name2)); } -struct iguana_info *LP_coinadd(struct iguana_info *cdata) -{ - struct iguana_info *coin; - //printf("%s: (%s) (%s)\n",symbol,cdata.serverport,cdata.userpass); - LP_coins = realloc(LP_coins,sizeof(*LP_coins) * (LP_numcoins+1)); - coin = &LP_coins[LP_numcoins]; - *coin = *cdata; - LP_numcoins++; - return(coin); -} - -struct iguana_info *LP_coinsearch(char *symbol) -{ - int32_t i; - for (i=0; i #include "LP_include.h" -portable_mutex_t LP_peermutex,LP_UTXOmutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex,LP_networkmutex,LP_psockmutex; +portable_mutex_t LP_peermutex,LP_UTXOmutex,LP_utxomutex,LP_commandmutex,LP_cachemutex,LP_swaplistmutex,LP_forwardmutex,LP_pubkeymutex,LP_networkmutex,LP_psockmutex,LP_coinmutex; int32_t LP_canbind; #include "LP_network.c" struct LP_utxoinfo *LP_utxoinfos[2],*LP_utxoinfos2[2]; struct LP_peerinfo *LP_peerinfos,*LP_mypeer; struct LP_forwardinfo *LP_forwardinfos; +struct iguana_info *LP_coins; char *activecoins[] = { "BTC", "KMD" }; char GLOBAL_DBDIR[] = { "DB" }; @@ -192,18 +193,18 @@ int32_t LP_subsock_check(void *ctx,char *myipaddr,int32_t pubsock,int32_t sock,d void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo,double profitmargin) { - struct _LP_utxoinfo u; char str[65],destaddr[64]; uint32_t now = (uint32_t)time(NULL); + struct _LP_utxoinfo u; char str[65]; uint32_t now = (uint32_t)time(NULL); //printf("%s lag.%d\n",bits256_str(str,utxo->txid),now-utxo->lastspentcheck); if ( utxo->T.spentflag == 0 && now > utxo->T.lastspentcheck+60 ) { u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; utxo->T.lastspentcheck = now; - if ( LP_txvalue(destaddr,utxo->coin,utxo->payment.txid,utxo->payment.vout) == 0 ) + if ( LP_txvalue(0,utxo->coin,utxo->payment.txid,utxo->payment.vout) == 0 ) { printf("txid.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,utxo->payment.txid),utxo->payment.vout,dstr(utxo->payment.value)); LP_spentnotify(utxo,0); } - else if ( LP_txvalue(destaddr,utxo->coin,u.txid,u.vout) == 0 ) + else if ( LP_txvalue(0,utxo->coin,u.txid,u.vout) == 0 ) { printf("txid2.%s %s/v%d %.8f has been spent\n",utxo->coin,bits256_str(str,u.txid),u.vout,dstr(u.value)); LP_spentnotify(utxo,1); @@ -238,7 +239,7 @@ int32_t LP_peer_utxosquery(struct LP_peerinfo *mypeer,uint16_t myport,int32_t pu int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,uint16_t pushport,int32_t pullsock,uint16_t myport,char *passphrase,double profitmargin) { static uint32_t counter,lastforward,numpeers; - struct LP_utxoinfo *utxo,*utmp; char *retstr,*origipaddr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0,n=0,lastn=-1; + struct LP_utxoinfo *utxo,*utmp; struct iguana_info *coin,*ctmp; char *retstr,*origipaddr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t nonz = 0,n=0,lastn=-1; now = (uint32_t)time(NULL); if ( (origipaddr= myipaddr) == 0 ) origipaddr = "127.0.0.1"; @@ -332,6 +333,47 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int //LP_deadman_switch = 0; } } + HASH_ITER(hh,LP_coins,coin,ctmp) // firstrefht,firstscanht,lastscanht + { + cJSON *obj; int32_t height; bits256 zero; + memset(zero.bytes,0,sizeof(zero)); + if ( time(NULL) > coin->lastgetinfo+LP_GETINFO_INCR ) + { + if ( (obj= LP_getinfo(coin->symbol)) != 0 ) + { + if ( (height= jint(obj,"blocks")) > 0 ) + coin->longestchain = height; + free_json(obj); + } + coin->lastgetinfo = (uint32_t)time(NULL); + } + if ( coin->firstrefht == 0 ) + continue; + else if ( coin->firstscanht == 0 ) + coin->lastscanht = coin->firstscanht = coin->firstrefht; + else if ( coin->firstrefht < coin->firstscanht ) + { + printf("detected %s firstrefht.%d < firstscanht.%d\n",coin->symbol,coin->firstrefht,coin->firstscanht); + coin->lastscanht = coin->firstscanht = coin->firstrefht; + } + if ( coin->lastscanht == coin->longestchain ) + continue; + else if ( coin->lastscanht > coin->longestchain ) + { + printf("detected chain rewind lastscanht.%d vs longestchain.%d, first.%d ref.%d\n",coin->lastscanht,coin->longestchain,coin->firstscanht,coin->firstrefht); + LP_undospends(coin,coin->longestchain-1); + LP_mempoolscan(coin->symbol,zero); + coin->lastscanht = coin->longestchain - 1; + if ( coin->firstscanht < coin->lastscanht ) + coin->lastscanht = coin->firstscanht; + continue; + } + printf("%s ref.%d scan.%d to %d, longest.%d\n",coin->symbol,coin->firstrefht,coin->firstscanht,coin->lastscanht,coin->longestchain); + if ( LP_blockinit(coin,coin->lastscanht) < 0 ) + continue; + coin->lastscanht++; + break; + } counter++; return(nonz); } @@ -401,7 +443,7 @@ void LP_initpeers(int32_t pubsock,struct LP_peerinfo *mypeer,char *myipaddr,uint void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profitmargin,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) { - char *myipaddr=0; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; void *ctx = bitcoin_ctx(); + char *myipaddr=0,*retstr; long filesize,n; int32_t timeout,pullsock=-1,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128]; void *ctx = bitcoin_ctx(); IAMLP = !amclient; #ifndef __linux__ if ( IAMLP != 0 ) @@ -443,6 +485,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit portable_mutex_init(&LP_networkmutex); portable_mutex_init(&LP_forwardmutex); portable_mutex_init(&LP_psockmutex); + portable_mutex_init(&LP_coinmutex); portable_mutex_init(&LP_pubkeymutex); if ( profitmargin == 0. || profitmargin == 0.01 ) { @@ -498,6 +541,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,double profit printf("error launching stats rpcloop for port.%u\n",myport); exit(-1); } + if ( (retstr= basilisk_swapentry(0,0)) != 0 ) + free(retstr); while ( 1 ) { //fprintf(stderr,"."); diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 78ce4a783..532ec9fc3 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -536,7 +536,13 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti } else { + struct iguana_info *coin; int32_t ht; uint32_t locktime,blocktime; checktxid = jbits256(sentobj,"txid"); + if ( (coin= LP_coinfind(symbol)) != 0 && (ht= LP_txheight(&locktime,&blocktime,coin,txobj)) > 0 && ht > 0 ) + { + if ( coin->firstrefht == 0 || ht < coin->firstrefht ) + coin->firstrefht = ht; + } if ( bits256_nonz(checktxid) == 0 ) checktxid = jbits256(sentobj,"hash"); if ( bits256_cmp(checktxid,txid) == 0 ) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index a9198398f..85ad96f18 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -18,154 +18,242 @@ // marketmaker // -/*uint64_t oldLP_txvalue(char *symbol,bits256 txid,int32_t vout) +struct LP_transaction *LP_transactionfind(struct iguana_info *coin,bits256 txid) { - uint64_t value = 0; double interest; cJSON *txobj,*vouts,*utxoobj; int32_t numvouts; - if ( (txobj= LP_gettx(symbol,txid)) != 0 ) + struct LP_transaction *tx; + portable_mutex_lock(&coin->txmutex); + HASH_FIND(hh,coin->transactions,txid.bytes,sizeof(txid),tx); + portable_mutex_unlock(&coin->txmutex); + return(tx); +} + +struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,int32_t height,int32_t numvouts,int32_t numvins,uint32_t timestamp) +{ + struct LP_transaction *tx; int32_t i; + if ( (tx= LP_transactionfind(coin,txid)) == 0 ) { - //char str[65]; printf("%s.(%s) txobj.(%s)\n",symbol,bits256_str(str,txid),jprint(txobj,0)); - if ( (vouts= jarray(&numvouts,txobj,"vout")) != 0 && vout < numvouts ) + tx = calloc(1,sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts)); + for (i=0; ioutpoints[i].spendvini = -1; + tx->height = height; + tx->numvouts = numvouts; + tx->numvins = numvins; + tx->timestamp = timestamp; + portable_mutex_lock(&coin->txmutex); + char str[65]; printf("%s ht.%d u.%u NEW TXID.(%s) vouts.[%d]\n",coin->symbol,tx->height,tx->timestamp,bits256_str(str,tx->txid),numvouts); + HASH_ADD_KEYPTR(hh,coin->transactions,tx->txid.bytes,sizeof(tx->txid),tx); + portable_mutex_unlock(&coin->txmutex); + } // else printf("warning adding already existing txid %s\n",bits256_str(str,tx->txid)); + return(tx); +} + +int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info *coin,cJSON *txobj) +{ + bits256 blockhash; cJSON *blockobj; int32_t height = 0; + *timestampp = juint(txobj,"locktime"); + *blocktimep = juint(txobj,"blocktime"); + blockhash = jbits256(txobj,"blockhash"); + if ( bits256_nonz(blockhash) != 0 && (blockobj= LP_getblock(coin->symbol,blockhash)) != 0 ) + { + height = jint(blockobj,"height"); + free_json(blockobj); + } + return(height); +} + +int32_t LP_undospends(struct iguana_info *coin,int32_t lastheight) +{ + int32_t i,ht,num = 0; uint32_t timestamp,blocktime; struct LP_transaction *tx,*tmp; cJSON *txobj; + HASH_ITER(hh,coin->transactions,tx,tmp) + { + for (i=0; inumvouts; i++) { - utxoobj = jitem(vouts,vout); - if ( (value= jdouble(utxoobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(utxoobj,"value")*SATOSHIDEN) == 0 ) - { - char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d/%d\n",symbol,bits256_str(str,txid),jprint(utxoobj,0),vout,numvouts); - } - else if ( strcmp(symbol,"KMD") == 0 ) + if ( bits256_nonz(tx->outpoints[i].spendtxid) == 0 ) + continue; + if ( (ht= tx->outpoints[i].spendheight) == 0 ) { - if ( (utxoobj= LP_gettxout(symbol,txid,vout)) != 0 ) + if ( (txobj= LP_gettx(coin->symbol,tx->outpoints[i].spendtxid)) != 0 ) { - if ( (interest= jdouble(utxoobj,"interest")) != 0. ) - { - //printf("add interest of %.8f to %.8f\n",interest,dstr(value)); - value += SATOSHIDEN * interest; - } - free_json(utxoobj); + tx->outpoints[i].spendheight = LP_txheight(×tamp,&blocktime,coin,txobj); + free_json(txobj); } } + if ( (ht= tx->outpoints[i].spendheight) != 0 && ht > lastheight ) + { + char str[65]; printf("clear spend %s/v%d at ht.%d > lastheight.%d\n",bits256_str(str,tx->txid),i,ht,lastheight); + tx->outpoints[i].spendheight = 0; + tx->outpoints[i].spendvini = -1; + memset(tx->outpoints[i].spendtxid.bytes,0,sizeof(bits256)); + } } - free_json(txobj); } - return(value); -}*/ + return(num); +} -uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) +uint64_t LP_txinterestvalue(uint64_t *interestp,char *destaddr,struct iguana_info *coin,bits256 txid,int32_t vout) { - uint64_t value = 0; double interest; cJSON *txobj,*sobj,*array; int32_t n; struct iguana_info *coin; - if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) - return(0); - coinaddr[0] = 0; - if ( (txobj= LP_gettxout(symbol,txid,vout)) != 0 ) + uint64_t interest,value = 0; cJSON *txobj,*sobj,*array; int32_t n=0; + *interestp = 0; + destaddr[0] = 0; + if ( (txobj= LP_gettxout(coin->symbol,txid,vout)) != 0 ) { if ( (value= jdouble(txobj,"amount")*SATOSHIDEN) == 0 && (value= jdouble(txobj,"value")*SATOSHIDEN) == 0 ) { - char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d\n",symbol,bits256_str(str,txid),jprint(txobj,0),vout); + char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d\n",coin->symbol,bits256_str(str,txid),jprint(txobj,0),vout); } - else if ( strcmp(symbol,"KMD") == 0 ) + else if ( strcmp(coin->symbol,"KMD") == 0 ) { if ( (interest= jdouble(txobj,"interest")) != 0. ) { //printf("add interest of %.8f to %.8f\n",interest,dstr(value)); - value += SATOSHIDEN * interest; + *interestp = SATOSHIDEN * interest; } } if ( (sobj= jobj(txobj,"scriptPubKey")) != 0 && (array= jarray(&n,sobj,"addresses")) != 0 ) - strcpy(coinaddr,jstri(array,0)); + { + strcpy(destaddr,jstri(array,0)); + if ( n > 1 ) + printf("LP_txinterestvalue warning: violation of 1 output assumption n.%d\n",n); + } else printf("LP_txinterestvalue no addresses found?\n"); //char str[65]; printf("%.8f <- %s.(%s) txobj.(%s)\n",dstr(value),symbol,bits256_str(str,txid),jprint(txobj,0)); free_json(txobj); } return(value); } -int32_t LP_vinscan(bits256 *spendtxidp,int32_t *spendvinip,char *symbol,bits256 txid,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) +int32_t LP_transactioninit(struct iguana_info *coin,bits256 txid) { - cJSON *txobj,*vins,*vin; bits256 spenttxid; struct iguana_info *coin; int32_t j,numvins,spentvout,retval = -1; - memset(spendtxidp,0,sizeof(*spendtxidp)); - *spendvinip = -1; - if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) - return(retval); - if ( (txobj= LP_gettx(symbol,txid)) != 0 ) + struct LP_transaction *tx; int32_t i,height,numvouts,numvins,spentvout; uint32_t timestamp,blocktime; cJSON *txobj,*vins,*vouts,*vout,*vin; bits256 spenttxid; char str[65]; + if ( (txobj=LP_gettx(coin->symbol,txid)) != 0 ) { - if ( bits256_cmp(txid,jbits256(txobj,"txid")) != 0 ) - { - char str[65]; printf("txid mismatch error %s vs %s\n",bits256_str(str,txid),jprint(txobj,0)); - free_json(txobj); - return(-2); - } + height = LP_txheight(×tamp,&blocktime,coin,txobj); + if ( timestamp == 0 && height > 0 ) + timestamp = blocktime; vins = jarray(&numvins,txobj,"vin"); - for (j=0; joutpoints[i].value= SATOSHIDEN * jdouble(vout,"value")) == 0 ) + tx->outpoints[i].value = SATOSHIDEN * jdouble(vout,"amount"); + tx->outpoints[i].interest = SATOSHIDEN * jdouble(vout,"interest"); } - else if ( spentvout == searchvout2 && bits256_cmp(spenttxid,searchtxid2) == 0 ) + } + if ( vins != 0 ) + { + for (i=0; inumvouts ) + { + tx->outpoints[spentvout].spendtxid = txid; + tx->outpoints[spentvout].spendvini = i; + tx->outpoints[spentvout].spendheight = height; + } else printf("LP_transactioninint: %s spentvout.%d < numvouts.%d\n",bits256_str(str,spenttxid),spentvout,tx->numvouts); + } } } free_json(txobj); - } else printf("unexpected missing txid\n"), retval = -3; - return(retval); + return(0); + } else printf("LP_transactioninit error for %s\n",bits256_str(str,txid)); + return(-1); } -int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 searchtxid,int32_t searchvout) +int32_t LP_blockinit(struct iguana_info *coin,int32_t height) { - char destaddr[64]; struct iguana_info *coin; cJSON *blockjson,*txids,*txobj; bits256 hash,txid; int32_t h,i,j,numtxids,loadheight,errs = 0; - *indp = -1; - if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) - return(0); - memset(spendtxidp,0,sizeof(*spendtxidp)); - if ( LP_txvalue(destaddr,symbol,searchtxid,searchvout) > 0 ) - return(0); - if ( (txobj= LP_gettx(symbol,searchtxid)) == 0 ) - return(0); - hash = jbits256(txobj,"blockhash"); - free_json(txobj); - if ( bits256_nonz(hash) == 0 ) + int32_t i,numtx,checkht=-1; cJSON *blockobj,*txs; bits256 txid; struct LP_transaction *tx; + if ( (blockobj= LP_blockjson(&checkht,coin->symbol,0,height)) != 0 ) + { + if ( (txs= jarray(&numtx,blockobj,"tx")) != 0 ) + { + for (i=0; iheight == 0 ) + tx->height = height; + else if ( tx->height != height ) + { + printf("LP_blockinit: tx->height %d != %d\n",tx->height,height); + tx->height = height; + } + } else LP_transactioninit(coin,txid); + } + } + free_json(blockobj); + } + if ( checkht == height ) return(0); - if ( (blockjson= LP_getblock(symbol,hash)) == 0 ) + else return(-1); +} + +int64_t basilisk_txvalue(char *symbol,bits256 txid,int32_t vout) +{ + char destaddr[64]; uint64_t value,interest = 0; struct iguana_info *coin; + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) return(0); - loadheight = jint(blockjson,"height"); - free_json(blockjson); - if ( loadheight <= 0 ) + //char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid)); + value = LP_txinterestvalue(&interest,destaddr,coin,txid,vout); + return(value + interest); +} + +uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) +{ + struct LP_transaction *tx; uint64_t interest = 0,value = 0; struct iguana_info *coin; + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) return(0); - while ( errs == 0 && *indp < 0 ) + if ( coinaddr != 0 ) + coinaddr[0] = 0; + if ( (tx= LP_transactionfind(coin,txid)) != 0 ) { - //printf("search %s ht.%d\n",symbol,loadheight); - if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 && h == loadheight ) + if ( vout < tx->numvouts ) { - if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) + if ( bits256_nonz(tx->outpoints[vout].spendtxid) != 0 ) + return(0); + else { - for (i=0; i= 0 ) - break; + value = LP_txinterestvalue(&tx->outpoints[vout].interest,coinaddr,coin,txid,vout); } + return(tx->outpoints[vout].value + tx->outpoints[vout].interest); } - free_json(blockjson); - } else errs++; - loadheight++; + } } - char str[65]; printf("reached %s ht.%d %s/v%d\n",symbol,loadheight,bits256_str(str,*spendtxidp),*indp); - if ( bits256_nonz(*spendtxidp) != 0 && *indp >= 0 ) - return(loadheight); - else return(0); + if ( coinaddr != 0 ) + value = LP_txinterestvalue(&interest,coinaddr,coin,txid,vout); + return(value + interest); } -int32_t LP_mempoolscan(char *symbol,bits256 txid) +int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 searchtxid,int32_t searchvout) { - int32_t i,n; cJSON *array; struct iguana_info *coin; + struct LP_transaction *tx; struct iguana_info *coin; + *indp = -1; + if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) + return(-1); + memset(spendtxidp,0,sizeof(*spendtxidp)); + if ( (tx= LP_transactionfind(coin,searchtxid)) != 0 ) + { + if ( searchvout < tx->numvouts && tx->outpoints[searchvout].spendvini >= 0 ) + { + *spendtxidp = tx->outpoints[searchvout].spendtxid; + *indp = tx->outpoints[searchvout].spendvini; + return(tx->outpoints[searchvout].spendheight); + } + } + return(-1); +} + +int32_t LP_mempoolscan(char *symbol,bits256 searchtxid) +{ + int32_t i,n; cJSON *array; bits256 txid; struct iguana_info *coin; struct LP_transaction *tx; if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) return(-1); if ( (array= LP_getmempool(symbol)) != 0 ) @@ -173,11 +261,16 @@ int32_t LP_mempoolscan(char *symbol,bits256 txid) if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; i= 0 ) return(0); - usleep(250000); + usleep(500000); } return(-1); } int32_t LP_mempool_vinscan(bits256 *spendtxidp,int32_t *spendvinp,char *symbol,bits256 searchtxid,int32_t searchvout,bits256 searchtxid2,int32_t searchvout2) { - int32_t i,n; cJSON *array; bits256 mempooltxid; struct iguana_info *coin; + struct iguana_info *coin; int32_t selector; cJSON *array; if ( symbol == 0 || symbol[0] == 0 || bits256_nonz(searchtxid) == 0 || bits256_nonz(searchtxid2) == 0 ) return(-1); if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) return(-1); - if ( (array= LP_getmempool(symbol)) != 0 ) + if ( time(NULL) > coin->lastmempool+LP_MEMPOOL_TIMEINCR ) { - if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + if ( (array= LP_getmempool(symbol)) != 0 ) { - for (i=0; i= 0 ) - return(i); - } free_json(array); + coin->lastmempool = (uint32_t)time(NULL); } } + if ( (selector= LP_spendsearch(spendtxidp,spendvinp,symbol,searchtxid,searchvout)) >= 0 ) + return(selector); + else if ( (selector= LP_spendsearch(spendtxidp,spendvinp,symbol,searchtxid2,searchvout2)) >= 0 ) + return(selector); return(-1); } diff --git a/iguana/exchanges/LP_statemachine.c b/iguana/exchanges/LP_statemachine.c index 70e6d1c7b..b5c5a27f8 100644 --- a/iguana/exchanges/LP_statemachine.c +++ b/iguana/exchanges/LP_statemachine.c @@ -1432,4 +1432,51 @@ if ( (array= LP_tradecandidates(base)) != 0 ) LP_priceping(pubsock,utxo,"BTC",profitmargin); else LP_priceping(pubsock,utxo,"KMD",profitmargin); }*/ +/*if ( LP_txvalue(destaddr,symbol,searchtxid,searchvout) > 0 ) + return(0); + if ( (txobj= LP_gettx(symbol,searchtxid)) == 0 ) + return(0); + hash = jbits256(txobj,"blockhash"); + free_json(txobj); + if ( bits256_nonz(hash) == 0 ) + return(0); + if ( (blockjson= LP_getblock(symbol,hash)) == 0 ) + return(0); + loadheight = jint(blockjson,"height"); + free_json(blockjson); + if ( loadheight <= 0 ) + return(0); + while ( errs == 0 && *indp < 0 ) + { + //printf("search %s ht.%d\n",symbol,loadheight); + if ( (blockjson= LP_blockjson(&h,symbol,0,loadheight)) != 0 && h == loadheight ) + { + if ( (txids= jarray(&numtxids,blockjson,"tx")) != 0 ) + { + for (i=0; i= 0 ) + break; + } + } + free_json(blockjson); + } else errs++; + loadheight++; + } + char str[65]; printf("reached %s ht.%d %s/v%d\n",symbol,loadheight,bits256_str(str,*spendtxidp),*indp); + if ( bits256_nonz(*spendtxidp) != 0 && *indp >= 0 ) + return(loadheight); + else return(0);*/ + +/*if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i= 0 ) + return(selector); + } + }*/ + diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c index d67031477..ea9aaae24 100644 --- a/iguana/exchanges/LP_transaction.c +++ b/iguana/exchanges/LP_transaction.c @@ -13,12 +13,12 @@ * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ + // // LP_transaction.c // marketmaker // - bits256 LP_broadcast(char *txname,char *symbol,char *txbytes,bits256 expectedtxid) { char *retstr; bits256 txid; cJSON *retjson,*errorobj; int32_t i,sentflag = 0; @@ -816,24 +816,6 @@ int32_t basilisk_swap_getsigscript(char *symbol,uint8_t *script,int32_t maxlen,b return(scriptlen); } -int64_t basilisk_txvalue(char *symbol,bits256 txid,int32_t vout) -{ - cJSON *txobj,*vouts,*item; int32_t n; int64_t value = 0; - //char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid)); - if ( (txobj= LP_gettx(symbol,txid)) != 0 ) - { - //printf("txobj.(%s)\n",jprint(txobj,0)); - if ( (vouts= jarray(&n,txobj,"vout")) != 0 ) - { - item = jitem(vouts,vout); - if ( (value= jdouble(item,"amount") * SATOSHIDEN) == 0 ) - value = jdouble(item,"value") * SATOSHIDEN; - } - free_json(txobj); - } - return(value); -} - bits256 _LP_swap_spendtxid(char *symbol,char *destaddr,char *coinaddr,bits256 utxotxid,int32_t vout) { char *retstr,*addr; cJSON *array,*item,*array2; int32_t i,n,m; bits256 spendtxid,txid; diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index c0e539aff..0575ffe1e 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -379,7 +379,7 @@ void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector) char *LP_spentcheck(cJSON *argjson) { - char destaddr[64]; bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; int32_t iambob,retval = 0; + bits256 txid,checktxid; int32_t vout,checkvout; struct LP_utxoinfo *utxo; int32_t iambob,retval = 0; txid = jbits256(argjson,"txid"); vout = jint(argjson,"vout"); for (iambob=0; iambob<=1; iambob++) @@ -393,7 +393,7 @@ char *LP_spentcheck(cJSON *argjson) checktxid = jbits256(argjson,"checktxid"); checkvout = jint(argjson,"checkvout"); } - if ( LP_txvalue(destaddr,utxo->coin,checktxid,checkvout) == 0 ) + if ( LP_txvalue(0,utxo->coin,checktxid,checkvout) == 0 ) { if ( LP_mypeer != 0 && LP_mypeer->numutxos > 0 ) LP_mypeer->numutxos--; @@ -438,7 +438,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit if ( dispflag != 0 ) printf("%.8f %.8f %s iambob.%d %s utxoadd.(%.8f %.8f) %s %s\n",dstr(val),dstr(val2),coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); dispflag = 1; - if ( 0 && (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) + if ( (selector= LP_mempool_vinscan(&spendtxid,&spendvini,symbol,txid,vout,txid2,vout2)) >= 0 ) { printf("utxoadd selector.%d in mempool %s vini.%d",selector,bits256_str(str,spendtxid),spendvini); return(0); @@ -457,7 +457,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,int32_t mypubsock,char *symbol,bit char str[65],str2[65],str3[65],str4[65],str5[65],str6[65]; if ( dispflag != 0 ) printf("error on subsequent utxo iambob.%d %.8f %.8f add.(%s %s) when.(%s %s) %d %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",iambob,dstr(val),dstr(val2),bits256_str(str,txid),bits256_str(str2,txid2),bits256_str(str3,utxo->payment.txid),bits256_str(str4,utxo->deposit.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(spendscript,utxo->spendscript) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str5,pubkey),bits256_str(str6,utxo->pubkey)); - if ( utxo->T.spentflag != 0 || LP_txvalue(utxo->coinaddr,utxo->coin,utxo->payment.txid,utxo->payment.vout) < utxo->payment.value || LP_txvalue(utxo->coinaddr,utxo->coin,u.txid,u.vout) < u.value ) + if ( utxo->T.spentflag != 0 || LP_txvalue(0,utxo->coin,utxo->payment.txid,utxo->payment.vout) < utxo->payment.value || LP_txvalue(0,utxo->coin,u.txid,u.vout) < u.value ) { if ( utxo->T.spentflag == 0 ) utxo->T.spentflag = (uint32_t)time(NULL); @@ -777,19 +777,16 @@ bits256 LP_privkeycalc(void *ctx,uint8_t *pubkey33,bits256 *pubkeyp,struct iguan void LP_privkey_updates(void *ctx,int32_t pubsock,char *passphrase,int32_t initonly) { - int32_t i; struct iguana_info *coin; bits256 pubkey,privkey; uint8_t pubkey33[33]; + struct iguana_info *coin,*tmp; bits256 pubkey,privkey; uint8_t pubkey33[33]; memset(privkey.bytes,0,sizeof(privkey)); pubkey = privkey; - for (i=0; ismartaddr[0] == 0 ) - privkey = LP_privkeycalc(ctx,pubkey33,&pubkey,coin,passphrase,""); - if ( coin->inactive == 0 && initonly == 0 ) - LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33); - } + if ( bits256_nonz(privkey) == 0 || coin->smartaddr[0] == 0 ) + privkey = LP_privkeycalc(ctx,pubkey33,&pubkey,coin,passphrase,""); + if ( coin->inactive == 0 && initonly == 0 ) + LP_privkey_init(pubsock,coin,privkey,pubkey,pubkey33); } } From ae0486c3d0260305b7a851c53922e07107b92b4a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:03:26 +0300 Subject: [PATCH 1940/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index b29d44428..7b0c1e5ad 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -269,7 +269,7 @@ struct iguana_info *LP_coinfind(char *symbol) coin->inactive = 0; else if ( strcmp(symbol,"BTC") == 0 ) { - coin->inactive = (uint32_t)time(NULL); + coin->inactive = !IAMLP * (uint32_t)time(NULL); printf("BTC inactive.%u\n",coin->inactive); } } From 96cc03a07d72bb3a91aceb13c24352579a418ab7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:11:18 +0300 Subject: [PATCH 1941/2705] Test --- iguana/exchanges/LP_scan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 85ad96f18..8915ddfca 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -211,7 +211,7 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) return(0); if ( coinaddr != 0 ) coinaddr[0] = 0; - if ( (tx= LP_transactionfind(coin,txid)) != 0 ) + if ( (tx= LP_transactionfind(coin,txid)) == 0 ) { if ( vout < tx->numvouts ) { @@ -228,7 +228,10 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) } } if ( coinaddr != 0 ) + { + LP_transactioninit(coin,txid); value = LP_txinterestvalue(&interest,coinaddr,coin,txid,vout); + } return(value + interest); } From 0ad1ac27ef6a49eb753352736d1521b680eb66bb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:16:07 +0300 Subject: [PATCH 1942/2705] Test --- iguana/exchanges/LP_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 8915ddfca..0be875e55 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -211,7 +211,7 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) return(0); if ( coinaddr != 0 ) coinaddr[0] = 0; - if ( (tx= LP_transactionfind(coin,txid)) == 0 ) + if ( (tx= LP_transactionfind(coin,txid)) != 0 ) { if ( vout < tx->numvouts ) { From 696417208ef7d34aa196224d43051a0daa96f440 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:21:36 +0300 Subject: [PATCH 1943/2705] Test --- iguana/exchanges/LP_scan.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 0be875e55..20b4fa222 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -32,6 +32,9 @@ struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,i struct LP_transaction *tx; int32_t i; if ( (tx= LP_transactionfind(coin,txid)) == 0 ) { + char str[65]; printf("%s ht.%d u.%u NEW TXID.(%s) vouts.[%d]\n",coin->symbol,height,timestamp,bits256_str(str,txid),numvouts); + if ( tx->height == 0 ) + getchar(); tx = calloc(1,sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts)); for (i=0; ioutpoints[i].spendvini = -1; @@ -40,7 +43,6 @@ struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,i tx->numvins = numvins; tx->timestamp = timestamp; portable_mutex_lock(&coin->txmutex); - char str[65]; printf("%s ht.%d u.%u NEW TXID.(%s) vouts.[%d]\n",coin->symbol,tx->height,tx->timestamp,bits256_str(str,tx->txid),numvouts); HASH_ADD_KEYPTR(hh,coin->transactions,tx->txid.bytes,sizeof(tx->txid),tx); portable_mutex_unlock(&coin->txmutex); } // else printf("warning adding already existing txid %s\n",bits256_str(str,tx->txid)); From cbc3270d9e50e7620088d38e75797381cf7f61b9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:22:27 +0300 Subject: [PATCH 1944/2705] Test --- iguana/exchanges/LP_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 20b4fa222..6307a80cf 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -33,7 +33,7 @@ struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,i if ( (tx= LP_transactionfind(coin,txid)) == 0 ) { char str[65]; printf("%s ht.%d u.%u NEW TXID.(%s) vouts.[%d]\n",coin->symbol,height,timestamp,bits256_str(str,txid),numvouts); - if ( tx->height == 0 ) + if ( bits256_nonz(txid) == 0 && tx->height == 0 ) getchar(); tx = calloc(1,sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts)); for (i=0; i Date: Sun, 2 Jul 2017 15:31:35 +0300 Subject: [PATCH 1945/2705] Test --- iguana/exchanges/LP_scan.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 6307a80cf..64d801edb 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -157,6 +157,7 @@ int32_t LP_transactioninit(struct iguana_info *coin,bits256 txid) tx->outpoints[spentvout].spendtxid = txid; tx->outpoints[spentvout].spendvini = i; tx->outpoints[spentvout].spendheight = height; + printf("spend %s/v%d at ht.%d\n",bits256_str(str,tx->txid),spentvout,height); } else printf("LP_transactioninint: %s spentvout.%d < numvouts.%d\n",bits256_str(str,spenttxid),spentvout,tx->numvouts); } } @@ -208,7 +209,7 @@ int64_t basilisk_txvalue(char *symbol,bits256 txid,int32_t vout) uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) { - struct LP_transaction *tx; uint64_t interest = 0,value = 0; struct iguana_info *coin; + struct LP_transaction *tx; char _coinaddr[64]; uint64_t interest = 0,value = 0; struct iguana_info *coin; if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) return(0); if ( coinaddr != 0 ) @@ -218,22 +219,27 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) if ( vout < tx->numvouts ) { if ( bits256_nonz(tx->outpoints[vout].spendtxid) != 0 ) + { + char str[65]; printf("%s/v%d is spent\n",bits256_str(str,txid),vout); return(0); + } else { if ( coinaddr != 0 && strcmp(symbol,"KMD") == 0 ) { value = LP_txinterestvalue(&tx->outpoints[vout].interest,coinaddr,coin,txid,vout); } + printf("return value %.8f + interest %.8f\n",dstr(tx->outpoints[vout].value),dstr(tx->outpoints[vout].interest)); return(tx->outpoints[vout].value + tx->outpoints[vout].interest); } - } + } else printf("vout.%d >= tx->numvouts.%d\n",vout,tx->numvouts); } - if ( coinaddr != 0 ) - { + if ( tx == 0 ) LP_transactioninit(coin,txid); - value = LP_txinterestvalue(&interest,coinaddr,coin,txid,vout); - } + if ( coinaddr == 0 ) + coinaddr = _coinaddr; + value = LP_txinterestvalue(&interest,coinaddr,coin,txid,vout); + printf("coinaddr.(%s) value %.8f interest %.8f\n",coinaddr,dstr(value),dstr(interest)); return(value + interest); } From f5734fe64f30ab20170580b658a05ef237faffa4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:37:21 +0300 Subject: [PATCH 1946/2705] Test --- iguana/exchanges/LP_scan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 64d801edb..3f681100b 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -32,9 +32,9 @@ struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,i struct LP_transaction *tx; int32_t i; if ( (tx= LP_transactionfind(coin,txid)) == 0 ) { - char str[65]; printf("%s ht.%d u.%u NEW TXID.(%s) vouts.[%d]\n",coin->symbol,height,timestamp,bits256_str(str,txid),numvouts); - if ( bits256_nonz(txid) == 0 && tx->height == 0 ) - getchar(); + //char str[65]; printf("%s ht.%d u.%u NEW TXID.(%s) vouts.[%d]\n",coin->symbol,height,timestamp,bits256_str(str,txid),numvouts); + //if ( bits256_nonz(txid) == 0 && tx->height == 0 ) + // getchar(); tx = calloc(1,sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts)); for (i=0; ioutpoints[i].spendvini = -1; @@ -239,7 +239,7 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) if ( coinaddr == 0 ) coinaddr = _coinaddr; value = LP_txinterestvalue(&interest,coinaddr,coin,txid,vout); - printf("coinaddr.(%s) value %.8f interest %.8f\n",coinaddr,dstr(value),dstr(interest)); + //printf("coinaddr.(%s) value %.8f interest %.8f\n",coinaddr,dstr(value),dstr(interest)); return(value + interest); } From 134bbca55216f8c133fffcd1d566e55b60079675 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:48:35 +0300 Subject: [PATCH 1947/2705] Test --- iguana/exchanges/LP_rpc.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index aae5e7b93..097feaef9 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -117,22 +117,21 @@ char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utx char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *ipaddr,uint16_t pushport) { - char url[512],str[65];//*retstr; + char url[512],str[65],*retstr; sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s&pushport=%u",destip,destport,bits256_str(str,pubkey),ipaddr,pushport); - return(LP_issue_curl("register",destip,destport,url)); - //retstr = issue_curlt(url,LP_HTTP_TIMEOUT); + //return(LP_issue_curl("register",destip,destport,url)); + retstr = issue_curlt(url,LP_HTTP_TIMEOUT*3); //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); - //return(retstr); + return(retstr); } char *issue_LP_psock(char *destip,uint16_t destport,int32_t ispaired) { - char url[512]; + char url[512],*retstr; sprintf(url,"http://%s:%u/api/stats/psock?ispaired=%d",destip,destport,ispaired); - return(LP_issue_curl("psock",destip,destport,url)); - //retstr = issue_curlt(url,LP_HTTP_TIMEOUT); - //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); - //return(retstr); + //return(LP_issue_curl("psock",destip,destport,url)); + retstr = issue_curlt(url,LP_HTTP_TIMEOUT*3); + return(retstr); } uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired) From d619a279335bcdddce7ee700e10f2486c5dfe892 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:52:50 +0300 Subject: [PATCH 1948/2705] Test --- iguana/exchanges/LP_commands.c | 2 +- iguana/exchanges/LP_rpc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 5d9dfb80a..e1d5398ed 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -238,7 +238,7 @@ forwardhex(pubkey,hex)\n\ if ( strcmp(method,"register") == 0 ) { retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr"),juint(argjson,"pushport")); - //printf("got (%s) from register\n",retstr!=0?retstr:""); + printf("got (%s) from register\n",retstr!=0?retstr:""); return(retstr); } else if ( strcmp(method,"lookup") == 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index 097feaef9..ee59204e5 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -121,7 +121,7 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *ipad sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s&pushport=%u",destip,destport,bits256_str(str,pubkey),ipaddr,pushport); //return(LP_issue_curl("register",destip,destport,url)); retstr = issue_curlt(url,LP_HTTP_TIMEOUT*3); - //printf("getutxo.(%s) -> (%s)\n",url,retstr!=0?retstr:""); + printf("register.(%s) -> (%s)\n",url,retstr!=0?retstr:""); return(retstr); } From f28b9f7c940da62468feea4f0fe6cb1efcd881ec Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 15:59:12 +0300 Subject: [PATCH 1949/2705] Test --- iguana/exchanges/LP_commands.c | 10 +++++----- iguana/exchanges/LP_forwarding.c | 16 ++++++++-------- iguana/exchanges/LP_rpc.c | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index e1d5398ed..65aca1bb3 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -184,9 +184,9 @@ forwardhex(pubkey,hex)\n\ return(LP_pubkey_trustset(jbits256(argjson,"pubkey"),jint(argjson,"trust"))); } if ( LP_isdisabled(base,rel) != 0 ) - retstr = clonestr("{\"error\":\"at least one of coins disabled\"}"); + retstr = clonestr("{\"result\":\"at least one of coins disabled\"}"); else if ( LP_isdisabled(jstr(argjson,"coin"),0) != 0 ) - retstr = clonestr("{\"error\":\"coin is disabled\"}"); + retstr = clonestr("{\"result\":\"coin is disabled\"}"); else if ( strcmp(method,"reserved") == 0 ) retstr = LP_quotereceived(argjson); else if ( strcmp(method,"connected") == 0 ) @@ -213,8 +213,8 @@ forwardhex(pubkey,hex)\n\ //printf("FORWARDED.(%s)\n",jprint(argjson,0)); if ( LP_forward(ctx,myipaddr,pubsock,profitmargin,jbits256(argjson,"pubkey"),jprint(reqjson,1),1) > 0 ) retstr = clonestr("{\"result\":\"success\"}"); - else retstr = clonestr("{\"error\":\"error forwarding\"}"); - } else retstr = clonestr("{\"error\":\"cant recurse forwards\"}"); + else retstr = clonestr("{\"result\":\"error forwarding\"}"); + } else retstr = clonestr("{\"result\":\"cant recurse forwards\"}"); } else if ( strcmp(method,"keepalive") == 0 ) @@ -231,7 +231,7 @@ forwardhex(pubkey,hex)\n\ { if ( LP_utxoaddjson(1,LP_mypubsock,argjson) != 0 ) return(clonestr("{\"result\":\"success\",\"notifyutxo\":\"received\"}")); - else return(clonestr("{\"error\":\"couldnt add utxo\"}")); + else return(clonestr("{\"result\":\"couldnt add utxo\"}")); } else if ( IAMLP != 0 ) { diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c index cbde40d71..81706ccd8 100644 --- a/iguana/exchanges/LP_forwarding.c +++ b/iguana/exchanges/LP_forwarding.c @@ -42,10 +42,10 @@ struct LP_forwardinfo *LP_forwardfind(bits256 pubkey) char *LP_lookup(bits256 pubkey) { if ( bits256_nonz(pubkey) == 0 ) - return(clonestr("{\"error\":\"illegal pubkey\"}")); + return(clonestr("{\"result\":\"illegal pubkey\"}")); if ( LP_forwardfind(pubkey) != 0 ) return(clonestr("{\"result\":\"success\",\"forwarding\":1}")); - else return(clonestr("{\"error\":\"notfound\"}")); + else return(clonestr("{\"result\":\"notfound\"}")); } int32_t LP_hello(struct LP_forwardinfo *ptr) @@ -108,7 +108,7 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) { struct LP_forwardinfo *ptr=0; int32_t pushsock; char pushaddr[64]; if ( ipaddr == 0 || ipaddr[0] == 0 || is_ipaddr(ipaddr) == 0 || bits256_nonz(pubkey) == 0 ) - return(clonestr("{\"error\":\"illegal ipaddr or null pubkey\"}")); + return(clonestr("{\"result\":\"illegal ipaddr or null pubkey\"}")); nanomsg_transportname(0,pushaddr,ipaddr,port); char str[65]; printf("register.(%s) %s\n",pushaddr,bits256_str(str,pubkey)); if ( (ptr= LP_forwardfind(pubkey)) != 0 ) @@ -126,13 +126,13 @@ char *LP_register(bits256 pubkey,char *ipaddr,uint16_t port) char str[65]; printf("%u recreate pushsock for %s <- %s\n",(uint32_t)time(NULL),pushaddr,bits256_str(str,pubkey)); strcpy(ptr->pushaddr,pushaddr); if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 ) - return(clonestr("{\"error\":\"couldnt recreate pushsock\",\"registered\":0}")); + return(clonestr("{\"result\":\"couldnt recreate pushsock\",\"registered\":0}")); } //else printf("no need to create identical endpoint\n"); } - return(clonestr("{\"error\":\"already registered\",\"registered\":1}")); + return(clonestr("{\"result\":\"already registered\",\"registered\":1}")); } else if ( (pushsock= LP_pushsock_create(0,pushaddr)) < 0 ) - return(clonestr("{\"error\":\"couldnt create pushsock\"}")); + return(clonestr("{\"result\":\"couldnt create pushsock\"}")); else { ptr = calloc(1,sizeof(*ptr)); @@ -216,7 +216,7 @@ char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) { struct LP_forwardinfo *ptr=0; uint8_t *data; int32_t datalen=0,sentbytes=0; char *msg,*retstr=0; cJSON *retjson=0,*argjson=0,*reqjson=0; if ( hexstr == 0 || hexstr[0] == 0 ) - return(clonestr("{\"error\":\"nohex\"}")); + return(clonestr("{\"result\":\"nohex\"}")); datalen = (int32_t)strlen(hexstr) >> 1; data = malloc(datalen); decode_hex(data,datalen,hexstr); @@ -266,7 +266,7 @@ char *LP_forwardhex(void *ctx,int32_t pubsock,bits256 pubkey,char *hexstr) msg = jprint(reqjson,0); LP_send(pubsock,msg,(int32_t)strlen(msg)+1,1); } - retstr = clonestr("{\"error\":\"notfound\"}"); + retstr = clonestr("{\"result\":\"notfound\"}"); } free(data); if ( reqjson != 0 ) diff --git a/iguana/exchanges/LP_rpc.c b/iguana/exchanges/LP_rpc.c index ee59204e5..59deb28e3 100644 --- a/iguana/exchanges/LP_rpc.c +++ b/iguana/exchanges/LP_rpc.c @@ -121,7 +121,7 @@ char *issue_LP_register(char *destip,uint16_t destport,bits256 pubkey,char *ipad sprintf(url,"http://%s:%u/api/stats/register?client=%s&pushaddr=%s&pushport=%u",destip,destport,bits256_str(str,pubkey),ipaddr,pushport); //return(LP_issue_curl("register",destip,destport,url)); retstr = issue_curlt(url,LP_HTTP_TIMEOUT*3); - printf("register.(%s) -> (%s)\n",url,retstr!=0?retstr:""); + //printf("register.(%s) -> (%s)\n",url,retstr!=0?retstr:""); return(retstr); } @@ -196,7 +196,7 @@ cJSON *bitcoin_json(struct iguana_info *coin,char *method,char *params) } //usleep(1000); //printf("dpow_gettxout.(%s)\n",retstr); - } else retjson = cJSON_Parse("{\"error\":\"disabled\"}"); + } else retjson = cJSON_Parse("{\"result\":\"disabled\"}"); } else printf("bitcoin_json cant talk to NULL coin\n"); return(retjson); } From 5e1f7b67730927520cd3f2bbf08b9b9907c83954 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 16:00:52 +0300 Subject: [PATCH 1950/2705] Tests --- iguana/exchanges/LP_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_commands.c b/iguana/exchanges/LP_commands.c index 65aca1bb3..607be2520 100644 --- a/iguana/exchanges/LP_commands.c +++ b/iguana/exchanges/LP_commands.c @@ -238,7 +238,7 @@ forwardhex(pubkey,hex)\n\ if ( strcmp(method,"register") == 0 ) { retstr = LP_register(jbits256(argjson,"client"),jstr(argjson,"pushaddr"),juint(argjson,"pushport")); - printf("got (%s) from register\n",retstr!=0?retstr:""); + //printf("got (%s) from register\n",retstr!=0?retstr:""); return(retstr); } else if ( strcmp(method,"lookup") == 0 ) From a25a1c62d046e3e09012ede6bb0598835005f0a8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 16:30:57 +0300 Subject: [PATCH 1951/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index a0ec299a4..e850610aa 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -341,8 +341,11 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int { if ( (obj= LP_getinfo(coin->symbol)) != 0 ) { - if ( (height= jint(obj,"blocks")) > 0 ) + if ( (height= jint(obj,"blocks")) > coin->longestchain ) + { coin->longestchain = height; + printf(">>>>>>>>>> set %s longestchain %d (ref.%d [%d, %d])\n",coin->symbol,height,coin->firstrefht,coin->firstscanht,coin->lastscanht); + } free_json(obj); } coin->lastgetinfo = (uint32_t)time(NULL); @@ -370,7 +373,10 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int } printf("%s ref.%d scan.%d to %d, longest.%d\n",coin->symbol,coin->firstrefht,coin->firstscanht,coin->lastscanht,coin->longestchain); if ( LP_blockinit(coin,coin->lastscanht) < 0 ) + { + printf("blockinit.%s %d error\n",coin->symbol,coin->lastscanht); continue; + } coin->lastscanht++; break; } From e356e339b03957785429825dcba354c3cf1c9646 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 16:49:03 +0300 Subject: [PATCH 1952/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index e850610aa..0a393c14d 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -336,6 +336,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int HASH_ITER(hh,LP_coins,coin,ctmp) // firstrefht,firstscanht,lastscanht { cJSON *obj; int32_t height; bits256 zero; + printf("%s ref.%d scan.%d to %d, longest.%d\n",coin->symbol,coin->firstrefht,coin->firstscanht,coin->lastscanht,coin->longestchain); memset(zero.bytes,0,sizeof(zero)); if ( time(NULL) > coin->lastgetinfo+LP_GETINFO_INCR ) { @@ -345,9 +346,9 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int { coin->longestchain = height; printf(">>>>>>>>>> set %s longestchain %d (ref.%d [%d, %d])\n",coin->symbol,height,coin->firstrefht,coin->firstscanht,coin->lastscanht); - } + } else printf("cant find blocks in (%s)\n",jprint(obj,0)); free_json(obj); - } + } else printf("error getting info.%s\n",coin->symbol); coin->lastgetinfo = (uint32_t)time(NULL); } if ( coin->firstrefht == 0 ) From b0184bbba6c0c68c5f48221dc6a080e34182cd43 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 16:54:54 +0300 Subject: [PATCH 1953/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- iguana/exchanges/LP_remember.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 7b0c1e5ad..57de45e2d 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -237,7 +237,7 @@ int32_t LP_isdisabled(char *base,char *rel) struct iguana_info *LP_coinfind(char *symbol) { - struct iguana_info *coin,cdata; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*assetname; + struct iguana_info *coin,cdata; int32_t isPoS,longestchain = 1; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name,*assetname; if ( (coin= LP_coinsearch(symbol)) != 0 ) return(coin); if ( (port= LP_rpcport(symbol)) == 0 ) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 532ec9fc3..921429d3e 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -532,17 +532,17 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti { if ( (sentobj= LP_gettx(symbol,txid)) == 0 ) { - //printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); + char str2[65]; printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid)); } else { - struct iguana_info *coin; int32_t ht; uint32_t locktime,blocktime; + struct iguana_info *coin; int32_t ht = -1; uint32_t locktime,blocktime; checktxid = jbits256(sentobj,"txid"); if ( (coin= LP_coinfind(symbol)) != 0 && (ht= LP_txheight(&locktime,&blocktime,coin,txobj)) > 0 && ht > 0 ) { if ( coin->firstrefht == 0 || ht < coin->firstrefht ) coin->firstrefht = ht; - } + } else printf("coin.%p ht.%d\n",coin,ht); if ( bits256_nonz(checktxid) == 0 ) checktxid = jbits256(sentobj,"hash"); if ( bits256_cmp(checktxid,txid) == 0 ) From a8750c6acbad6e101581aabc8fea483002862208 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 16:56:15 +0300 Subject: [PATCH 1954/2705] Test --- iguana/exchanges/LP_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 3f681100b..9b1f03d1a 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -59,7 +59,7 @@ int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info { height = jint(blockobj,"height"); free_json(blockobj); - } + } else printf("LP_txheight error (%s)\n",jprint(txobj,0)); return(height); } From 39a359c998c21932499fa732ef05de591a2ce444 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 16:57:12 +0300 Subject: [PATCH 1955/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 921429d3e..ddefd1075 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -538,7 +538,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti { struct iguana_info *coin; int32_t ht = -1; uint32_t locktime,blocktime; checktxid = jbits256(sentobj,"txid"); - if ( (coin= LP_coinfind(symbol)) != 0 && (ht= LP_txheight(&locktime,&blocktime,coin,txobj)) > 0 && ht > 0 ) + if ( (coin= LP_coinfind(symbol)) != 0 && (ht= LP_txheight(&locktime,&blocktime,coin,sentobj)) > 0 && ht > 0 ) { if ( coin->firstrefht == 0 || ht < coin->firstrefht ) coin->firstrefht = ht; From 989e7b7c864921cea27003108375e10f5cc22d37 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 17:01:57 +0300 Subject: [PATCH 1956/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_remember.c | 2 +- iguana/exchanges/LP_scan.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0a393c14d..95a909c89 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -336,7 +336,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int HASH_ITER(hh,LP_coins,coin,ctmp) // firstrefht,firstscanht,lastscanht { cJSON *obj; int32_t height; bits256 zero; - printf("%s ref.%d scan.%d to %d, longest.%d\n",coin->symbol,coin->firstrefht,coin->firstscanht,coin->lastscanht,coin->longestchain); + //printf("%s ref.%d scan.%d to %d, longest.%d\n",coin->symbol,coin->firstrefht,coin->firstscanht,coin->lastscanht,coin->longestchain); memset(zero.bytes,0,sizeof(zero)); if ( time(NULL) > coin->lastgetinfo+LP_GETINFO_INCR ) { diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index ddefd1075..6292699a2 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -542,7 +542,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti { if ( coin->firstrefht == 0 || ht < coin->firstrefht ) coin->firstrefht = ht; - } else printf("coin.%p ht.%d\n",coin,ht); + } if ( bits256_nonz(checktxid) == 0 ) checktxid = jbits256(sentobj,"hash"); if ( bits256_cmp(checktxid,txid) == 0 ) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 9b1f03d1a..1bc588e0e 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -58,6 +58,7 @@ int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info if ( bits256_nonz(blockhash) != 0 && (blockobj= LP_getblock(coin->symbol,blockhash)) != 0 ) { height = jint(blockobj,"height"); + printf("LP_txheight.%d\n",height); free_json(blockobj); } else printf("LP_txheight error (%s)\n",jprint(txobj,0)); return(height); From 67e3685936c69e8bc75ce640803d1e6268051123 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 17:23:56 +0300 Subject: [PATCH 1957/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 8 +++++--- iguana/exchanges/LP_scan.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 95a909c89..c9c0be3cc 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -337,16 +337,18 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int { cJSON *obj; int32_t height; bits256 zero; //printf("%s ref.%d scan.%d to %d, longest.%d\n",coin->symbol,coin->firstrefht,coin->firstscanht,coin->lastscanht,coin->longestchain); + if ( coin->inactive != 0 ) + continue; memset(zero.bytes,0,sizeof(zero)); if ( time(NULL) > coin->lastgetinfo+LP_GETINFO_INCR ) { if ( (obj= LP_getinfo(coin->symbol)) != 0 ) { - if ( (height= jint(obj,"blocks")) > coin->longestchain ) + if ( (height= jint(obj,"blocks")) >= coin->longestchain ) { - coin->longestchain = height; + coin->longestchain = height - 1; printf(">>>>>>>>>> set %s longestchain %d (ref.%d [%d, %d])\n",coin->symbol,height,coin->firstrefht,coin->firstscanht,coin->lastscanht); - } else printf("cant find blocks in (%s)\n",jprint(obj,0)); + } free_json(obj); } else printf("error getting info.%s\n",coin->symbol); coin->lastgetinfo = (uint32_t)time(NULL); diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 1bc588e0e..af859465f 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -58,7 +58,7 @@ int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info if ( bits256_nonz(blockhash) != 0 && (blockobj= LP_getblock(coin->symbol,blockhash)) != 0 ) { height = jint(blockobj,"height"); - printf("LP_txheight.%d\n",height); + printf("%s LP_txheight.%d\n",coin->symbol,height); free_json(blockobj); } else printf("LP_txheight error (%s)\n",jprint(txobj,0)); return(height); From 107cba6a783a8937d545db295ec085afecce0610 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 17:26:51 +0300 Subject: [PATCH 1958/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 2 +- iguana/exchanges/LP_scan.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index c9c0be3cc..0895cb79f 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -348,7 +348,7 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int { coin->longestchain = height - 1; printf(">>>>>>>>>> set %s longestchain %d (ref.%d [%d, %d])\n",coin->symbol,height,coin->firstrefht,coin->firstscanht,coin->lastscanht); - } + } else LP_mempoolscan(coin->symbol,zero); free_json(obj); } else printf("error getting info.%s\n",coin->symbol); coin->lastgetinfo = (uint32_t)time(NULL); diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index af859465f..bd45296f2 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -58,7 +58,7 @@ int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info if ( bits256_nonz(blockhash) != 0 && (blockobj= LP_getblock(coin->symbol,blockhash)) != 0 ) { height = jint(blockobj,"height"); - printf("%s LP_txheight.%d\n",coin->symbol,height); + //printf("%s LP_txheight.%d\n",coin->symbol,height); free_json(blockobj); } else printf("LP_txheight error (%s)\n",jprint(txobj,0)); return(height); From 3c8b16053cf1441c98f85dadc49e5c7f0bd055a5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 17:29:27 +0300 Subject: [PATCH 1959/2705] Test --- iguana/exchanges/LP_coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_coins.c b/iguana/exchanges/LP_coins.c index 57de45e2d..98bb8acb5 100644 --- a/iguana/exchanges/LP_coins.c +++ b/iguana/exchanges/LP_coins.c @@ -282,7 +282,7 @@ struct iguana_info *LP_coinfind(char *symbol) struct iguana_info *LP_coincreate(cJSON *item) { - struct iguana_info cdata,*coin=0; int32_t isPoS,longestchain = 1000000; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name=0,*symbol,*assetname=0; + struct iguana_info cdata,*coin=0; int32_t isPoS,longestchain = 1; uint16_t port; uint64_t txfee; double estimatedrate; uint8_t pubtype,p2shtype,wiftype; char *name=0,*symbol,*assetname=0; if ( (symbol= jstr(item,"coin")) != 0 && symbol[0] != 0 && strlen(symbol) < 16 && LP_coinfind(symbol) == 0 && (port= juint(item,"rpcport")) != 0 ) { isPoS = jint(item,"isPoS"); From 97d442dbde2977d5f262a112eada9890cce76fdf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 17:43:30 +0300 Subject: [PATCH 1960/2705] test --- iguana/exchanges/LP_scan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index bd45296f2..18e9d0d46 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -42,6 +42,7 @@ struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,i tx->numvouts = numvouts; tx->numvins = numvins; tx->timestamp = timestamp; + tx->txid = txid; portable_mutex_lock(&coin->txmutex); HASH_ADD_KEYPTR(hh,coin->transactions,tx->txid.bytes,sizeof(tx->txid),tx); portable_mutex_unlock(&coin->txmutex); From 2befd66b1317d9403d870cc8667ed79addcbf6cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 17:44:20 +0300 Subject: [PATCH 1961/2705] Test --- iguana/exchanges/LP_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 18e9d0d46..f28e9f2fe 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -231,7 +231,7 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) { value = LP_txinterestvalue(&tx->outpoints[vout].interest,coinaddr,coin,txid,vout); } - printf("return value %.8f + interest %.8f\n",dstr(tx->outpoints[vout].value),dstr(tx->outpoints[vout].interest)); + //printf("return value %.8f + interest %.8f\n",dstr(tx->outpoints[vout].value),dstr(tx->outpoints[vout].interest)); return(tx->outpoints[vout].value + tx->outpoints[vout].interest); } } else printf("vout.%d >= tx->numvouts.%d\n",vout,tx->numvouts); From d219398fcfb56a37cfe434a48b6185f25b0d2dd7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 18:00:29 +0300 Subject: [PATCH 1962/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 0895cb79f..469b684d4 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -344,9 +344,9 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int { if ( (obj= LP_getinfo(coin->symbol)) != 0 ) { - if ( (height= jint(obj,"blocks")) >= coin->longestchain ) + if ( (height= jint(obj,"blocks")) > coin->longestchain ) { - coin->longestchain = height - 1; + coin->longestchain = height; printf(">>>>>>>>>> set %s longestchain %d (ref.%d [%d, %d])\n",coin->symbol,height,coin->firstrefht,coin->firstscanht,coin->lastscanht); } else LP_mempoolscan(coin->symbol,zero); free_json(obj); From 182794cad5d0b9a7af67ac5b027fd43221840bcc Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 18:05:11 +0300 Subject: [PATCH 1963/2705] Test --- iguana/exchanges/LP_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index f28e9f2fe..506ed7544 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -61,7 +61,7 @@ int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info height = jint(blockobj,"height"); //printf("%s LP_txheight.%d\n",coin->symbol,height); free_json(blockobj); - } else printf("LP_txheight error (%s)\n",jprint(txobj,0)); + } else printf("%sLP_txheight error (%s)\n",coin->symbol,jprint(txobj,0)); return(height); } From 94babb4db77107b815a016e4674d97115ada1076 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 18:23:41 +0300 Subject: [PATCH 1964/2705] Test --- iguana/exchanges/LP_remember.c | 2 +- iguana/exchanges/LP_scan.c | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c index 6292699a2..8f93bbc9b 100644 --- a/iguana/exchanges/LP_remember.c +++ b/iguana/exchanges/LP_remember.c @@ -538,7 +538,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti { struct iguana_info *coin; int32_t ht = -1; uint32_t locktime,blocktime; checktxid = jbits256(sentobj,"txid"); - if ( (coin= LP_coinfind(symbol)) != 0 && (ht= LP_txheight(&locktime,&blocktime,coin,sentobj)) > 0 && ht > 0 ) + if ( (coin= LP_coinfind(symbol)) != 0 && (ht= LP_txheight(&locktime,&blocktime,coin,txid)) > 0 && ht > 0 ) { if ( coin->firstrefht == 0 || ht < coin->firstrefht ) coin->firstrefht = ht; diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 506ed7544..3e230f193 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -50,24 +50,28 @@ struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,i return(tx); } -int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info *coin,cJSON *txobj) +int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info *coin,bits256 txid) { - bits256 blockhash; cJSON *blockobj; int32_t height = 0; - *timestampp = juint(txobj,"locktime"); - *blocktimep = juint(txobj,"blocktime"); - blockhash = jbits256(txobj,"blockhash"); - if ( bits256_nonz(blockhash) != 0 && (blockobj= LP_getblock(coin->symbol,blockhash)) != 0 ) + bits256 blockhash; cJSON *blockobj,*txobj; int32_t height = 0; + if ( (txobj= LP_gettx(coin->symbol,txid)) != 0 ) { - height = jint(blockobj,"height"); - //printf("%s LP_txheight.%d\n",coin->symbol,height); - free_json(blockobj); - } else printf("%sLP_txheight error (%s)\n",coin->symbol,jprint(txobj,0)); + *timestampp = juint(txobj,"locktime"); + *blocktimep = juint(txobj,"blocktime"); + blockhash = jbits256(txobj,"blockhash"); + if ( bits256_nonz(blockhash) != 0 && (blockobj= LP_getblock(coin->symbol,blockhash)) != 0 ) + { + height = jint(blockobj,"height"); + //printf("%s LP_txheight.%d\n",coin->symbol,height); + free_json(blockobj); + } else printf("%sLP_txheight error (%s)\n",coin->symbol,jprint(txobj,0)); + free_json(txobj); + } return(height); } int32_t LP_undospends(struct iguana_info *coin,int32_t lastheight) { - int32_t i,ht,num = 0; uint32_t timestamp,blocktime; struct LP_transaction *tx,*tmp; cJSON *txobj; + int32_t i,ht,num = 0; uint32_t timestamp,blocktime; struct LP_transaction *tx,*tmp; HASH_ITER(hh,coin->transactions,tx,tmp) { for (i=0; inumvouts; i++) @@ -76,11 +80,7 @@ int32_t LP_undospends(struct iguana_info *coin,int32_t lastheight) continue; if ( (ht= tx->outpoints[i].spendheight) == 0 ) { - if ( (txobj= LP_gettx(coin->symbol,tx->outpoints[i].spendtxid)) != 0 ) - { - tx->outpoints[i].spendheight = LP_txheight(×tamp,&blocktime,coin,txobj); - free_json(txobj); - } + tx->outpoints[i].spendheight = LP_txheight(×tamp,&blocktime,coin,tx->outpoints[i].spendtxid); } if ( (ht= tx->outpoints[i].spendheight) != 0 && ht > lastheight ) { @@ -130,7 +130,7 @@ int32_t LP_transactioninit(struct iguana_info *coin,bits256 txid) struct LP_transaction *tx; int32_t i,height,numvouts,numvins,spentvout; uint32_t timestamp,blocktime; cJSON *txobj,*vins,*vouts,*vout,*vin; bits256 spenttxid; char str[65]; if ( (txobj=LP_gettx(coin->symbol,txid)) != 0 ) { - height = LP_txheight(×tamp,&blocktime,coin,txobj); + height = LP_txheight(×tamp,&blocktime,coin,txid); if ( timestamp == 0 && height > 0 ) timestamp = blocktime; vins = jarray(&numvins,txobj,"vin"); From f425cf8ba20d9b3a8facd2ee8ca5db08741f31ae Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 18:28:10 +0300 Subject: [PATCH 1965/2705] Test --- iguana/exchanges/LP_scan.c | 2 +- iguana/exchanges/LP_utxos.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 3e230f193..739f91d4f 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -63,7 +63,7 @@ int32_t LP_txheight(uint32_t *timestampp,uint32_t *blocktimep,struct iguana_info height = jint(blockobj,"height"); //printf("%s LP_txheight.%d\n",coin->symbol,height); free_json(blockobj); - } else printf("%sLP_txheight error (%s)\n",coin->symbol,jprint(txobj,0)); + } //else printf("%s LP_txheight error (%s)\n",coin->symbol,jprint(txobj,0)); free_json(txobj); } return(height); diff --git a/iguana/exchanges/LP_utxos.c b/iguana/exchanges/LP_utxos.c index 0575ffe1e..cab530037 100644 --- a/iguana/exchanges/LP_utxos.c +++ b/iguana/exchanges/LP_utxos.c @@ -276,7 +276,7 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol if ( (val2= LP_txvalue(destaddr2,symbol,txid2,vout2)) >= threshold ) { if ( strcmp(destaddr,destaddr2) != 0 ) - printf("mismatched %s destaddr %s vs %s\n",symbol,destaddr,destaddr2); + printf("mismatched %s destaddr (%s) vs (%s)\n",symbol,destaddr,destaddr2); else if ( (iambob == 0 && val2 > val) || (iambob != 0 && val2 <= satoshis) ) printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f diff %lld\n",iambob,dstr(val),dstr(val2),dstr(satoshis),(long long)(val2 - val)); else From b7757e1e92328cbdbc80f1271e1e94a835bdc0a2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 18:38:16 +0300 Subject: [PATCH 1966/2705] Test --- iguana/exchanges/LP_scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c index 739f91d4f..65c26cf22 100644 --- a/iguana/exchanges/LP_scan.c +++ b/iguana/exchanges/LP_scan.c @@ -159,7 +159,7 @@ int32_t LP_transactioninit(struct iguana_info *coin,bits256 txid) tx->outpoints[spentvout].spendtxid = txid; tx->outpoints[spentvout].spendvini = i; tx->outpoints[spentvout].spendheight = height; - printf("spend %s/v%d at ht.%d\n",bits256_str(str,tx->txid),spentvout,height); + //printf("spend %s %s/v%d at ht.%d\n",coin->symbol,bits256_str(str,tx->txid),spentvout,height); } else printf("LP_transactioninint: %s spentvout.%d < numvouts.%d\n",bits256_str(str,spenttxid),spentvout,tx->numvouts); } } From eff9cf99cf533ee6ed560667eff542b8d1bb5490 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 18:44:03 +0300 Subject: [PATCH 1967/2705] Test --- iguana/exchanges/install | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iguana/exchanges/install b/iguana/exchanges/install index 0d635a3ee..8aa0b8209 100755 --- a/iguana/exchanges/install +++ b/iguana/exchanges/install @@ -1 +1,4 @@ cp orderbook autotrade client run_osx client_osx run coins disable enable forward myprice myprices getcoins getpeers getpeersIP getprices getutxos help inv lookup pub setprice status utxos ../dexscripts +cd ../dexscripts +cp ../exchanges/randval ../exchanges/userpass . +echo you will need to modify randval file with your passphrase and userpass file with userpass value From ea1a9bdaf60923ae3bde8d8e0b835ba6678d6a71 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 18:55:54 +0300 Subject: [PATCH 1968/2705] Test --- iguana/exchanges/LP_nativeDEX.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c index 469b684d4..eaa9a9585 100644 --- a/iguana/exchanges/LP_nativeDEX.c +++ b/iguana/exchanges/LP_nativeDEX.c @@ -347,7 +347,8 @@ int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int if ( (height= jint(obj,"blocks")) > coin->longestchain ) { coin->longestchain = height; - printf(">>>>>>>>>> set %s longestchain %d (ref.%d [%d, %d])\n",coin->symbol,height,coin->firstrefht,coin->firstscanht,coin->lastscanht); + if ( coin->firstrefht != 0 ) + printf(">>>>>>>>>> set %s longestchain %d (ref.%d [%d, %d])\n",coin->symbol,height,coin->firstrefht,coin->firstscanht,coin->lastscanht); } else LP_mempoolscan(coin->symbol,zero); free_json(obj); } else printf("error getting info.%s\n",coin->symbol); From ca02953d19ad84ac6526ba1ea3f83c0ddc37088a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 2 Jul 2017 19:14:33 +0300 Subject: [PATCH 1969/2705] Test --- iguana/exchanges/README.md | 89 +++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/iguana/exchanges/README.md b/iguana/exchanges/README.md index d66036859..5b2257bf5 100644 --- a/iguana/exchanges/README.md +++ b/iguana/exchanges/README.md @@ -1,26 +1,75 @@ -You need to build iguana onetime from ~/SuperNET/iguana: - +DEPENDENCIES +First of all you are going to need to have the komodod daemon and the assetchains running. +Install dependency packages: +sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool libncurses5-dev unzip git python zlib1g-dev wget bsdmainutils automake libboost-all-dev libssl-dev libprotobuf-dev protobuf-compiler libqt4-dev libqrencode-dev libdb++-dev ntp ntpdate vim software-properties-common curl libcurl4-gnutls-dev cmake clang +Some Linux machines are now providing nanomsg package version 1.0. If it is available via package manager, you can install it from there. Else, you should use github repo of nanomsg and compile it yourself. +For Ubuntu 14.04 you need to install it yourself +cd /tmp +wget https://github.com/nanomsg/nanomsg/archive/1.0.0.tar.gz -O nanomsg-1.0.0.tar.gz +tar -xzvf nanomsg-1.0.0.tar.gz +cd nanomsg-1.0.0 +mkdir build +cd build +cmake .. -DCMAKE_INSTALL_PREFIX=/usr +cmake --build . +sudo cmake --build . --target install +sudo ldconfig +Or the following for 16.04 +git clone https://github.com/nanomsg/nanomsg +cd nanomsg +cmake . +make +sudo make install +sudo ldconfig +COMPILE LP NODE +To compile the BarterDEX you need to build iguana one time: +cd ~ +git clone https://github.com/jl777/SuperNET +cd SuperNET/iguana +git checkout dev ./m_LP - -Then launch it to run in background ../agents/iguana & - +IGUANA DAEMON STARTUP +Then launch the iguana daemon by executing: +../agents/iguana & Now iguana should be running and providing port 7778 API: 127.0.0.1:7778 page in the browser will show the API testpage, but for marketmaker these functions are not used very much. it is port 7779 that is used and the marketmaker program is what provides those functions. - -From ~/SuperNET/iguana/exchanges: - +BarterDEX EXCHANGE INSTALL +cd ~/SuperNET/iguana/exchanges ./install - -From ~/SuperNET/iguana/dexscripts: - -Now in the ~/SuperNET/iguana/dexscripts directory you will have example scripts that you can change without new git updates overwriting them. Of course, if a new update to a script is made and you dont run install again then you wont have the latest versions. All these scripts are expecting a userpass file, which contains the definition of the $userpass variable to authenticate API access. This avoids evil webpages that try to issue port 7779 calls to steal your money. The userpass variable is linked to each passphrase and that is defined in the randval file. Put your passphrase in that file. You can find templates for these two files in the iguana/exchanges dir. - -Next step is to actually start the marketmaker from ~/SuperNET/iguana/dexscripts. Use ./run for LP node and ./client for client mode - -At first you wont know the value of userpass. To find out, just run any API script. The first one will return all the required data, the "userpass" field is first and you can copy that value and put it into ~/SuperNET/iguana/dexscripts/userpass file. If you dont, all subsequent API calls will get authorization errors. - +Now, move to ~/SuperNET/iguana/dexscripts: +cd ~/SuperNET/iguana/dexscripts +Now in the ~/SuperNET/iguana/dexscripts directory you will have example scripts that you can change without new git updates overwriting them. These scripts will have example commands that you will need to customize to work with the coins you want to trade. Of course, if a new update to a script is made and you dont run install again then you wont have the latest versions. +For example: if you want to enable the JUMBLR coin, you need to edit the enable file: +nano ~SuperNET/iguana/dexscripts/enable +copy the default command and paste it below but with the coin edited to JUMBLR in this case: +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"enable\",\"coin\":\"JUMBLR\"}" +The same will happen for any other script in the dexscripts directory. You will need to edit the scripts to include or exclude the coins you want to trade. +IMPORTANT: All these scripts are expecting a userpass file, which contains the definition of the $userpass variable to authenticate API access. This avoids evil webpages that try to issue port 7779 calls to steal your money. At first you wont know the value of userpass. To find out, just run any API script. The first one will return all the required data, the "userpass" field is first and you can copy that value and put it into ~/SuperNET/iguana/dexscripts/userpass file. If you dont, all subsequent API calls will get authorization errors.The userpass variable is linked to each passphrase and that is defined in the randval file. Put your passphrase in that file. You can find templates for these two files in the iguana/exchanges dir. (you need to copy the edited version of these files to ~/SuperNET/iguana/dexscripts). +cd ~/SuperNET/iguana/dexscripts +./enable +(look for the userpass passphrase that will be generated and copy it) +Now you have to paste the passphrase in both userpass and randval files: +nano ./userpass +nano ./randval +( paste the passphrase generated into the files where it says: “”) +EXCHANGE CLIENT STARTUP +Next step is to actually start the marketmaker from ~/SuperNET/iguana/dexscripts. + cd ~/SuperNET/iguana/dexscripts + ./client (for client mode) or + ./run (for LPnode mode) Assuming you created the userpass file properly, you can now issue barterDEX api calls using all the scripts in the dexscripts dir. Please look at these scripts, they are simple curl invocations of a couple lines. Nothing scary and should be self explanatory. - The help script displays all the api endpoints you should need. You can customize any of the dexscripts for your desired usage, make sure you edit them with the right coins, as if you issue a script for BTC it will do it for BTC instead of the coin you wanted. These scripts wont read your mind, they just do what is in them - -In order to start trading, you need to fund your smartaddress (as listed on the first API call return) from the getcoins API call. To make sure you have utxo pairs for both the bob and alice usage, it is best to send utxo in triplets of X, 1.2 X and 0.01 X. So if X is 10, send 10, 12, and 0.1 coins using sendtoaddress to your smartaddress. After this, it should appear in the inventory. After you setprice, then it will appear in orderbooks with that coin in either the base or rel. +FUNDING SMARTADDRESS +In order to start trading, you need to fund your smartaddress (as listed on the first API call return) from the getcoins API call. +To see which is your smart address go to ~/SuperNET/iguana/dexscritps and execute: +./getcoins +To make sure you have utxo pairs for both the bob and alice usage, it is best to send utxo in triplets of X, 1.2 X and 0.01 X. So if X is 10, send 10, 12, and 0.1 coins using sendtoaddress to your smartaddress. This means you will have to send 3 different transactions to the same address with 3 different quantities +for example: +If i want to fund my komodo smartaddress with 100 komodo i need to first send a tx with 100kmd then another tx with 120kmd and a third tx with only 10kmd +After this, it should appear in the inventory. To see the inventory you need to execute: +./inv +SETTING PRICE + To set price you need to edit the ./setprice script in the dexscripts folder. This scripts contains a curl command that looks like this: +curl --url "http://127.0.0.1:7779" --data "{\"userpass\":\"$userpass\",\"method\":\"setprice\",\"base\":\"REVS\",\"rel\":\"KMD\",\"price\":1.234}" +In this command you should edit the coin (in this case is REVS) and then set the price per coin based in Komodo. In the command above we are setting a price of 1.23KMD per REVS. +After you setprice (./setprice), then it will appear in orderbooks with that coin in either the base or rel. From 88fc53e6b4075d9a2a0fe720c2cb01912daeacd0 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 2 Jul 2017 20:01:19 +0200 Subject: [PATCH 1970/2705] win cross libs --- nanomsg/bin/libnanomsg.dll | Bin 0 -> 396572 bytes nanomsg/bin/nanocat.exe | Bin 0 -> 136489 bytes nanomsg/include/nanomsg/bus.h | 39 + nanomsg/include/nanomsg/inproc.h | 37 + nanomsg/include/nanomsg/ipc.h | 42 + nanomsg/include/nanomsg/nn.h | 412 +++ nanomsg/include/nanomsg/pair.h | 39 + nanomsg/include/nanomsg/pipeline.h | 41 + nanomsg/include/nanomsg/pubsub.h | 43 + nanomsg/include/nanomsg/reqrep.h | 50 + nanomsg/include/nanomsg/survey.h | 46 + nanomsg/include/nanomsg/tcp.h | 39 + nanomsg/include/nanomsg/ws.h | 49 + nanomsg/lib/libnanomsg.dll | Bin 0 -> 14862 bytes nanomsg/lib/libnanomsg.dll.a | Bin 0 -> 14862 bytes nanomsg/lib/pkgconfig/nanomsg.pc | 13 + win_lib/bin/curl-config | 178 ++ win_lib/bin/curl.exe | Bin 0 -> 969892 bytes win_lib/bin/libcurl-4.dll | Bin 0 -> 563337 bytes win_lib/include/curl/curl.h | 2528 ++++++++++++++++ win_lib/include/curl/curlbuild.h | 198 ++ win_lib/include/curl/curlrules.h | 262 ++ win_lib/include/curl/curlver.h | 77 + win_lib/include/curl/easy.h | 102 + win_lib/include/curl/mprintf.h | 50 + win_lib/include/curl/multi.h | 439 +++ win_lib/include/curl/stdcheaders.h | 33 + win_lib/include/curl/typecheck-gcc.h | 623 ++++ win_lib/lib/libcurl.a | Bin 0 -> 575990 bytes win_lib/lib/libcurl.dll.a | Bin 0 -> 39898 bytes win_lib/lib/libcurl.la | 41 + win_lib/lib/pkgconfig/libcurl.pc | 39 + win_lib/share/aclocal/libcurl.m4 | 272 ++ win_lib/share/man/man1/curl-config.1 | 98 + win_lib/share/man/man1/curl.1 | 2668 +++++++++++++++++ .../share/man/man3/CURLINFO_ACTIVESOCKET.3 | 51 + .../share/man/man3/CURLINFO_APPCONNECT_TIME.3 | 47 + win_lib/share/man/man3/CURLINFO_CERTINFO.3 | 51 + .../share/man/man3/CURLINFO_CONDITION_UNMET.3 | 45 + .../share/man/man3/CURLINFO_CONNECT_TIME.3 | 44 + .../man3/CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 | 45 + .../man/man3/CURLINFO_CONTENT_LENGTH_UPLOAD.3 | 43 + .../share/man/man3/CURLINFO_CONTENT_TYPE.3 | 48 + win_lib/share/man/man3/CURLINFO_COOKIELIST.3 | 50 + .../share/man/man3/CURLINFO_EFFECTIVE_URL.3 | 48 + win_lib/share/man/man3/CURLINFO_FILETIME.3 | 49 + .../share/man/man3/CURLINFO_FTP_ENTRY_PATH.3 | 48 + win_lib/share/man/man3/CURLINFO_HEADER_SIZE.3 | 44 + .../share/man/man3/CURLINFO_HTTPAUTH_AVAIL.3 | 44 + .../man/man3/CURLINFO_HTTP_CONNECTCODE.3 | 44 + .../share/man/man3/CURLINFO_HTTP_VERSION.3 | 56 + win_lib/share/man/man3/CURLINFO_LASTSOCKET.3 | 53 + win_lib/share/man/man3/CURLINFO_LOCAL_IP.3 | 51 + win_lib/share/man/man3/CURLINFO_LOCAL_PORT.3 | 43 + .../share/man/man3/CURLINFO_NAMELOOKUP_TIME.3 | 44 + .../share/man/man3/CURLINFO_NUM_CONNECTS.3 | 46 + win_lib/share/man/man3/CURLINFO_OS_ERRNO.3 | 43 + .../man/man3/CURLINFO_PRETRANSFER_TIME.3 | 47 + win_lib/share/man/man3/CURLINFO_PRIMARY_IP.3 | 49 + .../share/man/man3/CURLINFO_PRIMARY_PORT.3 | 42 + win_lib/share/man/man3/CURLINFO_PRIVATE.3 | 45 + win_lib/share/man/man3/CURLINFO_PROTOCOL.3 | 55 + .../share/man/man3/CURLINFO_PROXYAUTH_AVAIL.3 | 44 + .../man3/CURLINFO_PROXY_SSL_VERIFYRESULT.3 | 43 + .../share/man/man3/CURLINFO_REDIRECT_COUNT.3 | 42 + .../share/man/man3/CURLINFO_REDIRECT_TIME.3 | 46 + .../share/man/man3/CURLINFO_REDIRECT_URL.3 | 45 + .../share/man/man3/CURLINFO_REQUEST_SIZE.3 | 45 + .../share/man/man3/CURLINFO_RESPONSE_CODE.3 | 60 + .../man/man3/CURLINFO_RTSP_CLIENT_CSEQ.3 | 42 + .../share/man/man3/CURLINFO_RTSP_CSEQ_RECV.3 | 44 + .../man/man3/CURLINFO_RTSP_SERVER_CSEQ.3 | 47 + .../share/man/man3/CURLINFO_RTSP_SESSION_ID.3 | 49 + win_lib/share/man/man3/CURLINFO_SCHEME.3 | 59 + .../share/man/man3/CURLINFO_SIZE_DOWNLOAD.3 | 45 + win_lib/share/man/man3/CURLINFO_SIZE_UPLOAD.3 | 42 + .../share/man/man3/CURLINFO_SPEED_DOWNLOAD.3 | 42 + .../share/man/man3/CURLINFO_SPEED_UPLOAD.3 | 42 + win_lib/share/man/man3/CURLINFO_SSL_ENGINES.3 | 47 + .../man/man3/CURLINFO_SSL_VERIFYRESULT.3 | 43 + .../man/man3/CURLINFO_STARTTRANSFER_TIME.3 | 46 + win_lib/share/man/man3/CURLINFO_TLS_SESSION.3 | 60 + win_lib/share/man/man3/CURLINFO_TLS_SSL_PTR.3 | 141 + win_lib/share/man/man3/CURLINFO_TOTAL_TIME.3 | 45 + .../man3/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.3 | 48 + .../CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.3 | 47 + win_lib/share/man/man3/CURLMOPT_MAXCONNECTS.3 | 62 + .../man/man3/CURLMOPT_MAX_HOST_CONNECTIONS.3 | 58 + .../man/man3/CURLMOPT_MAX_PIPELINE_LENGTH.3 | 51 + .../man/man3/CURLMOPT_MAX_TOTAL_CONNECTIONS.3 | 50 + win_lib/share/man/man3/CURLMOPT_PIPELINING.3 | 80 + .../man/man3/CURLMOPT_PIPELINING_SERVER_BL.3 | 60 + .../man/man3/CURLMOPT_PIPELINING_SITE_BL.3 | 56 + win_lib/share/man/man3/CURLMOPT_PUSHDATA.3 | 49 + .../share/man/man3/CURLMOPT_PUSHFUNCTION.3 | 133 + win_lib/share/man/man3/CURLMOPT_SOCKETDATA.3 | 49 + .../share/man/man3/CURLMOPT_SOCKETFUNCTION.3 | 74 + win_lib/share/man/man3/CURLMOPT_TIMERDATA.3 | 48 + .../share/man/man3/CURLMOPT_TIMERFUNCTION.3 | 101 + .../share/man/man3/CURLOPT_ACCEPTTIMEOUT_MS.3 | 54 + .../share/man/man3/CURLOPT_ACCEPT_ENCODING.3 | 85 + .../share/man/man3/CURLOPT_ADDRESS_SCOPE.3 | 44 + win_lib/share/man/man3/CURLOPT_APPEND.3 | 55 + win_lib/share/man/man3/CURLOPT_AUTOREFERER.3 | 45 + win_lib/share/man/man3/CURLOPT_BUFFERSIZE.3 | 50 + win_lib/share/man/man3/CURLOPT_CAINFO.3 | 63 + win_lib/share/man/man3/CURLOPT_CAPATH.3 | 53 + win_lib/share/man/man3/CURLOPT_CERTINFO.3 | 47 + .../man/man3/CURLOPT_CHUNK_BGN_FUNCTION.3 | 69 + win_lib/share/man/man3/CURLOPT_CHUNK_DATA.3 | 45 + .../man/man3/CURLOPT_CHUNK_END_FUNCTION.3 | 54 + .../share/man/man3/CURLOPT_CLOSESOCKETDATA.3 | 45 + .../man/man3/CURLOPT_CLOSESOCKETFUNCTION.3 | 56 + .../share/man/man3/CURLOPT_CONNECTTIMEOUT.3 | 60 + .../man/man3/CURLOPT_CONNECTTIMEOUT_MS.3 | 60 + win_lib/share/man/man3/CURLOPT_CONNECT_ONLY.3 | 52 + win_lib/share/man/man3/CURLOPT_CONNECT_TO.3 | 111 + .../man3/CURLOPT_CONV_FROM_NETWORK_FUNCTION.3 | 82 + .../man3/CURLOPT_CONV_FROM_UTF8_FUNCTION.3 | 81 + .../man3/CURLOPT_CONV_TO_NETWORK_FUNCTION.3 | 82 + win_lib/share/man/man3/CURLOPT_COOKIE.3 | 80 + win_lib/share/man/man3/CURLOPT_COOKIEFILE.3 | 67 + win_lib/share/man/man3/CURLOPT_COOKIEJAR.3 | 62 + win_lib/share/man/man3/CURLOPT_COOKIELIST.3 | 120 + .../share/man/man3/CURLOPT_COOKIESESSION.3 | 51 + .../share/man/man3/CURLOPT_COPYPOSTFIELDS.3 | 70 + win_lib/share/man/man3/CURLOPT_CRLF.3 | 47 + win_lib/share/man/man3/CURLOPT_CRLFILE.3 | 60 + .../share/man/man3/CURLOPT_CUSTOMREQUEST.3 | 95 + win_lib/share/man/man3/CURLOPT_DEBUGDATA.3 | 45 + .../share/man/man3/CURLOPT_DEBUGFUNCTION.3 | 187 ++ .../share/man/man3/CURLOPT_DEFAULT_PROTOCOL.3 | 79 + win_lib/share/man/man3/CURLOPT_DIRLISTONLY.3 | 61 + .../man/man3/CURLOPT_DNS_CACHE_TIMEOUT.3 | 56 + .../share/man/man3/CURLOPT_DNS_INTERFACE.3 | 48 + .../share/man/man3/CURLOPT_DNS_LOCAL_IP4.3 | 51 + .../share/man/man3/CURLOPT_DNS_LOCAL_IP6.3 | 51 + win_lib/share/man/man3/CURLOPT_DNS_SERVERS.3 | 56 + .../man/man3/CURLOPT_DNS_USE_GLOBAL_CACHE.3 | 50 + win_lib/share/man/man3/CURLOPT_EGDSOCKET.3 | 45 + win_lib/share/man/man3/CURLOPT_ERRORBUFFER.3 | 90 + .../man/man3/CURLOPT_EXPECT_100_TIMEOUT_MS.3 | 49 + win_lib/share/man/man3/CURLOPT_FAILONERROR.3 | 56 + win_lib/share/man/man3/CURLOPT_FILETIME.3 | 47 + win_lib/share/man/man3/CURLOPT_FNMATCH_DATA.3 | 46 + .../share/man/man3/CURLOPT_FNMATCH_FUNCTION.3 | 56 + .../share/man/man3/CURLOPT_FOLLOWLOCATION.3 | 80 + win_lib/share/man/man3/CURLOPT_FORBID_REUSE.3 | 50 + .../share/man/man3/CURLOPT_FRESH_CONNECT.3 | 52 + win_lib/share/man/man3/CURLOPT_FTPPORT.3 | 72 + win_lib/share/man/man3/CURLOPT_FTPSSLAUTH.3 | 53 + win_lib/share/man/man3/CURLOPT_FTP_ACCOUNT.3 | 46 + .../man3/CURLOPT_FTP_ALTERNATIVE_TO_USER.3 | 50 + .../man3/CURLOPT_FTP_CREATE_MISSING_DIRS.3 | 70 + .../share/man/man3/CURLOPT_FTP_FILEMETHOD.3 | 62 + .../man/man3/CURLOPT_FTP_RESPONSE_TIMEOUT.3 | 50 + .../share/man/man3/CURLOPT_FTP_SKIP_PASV_IP.3 | 52 + win_lib/share/man/man3/CURLOPT_FTP_SSL_CCC.3 | 54 + win_lib/share/man/man3/CURLOPT_FTP_USE_EPRT.3 | 47 + win_lib/share/man/man3/CURLOPT_FTP_USE_EPSV.3 | 48 + win_lib/share/man/man3/CURLOPT_FTP_USE_PRET.3 | 46 + .../man/man3/CURLOPT_GSSAPI_DELEGATION.3 | 48 + win_lib/share/man/man3/CURLOPT_HEADER.3 | 63 + win_lib/share/man/man3/CURLOPT_HEADERDATA.3 | 50 + .../share/man/man3/CURLOPT_HEADERFUNCTION.3 | 106 + win_lib/share/man/man3/CURLOPT_HEADEROPT.3 | 57 + .../share/man/man3/CURLOPT_HTTP200ALIASES.3 | 58 + win_lib/share/man/man3/CURLOPT_HTTPAUTH.3 | 116 + win_lib/share/man/man3/CURLOPT_HTTPGET.3 | 59 + win_lib/share/man/man3/CURLOPT_HTTPHEADER.3 | 110 + win_lib/share/man/man3/CURLOPT_HTTPPOST.3 | 79 + .../share/man/man3/CURLOPT_HTTPPROXYTUNNEL.3 | 54 + .../man/man3/CURLOPT_HTTP_CONTENT_DECODING.3 | 49 + .../man/man3/CURLOPT_HTTP_TRANSFER_DECODING.3 | 48 + win_lib/share/man/man3/CURLOPT_HTTP_VERSION.3 | 73 + .../man/man3/CURLOPT_IGNORE_CONTENT_LENGTH.3 | 67 + win_lib/share/man/man3/CURLOPT_INFILESIZE.3 | 71 + .../share/man/man3/CURLOPT_INFILESIZE_LARGE.3 | 72 + win_lib/share/man/man3/CURLOPT_INTERFACE.3 | 55 + .../share/man/man3/CURLOPT_INTERLEAVEDATA.3 | 45 + .../man/man3/CURLOPT_INTERLEAVEFUNCTION.3 | 68 + win_lib/share/man/man3/CURLOPT_IOCTLDATA.3 | 44 + .../share/man/man3/CURLOPT_IOCTLFUNCTION.3 | 76 + win_lib/share/man/man3/CURLOPT_IPRESOLVE.3 | 51 + win_lib/share/man/man3/CURLOPT_ISSUERCERT.3 | 58 + .../man/man3/CURLOPT_KEEP_SENDING_ON_ERROR.3 | 52 + win_lib/share/man/man3/CURLOPT_KEYPASSWD.3 | 48 + win_lib/share/man/man3/CURLOPT_KRBLEVEL.3 | 48 + win_lib/share/man/man3/CURLOPT_LOCALPORT.3 | 46 + .../share/man/man3/CURLOPT_LOCALPORTRANGE.3 | 50 + .../share/man/man3/CURLOPT_LOGIN_OPTIONS.3 | 53 + .../share/man/man3/CURLOPT_LOW_SPEED_LIMIT.3 | 46 + .../share/man/man3/CURLOPT_LOW_SPEED_TIME.3 | 45 + win_lib/share/man/man3/CURLOPT_MAIL_AUTH.3 | 58 + win_lib/share/man/man3/CURLOPT_MAIL_FROM.3 | 51 + win_lib/share/man/man3/CURLOPT_MAIL_RCPT.3 | 60 + win_lib/share/man/man3/CURLOPT_MAXCONNECTS.3 | 59 + win_lib/share/man/man3/CURLOPT_MAXFILESIZE.3 | 52 + .../man/man3/CURLOPT_MAXFILESIZE_LARGE.3 | 52 + win_lib/share/man/man3/CURLOPT_MAXREDIRS.3 | 64 + .../man/man3/CURLOPT_MAX_RECV_SPEED_LARGE.3 | 48 + .../man/man3/CURLOPT_MAX_SEND_SPEED_LARGE.3 | 50 + win_lib/share/man/man3/CURLOPT_NETRC.3 | 73 + win_lib/share/man/man3/CURLOPT_NETRC_FILE.3 | 48 + .../man/man3/CURLOPT_NEW_DIRECTORY_PERMS.3 | 48 + .../share/man/man3/CURLOPT_NEW_FILE_PERMS.3 | 48 + win_lib/share/man/man3/CURLOPT_NOBODY.3 | 59 + win_lib/share/man/man3/CURLOPT_NOPROGRESS.3 | 59 + win_lib/share/man/man3/CURLOPT_NOPROXY.3 | 51 + win_lib/share/man/man3/CURLOPT_NOSIGNAL.3 | 55 + .../share/man/man3/CURLOPT_OPENSOCKETDATA.3 | 44 + .../man/man3/CURLOPT_OPENSOCKETFUNCTION.3 | 90 + win_lib/share/man/man3/CURLOPT_PASSWORD.3 | 50 + win_lib/share/man/man3/CURLOPT_PATH_AS_IS.3 | 65 + .../share/man/man3/CURLOPT_PINNEDPUBLICKEY.3 | 119 + win_lib/share/man/man3/CURLOPT_PIPEWAIT.3 | 63 + win_lib/share/man/man3/CURLOPT_PORT.3 | 51 + win_lib/share/man/man3/CURLOPT_POST.3 | 77 + win_lib/share/man/man3/CURLOPT_POSTFIELDS.3 | 86 + .../share/man/man3/CURLOPT_POSTFIELDSIZE.3 | 62 + .../man/man3/CURLOPT_POSTFIELDSIZE_LARGE.3 | 64 + win_lib/share/man/man3/CURLOPT_POSTQUOTE.3 | 48 + win_lib/share/man/man3/CURLOPT_POSTREDIR.3 | 73 + win_lib/share/man/man3/CURLOPT_PREQUOTE.3 | 47 + win_lib/share/man/man3/CURLOPT_PRE_PROXY.3 | 69 + win_lib/share/man/man3/CURLOPT_PRIVATE.3 | 61 + win_lib/share/man/man3/CURLOPT_PROGRESSDATA.3 | 44 + .../share/man/man3/CURLOPT_PROGRESSFUNCTION.3 | 84 + win_lib/share/man/man3/CURLOPT_PROTOCOLS.3 | 93 + win_lib/share/man/man3/CURLOPT_PROXY.3 | 87 + win_lib/share/man/man3/CURLOPT_PROXYAUTH.3 | 55 + win_lib/share/man/man3/CURLOPT_PROXYHEADER.3 | 57 + .../share/man/man3/CURLOPT_PROXYPASSWORD.3 | 49 + win_lib/share/man/man3/CURLOPT_PROXYPORT.3 | 48 + win_lib/share/man/man3/CURLOPT_PROXYTYPE.3 | 54 + .../share/man/man3/CURLOPT_PROXYUSERNAME.3 | 53 + win_lib/share/man/man3/CURLOPT_PROXYUSERPWD.3 | 50 + win_lib/share/man/man3/CURLOPT_PROXY_CAINFO.3 | 70 + win_lib/share/man/man3/CURLOPT_PROXY_CAPATH.3 | 52 + .../share/man/man3/CURLOPT_PROXY_CRLFILE.3 | 63 + .../share/man/man3/CURLOPT_PROXY_KEYPASSWD.3 | 50 + .../man/man3/CURLOPT_PROXY_PINNEDPUBLICKEY.3 | 99 + .../man/man3/CURLOPT_PROXY_SERVICE_NAME.3 | 46 + .../share/man/man3/CURLOPT_PROXY_SSLCERT.3 | 58 + .../man/man3/CURLOPT_PROXY_SSLCERTTYPE.3 | 52 + win_lib/share/man/man3/CURLOPT_PROXY_SSLKEY.3 | 54 + .../share/man/man3/CURLOPT_PROXY_SSLKEYTYPE.3 | 46 + .../share/man/man3/CURLOPT_PROXY_SSLVERSION.3 | 74 + .../man/man3/CURLOPT_PROXY_SSL_CIPHER_LIST.3 | 68 + .../man/man3/CURLOPT_PROXY_SSL_OPTIONS.3 | 61 + .../man/man3/CURLOPT_PROXY_SSL_VERIFYHOST.3 | 82 + .../man/man3/CURLOPT_PROXY_SSL_VERIFYPEER.3 | 89 + .../man/man3/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 | 48 + .../man/man3/CURLOPT_PROXY_TLSAUTH_TYPE.3 | 56 + .../man/man3/CURLOPT_PROXY_TLSAUTH_USERNAME.3 | 48 + .../man/man3/CURLOPT_PROXY_TRANSFER_MODE.3 | 48 + win_lib/share/man/man3/CURLOPT_PUT.3 | 48 + win_lib/share/man/man3/CURLOPT_QUOTE.3 | 89 + win_lib/share/man/man3/CURLOPT_RANDOM_FILE.3 | 45 + win_lib/share/man/man3/CURLOPT_RANGE.3 | 70 + win_lib/share/man/man3/CURLOPT_READDATA.3 | 64 + win_lib/share/man/man3/CURLOPT_READFUNCTION.3 | 79 + .../share/man/man3/CURLOPT_REDIR_PROTOCOLS.3 | 100 + win_lib/share/man/man3/CURLOPT_REFERER.3 | 57 + win_lib/share/man/man3/CURLOPT_RESOLVE.3 | 86 + win_lib/share/man/man3/CURLOPT_RESUME_FROM.3 | 72 + .../man/man3/CURLOPT_RESUME_FROM_LARGE.3 | 74 + .../share/man/man3/CURLOPT_RTSP_CLIENT_CSEQ.3 | 45 + win_lib/share/man/man3/CURLOPT_RTSP_REQUEST.3 | 101 + .../share/man/man3/CURLOPT_RTSP_SERVER_CSEQ.3 | 45 + .../share/man/man3/CURLOPT_RTSP_SESSION_ID.3 | 49 + .../share/man/man3/CURLOPT_RTSP_STREAM_URI.3 | 53 + .../share/man/man3/CURLOPT_RTSP_TRANSPORT.3 | 49 + win_lib/share/man/man3/CURLOPT_SASL_IR.3 | 56 + win_lib/share/man/man3/CURLOPT_SEEKDATA.3 | 43 + win_lib/share/man/man3/CURLOPT_SEEKFUNCTION.3 | 76 + win_lib/share/man/man3/CURLOPT_SERVICE_NAME.3 | 47 + win_lib/share/man/man3/CURLOPT_SHARE.3 | 59 + win_lib/share/man/man3/CURLOPT_SOCKOPTDATA.3 | 44 + .../share/man/man3/CURLOPT_SOCKOPTFUNCTION.3 | 88 + .../man/man3/CURLOPT_SOCKS5_GSSAPI_NEC.3 | 47 + .../man/man3/CURLOPT_SOCKS5_GSSAPI_SERVICE.3 | 48 + .../share/man/man3/CURLOPT_SSH_AUTH_TYPES.3 | 50 + .../man3/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 | 48 + win_lib/share/man/man3/CURLOPT_SSH_KEYDATA.3 | 44 + .../share/man/man3/CURLOPT_SSH_KEYFUNCTION.3 | 105 + .../share/man/man3/CURLOPT_SSH_KNOWNHOSTS.3 | 49 + .../man/man3/CURLOPT_SSH_PRIVATE_KEYFILE.3 | 51 + .../man/man3/CURLOPT_SSH_PUBLIC_KEYFILE.3 | 53 + win_lib/share/man/man3/CURLOPT_SSLCERT.3 | 55 + win_lib/share/man/man3/CURLOPT_SSLCERTTYPE.3 | 48 + win_lib/share/man/man3/CURLOPT_SSLENGINE.3 | 55 + .../man/man3/CURLOPT_SSLENGINE_DEFAULT.3 | 54 + win_lib/share/man/man3/CURLOPT_SSLKEY.3 | 50 + win_lib/share/man/man3/CURLOPT_SSLKEYTYPE.3 | 50 + win_lib/share/man/man3/CURLOPT_SSLVERSION.3 | 80 + .../share/man/man3/CURLOPT_SSL_CIPHER_LIST.3 | 65 + win_lib/share/man/man3/CURLOPT_SSL_CTX_DATA.3 | 46 + .../share/man/man3/CURLOPT_SSL_CTX_FUNCTION.3 | 141 + .../share/man/man3/CURLOPT_SSL_ENABLE_ALPN.3 | 45 + .../share/man/man3/CURLOPT_SSL_ENABLE_NPN.3 | 45 + .../share/man/man3/CURLOPT_SSL_FALSESTART.3 | 48 + win_lib/share/man/man3/CURLOPT_SSL_OPTIONS.3 | 63 + .../man/man3/CURLOPT_SSL_SESSIONID_CACHE.3 | 49 + .../share/man/man3/CURLOPT_SSL_VERIFYHOST.3 | 87 + .../share/man/man3/CURLOPT_SSL_VERIFYPEER.3 | 81 + .../share/man/man3/CURLOPT_SSL_VERIFYSTATUS.3 | 53 + win_lib/share/man/man3/CURLOPT_STDERR.3 | 54 + .../share/man/man3/CURLOPT_STREAM_DEPENDS.3 | 56 + .../share/man/man3/CURLOPT_STREAM_DEPENDS_E.3 | 59 + .../share/man/man3/CURLOPT_STREAM_WEIGHT.3 | 63 + win_lib/share/man/man3/CURLOPT_TCP_FASTOPEN.3 | 47 + .../share/man/man3/CURLOPT_TCP_KEEPALIVE.3 | 63 + win_lib/share/man/man3/CURLOPT_TCP_KEEPIDLE.3 | 61 + .../share/man/man3/CURLOPT_TCP_KEEPINTVL.3 | 59 + win_lib/share/man/man3/CURLOPT_TCP_NODELAY.3 | 56 + .../share/man/man3/CURLOPT_TELNETOPTIONS.3 | 47 + win_lib/share/man/man3/CURLOPT_TFTP_BLKSIZE.3 | 48 + .../share/man/man3/CURLOPT_TFTP_NO_OPTIONS.3 | 71 + .../share/man/man3/CURLOPT_TIMECONDITION.3 | 65 + win_lib/share/man/man3/CURLOPT_TIMEOUT.3 | 70 + win_lib/share/man/man3/CURLOPT_TIMEOUT_MS.3 | 74 + win_lib/share/man/man3/CURLOPT_TIMEVALUE.3 | 59 + .../share/man/man3/CURLOPT_TLSAUTH_PASSWORD.3 | 47 + win_lib/share/man/man3/CURLOPT_TLSAUTH_TYPE.3 | 52 + .../share/man/man3/CURLOPT_TLSAUTH_USERNAME.3 | 47 + win_lib/share/man/man3/CURLOPT_TRANSFERTEXT.3 | 51 + .../man/man3/CURLOPT_TRANSFER_ENCODING.3 | 54 + .../share/man/man3/CURLOPT_UNIX_SOCKET_PATH.3 | 78 + .../man/man3/CURLOPT_UNRESTRICTED_AUTH.3 | 48 + win_lib/share/man/man3/CURLOPT_UPLOAD.3 | 78 + win_lib/share/man/man3/CURLOPT_URL.3 | 336 +++ win_lib/share/man/man3/CURLOPT_USERAGENT.3 | 56 + win_lib/share/man/man3/CURLOPT_USERNAME.3 | 71 + win_lib/share/man/man3/CURLOPT_USERPWD.3 | 76 + win_lib/share/man/man3/CURLOPT_USE_SSL.3 | 69 + win_lib/share/man/man3/CURLOPT_VERBOSE.3 | 63 + .../share/man/man3/CURLOPT_WILDCARDMATCH.3 | 87 + win_lib/share/man/man3/CURLOPT_WRITEDATA.3 | 60 + .../share/man/man3/CURLOPT_WRITEFUNCTION.3 | 81 + win_lib/share/man/man3/CURLOPT_XFERINFODATA.3 | 46 + .../share/man/man3/CURLOPT_XFERINFOFUNCTION.3 | 81 + .../share/man/man3/CURLOPT_XOAUTH2_BEARER.3 | 49 + win_lib/share/man/man3/curl_easy_cleanup.3 | 68 + win_lib/share/man/man3/curl_easy_duphandle.3 | 52 + win_lib/share/man/man3/curl_easy_escape.3 | 58 + win_lib/share/man/man3/curl_easy_getinfo.3 | 232 ++ win_lib/share/man/man3/curl_easy_init.3 | 59 + win_lib/share/man/man3/curl_easy_pause.3 | 103 + win_lib/share/man/man3/curl_easy_perform.3 | 75 + win_lib/share/man/man3/curl_easy_recv.3 | 84 + win_lib/share/man/man3/curl_easy_reset.3 | 44 + win_lib/share/man/man3/curl_easy_send.3 | 75 + win_lib/share/man/man3/curl_easy_setopt.3 | 588 ++++ win_lib/share/man/man3/curl_easy_strerror.3 | 40 + win_lib/share/man/man3/curl_easy_unescape.3 | 54 + win_lib/share/man/man3/curl_escape.3 | 48 + win_lib/share/man/man3/curl_formadd.3 | 258 ++ win_lib/share/man/man3/curl_formfree.3 | 44 + win_lib/share/man/man3/curl_formget.3 | 70 + win_lib/share/man/man3/curl_free.3 | 35 + win_lib/share/man/man3/curl_getdate.3 | 108 + win_lib/share/man/man3/curl_getenv.3 | 49 + win_lib/share/man/man3/curl_global_cleanup.3 | 55 + win_lib/share/man/man3/curl_global_init.3 | 97 + win_lib/share/man/man3/curl_global_init_mem.3 | 65 + win_lib/share/man/man3/curl_mprintf.3 | 103 + .../share/man/man3/curl_multi_add_handle.3 | 71 + win_lib/share/man/man3/curl_multi_assign.3 | 63 + win_lib/share/man/man3/curl_multi_cleanup.3 | 47 + win_lib/share/man/man3/curl_multi_fdset.3 | 83 + win_lib/share/man/man3/curl_multi_info_read.3 | 94 + win_lib/share/man/man3/curl_multi_init.3 | 40 + win_lib/share/man/man3/curl_multi_perform.3 | 128 + .../share/man/man3/curl_multi_remove_handle.3 | 44 + win_lib/share/man/man3/curl_multi_setopt.3 | 78 + win_lib/share/man/man3/curl_multi_socket.3 | 158 + .../share/man/man3/curl_multi_socket_action.3 | 156 + .../share/man/man3/curl_multi_socket_all.3 | 1 + win_lib/share/man/man3/curl_multi_strerror.3 | 37 + win_lib/share/man/man3/curl_multi_timeout.3 | 79 + win_lib/share/man/man3/curl_multi_wait.3 | 122 + win_lib/share/man/man3/curl_share_cleanup.3 | 40 + win_lib/share/man/man3/curl_share_init.3 | 44 + win_lib/share/man/man3/curl_share_setopt.3 | 86 + win_lib/share/man/man3/curl_share_strerror.3 | 37 + win_lib/share/man/man3/curl_slist_append.3 | 60 + win_lib/share/man/man3/curl_slist_free_all.3 | 37 + win_lib/share/man/man3/curl_strequal.3 | 51 + win_lib/share/man/man3/curl_unescape.3 | 48 + win_lib/share/man/man3/curl_version.3 | 39 + win_lib/share/man/man3/curl_version_info.3 | 176 ++ win_lib/share/man/man3/libcurl-easy.3 | 58 + win_lib/share/man/man3/libcurl-errors.3 | 308 ++ win_lib/share/man/man3/libcurl-multi.3 | 183 ++ win_lib/share/man/man3/libcurl-share.3 | 66 + win_lib/share/man/man3/libcurl-symbols.3 | 1732 +++++++++++ win_lib/share/man/man3/libcurl-thread.3 | 105 + win_lib/share/man/man3/libcurl-tutorial.3 | 1366 +++++++++ win_lib/share/man/man3/libcurl.3 | 223 ++ 400 files changed, 35430 insertions(+) create mode 100755 nanomsg/bin/libnanomsg.dll create mode 100755 nanomsg/bin/nanocat.exe create mode 100644 nanomsg/include/nanomsg/bus.h create mode 100644 nanomsg/include/nanomsg/inproc.h create mode 100644 nanomsg/include/nanomsg/ipc.h create mode 100644 nanomsg/include/nanomsg/nn.h create mode 100644 nanomsg/include/nanomsg/pair.h create mode 100644 nanomsg/include/nanomsg/pipeline.h create mode 100644 nanomsg/include/nanomsg/pubsub.h create mode 100644 nanomsg/include/nanomsg/reqrep.h create mode 100644 nanomsg/include/nanomsg/survey.h create mode 100644 nanomsg/include/nanomsg/tcp.h create mode 100644 nanomsg/include/nanomsg/ws.h create mode 100644 nanomsg/lib/libnanomsg.dll create mode 100644 nanomsg/lib/libnanomsg.dll.a create mode 100644 nanomsg/lib/pkgconfig/nanomsg.pc create mode 100755 win_lib/bin/curl-config create mode 100755 win_lib/bin/curl.exe create mode 100755 win_lib/bin/libcurl-4.dll create mode 100644 win_lib/include/curl/curl.h create mode 100644 win_lib/include/curl/curlbuild.h create mode 100644 win_lib/include/curl/curlrules.h create mode 100644 win_lib/include/curl/curlver.h create mode 100644 win_lib/include/curl/easy.h create mode 100644 win_lib/include/curl/mprintf.h create mode 100644 win_lib/include/curl/multi.h create mode 100644 win_lib/include/curl/stdcheaders.h create mode 100644 win_lib/include/curl/typecheck-gcc.h create mode 100644 win_lib/lib/libcurl.a create mode 100755 win_lib/lib/libcurl.dll.a create mode 100755 win_lib/lib/libcurl.la create mode 100644 win_lib/lib/pkgconfig/libcurl.pc create mode 100644 win_lib/share/aclocal/libcurl.m4 create mode 100644 win_lib/share/man/man1/curl-config.1 create mode 100644 win_lib/share/man/man1/curl.1 create mode 100644 win_lib/share/man/man3/CURLINFO_ACTIVESOCKET.3 create mode 100644 win_lib/share/man/man3/CURLINFO_APPCONNECT_TIME.3 create mode 100644 win_lib/share/man/man3/CURLINFO_CERTINFO.3 create mode 100644 win_lib/share/man/man3/CURLINFO_CONDITION_UNMET.3 create mode 100644 win_lib/share/man/man3/CURLINFO_CONNECT_TIME.3 create mode 100644 win_lib/share/man/man3/CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 create mode 100644 win_lib/share/man/man3/CURLINFO_CONTENT_LENGTH_UPLOAD.3 create mode 100644 win_lib/share/man/man3/CURLINFO_CONTENT_TYPE.3 create mode 100644 win_lib/share/man/man3/CURLINFO_COOKIELIST.3 create mode 100644 win_lib/share/man/man3/CURLINFO_EFFECTIVE_URL.3 create mode 100644 win_lib/share/man/man3/CURLINFO_FILETIME.3 create mode 100644 win_lib/share/man/man3/CURLINFO_FTP_ENTRY_PATH.3 create mode 100644 win_lib/share/man/man3/CURLINFO_HEADER_SIZE.3 create mode 100644 win_lib/share/man/man3/CURLINFO_HTTPAUTH_AVAIL.3 create mode 100644 win_lib/share/man/man3/CURLINFO_HTTP_CONNECTCODE.3 create mode 100644 win_lib/share/man/man3/CURLINFO_HTTP_VERSION.3 create mode 100644 win_lib/share/man/man3/CURLINFO_LASTSOCKET.3 create mode 100644 win_lib/share/man/man3/CURLINFO_LOCAL_IP.3 create mode 100644 win_lib/share/man/man3/CURLINFO_LOCAL_PORT.3 create mode 100644 win_lib/share/man/man3/CURLINFO_NAMELOOKUP_TIME.3 create mode 100644 win_lib/share/man/man3/CURLINFO_NUM_CONNECTS.3 create mode 100644 win_lib/share/man/man3/CURLINFO_OS_ERRNO.3 create mode 100644 win_lib/share/man/man3/CURLINFO_PRETRANSFER_TIME.3 create mode 100644 win_lib/share/man/man3/CURLINFO_PRIMARY_IP.3 create mode 100644 win_lib/share/man/man3/CURLINFO_PRIMARY_PORT.3 create mode 100644 win_lib/share/man/man3/CURLINFO_PRIVATE.3 create mode 100644 win_lib/share/man/man3/CURLINFO_PROTOCOL.3 create mode 100644 win_lib/share/man/man3/CURLINFO_PROXYAUTH_AVAIL.3 create mode 100644 win_lib/share/man/man3/CURLINFO_PROXY_SSL_VERIFYRESULT.3 create mode 100644 win_lib/share/man/man3/CURLINFO_REDIRECT_COUNT.3 create mode 100644 win_lib/share/man/man3/CURLINFO_REDIRECT_TIME.3 create mode 100644 win_lib/share/man/man3/CURLINFO_REDIRECT_URL.3 create mode 100644 win_lib/share/man/man3/CURLINFO_REQUEST_SIZE.3 create mode 100644 win_lib/share/man/man3/CURLINFO_RESPONSE_CODE.3 create mode 100644 win_lib/share/man/man3/CURLINFO_RTSP_CLIENT_CSEQ.3 create mode 100644 win_lib/share/man/man3/CURLINFO_RTSP_CSEQ_RECV.3 create mode 100644 win_lib/share/man/man3/CURLINFO_RTSP_SERVER_CSEQ.3 create mode 100644 win_lib/share/man/man3/CURLINFO_RTSP_SESSION_ID.3 create mode 100644 win_lib/share/man/man3/CURLINFO_SCHEME.3 create mode 100644 win_lib/share/man/man3/CURLINFO_SIZE_DOWNLOAD.3 create mode 100644 win_lib/share/man/man3/CURLINFO_SIZE_UPLOAD.3 create mode 100644 win_lib/share/man/man3/CURLINFO_SPEED_DOWNLOAD.3 create mode 100644 win_lib/share/man/man3/CURLINFO_SPEED_UPLOAD.3 create mode 100644 win_lib/share/man/man3/CURLINFO_SSL_ENGINES.3 create mode 100644 win_lib/share/man/man3/CURLINFO_SSL_VERIFYRESULT.3 create mode 100644 win_lib/share/man/man3/CURLINFO_STARTTRANSFER_TIME.3 create mode 100644 win_lib/share/man/man3/CURLINFO_TLS_SESSION.3 create mode 100644 win_lib/share/man/man3/CURLINFO_TLS_SSL_PTR.3 create mode 100644 win_lib/share/man/man3/CURLINFO_TOTAL_TIME.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_MAXCONNECTS.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_MAX_HOST_CONNECTIONS.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_MAX_PIPELINE_LENGTH.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_MAX_TOTAL_CONNECTIONS.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_PIPELINING.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_PIPELINING_SERVER_BL.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_PIPELINING_SITE_BL.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_PUSHDATA.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_PUSHFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_SOCKETDATA.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_SOCKETFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_TIMERDATA.3 create mode 100644 win_lib/share/man/man3/CURLMOPT_TIMERFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_ACCEPTTIMEOUT_MS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_ACCEPT_ENCODING.3 create mode 100644 win_lib/share/man/man3/CURLOPT_ADDRESS_SCOPE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_APPEND.3 create mode 100644 win_lib/share/man/man3/CURLOPT_AUTOREFERER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_BUFFERSIZE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CAINFO.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CAPATH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CERTINFO.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CHUNK_BGN_FUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CHUNK_DATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CHUNK_END_FUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CLOSESOCKETDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CLOSESOCKETFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CONNECTTIMEOUT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CONNECTTIMEOUT_MS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CONNECT_ONLY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CONNECT_TO.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CONV_FROM_NETWORK_FUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CONV_FROM_UTF8_FUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CONV_TO_NETWORK_FUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_COOKIE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_COOKIEFILE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_COOKIEJAR.3 create mode 100644 win_lib/share/man/man3/CURLOPT_COOKIELIST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_COOKIESESSION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_COPYPOSTFIELDS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CRLF.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CRLFILE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_CUSTOMREQUEST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DEBUGDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DEBUGFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DEFAULT_PROTOCOL.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DIRLISTONLY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DNS_CACHE_TIMEOUT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DNS_INTERFACE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DNS_LOCAL_IP4.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DNS_LOCAL_IP6.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DNS_SERVERS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_DNS_USE_GLOBAL_CACHE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_EGDSOCKET.3 create mode 100644 win_lib/share/man/man3/CURLOPT_ERRORBUFFER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_EXPECT_100_TIMEOUT_MS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FAILONERROR.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FILETIME.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FNMATCH_DATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FNMATCH_FUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FOLLOWLOCATION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FORBID_REUSE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FRESH_CONNECT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTPPORT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTPSSLAUTH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_ACCOUNT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_ALTERNATIVE_TO_USER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_CREATE_MISSING_DIRS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_FILEMETHOD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_RESPONSE_TIMEOUT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_SKIP_PASV_IP.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_SSL_CCC.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_USE_EPRT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_USE_EPSV.3 create mode 100644 win_lib/share/man/man3/CURLOPT_FTP_USE_PRET.3 create mode 100644 win_lib/share/man/man3/CURLOPT_GSSAPI_DELEGATION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HEADER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HEADERDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HEADERFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HEADEROPT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTP200ALIASES.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTPAUTH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTPGET.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTPHEADER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTPPOST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTPPROXYTUNNEL.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTP_CONTENT_DECODING.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTP_TRANSFER_DECODING.3 create mode 100644 win_lib/share/man/man3/CURLOPT_HTTP_VERSION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_IGNORE_CONTENT_LENGTH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_INFILESIZE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_INFILESIZE_LARGE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_INTERFACE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_INTERLEAVEDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_INTERLEAVEFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_IOCTLDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_IOCTLFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_IPRESOLVE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_ISSUERCERT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_KEEP_SENDING_ON_ERROR.3 create mode 100644 win_lib/share/man/man3/CURLOPT_KEYPASSWD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_KRBLEVEL.3 create mode 100644 win_lib/share/man/man3/CURLOPT_LOCALPORT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_LOCALPORTRANGE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_LOGIN_OPTIONS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_LOW_SPEED_LIMIT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_LOW_SPEED_TIME.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAIL_AUTH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAIL_FROM.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAIL_RCPT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAXCONNECTS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAXFILESIZE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAXFILESIZE_LARGE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAXREDIRS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAX_RECV_SPEED_LARGE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_MAX_SEND_SPEED_LARGE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_NETRC.3 create mode 100644 win_lib/share/man/man3/CURLOPT_NETRC_FILE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_NEW_DIRECTORY_PERMS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_NEW_FILE_PERMS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_NOBODY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_NOPROGRESS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_NOPROXY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_NOSIGNAL.3 create mode 100644 win_lib/share/man/man3/CURLOPT_OPENSOCKETDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_OPENSOCKETFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PASSWORD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PATH_AS_IS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PINNEDPUBLICKEY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PIPEWAIT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PORT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_POST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_POSTFIELDS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_POSTFIELDSIZE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_POSTFIELDSIZE_LARGE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_POSTQUOTE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_POSTREDIR.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PREQUOTE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PRE_PROXY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PRIVATE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROGRESSDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROGRESSFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROTOCOLS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXYAUTH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXYHEADER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXYPASSWORD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXYPORT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXYTYPE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXYUSERNAME.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXYUSERPWD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_CAINFO.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_CAPATH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_CRLFILE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_KEYPASSWD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_PINNEDPUBLICKEY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SERVICE_NAME.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSLCERT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSLCERTTYPE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSLKEY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSLKEYTYPE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSLVERSION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSL_CIPHER_LIST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSL_OPTIONS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSL_VERIFYHOST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_SSL_VERIFYPEER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_TLSAUTH_PASSWORD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_TLSAUTH_TYPE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_TLSAUTH_USERNAME.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PROXY_TRANSFER_MODE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_PUT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_QUOTE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RANDOM_FILE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RANGE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_READDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_READFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_REDIR_PROTOCOLS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_REFERER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RESOLVE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RESUME_FROM.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RESUME_FROM_LARGE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RTSP_CLIENT_CSEQ.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RTSP_REQUEST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RTSP_SERVER_CSEQ.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RTSP_SESSION_ID.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RTSP_STREAM_URI.3 create mode 100644 win_lib/share/man/man3/CURLOPT_RTSP_TRANSPORT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SASL_IR.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SEEKDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SEEKFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SERVICE_NAME.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SHARE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SOCKOPTDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SOCKOPTFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SOCKS5_GSSAPI_NEC.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SOCKS5_GSSAPI_SERVICE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSH_AUTH_TYPES.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSH_KEYDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSH_KEYFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSH_KNOWNHOSTS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSH_PRIVATE_KEYFILE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSH_PUBLIC_KEYFILE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSLCERT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSLCERTTYPE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSLENGINE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSLENGINE_DEFAULT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSLKEY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSLKEYTYPE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSLVERSION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_CIPHER_LIST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_CTX_DATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_CTX_FUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_ENABLE_ALPN.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_ENABLE_NPN.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_FALSESTART.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_OPTIONS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_SESSIONID_CACHE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_VERIFYHOST.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_VERIFYPEER.3 create mode 100644 win_lib/share/man/man3/CURLOPT_SSL_VERIFYSTATUS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_STDERR.3 create mode 100644 win_lib/share/man/man3/CURLOPT_STREAM_DEPENDS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_STREAM_DEPENDS_E.3 create mode 100644 win_lib/share/man/man3/CURLOPT_STREAM_WEIGHT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TCP_FASTOPEN.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TCP_KEEPALIVE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TCP_KEEPIDLE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TCP_KEEPINTVL.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TCP_NODELAY.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TELNETOPTIONS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TFTP_BLKSIZE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TFTP_NO_OPTIONS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TIMECONDITION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TIMEOUT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TIMEOUT_MS.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TIMEVALUE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TLSAUTH_PASSWORD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TLSAUTH_TYPE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TLSAUTH_USERNAME.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TRANSFERTEXT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_TRANSFER_ENCODING.3 create mode 100644 win_lib/share/man/man3/CURLOPT_UNIX_SOCKET_PATH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_UNRESTRICTED_AUTH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_UPLOAD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_URL.3 create mode 100644 win_lib/share/man/man3/CURLOPT_USERAGENT.3 create mode 100644 win_lib/share/man/man3/CURLOPT_USERNAME.3 create mode 100644 win_lib/share/man/man3/CURLOPT_USERPWD.3 create mode 100644 win_lib/share/man/man3/CURLOPT_USE_SSL.3 create mode 100644 win_lib/share/man/man3/CURLOPT_VERBOSE.3 create mode 100644 win_lib/share/man/man3/CURLOPT_WILDCARDMATCH.3 create mode 100644 win_lib/share/man/man3/CURLOPT_WRITEDATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_WRITEFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_XFERINFODATA.3 create mode 100644 win_lib/share/man/man3/CURLOPT_XFERINFOFUNCTION.3 create mode 100644 win_lib/share/man/man3/CURLOPT_XOAUTH2_BEARER.3 create mode 100644 win_lib/share/man/man3/curl_easy_cleanup.3 create mode 100644 win_lib/share/man/man3/curl_easy_duphandle.3 create mode 100644 win_lib/share/man/man3/curl_easy_escape.3 create mode 100644 win_lib/share/man/man3/curl_easy_getinfo.3 create mode 100644 win_lib/share/man/man3/curl_easy_init.3 create mode 100644 win_lib/share/man/man3/curl_easy_pause.3 create mode 100644 win_lib/share/man/man3/curl_easy_perform.3 create mode 100644 win_lib/share/man/man3/curl_easy_recv.3 create mode 100644 win_lib/share/man/man3/curl_easy_reset.3 create mode 100644 win_lib/share/man/man3/curl_easy_send.3 create mode 100644 win_lib/share/man/man3/curl_easy_setopt.3 create mode 100644 win_lib/share/man/man3/curl_easy_strerror.3 create mode 100644 win_lib/share/man/man3/curl_easy_unescape.3 create mode 100644 win_lib/share/man/man3/curl_escape.3 create mode 100644 win_lib/share/man/man3/curl_formadd.3 create mode 100644 win_lib/share/man/man3/curl_formfree.3 create mode 100644 win_lib/share/man/man3/curl_formget.3 create mode 100644 win_lib/share/man/man3/curl_free.3 create mode 100644 win_lib/share/man/man3/curl_getdate.3 create mode 100644 win_lib/share/man/man3/curl_getenv.3 create mode 100644 win_lib/share/man/man3/curl_global_cleanup.3 create mode 100644 win_lib/share/man/man3/curl_global_init.3 create mode 100644 win_lib/share/man/man3/curl_global_init_mem.3 create mode 100644 win_lib/share/man/man3/curl_mprintf.3 create mode 100644 win_lib/share/man/man3/curl_multi_add_handle.3 create mode 100644 win_lib/share/man/man3/curl_multi_assign.3 create mode 100644 win_lib/share/man/man3/curl_multi_cleanup.3 create mode 100644 win_lib/share/man/man3/curl_multi_fdset.3 create mode 100644 win_lib/share/man/man3/curl_multi_info_read.3 create mode 100644 win_lib/share/man/man3/curl_multi_init.3 create mode 100644 win_lib/share/man/man3/curl_multi_perform.3 create mode 100644 win_lib/share/man/man3/curl_multi_remove_handle.3 create mode 100644 win_lib/share/man/man3/curl_multi_setopt.3 create mode 100644 win_lib/share/man/man3/curl_multi_socket.3 create mode 100644 win_lib/share/man/man3/curl_multi_socket_action.3 create mode 100644 win_lib/share/man/man3/curl_multi_socket_all.3 create mode 100644 win_lib/share/man/man3/curl_multi_strerror.3 create mode 100644 win_lib/share/man/man3/curl_multi_timeout.3 create mode 100644 win_lib/share/man/man3/curl_multi_wait.3 create mode 100644 win_lib/share/man/man3/curl_share_cleanup.3 create mode 100644 win_lib/share/man/man3/curl_share_init.3 create mode 100644 win_lib/share/man/man3/curl_share_setopt.3 create mode 100644 win_lib/share/man/man3/curl_share_strerror.3 create mode 100644 win_lib/share/man/man3/curl_slist_append.3 create mode 100644 win_lib/share/man/man3/curl_slist_free_all.3 create mode 100644 win_lib/share/man/man3/curl_strequal.3 create mode 100644 win_lib/share/man/man3/curl_unescape.3 create mode 100644 win_lib/share/man/man3/curl_version.3 create mode 100644 win_lib/share/man/man3/curl_version_info.3 create mode 100644 win_lib/share/man/man3/libcurl-easy.3 create mode 100644 win_lib/share/man/man3/libcurl-errors.3 create mode 100644 win_lib/share/man/man3/libcurl-multi.3 create mode 100644 win_lib/share/man/man3/libcurl-share.3 create mode 100644 win_lib/share/man/man3/libcurl-symbols.3 create mode 100644 win_lib/share/man/man3/libcurl-thread.3 create mode 100644 win_lib/share/man/man3/libcurl-tutorial.3 create mode 100644 win_lib/share/man/man3/libcurl.3 diff --git a/nanomsg/bin/libnanomsg.dll b/nanomsg/bin/libnanomsg.dll new file mode 100755 index 0000000000000000000000000000000000000000..4a7fe2768b06e39284893c23437fef414f048d84 GIT binary patch literal 396572 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 z z08aN_-@0z-a-nF*`=vSw{{?Gz6^Mfo$IH`4Z$OKyC^lzXo#D4JOU&KxTP}s#`t-GUi4_6O<;E9?EbGic<2v z@xNPR>$>GlUw>|fL{XI`T$JB9*ot=?;l*w{Xp~5PAxI5 zQOXyk@tW641xeHzwL56PklyfhDDBs!ZQwL3rZoy*)u?Z%OFX3PNOC$6=|wVBF3$i` zf9Jt@KLs?8+@&>v9Mk~$a|qc0w&lC5<&tC8T)_T|Xvwrs4Ywz>d zR(EhWI|`6_;bUSSk{AKh$&qL3IxY-n4Z(huNs{~d87^Z3A>?tuhqR(tUd^tX@}T`+>Qc>Om61;!V?-20?*N}YiR#g2~)ZQQB3sUMr{l+O|GrCW~ z2D#KB{l=^w@r9l_P!{sV$qD%4PUj1JE2hbZ7hVoccZjAfqW8Z+ruT4YpEm)y_wPca z7s&1ixf96izbrChL*^nI(k~HVD{XK*7aMk%MPgOg-q$nAe>O zkt&cy5%L}&zxTgGnGXQD&m!!Lj|2JqKeLRV<#K(<&OdqycEm)Qx7*H3SBMRJVNn<> zb&#EBPQcC|b9NqRYUlmXbm%E-jVN+F;UUQU>HigL5dKvlPe#c1f&A#{Q07NK9{W*< zT!gOV>2o1+IgpJ%5k%sd>qBcw~u&sPLz?Y8swm15@?BA$873JJ;1b0=Wuhn$^r zP3`;!XuAEUtZA!wehXx#{7kGtwO9${nh043V}T?E~V*cY{0vWa>0) zjYw;A+5Gcm$XqQl2Kg3{B@yy3K%R(@{|Dp;5%My;f3O09#J&*AGdo%SDEKe+v^dk2 zr}-gnO@l+`haJd$q4CsNV+tM$*mwwvGUI9g1T0U#uw_>vnwtLg(Dazqv{gJWhRj!9 z#Ma=JwH(NOFAkAgf&4{;E7@6vOadedhpNlVcN@Px%h2mZqF!3q%EkhIV#aZWzY$MlX zKUFCyf-KrTmB$ztrUr+_>WAwL6h(jx4O>6jq@ z{OYuwxjtmW-+2ilg%!5{w%gA8ZsAD3cuMQBa?1qlJQcT89PAxJIl&3cm%&=Od&S$jLW^GIs)ba9)U1fOIbik@o;ux=;}5Tev=C=LgZTG+%jZ zS3IBZ6Fa{K;lU9SI+o&j=LGCL)7d%K)Xux1>DooCX{)|vFJuPZBG#Z<{1uS*N643f zym)CS^KBrH{r3?0Hz2QH5h533cmMvCf{2~DK4j-hu{>Unyx;D4p1DTsOe>tzLlc{G zvhxEIu=6};=Xz5+UjrB4bKLfvb8QG`ZzBt$~zMwCXH}As_Ou!e* zoG+TXBJ&Aodh|BSWi)yOh-r#=t)W(i5gxn0|o!dj1cL2Hf zLm@H(rL(a zhtPD}|6)yB+4)Z(bM_-vhRmGV3*?J`5+Yv!ax_Bz4#*?-hcaIW@|6fV4dmXBhB7|| z@_2;2s1rLIKE^WK+guIgoqIy$dLWDcG(>uUZ1}Sfc{`9fpA3;Zf&6G+h};9DM9Eo@ct&L1qss!24_YB1# z(egPLElqP6nQKJGz%N;d)zS!gHIToF zkn4baCqixnGWY9g%QHJ!z6$>4D;2KJzvTGttTCkqJvctSp1krue*%{OT44EP2%k!> z4`nw7?^XW}G|d!3%h!QywYs-zxxWvY`QKpsZ~%TB$P*Fr1t2FQ@=%-RB(yz^tc8_!Ou6xrdg`E7 z*)xIIpkL#*t5`$X>(VpI+L7Yckd~5K!7R>nPNWM$j)B87V9@O zD|E=hB@l>^&K^WVge-dGMGhG(meBk%KX<+utuIKfUl4jjYIsU&NYzXos?N=1>|6X! zi)J!4(hG%`#bO;PCQd$y|DL@9D+u`i;we{RNme;A^G#fP8i7jp=y(Gi|LWu40d?Rn z3<8;%_*YkIIv@x1Q|s=KlBK;boFVlQq!Y`%sn)$(weGp&SYD#emm^UZ zaLKpjpN}5EMjc*vxM0-zI*Y%8I@_pw^EkSTcg{S2dUbY)zgkDs!Yjnftz{O^me`o0 z*C6FN{)%yQ7r*ZjJ7>i2xIvVN`W5({+Ruf08((Mfdr)WV_uIzN{a4}ly-u%|J;_4c zL|WZj$}HZ2PKND+07xC;_xw1zi{JN2eVpHM>-j76JB=+D^1H9I_&unz^?Pj`-G3E+ z&tqnAp;2ZnW+@ktS=^6iej&fV-|3!hRLX_1Vru7oFJ{7LO<#v+h^SZkNU~_~#YSfT zbeTVk#W)wuk-m#e&F?)AA!rdokV%(|S?&bpew2&mbu;nBL!Q@t846#n3Zr@5$H7JY z-o;b0P1vw*fomUvRq+S{GOx$K`k=Yr68z=4UkA>p_VGb;Kl-{mwKe=E4pN$q=6+kp znfp#%+!Gp)dJGv^Fq&jcmo33AY zo%03q;Opos__^3!snMW@x@`(ncE-=OdaBj*~m{` zXjTqoAzyspH^moy@P#gme9?h>M)t)v%BBvo^BDfJooC`qSDe~c)_NOX0#{`afX|C( za`^wH_{;ZbgvJN?V(&P<5IcY0*?B`fsgG3CZzp{Kt$^*^yoV&#PeA6Fvol%JAJT(7 z3Yp^v2oPZ zN3Qt)B{m$_ls>M27s<%3V8=d%;zBg`f)qdBeS^f$byy>Mg}-ReD1IJr@$(?+tdG-x zXg<$<_+g~97{%C5{Jl_Ho`+_~ZTS~X%b^&1C$4ae#qZbwHV4Jn!BO^1vu6_|MEyLO zgxmWLB%nZWNE}`UtMEENqf|#6rn>pee0X`kjg40AbQxqaFO~Q~uRfMfvYFWcVOYcu zBll$HI0Pq|+mLIk%O!mab5Z;HhLt8+KAubb9D=%}F}~$4+1>y1maXoey|%Z9Rt!xI z&D~AxQ!BG<=6Eu8jcAUvf|ljFIVBYbFEtkOHI=MLYLDl=6qI^STZ| zUN3*0&a6x~&2n4HfNS=;b?eAJ%oX#Pa!97TyPM8i$u+loq2lxF3Hn)CRAG;@k$$HZ6zR;4WO@HuxHx>4Vzf zu?e)n9j*g@$C_gAH1rTvLVS({QMkF=lJ;@g498=aSVSs zHmFr=L(&|8-f!dBSfy17|BHIv(-5}e$92`*G~c#e@c;X_YD#WZ^4c5fWK(ZC=$N!BH>M}eoE>z(rcg%^$QnI z86}0)LD4b|o*pk+o`uX-{H14D7f+!+TptusSHjEOmM=j}=!l|z{&UF6{XB%5929la z$Jn3a&9&x2W1eeKFB7*EiMo4T)M4<%kC3K+g7j%b!u*%ph|<+HwR`EC=rYoqIwpctD8XK`(#)emW))KhL=Mc?Kmw{os)J`EVFN!@2O*+}(ezey4tK9%0mA7`W@o0lO#!SbdbLuha=cubE9jLAYagW6#HT(Qo7<~ z=P?w*cD_NfM*owYJIArJ*zhl$4JrE{Bj)`fF+UL-`ulF5U(U1*xfRNF`JZg~nRkc{ z=RyPR53=FEPr!!jk^4e6e8kzXSE>;GPc~dJ0UI83Hmnxvg#W5?+n&2u_4mmp2V5>iwQT7;x{0 zO+HNyYH?#OS~`%@Vl=|;feiP42awVSwaQD-B)L^SiWL5&4jN$(0z;>bI-`4Ua!}OW zF;3J`7Fx|XkH*0x>`|nyh)R;DFk2x*W3StVvSZ-U=k7b@8U(oL} z@+{@8Eq(D16Y#|W=yM@oG|+I^7oTbAi`^6O#hD5C;uE5{W3iv;gS+oL8 zz#{fZ-;znOPgm?y6+69~6|*l@>|K*$pQ_ktJ|A&)PE+jHDE1YTVyEDVxE7vQ?0C^X zmRZ!H*!w2M{tTK)%zjR>(@+!1EP91vUpp!G^NRhfVyCa5$L!M;`}#?-pHu8lDfaV< z{UXIaG%5D8iv5gY$A>ghx}Qe}Vy$6YTy;|HPbv1(iv6r&e_FARO^W@DVn3zWpHl2U zQ0!YL#eQ0`pH%E;6#EIqzI{^crxg1M#eQ0`e^s&XoD};>#eQ6|pHl3H75nZvh+;pa*y+A7w)}mH{m`V?4=eVAiv5UU-=Wx#Op5)GVn3kR4=eWHRqV$m z#ePt+KdjgfDfThNeqvJW2Ne5$#ePt+mlgY|NwGhy*!L;+1ByMb*w0LgeZOMgtJoh_ z?CTW!*-5eQRqT5d`#!~fqhdclDfR~x`~8Z2uVP=S*fUp8=3ZuxV&ARUA5iS`75lVF zvEQ%QcPaKgihYh^pD`)+-HLsuV!vOpU#-|@PKte(V&9?IcPsWQ6nn>{*mo-S?TUSu zVtuGs&jP3&70`nw0Jh#a>eEV~YK675j=wu@5Qs^@_cu*mo=T zzDcp?75g2EeMqtYfoHeR6qdNP)7EcO`f}v`rhv=diLVtcz?nYOT3j<3`*wp{oogmz z-)ox#0@H7d^ERcgvpiu5>TGqtaU9)cMe%vmt8=ETH8tBsX;&tv%i3UTnZ;Mgs#>$R zDXs4P6N^+Yw&<4M2u^XdMb{l#g$FmaJ35F_V(4pWs24uZy-5prNH&FD? z^J=lXa`Z6`U&AKWpzA+$b*ASIuL8ol&^0-J44G}N*MiC!tsFg@I5f_)3DI53^v@j* zIUCBJiVl=TEba;K;@#pec@nX33nHTNL}+HnHze>?OrMrr1}tiG90bA5!cM#ZIGDJN&*)vF8 zNwN1T_O*)roO;?dxt?}Nv9D0<{fhnH+Qgn$>^+JdA3&A9h3A=zPPU1Cy<+cD?7fQp zc$?VoQ0z+;`wGSWWSiLg6?>;*?^5jh+QisAS&DsDo7kr*_UVd!reeRSP3%(@`!vOVg!;W*5^G`v=>^eonEUSL{<2`<6DbpHb{jDfaVf zX4Tmy_S1^}jAB2h*k9Ww_EU=ev|>N2*e`7p`w7K}T-a7Aioi&A-&F^0;C@ zq1aC=_OG{z{g`4uuGmj0_JeI=Kcd)=D)tkK{k}G_A6D!~6#H?-{_ZxhA5!dx75g#8 zKGY`mgNpr-Vn3?b={sBPi1`DG{h(q$qS%+ViTz>4en7DwR_t@z#J*p#KdjgfDfY|T z#J*3l?^o>fR;Kl`U8|%$1MTqpUd6sou^&+E=i0P-@PK09tJoh_?5EnqzDKb?pxE~- z_OG{z{eH#1N3riy?1v}7?%r`8=l!o~YQ-$$OXe8soSv@Fq6HIJF`EecJ~g9$K+S3Q zt9f0Y+PMewn8QDVo(TJP#lBUs?@;V#C$Mrd5%#KLA5!cM#eSeo>?OsXSL{{A{^xCC zpRb}W*r{TpZnlcLJKGd>T}t;JrF);!eRi94U#i%<6nn2?zr0QCOBDN3#lAwZ|6~I9 z?-PmnPQ|`NvG*wUGi_p@uh=^kdzWHA-X`|hihYh^?^Ns`Y!mxgHOibzx3A8OVlQE8 zaiQ78MEw4gVn3_cpFs~E&uvz>iT$KvKc(28Qtam^FteJ7?nf2-F~v@Ay~n!m_3ZXp z(pEJt?{MXq!4KctqvIF&d=f6;co`5{m!Q-|nWS7!M)4Jd2T+bhsw0iuP`1WzmUY-% zzkyuG5B#|3%jp3k{WF)m4v6eXWTXyckBw(=73=kCHdmlp_;TJ0nHc#1kn@N-t`A-N zcqEh5tF>aeF}TybjUqMtR3t;W{vODF`T7UGTxvc;p5dL0Vx8IYL$Rrrozj9ddm z#!AlB4P*>LlwxEJkn>mZu0uw0KxB^@BMl&QU{JHUehz+kRKebvJpQOOyxmJ)&gk%-6707Xz z14TiLq*lmn>bh=GoNE_ko(Z^;u~L%D%!Cj}6iNT7D*1~*WUZUE_#Vm32y6ILldB`B z^JVx1Az9RGaV-#hBqQMZA3*5vG6@h_-DR$AK!%o!UL^f-Amlw?=ZAo-cY2Y`<3KzY z^*{K1+)N%7qEfl!Z$L&?7`T0vl6x{8xb91S8Zz?x)SPQ-SB8E@%=DRzTm?j)JTlS+ zgbuG)UzY&_WPOAr=nv6BX81kd4qL-2WKKgbDwRuqClGqZ!AO#fl<^tLjVq!)>JK3! zPewS`Ujm`S*XK}ICUXSVAP=$3w}HqzER6gR$R3>1=)lN-0g-3xjJ%{97jgKKe;vrV z$QN$}awbCFYIAw^ULZbtsl*BpSqEUQ_ff7W>OKZU-dtdrPmv4`U!Ma&WYlAsZvc59 zs?QIA$Q=;NoCQMB;&sp5kS_U^Kx93fbG=c?bOV`F|;83&<>qV(jHTh01+<|N7?y;=8L zC|5bu{SF|zr-)3_sFW(B1@nf3jYIgW1b+o1h(Yq^HzU0V%P41SG-ulaWZDZ{4HJC) zI=Q+3XjGr~L*}^CJsBJS`Hw(mwlAlSS4Grl{^yVxgNk0$$AGMGC6iZ9 z0y!SB{|rbxdcNpJypge1?2`=gyqDhvmioK~GIV$^F9tF*VqXb_G{qll`CEa^M)DGe zl!3_IAA4sT5IVe7?*l^fI-lzyl8HR{ILSmM9|v+G()|ZO`t6-Bb3F^BC(8A*w-I-! z*8(8tA$|!^&eaDb_HqK`cqFq$m9s-3p9He&Cb2WIJ_>~H2L_;Isuu^NYnoSLWlRx3s$6&*8*7|>ApnCyiFmuD&%g3Y*)y~f!q<*@Uw(O?0*lW zFG5ZNc{s}TZ$P$1$TL9b@S4tAi6ngCkv9^8!y|77ay}|&C6GCg@m?MPGBuLf3goOq zFrzlk*d6sYe*~GmPKH=N3gjt=m>zqmmf^2SbXYI%gUo&>L%ANITv0@w0ilb{6E5KR5M*ZI|7rNk$VY)Ju_>B|qp!0w5P*=OSwRjq+#Yd# z2DwfvuklB${r>??ydPiuDR|BDgYshO> z_t5k?7~dB~G9-NykVD|YA5$lM%@|0BW9R#V;p$N2uTjXHit6(}fmB^CD)~MjblCa~ z;l~B*U7a4Gv(G_hS5(epR5Fa?M~9O@)>}eo#qFgV#1@RO0*t3Dq;r;bSAQT@S zc^ilPq!Y}^f`6nXjGK;)ORSc?w>S&LIjG4g33bEA?U12Quz=bwNag}9B4HKjtKnzsDY zkfFoJ;m?4qh)SN0Rtq5LGhYdW4(n4y9sXqcBCEa*GP5D$XGGTn*^arLkHeKwIaK0r z16dN4lLI0<(^&WS0=YlZ^pB!)_8~PdUlFmYy&oRBIKig)|!3+)yD; zKu@W3Gk(<*Vr%H-NH6bwSARRs>X_k>KTp958TYY=bn3ngOx@t ze{0$5q<7_-eoRe~!f%}7hG0Xn-YC@Y9EJ>I(R?9|W9n6?T4V4zG7X!DV!+K$X8J@0 z+Otr-QK?qRLY%~eJJ%QsQrUdI79=ZG*xFLns|74)NI63zjeKRaEa{l=&}>^-3*>4BV_=Wvpg#~MTV z8X^WPwjdZ0zg3*nanptMHo8zM4tTl%&y^}zcr_I)Gzb@qz=B~iS1FhAqZ%w3I-6FF zq&oCGNY0U;!mfenE#|_y!3#+PEu>CAE}FhTl#R_*u2HN^frC~|)vN??Rx6cKSg09v z*n{;DAF7n{);{Lm)V2XzdT=$&gx}+ej9M*L3miA56M~r?;#}zv-v$H7wnT@(f`#HH zTN#JK#%w8vKvQv)!-C)?EJ5hzvyH4#zyQb;1LQk@nY`yy0RuTD4jy>c_Z#Li0VcCa zIqgjfMM3Y;42nqW?OGV)xbR`CD(&rhR;?EaPVdqkDypgm)B8%JJ zD0YznQ?3v!G_1`WcgFS2!^x&>X{3;pF${4_0ybb98=t}#7~;t)aJLT_O1SD#0?}+8 zODS(#O67(s=#Y}pN^N5x!;gogWRq$z(_kGA-h>i8pNAZ)hqAc_+Lx)M2WhrYsIyjt z4i;<+qy$Ycl3Jz0{uacQ5OMf6Zsh7k41!M5H4(ZNHlQG#lq*IXpJ_B(O)#)pW00se z5uv15g~wk?dW*S~wHWn~-dHB(bTBDhexo>y83@m`;9X9-O!lf*mH}@IN!uR6Cc`$v zP}pb;LW6J2N=Qshh_qan$+ljXrjyDDd(eU2&<+~HtfdK~fi*2l*MpE6F|F5CnUgM~ zz3L6cfHzc-P6oLH5XjojCgY&6U_4+mNKa!;EOD|#b4d;o2C}(a!OrOfK>NVlA;=UC z{Ve2qQBJyngOhghQLH4n%5b$*aB&%3rV%M1sZSrvrGGQPw6b6zd z&6aZoxRyH&#?Tk?J{am(xWh>r*?KV4g`o4I1uMa9+e1yHynDS^(Z_%VUCh{Yx*+`g zZf?Z7#fq4T6tzra91CK+GtnGk)amo!EJA1tbk7wk9yf8Rg+bGGF$CBG7X-eUu=l^ zE*-jf62hGooFutX%MJ6K%}H5LyL4PxDp}Vm)|q4mMoJrVmFi}i!rNK8E74sODtfk) z4D;|=7|eSmDd9#vN;st`0ex&IXXJ_-%2}SeQ*xwSkAcxF-RC1p2C}$CsA2OZFDMxd z?bt52lLV!F%cfLx^F_dDJ&PyuNwrch^6lSE5vV+04HwL-N-(J@fTvso~HwueQ4f7`Fx4G4 zNmni>&7)6>OHT4`I%AxCC8=OsN^%2c*$N^SF<0*%DPX?sYRySkHYdIFIbEe)9>m2- ztfgRWIRL759>JI6;0v%6i*u_HF~#BbJ71w`tjrYzkg2mxZzy2uDl+vj)+yn5D1pYv zF+&OGiaM>F8cO^&aUq*e=m+^QA2%ZyR#Zt@d&QZ`rd{c1ekJZ&umjSbRciTSIa}MD z+{lu13E0`T^2zD+i>J9Rga$1^{OodItPJ_+4On*(nP2dV+xnRO;Qm#CclJZPK z78E&?sgS{?Y?Fw~c5_2>EtkbYm~=@FaWaE<`*6p(s|n7f9yqnNFv6w|IHQ8YV%&Kt zSoXrXD-!2YBu;ISI1^QH8dVl)L=g=+73?sy{q2BPhAwcg=$3*6ahy&@m>ppGUE0j7 zq}4dIST}chwm~}>^>UMG2WHXbp=&YraiG#*V5Dvq!OT7Xra_tM5bPQgC7cSB$QLl2 zR@ell0C6ZKoZ%_KcLJskMiBD^THK@Ic*L$Hj>&~o6%6j`U{bCUCKcAg0Af^=um&~f zb~rTW;$D+5H-J2CF=-c>Cgn7-*W7}eNyC(~XkyZVswN#Q#&P~8x>ILu%%3(&bp-ok z=~gm*Va#1go6B7A_A*ItFq4cdW)NpGlMWi(s8z%=H1Xe$GR z#xg)?Ed#Vr-r7qmA5Pa$3nWA3kxVHMBv2kHuRIc7c_aemk&2ZE;Dd(U87YtJvGM?7 zqwy2JvM{Z)HdJ7!)J;4Oaq@00FDnEiPPc$5p1##PwIN6%*1;v0WlwiOhl8|!Bp|uU9;s}5bBP3iD;oJog z&V39a5rq)aK?IqU?{0}O3K*oLctJV}7s}rxD#j!%(%KU4wWXBTmQqoxA;4)%3DK6$ zMO!*|+EOCa)?{*BD5bEb=>``{huTs))RxkrwkCfQZEJ5wq$v|^+HC*c>AYAFAG)~F{-M)mQGwgX=5`9!`$#6RQ#ECpYOFBIlNl0a4Aia0bz|c6m>(}mnv~-nYf)Q+ zJGYutoG0|9x$HvNRFPM}Y$?X2=3IPg5`j}q+9_#LPD^{u2Q(1`ZZ+2f7nyVz(4u16 zE)Z-Q(FPB74`SL}OX=?KEzDJEzErw2UpfzTj{=&jAr5vatS*V&5OS_{n>q)ro6@l{ zqIfmM#l~nAwRoIv2BhY}>#jP(pxsIi7a9Q;8YzGSrw6EWeSkTg11xZJfHrG|^^w}9 z!sZGO^QkV&U30oP#A)IXxBTdkP%{S>%TZtE@IYUOIc*){bahD3jX5mvv%}&i$D(xD zt2t3vOrp$Tfk7SC%$$fL=WV*4vS@hO88rl*T|+Q5WQYe{i6ix`%0a$yIVfmj4huXG zk~mw0pz}ir2CfLY&i34h${oz|fu!46W(FX11htwaQ@d*hBzlDglBgY6AJCVvpGA zi~!W8cz&HPW4Xdi(TA`MNt+x@_f4?#6eS$7x#Az=QPLA~%95ExIB_8$Y~sa1TCYZ3 zDkZzN!$`Kwi!69lhm|Mn-8EGzVKugf&10dw*;^6<^uQxKOxwa-?LFjl@K9hr4|;t< z%xV=tp>7@yHKbOss1wtq9PXox78WU#J!1OcToNopStN)dJkK^;J6*RfK-f?O!;-z* zvnE*7;R+a56)!6r244+9f@%olsv$sF4Z*@{2o_aCz_1#s78Y>sv}xx{n}$mKz~81r zay;Tm;w68F1jPgaPnV-BLFs5Nfq6+1E6ZtUr0jBF1=~JgkOfkQI0}dO#~KcD9g{;` zzl7&a#%0bn0=R+&2*bRIfkZ6W6(NxGv;*8=YztD=5g&(l11@*eW^4(e|Fd|J%C}vU za@z1U-}jibZ>%nd|h{{Hza1j;n+za{`0)11bl#5tXwJ^qAepB_J zxUh-=9E_3y8Vr+lf`h0<$~l>@c_*8+cd|`NXG{gT7Gkai;Yim)o0;pO&9H_P+})a# zs|R26^)P8)51W)=qkV(r6rY>gyIzP=-sk38Sap*( ztU5`k)`0;FHl}NB{?|AwYxHkR1(%9!fa7m@D2al=N2NlmsAM z3iYO|q1ppThtX$>vYF{x7yy)x3L_w0SQvPwuqJT_JmAb3G0RDbkkecY6(Atw(2&K)HWJv1Oka&FBuwCTMN!$fWhhrh zONIOfY^(uLf#h%PQFDKh_8kC)G#YLBXo989R7N=mw#HeSI%)AyURdjS^mYBN1rD_mSME z&>kCX%JH3y0i=@H>t}K#W)}^8#Gq2!JP(o5m^UBx&5o_XOHFuU09!VO=#`lqS+!ay zUcY2fQX47LR#%jTEnL`r3Z_v!HKR(+TQq-BCrU`zN7!&g(g|E{)Tld(K!A!C0lbez zQH5g^_r=D~R0iV0iA06xqz_N$;2mB%Q_|nNhCb{jO(}gX^UT0vC>RawA2ViA=Ri#Xh%npks}0j;A>)ifjV_^$6*uLJ*Gu8cXdqo- zUg|WLsRQB30>7%-(|=3w=BlbA+6;$>sVNPWY;u!qVlmc;hJ2&>tz{ky@~;25u~9(&CDP_Q@+zf51p zTVV*W1*R9G{?o)GyQ7TvE;rFWD|B=tRsQ%6g<<$`*i@KZx)SegAq1!+4FaxgEO;_ipvs?%M9t$EHo2%%vz<5?% zsG&0~qI0G9txYIgsC3#qpH#4k9

fq=9i5Z--It_yYPnnqinL!`Zv&K^FF9Y{r5J z-lM~~M-Qnf7w!uh^cgtkJ8u)%!i?NK1={n0<=>h&rxgSrpkGQ8AtuIKzp2~a- zK~;R&8WVfzUJub-o+OzK$W zrH^H260NRrGs7z@zF+9WJGX2PBY+;dMTciDyB%DKd5MB|kr(iOh^rFJ<||~rrfa4& zXx}nRJNWXzo19xy=+ZaiH-Es(T;w<{BIoL(+uTY?#4Ra6_3U_>_%Czk;228%1u%y>oY|q?)V`XZsZ!@pD46kQ;ke z)?sn-GR717m<2-nuF_q}b*2lBrUcz)RTvG4Iu)*^e5?lZzV3eMikja7C%wy8AzSOl z;%p(`W|AOIIU3b<9UMmrjVy&AgrF#WCN42|EG9ywzGS3vEM&hUil~(SBkc&nm_k1epWV4hX{L{Cnd3W zc<{?su_n#;DKrl9!V%Z9A0L%L!)+8~c%Z0=W?bfN%5i%$E~!|_!NK0fb@%$R89C8^ zpy|=%?P4yZ+}wlEQsn@ONsS1~4a57~p^YC~%7!I`NGz!w#z3#pe~cM48u-ehKq zj%@(~AsNJ&h*ws_zBZV}n|j!oa!M>G{l-)x$C zp=;JN;+|}-6m-tG!!n<;DC#3YcWmpO;?k1kBGa8IFRh! zRubP58y)Odk24ASR@`pcsV?6^HEUV)>av^sB7VlV0oFDOwU!Y9FQbW}DYfcE;UH=2 zzU}mzckZ}%iRYBz9ga~B1+Szw-E}?9Ke-1sp8yIcanQgmKfp_}@`MaQz>HG25ZrP4 zTPHV;BZTQ&dp4l$*R6ec2kkR$LvA1To5waskK4K6Mt=%T8k17D;%>~|l*^Sc)yMKs zwoV&!*8KL($!*=ew=Pdsb>F;vjh&I`g$SuKOuWY24)$Y(vAa%vHl3Lk5%egoyOPzI z;5Mywt)o|HjLW@e{7l{Hf)M7HDy=R&^hR@C>W%>f_xkXpGgf-41jErIl=QvlI6C`? zlYs@pS#&E_AF0H5VyMzGbR}hs5bhoYVIeENCMM|#lIb6OJ8s!P_&Wh?a8!pog!m?g z0-{;}0b7i>@`G&gB3y7QgEeSc9Vk*u2=5?}$2>!h$LIL&5dK><7H$ZNqN3&_arA8t@>j|5!+~i9?j~-xXW4+-%41oSZ_8a@zCK)sptkG=3 zblT~g35tuB3o3j~nUnRFuP|D@v6^RZC{r2^BYI62WS3H~fg){_)D({tQ9Bt;ZnNVX zh4FY3g)}|oh!z)oD+v4D^x9c^5-wdz%N4U$Q-$C@P(%yytLW+rY>3maZ6X>qa*Wad-DW@7e9kN<>By;p2V$~bD%Vz zq%;||bF5S_XN(YI=XKiu0NLP^G3Yy1Dz CPA^0N literal 0 HcmV?d00001 diff --git a/nanomsg/bin/nanocat.exe b/nanomsg/bin/nanocat.exe new file mode 100755 index 0000000000000000000000000000000000000000..b34b8984e680936ed8c9682955dd7e1e0ad7913d GIT binary patch literal 136489 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

Gfv4wJz<#ZCzRz{2!AfY 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 Ax&QzG literal 0 HcmV?d00001 diff --git a/nanomsg/include/nanomsg/bus.h b/nanomsg/include/nanomsg/bus.h new file mode 100644 index 000000000..7572903ed --- /dev/null +++ b/nanomsg/include/nanomsg/bus.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2013 Martin Sustrik All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef BUS_H_INCLUDED +#define BUS_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_PROTO_BUS 7 + +#define NN_BUS (NN_PROTO_BUS * 16 + 0) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/inproc.h b/nanomsg/include/nanomsg/inproc.h new file mode 100644 index 000000000..ed3879908 --- /dev/null +++ b/nanomsg/include/nanomsg/inproc.h @@ -0,0 +1,37 @@ +/* + Copyright (c) 2012 Martin Sustrik All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef INPROC_H_INCLUDED +#define INPROC_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_INPROC -1 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/ipc.h b/nanomsg/include/nanomsg/ipc.h new file mode 100644 index 000000000..a78bfb833 --- /dev/null +++ b/nanomsg/include/nanomsg/ipc.h @@ -0,0 +1,42 @@ +/* + Copyright (c) 2012 Martin Sustrik All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef IPC_H_INCLUDED +#define IPC_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_IPC -2 + +/* The object set here must be valid as long as you are using the socket */ +#define NN_IPC_SEC_ATTR 1 +#define NN_IPC_OUTBUFSZ 2 +#define NN_IPC_INBUFSZ 3 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/nn.h b/nanomsg/include/nanomsg/nn.h new file mode 100644 index 000000000..ce5efe33b --- /dev/null +++ b/nanomsg/include/nanomsg/nn.h @@ -0,0 +1,412 @@ +/* + Copyright (c) 2012-2014 Martin Sustrik All rights reserved. + Copyright (c) 2013 GoPivotal, Inc. All rights reserved. + Copyright 2016 Garrett D'Amore + Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef NN_H_INCLUDED +#define NN_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* Handle DSO symbol visibility. */ +#if !defined(NN_EXPORT) +# if defined(_WIN32) && !defined(NN_STATIC_LIB) +# if defined NN_SHARED_LIB +# define NN_EXPORT __declspec(dllexport) +# else +# define NN_EXPORT __declspec(dllimport) +# endif +# else +# define NN_EXPORT extern +# endif +#endif + +/******************************************************************************/ +/* ABI versioning support. */ +/******************************************************************************/ + +/* Don't change this unless you know exactly what you're doing and have */ +/* read and understand the following documents: */ +/* www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ +/* www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html */ + +/* The current interface version. */ +#define NN_VERSION_CURRENT 5 + +/* The latest revision of the current interface. */ +#define NN_VERSION_REVISION 0 + +/* How many past interface versions are still supported. */ +#define NN_VERSION_AGE 0 + +/******************************************************************************/ +/* Errors. */ +/******************************************************************************/ + +/* A number random enough not to collide with different errno ranges on */ +/* different OSes. The assumption is that error_t is at least 32-bit type. */ +#define NN_HAUSNUMERO 156384712 + +/* On some platforms some standard POSIX errnos are not defined. */ +#ifndef ENOTSUP +#define ENOTSUP (NN_HAUSNUMERO + 1) +#endif +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT (NN_HAUSNUMERO + 2) +#endif +#ifndef ENOBUFS +#define ENOBUFS (NN_HAUSNUMERO + 3) +#endif +#ifndef ENETDOWN +#define ENETDOWN (NN_HAUSNUMERO + 4) +#endif +#ifndef EADDRINUSE +#define EADDRINUSE (NN_HAUSNUMERO + 5) +#endif +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL (NN_HAUSNUMERO + 6) +#endif +#ifndef ECONNREFUSED +#define ECONNREFUSED (NN_HAUSNUMERO + 7) +#endif +#ifndef EINPROGRESS +#define EINPROGRESS (NN_HAUSNUMERO + 8) +#endif +#ifndef ENOTSOCK +#define ENOTSOCK (NN_HAUSNUMERO + 9) +#endif +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT (NN_HAUSNUMERO + 10) +#endif +#ifndef EPROTO +#define EPROTO (NN_HAUSNUMERO + 11) +#endif +#ifndef EAGAIN +#define EAGAIN (NN_HAUSNUMERO + 12) +#endif +#ifndef EBADF +#define EBADF (NN_HAUSNUMERO + 13) +#endif +#ifndef EINVAL +#define EINVAL (NN_HAUSNUMERO + 14) +#endif +#ifndef EMFILE +#define EMFILE (NN_HAUSNUMERO + 15) +#endif +#ifndef EFAULT +#define EFAULT (NN_HAUSNUMERO + 16) +#endif +#ifndef EACCES +#define EACCES (NN_HAUSNUMERO + 17) +#endif +#ifndef EACCESS +#define EACCESS (EACCES) +#endif +#ifndef ENETRESET +#define ENETRESET (NN_HAUSNUMERO + 18) +#endif +#ifndef ENETUNREACH +#define ENETUNREACH (NN_HAUSNUMERO + 19) +#endif +#ifndef EHOSTUNREACH +#define EHOSTUNREACH (NN_HAUSNUMERO + 20) +#endif +#ifndef ENOTCONN +#define ENOTCONN (NN_HAUSNUMERO + 21) +#endif +#ifndef EMSGSIZE +#define EMSGSIZE (NN_HAUSNUMERO + 22) +#endif +#ifndef ETIMEDOUT +#define ETIMEDOUT (NN_HAUSNUMERO + 23) +#endif +#ifndef ECONNABORTED +#define ECONNABORTED (NN_HAUSNUMERO + 24) +#endif +#ifndef ECONNRESET +#define ECONNRESET (NN_HAUSNUMERO + 25) +#endif +#ifndef ENOPROTOOPT +#define ENOPROTOOPT (NN_HAUSNUMERO + 26) +#endif +#ifndef EISCONN +#define EISCONN (NN_HAUSNUMERO + 27) +#define NN_EISCONN_DEFINED +#endif +#ifndef ESOCKTNOSUPPORT +#define ESOCKTNOSUPPORT (NN_HAUSNUMERO + 28) +#endif + +/* Native nanomsg error codes. */ +#ifndef ETERM +#define ETERM (NN_HAUSNUMERO + 53) +#endif +#ifndef EFSM +#define EFSM (NN_HAUSNUMERO + 54) +#endif + +/* This function retrieves the errno as it is known to the library. */ +/* The goal of this function is to make the code 100% portable, including */ +/* where the library is compiled with certain CRT library (on Windows) and */ +/* linked to an application that uses different CRT library. */ +NN_EXPORT int nn_errno (void); + +/* Resolves system errors and native errors to human-readable string. */ +NN_EXPORT const char *nn_strerror (int errnum); + + +/* Returns the symbol name (e.g. "NN_REQ") and value at a specified index. */ +/* If the index is out-of-range, returns NULL and sets errno to EINVAL */ +/* General usage is to start at i=0 and iterate until NULL is returned. */ +NN_EXPORT const char *nn_symbol (int i, int *value); + +/* Constants that are returned in `ns` member of nn_symbol_properties */ +#define NN_NS_NAMESPACE 0 +#define NN_NS_VERSION 1 +#define NN_NS_DOMAIN 2 +#define NN_NS_TRANSPORT 3 +#define NN_NS_PROTOCOL 4 +#define NN_NS_OPTION_LEVEL 5 +#define NN_NS_SOCKET_OPTION 6 +#define NN_NS_TRANSPORT_OPTION 7 +#define NN_NS_OPTION_TYPE 8 +#define NN_NS_OPTION_UNIT 9 +#define NN_NS_FLAG 10 +#define NN_NS_ERROR 11 +#define NN_NS_LIMIT 12 +#define NN_NS_EVENT 13 +#define NN_NS_STATISTIC 14 + +/* Constants that are returned in `type` member of nn_symbol_properties */ +#define NN_TYPE_NONE 0 +#define NN_TYPE_INT 1 +#define NN_TYPE_STR 2 + +/* Constants that are returned in the `unit` member of nn_symbol_properties */ +#define NN_UNIT_NONE 0 +#define NN_UNIT_BYTES 1 +#define NN_UNIT_MILLISECONDS 2 +#define NN_UNIT_PRIORITY 3 +#define NN_UNIT_BOOLEAN 4 +#define NN_UNIT_MESSAGES 5 +#define NN_UNIT_COUNTER 6 + +/* Structure that is returned from nn_symbol */ +struct nn_symbol_properties { + + /* The constant value */ + int value; + + /* The constant name */ + const char* name; + + /* The constant namespace, or zero for namespaces themselves */ + int ns; + + /* The option type for socket option constants */ + int type; + + /* The unit for the option value for socket option constants */ + int unit; +}; + +/* Fills in nn_symbol_properties structure and returns it's length */ +/* If the index is out-of-range, returns 0 */ +/* General usage is to start at i=0 and iterate until zero is returned. */ +NN_EXPORT int nn_symbol_info (int i, + struct nn_symbol_properties *buf, int buflen); + +/******************************************************************************/ +/* Helper function for shutting down multi-threaded applications. */ +/******************************************************************************/ + +NN_EXPORT void nn_term (void); + +/******************************************************************************/ +/* Zero-copy support. */ +/******************************************************************************/ + +#define NN_MSG ((size_t) -1) + +NN_EXPORT void *nn_allocmsg (size_t size, int type); +NN_EXPORT void *nn_reallocmsg (void *msg, size_t size); +NN_EXPORT int nn_freemsg (void *msg); + +/******************************************************************************/ +/* Socket definition. */ +/******************************************************************************/ + +struct nn_iovec { + void *iov_base; + size_t iov_len; +}; + +struct nn_msghdr { + struct nn_iovec *msg_iov; + int msg_iovlen; + void *msg_control; + size_t msg_controllen; +}; + +struct nn_cmsghdr { + size_t cmsg_len; + int cmsg_level; + int cmsg_type; +}; + +/* Internal stuff. Not to be used directly. */ +NN_EXPORT struct nn_cmsghdr *nn_cmsg_nxthdr_ ( + const struct nn_msghdr *mhdr, + const struct nn_cmsghdr *cmsg); +#define NN_CMSG_ALIGN_(len) \ + (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) + +/* POSIX-defined msghdr manipulation. */ + +#define NN_CMSG_FIRSTHDR(mhdr) \ + nn_cmsg_nxthdr_ ((struct nn_msghdr*) (mhdr), NULL) + +#define NN_CMSG_NXTHDR(mhdr, cmsg) \ + nn_cmsg_nxthdr_ ((struct nn_msghdr*) (mhdr), (struct nn_cmsghdr*) (cmsg)) + +#define NN_CMSG_DATA(cmsg) \ + ((unsigned char*) (((struct nn_cmsghdr*) (cmsg)) + 1)) + +/* Extensions to POSIX defined by RFC 3542. */ + +#define NN_CMSG_SPACE(len) \ + (NN_CMSG_ALIGN_ (len) + NN_CMSG_ALIGN_ (sizeof (struct nn_cmsghdr))) + +#define NN_CMSG_LEN(len) \ + (NN_CMSG_ALIGN_ (sizeof (struct nn_cmsghdr)) + (len)) + +/* SP address families. */ +#define AF_SP 1 +#define AF_SP_RAW 2 + +/* Max size of an SP address. */ +#define NN_SOCKADDR_MAX 128 + +/* Socket option levels: Negative numbers are reserved for transports, + positive for socket types. */ +#define NN_SOL_SOCKET 0 + +/* Generic socket options (NN_SOL_SOCKET level). */ +#define NN_LINGER 1 +#define NN_SNDBUF 2 +#define NN_RCVBUF 3 +#define NN_SNDTIMEO 4 +#define NN_RCVTIMEO 5 +#define NN_RECONNECT_IVL 6 +#define NN_RECONNECT_IVL_MAX 7 +#define NN_SNDPRIO 8 +#define NN_RCVPRIO 9 +#define NN_SNDFD 10 +#define NN_RCVFD 11 +#define NN_DOMAIN 12 +#define NN_PROTOCOL 13 +#define NN_IPV4ONLY 14 +#define NN_SOCKET_NAME 15 +#define NN_RCVMAXSIZE 16 +#define NN_MAXTTL 17 + +/* Send/recv options. */ +#define NN_DONTWAIT 1 + +/* Ancillary data. */ +#define PROTO_SP 1 +#define SP_HDR 1 + +NN_EXPORT int nn_socket (int domain, int protocol); +NN_EXPORT int nn_close (int s); +NN_EXPORT int nn_setsockopt (int s, int level, int option, const void *optval, + size_t optvallen); +NN_EXPORT int nn_getsockopt (int s, int level, int option, void *optval, + size_t *optvallen); +NN_EXPORT int nn_bind (int s, const char *addr); +NN_EXPORT int nn_connect (int s, const char *addr); +NN_EXPORT int nn_shutdown (int s, int how); +NN_EXPORT int nn_send (int s, const void *buf, size_t len, int flags); +NN_EXPORT int nn_recv (int s, void *buf, size_t len, int flags); +NN_EXPORT int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags); +NN_EXPORT int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags); + +/******************************************************************************/ +/* Socket mutliplexing support. */ +/******************************************************************************/ + +#define NN_POLLIN 1 +#define NN_POLLOUT 2 + +struct nn_pollfd { + int fd; + short events; + short revents; +}; + +NN_EXPORT int nn_poll (struct nn_pollfd *fds, int nfds, int timeout); + +/******************************************************************************/ +/* Built-in support for devices. */ +/******************************************************************************/ + +NN_EXPORT int nn_device (int s1, int s2); + +/******************************************************************************/ +/* Statistics. */ +/******************************************************************************/ + +/* Transport statistics */ +#define NN_STAT_ESTABLISHED_CONNECTIONS 101 +#define NN_STAT_ACCEPTED_CONNECTIONS 102 +#define NN_STAT_DROPPED_CONNECTIONS 103 +#define NN_STAT_BROKEN_CONNECTIONS 104 +#define NN_STAT_CONNECT_ERRORS 105 +#define NN_STAT_BIND_ERRORS 106 +#define NN_STAT_ACCEPT_ERRORS 107 + +#define NN_STAT_CURRENT_CONNECTIONS 201 +#define NN_STAT_INPROGRESS_CONNECTIONS 202 +#define NN_STAT_CURRENT_EP_ERRORS 203 + +/* The socket-internal statistics */ +#define NN_STAT_MESSAGES_SENT 301 +#define NN_STAT_MESSAGES_RECEIVED 302 +#define NN_STAT_BYTES_SENT 303 +#define NN_STAT_BYTES_RECEIVED 304 +/* Protocol statistics */ +#define NN_STAT_CURRENT_SND_PRIORITY 401 + +NN_EXPORT uint64_t nn_get_statistic (int s, int stat); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/nanomsg/include/nanomsg/pair.h b/nanomsg/include/nanomsg/pair.h new file mode 100644 index 000000000..3409418f2 --- /dev/null +++ b/nanomsg/include/nanomsg/pair.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2012 Martin Sustrik All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef PAIR_H_INCLUDED +#define PAIR_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_PROTO_PAIR 1 + +#define NN_PAIR (NN_PROTO_PAIR * 16 + 0) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/pipeline.h b/nanomsg/include/nanomsg/pipeline.h new file mode 100644 index 000000000..db9b7d729 --- /dev/null +++ b/nanomsg/include/nanomsg/pipeline.h @@ -0,0 +1,41 @@ +/* + Copyright (c) 2012 Martin Sustrik All rights reserved. + Copyright (c) 2013 GoPivotal, Inc. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef PIPELINE_H_INCLUDED +#define PIPELINE_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_PROTO_PIPELINE 5 + +#define NN_PUSH (NN_PROTO_PIPELINE * 16 + 0) +#define NN_PULL (NN_PROTO_PIPELINE * 16 + 1) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/pubsub.h b/nanomsg/include/nanomsg/pubsub.h new file mode 100644 index 000000000..04abb4f1f --- /dev/null +++ b/nanomsg/include/nanomsg/pubsub.h @@ -0,0 +1,43 @@ +/* + Copyright (c) 2012 Martin Sustrik All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef PUBSUB_H_INCLUDED +#define PUBSUB_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_PROTO_PUBSUB 2 + +#define NN_PUB (NN_PROTO_PUBSUB * 16 + 0) +#define NN_SUB (NN_PROTO_PUBSUB * 16 + 1) + +#define NN_SUB_SUBSCRIBE 1 +#define NN_SUB_UNSUBSCRIBE 2 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/reqrep.h b/nanomsg/include/nanomsg/reqrep.h new file mode 100644 index 000000000..fea7a7eb2 --- /dev/null +++ b/nanomsg/include/nanomsg/reqrep.h @@ -0,0 +1,50 @@ +/* + Copyright (c) 2012 Martin Sustrik All rights reserved. + Copyright 2016 Garrett D'Amore + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef REQREP_H_INCLUDED +#define REQREP_H_INCLUDED + +#include "nn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_PROTO_REQREP 3 + +#define NN_REQ (NN_PROTO_REQREP * 16 + 0) +#define NN_REP (NN_PROTO_REQREP * 16 + 1) + +#define NN_REQ_RESEND_IVL 1 + +typedef union nn_req_handle { + int i; + void *ptr; +} nn_req_handle; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/survey.h b/nanomsg/include/nanomsg/survey.h new file mode 100644 index 000000000..ad594aa66 --- /dev/null +++ b/nanomsg/include/nanomsg/survey.h @@ -0,0 +1,46 @@ +/* + Copyright (c) 2012 Martin Sustrik All rights reserved. + Copyright 2015 Garrett D'Amore + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef SURVEY_H_INCLUDED +#define SURVEY_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_PROTO_SURVEY 6 + +/* NB: Version 0 used 16 + 0/1. That version lacked backtraces, and so + is wire-incompatible with this version. */ + +#define NN_SURVEYOR (NN_PROTO_SURVEY * 16 + 2) +#define NN_RESPONDENT (NN_PROTO_SURVEY * 16 + 3) + +#define NN_SURVEYOR_DEADLINE 1 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/tcp.h b/nanomsg/include/nanomsg/tcp.h new file mode 100644 index 000000000..1d9077655 --- /dev/null +++ b/nanomsg/include/nanomsg/tcp.h @@ -0,0 +1,39 @@ +/* + Copyright (c) 2012 Martin Sustrik All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef TCP_H_INCLUDED +#define TCP_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_TCP -3 + +#define NN_TCP_NODELAY 1 + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/nanomsg/include/nanomsg/ws.h b/nanomsg/include/nanomsg/ws.h new file mode 100644 index 000000000..b7f66b4b3 --- /dev/null +++ b/nanomsg/include/nanomsg/ws.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2012 250bpm s.r.o. All rights reserved. + Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. + Copyright 2015 Garrett D'Amore + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom + the Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef WS_H_INCLUDED +#define WS_H_INCLUDED + +#include "nn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NN_WS -4 + +/* NN_WS level socket/cmsg options. Note that only NN_WSMG_TYPE_TEXT and + NN_WS_MSG_TYPE_BINARY messages are supported fully by this implementation. + Attempting to set other message types is undefined. */ +#define NN_WS_MSG_TYPE 1 + +/* WebSocket opcode constants as per RFC 6455 5.2 */ +#define NN_WS_MSG_TYPE_TEXT 0x01 +#define NN_WS_MSG_TYPE_BINARY 0x02 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/nanomsg/lib/libnanomsg.dll b/nanomsg/lib/libnanomsg.dll new file mode 100644 index 0000000000000000000000000000000000000000..8ffe03686ad262b45628bd7843f4bdf4b980f9fd GIT binary patch literal 14862 zcmeHO&2HO95FXRNQ4;?oju9Ab$|Mfp28K$>`mu{52#Oy24zw)Mu~3;bBqnv=p$8v& zE{dY3K0uF!&pqS`dMbM8p@%#`0e5C+|0t0$<&$J)f#q^%cd6akZ@*a%SC7AF_1niU zN}svOP^smHNpZ6-Fn6SAM70^Sfc|Bmmz(4qBa|GVsIDkAwaR z7I#lheUnA`;JcHtzIu`4>vSI ztaBRmdRAM`qWqQBZ9NaRkn8w^xD|H?akp(f1gqI{ta;QAf@C+e1WR#3LVG@C9!omG zn{JzcqL82jSk{ihFlgJV))FekpYy}B__)*et@cSV)$2tA`v+tmOAfnX$7;!0lpFQw zUTIOs!%(f2Be~%1bzZ?D*X3)YRuikf+NermI4FHRGmA?d02dw1iM#oka<|ipTU)p; zIgtE&mC>npA?wwZi0YlIj81jErV_2<%?~Q0Q}06Enq^zYWs57_>dy>TnpG0<%Z@D( zzdfVS3f5)fKV?;eF4I*=LSjU7k_!DPk@3dyL z24(S3qU-4y8LA+&MuWrUq@zW+gIChXBG3$wCKr_^MNhBLt@!m(-BK%hJ~F$w^2H(Z zfj~~>S~I~GFEfgFbI(C-AI+EugkskG7Ix;A=m5?^9Gt~gkI>`*nkM*9%BbHicn1<) z8l9w}zcDUQ1q__%InZ-O_0UYgYI;3AS5)s`jGO88(7JJ;*?FfjI`u9tpHb%gT#N8# z1CSDgxnkXu{ue|A8s(z6qu;gfY<*By^ePe~Ppl#_MxJSV?a>o;E75P#`YgOW3R-d5 z^XRFUmn6~V6D1^Nd{BD|^kkOY7kR!o@G0IH(v{XY4L~KvN;NlD>ea>wR(7ysS7Bw2 zI*);p_hDt(s)rk=i!^2=tUOGwH-eQX>Gd>L*6~?+vGRbhVsBQkEoqK8tfJVhRe>Ml zlA0dwQSVj8Zf#pU>%a?Tx6I%y1lhuD3^np&sKS0H@+%h&Lo19ScDAC{rw2o{!=qp@ z^n?ZC>cAeRV(+6o$=WeF(2{KQ)N`Y!$bOz>g&x%PBqB%6KS6?C7^sitE#4qU@e!2{ z`*{d0882Dv=c(lPY}X6SGI03?GtbB5`*`v)jT)RWRYsD{G#@<5wCYSqf5*C` z(1R5xm1)E$M(p2pnMSlv|0E%qW*m=larecy87unx<0RsR@UFf$7`!MuWGqwqzPKOg z!P#VE3A6bozc0DSJDU<=NPPF7T)vUryEfm*Qx0iRk$f|T|G2>K;kO7Y)+vyi$2ZpC z4BsS#X&@55KyM5m^6se3D#};TC5a*Hh|omtbJFeB28l5kyH#d^xH|9^rt~g0bOuVl zkq^tW(KL={xwu}PMM9H0OoqCj9!ARhuB8TN=*UR2(KCi$*&F>HT9nf}3xpm%Za78A zS(c1rIOvg-P~rf6LM9H%I9HkdHOm{rlU(4_7xRP~c@lMc_$KdHP<6ysn=CEJW}Eyz zhe$ohrJ%wI=uX2%3ngU@(d+8?=FJyW~zf9ykX{rZjHanIm H4M6_`R{oK% literal 0 HcmV?d00001 diff --git a/nanomsg/lib/libnanomsg.dll.a b/nanomsg/lib/libnanomsg.dll.a new file mode 100644 index 0000000000000000000000000000000000000000..8ffe03686ad262b45628bd7843f4bdf4b980f9fd GIT binary patch literal 14862 zcmeHO&2HO95FXRNQ4;?oju9Ab$|Mfp28K$>`mu{52#Oy24zw)Mu~3;bBqnv=p$8v& zE{dY3K0uF!&pqS`dMbM8p@%#`0e5C+|0t0$<&$J)f#q^%cd6akZ@*a%SC7AF_1niU zN}svOP^smHNpZ6-Fn6SAM70^Sfc|Bmmz(4qBa|GVsIDkAwaR z7I#lheUnA`;JcHtzIu`4>vSI ztaBRmdRAM`qWqQBZ9NaRkn8w^xD|H?akp(f1gqI{ta;QAf@C+e1WR#3LVG@C9!omG zn{JzcqL82jSk{ihFlgJV))FekpYy}B__)*et@cSV)$2tA`v+tmOAfnX$7;!0lpFQw zUTIOs!%(f2Be~%1bzZ?D*X3)YRuikf+NermI4FHRGmA?d02dw1iM#oka<|ipTU)p; zIgtE&mC>npA?wwZi0YlIj81jErV_2<%?~Q0Q}06Enq^zYWs57_>dy>TnpG0<%Z@D( zzdfVS3f5)fKV?;eF4I*=LSjU7k_!DPk@3dyL z24(S3qU-4y8LA+&MuWrUq@zW+gIChXBG3$wCKr_^MNhBLt@!m(-BK%hJ~F$w^2H(Z zfj~~>S~I~GFEfgFbI(C-AI+EugkskG7Ix;A=m5?^9Gt~gkI>`*nkM*9%BbHicn1<) z8l9w}zcDUQ1q__%InZ-O_0UYgYI;3AS5)s`jGO88(7JJ;*?FfjI`u9tpHb%gT#N8# z1CSDgxnkXu{ue|A8s(z6qu;gfY<*By^ePe~Ppl#_MxJSV?a>o;E75P#`YgOW3R-d5 z^XRFUmn6~V6D1^Nd{BD|^kkOY7kR!o@G0IH(v{XY4L~KvN;NlD>ea>wR(7ysS7Bw2 zI*);p_hDt(s)rk=i!^2=tUOGwH-eQX>Gd>L*6~?+vGRbhVsBQkEoqK8tfJVhRe>Ml zlA0dwQSVj8Zf#pU>%a?Tx6I%y1lhuD3^np&sKS0H@+%h&Lo19ScDAC{rw2o{!=qp@ z^n?ZC>cAeRV(+6o$=WeF(2{KQ)N`Y!$bOz>g&x%PBqB%6KS6?C7^sitE#4qU@e!2{ z`*{d0882Dv=c(lPY}X6SGI03?GtbB5`*`v)jT)RWRYsD{G#@<5wCYSqf5*C` z(1R5xm1)E$M(p2pnMSlv|0E%qW*m=larecy87unx<0RsR@UFf$7`!MuWGqwqzPKOg z!P#VE3A6bozc0DSJDU<=NPPF7T)vUryEfm*Qx0iRk$f|T|G2>K;kO7Y)+vyi$2ZpC z4BsS#X&@55KyM5m^6se3D#};TC5a*Hh|omtbJFeB28l5kyH#d^xH|9^rt~g0bOuVl zkq^tW(KL={xwu}PMM9H0OoqCj9!ARhuB8TN=*UR2(KCi$*&F>HT9nf}3xpm%Za78A zS(c1rIOvg-P~rf6LM9H%I9HkdHOm{rlU(4_7xRP~c@lMc_$KdHP<6ysn=CEJW}Eyz zhe$ohrJ%wI=uX2%3ngU@(d+8?=FJyW~zf9ykX{rZjHanIm H4M6_`R{oK% literal 0 HcmV?d00001 diff --git a/nanomsg/lib/pkgconfig/nanomsg.pc b/nanomsg/lib/pkgconfig/nanomsg.pc new file mode 100644 index 000000000..57459dd0b --- /dev/null +++ b/nanomsg/lib/pkgconfig/nanomsg.pc @@ -0,0 +1,13 @@ +prefix=/home/ca/Schreibtisch/supernet/iguana/nanomsg +exec_prefix=${prefix} +includedir=${prefix}/include +libdir=${prefix}/lib + +Name: nanomsg +Description: High-Performance Scalability Protocols +URL: http://nanomsg.org/ +Version: 1.0.0 +Requires: +Libs: -L${libdir} -lnanomsg +Libs.private: -lws2_32 -lmswsock -ladvapi32 +Cflags: -I${includedir} diff --git a/win_lib/bin/curl-config b/win_lib/bin/curl-config new file mode 100755 index 000000000..9fbbf0b50 --- /dev/null +++ b/win_lib/bin/curl-config @@ -0,0 +1,178 @@ +#! /bin/sh +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 2001 - 2012, Daniel Stenberg, , et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + +prefix=/home/ca/Schreibtisch/supernet/crypto777/curl-7.52.1/win_lib +exec_prefix=${prefix} +includedir=${prefix}/include +cppflag_curl_staticlib=-DCURL_STATICLIB + +usage() +{ + cat <&2 + exit 1 + fi + ;; + + --configure) + echo " '--enable-mingw' '--enable-static' '--disable-shared' '--prefix=/home/ca/Schreibtisch/supernet/crypto777/curl-7.52.1/win_lib' '--host=i686-w64-mingw32' '--with-ssl=openssl_lib/' 'host_alias=i686-w64-mingw32' 'CC=i686-w64-mingw32-gcc'" + ;; + + *) + echo "unknown option: $1" + usage 1 + ;; + esac + shift +done + +exit 0 diff --git a/win_lib/bin/curl.exe b/win_lib/bin/curl.exe new file mode 100755 index 0000000000000000000000000000000000000000..65de807ecc55d57fd5f0994a40608c16facdc32e GIT binary patch literal 969892 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'!k%f| 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 z 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 CNf*oj literal 0 HcmV?d00001 diff --git a/win_lib/bin/libcurl-4.dll b/win_lib/bin/libcurl-4.dll new file mode 100755 index 0000000000000000000000000000000000000000..6a73485a6319b8a6f848b93a4624e6edd1e4c67f GIT binary patch literal 563337 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Ⓢ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�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, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + +#include "curlver.h" /* libcurl version defines */ +#include "curlbuild.h" /* libcurl build definitions */ +#include "curlrules.h" /* libcurl rules enforcement */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else +typedef void CURL; +typedef void CURLSH; +#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist *contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + + + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char *b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. If this is not used, error messages go to stderr instead: */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of miliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAINFO, STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAPATH, STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CINIT(PROXY_SSLVERSION, LONG, 250), + + /* Set a username for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + + /* CRL file for proxy */ + CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CINIT(PROXY_SSL_OPTIONS, LONG, 261), + + /* Name of pre proxy to use. */ + CINIT(PRE_PROXY, STRINGPOINT, 262), + + /* The public key in DER form used to validate the proxy public key + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + CURL_SSLVERSION_TLSv1_3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + libcurl, see lib/README.curlx for details + + !checksrc! disable SPACEBEFOREPAREN 2 +*/ +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); + +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_CYASSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, + CURLSSLBACKEND_MBEDTLS = 11 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL 1 +#define CURLSSLBACKEND_BORINGSSL 1 +#define CURLSSLBACKEND_WOLFSSL 6 + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_SLIST + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_SLIST + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, + CURLINFO_PROTOCOL = CURLINFO_LONG + 48, + CURLINFO_SCHEME = CURLINFO_STRING + 49, + /* Fill in new entries below here! */ + + CURLINFO_LASTONE = 49 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FOURTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is suported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ +#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/win_lib/include/curl/curlbuild.h b/win_lib/include/curl/curlbuild.h new file mode 100644 index 000000000..80e4ba7ca --- /dev/null +++ b/win_lib/include/curl/curlbuild.h @@ -0,0 +1,198 @@ +/* include/curl/curlbuild.h. Generated from curlbuild.h.in by configure. */ +#ifndef __CURL_CURLBUILD_H +#define __CURL_CURLBUILD_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * If you think that something actually needs to be changed, adjusted + * or fixed in this file, then, report it on the libcurl development + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * This header file shall only export symbols which are 'curl' or 'CURL' + * prefixed, otherwise public name space would be polluted. + * + * NOTE 2: + * ------- + * + * Right now you might be staring at file include/curl/curlbuild.h.in or + * at file include/curl/curlbuild.h, this is due to the following reason: + * + * On systems capable of running the configure script, the configure process + * will overwrite the distributed include/curl/curlbuild.h file with one that + * is suitable and specific to the library being configured and built, which + * is generated from the include/curl/curlbuild.h.in template file. + * + */ + +/* ================================================================ */ +/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */ +/* ================================================================ */ + +#ifdef CURL_SIZEOF_LONG +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined +#endif + +#ifdef CURL_TYPEOF_CURL_OFF_T +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_T +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_FORMAT_CURL_OFF_TU +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined +#endif + +#ifdef CURL_FORMAT_OFF_T +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined +#endif + +#ifdef CURL_SIZEOF_CURL_OFF_T +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_T +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined +#endif + +#ifdef CURL_SUFFIX_CURL_OFF_TU +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined +#endif + +/* ================================================================ */ +/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */ +/* ================================================================ */ + +/* Configure process defines this to 1 when it finds out that system */ +/* header file ws2tcpip.h must be included by the external interface. */ +#define CURL_PULL_WS2TCPIP_H 1 +#ifdef CURL_PULL_WS2TCPIP_H +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif +# include +# include +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/types.h must be included by the external interface. */ +#define CURL_PULL_SYS_TYPES_H 1 +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file stdint.h must be included by the external interface. */ +#define CURL_PULL_STDINT_H 1 +#ifdef CURL_PULL_STDINT_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file inttypes.h must be included by the external interface. */ +#define CURL_PULL_INTTYPES_H 1 +#ifdef CURL_PULL_INTTYPES_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/socket.h must be included by the external interface. */ +/* #undef CURL_PULL_SYS_SOCKET_H */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +/* #undef CURL_PULL_SYS_POLL_H */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* The size of `long', as computed by sizeof. */ +#define CURL_SIZEOF_LONG 4 + +/* Integral data type used for curl_socklen_t. */ +#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t + +/* The size of `curl_socklen_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_SOCKLEN_T 4 + +/* Data type definition of curl_socklen_t. */ +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; + +/* Signed integral data type used for curl_off_t. */ +#define CURL_TYPEOF_CURL_OFF_T int64_t + +/* Data type definition of curl_off_t. */ +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; + +/* curl_off_t formatting string directive without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_T "I64d" + +/* unsigned curl_off_t formatting string without "%" conversion specifier. */ +#define CURL_FORMAT_CURL_OFF_TU "I64u" + +/* curl_off_t formatting string directive with "%" conversion specifier. */ +#define CURL_FORMAT_OFF_T "%I64d" + +/* The size of `curl_off_t', as computed by sizeof. */ +#define CURL_SIZEOF_CURL_OFF_T 8 + +/* curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_T LL + +/* unsigned curl_off_t constant suffix. */ +#define CURL_SUFFIX_CURL_OFF_TU ULL + +#endif /* __CURL_CURLBUILD_H */ diff --git a/win_lib/include/curl/curlrules.h b/win_lib/include/curl/curlrules.h new file mode 100644 index 000000000..55d21f68f --- /dev/null +++ b/win_lib/include/curl/curlrules.h @@ -0,0 +1,262 @@ +#ifndef __CURL_CURLRULES_H +#define __CURL_CURLRULES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* ================================================================ */ +/* COMPILE TIME SANITY CHECKS */ +/* ================================================================ */ + +/* + * NOTE 1: + * ------- + * + * All checks done in this file are intentionally placed in a public + * header file which is pulled by curl/curl.h when an application is + * being built using an already built libcurl library. Additionally + * this file is also included and used when building the library. + * + * If compilation fails on this file it is certainly sure that the + * problem is elsewhere. It could be a problem in the curlbuild.h + * header file, or simply that you are using different compilation + * settings than those used to build the library. + * + * Nothing in this file is intended to be modified or adjusted by the + * curl library user nor by the curl library builder. + * + * Do not deactivate any check, these are done to make sure that the + * library is properly built and used. + * + * You can find further help on the libcurl development mailing list: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + * + * NOTE 2 + * ------ + * + * Some of the following compile time checks are based on the fact + * that the dimension of a constant array can not be a negative one. + * In this way if the compile time verification fails, the compilation + * will fail issuing an error. The error description wording is compiler + * dependent but it will be quite similar to one of the following: + * + * "negative subscript or subscript is too large" + * "array must have at least one element" + * "-1 is an illegal array size" + * "size of array is negative" + * + * If you are building an application which tries to use an already + * built libcurl library and you are getting this kind of errors on + * this file, it is a clear indication that there is a mismatch between + * how the library was built and how you are trying to use it for your + * application. Your already compiled or binary library provider is the + * only one who can give you the details you need to properly use it. + */ + +/* + * Verify that some macros are actually defined. + */ + +#ifndef CURL_SIZEOF_LONG +# error "CURL_SIZEOF_LONG definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_SOCKLEN_T +# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_SOCKLEN_T +# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing +#endif + +#ifndef CURL_TYPEOF_CURL_OFF_T +# error "CURL_TYPEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_T +# error "CURL_FORMAT_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_FORMAT_CURL_OFF_TU +# error "CURL_FORMAT_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing +#endif + +#ifndef CURL_FORMAT_OFF_T +# error "CURL_FORMAT_OFF_T definition is missing!" + Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing +#endif + +#ifndef CURL_SIZEOF_CURL_OFF_T +# error "CURL_SIZEOF_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_T +# error "CURL_SUFFIX_CURL_OFF_T definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing +#endif + +#ifndef CURL_SUFFIX_CURL_OFF_TU +# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!" + Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing +#endif + +/* + * Macros private to this header file. + */ + +#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1 + +#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1 + +/* + * Verify that the size previously defined and expected for long + * is the same as the one reported by sizeof() at compile time. + */ + +typedef char + __curl_rule_01__ + [CurlchkszEQ(long, CURL_SIZEOF_LONG)]; + +/* + * Verify that the size previously defined and expected for + * curl_off_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_02__ + [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)]; + +/* + * Verify at compile time that the size of curl_off_t as reported + * by sizeof() is greater or equal than the one reported for long + * for the current compilation. + */ + +typedef char + __curl_rule_03__ + [CurlchkszGE(curl_off_t, long)]; + +/* + * Verify that the size previously defined and expected for + * curl_socklen_t is actually the the same as the one reported + * by sizeof() at compile time. + */ + +typedef char + __curl_rule_04__ + [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)]; + +/* + * Verify at compile time that the size of curl_socklen_t as reported + * by sizeof() is greater or equal than the one reported for int for + * the current compilation. + */ + +typedef char + __curl_rule_05__ + [CurlchkszGE(curl_socklen_t, int)]; + +/* ================================================================ */ +/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */ +/* ================================================================ */ + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +/* + * Get rid of macros private to this header file. + */ + +#undef CurlchkszEQ +#undef CurlchkszGE + +/* + * Get rid of macros not intended to exist beyond this point. + */ + +#undef CURL_PULL_WS2TCPIP_H +#undef CURL_PULL_SYS_TYPES_H +#undef CURL_PULL_SYS_SOCKET_H +#undef CURL_PULL_SYS_POLL_H +#undef CURL_PULL_STDINT_H +#undef CURL_PULL_INTTYPES_H + +#undef CURL_TYPEOF_CURL_SOCKLEN_T +#undef CURL_TYPEOF_CURL_OFF_T + +#ifdef CURL_NO_OLDIES +#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */ +#endif + +#endif /* __CURL_CURLRULES_H */ diff --git a/win_lib/include/curl/curlver.h b/win_lib/include/curl/curlver.h new file mode 100644 index 000000000..ae91b0d2b --- /dev/null +++ b/win_lib/include/curl/curlver.h @@ -0,0 +1,77 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2016 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.52.1" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 52 +#define LIBCURL_VERSION_PATCH 1 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x073401 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date should follow this template: + * + * "Mon Feb 12 11:35:33 UTC 2007" + */ +#define LIBCURL_TIMESTAMP "Fri Dec 23 07:22:31 UTC 2016" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --git a/win_lib/include/curl/easy.h b/win_lib/include/curl/easy.h new file mode 100644 index 000000000..752c5049f --- /dev/null +++ b/win_lib/include/curl/easy.h @@ -0,0 +1,102 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/win_lib/include/curl/mprintf.h b/win_lib/include/curl/mprintf.h new file mode 100644 index 000000000..e20f546e1 --- /dev/null +++ b/win_lib/include/curl/mprintf.h @@ -0,0 +1,50 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ +#include "curl.h" /* for CURL_EXTERN */ + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/win_lib/include/curl/multi.h b/win_lib/include/curl/multi.h new file mode 100644 index 000000000..d1e00cc5d --- /dev/null +++ b/win_lib/include/curl/multi.h @@ -0,0 +1,439 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else +typedef void CURLM; +#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on invidual transfers even when this + * returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic informations. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/win_lib/include/curl/stdcheaders.h b/win_lib/include/curl/stdcheaders.h new file mode 100644 index 000000000..027b6f421 --- /dev/null +++ b/win_lib/include/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread(void *, size_t, size_t, FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/win_lib/include/curl/typecheck-gcc.h b/win_lib/include/curl/typecheck-gcc.h new file mode 100644 index 000000000..4eb896eaa --- /dev/null +++ b/win_lib/include/curl/typecheck-gcc.h @@ -0,0 +1,623 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__(option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__(info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string ('char *' or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a 'FILE *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a 'struct curl_httppost *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to 'char *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (CURLINFO_SLIST < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true iff expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void *)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *)) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func), type*)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (_curl_write_callback2)(const char *, size_t, size_t, + const void *); +typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (_curl_write_callback5)(const void *, size_t, size_t, + const void *); +typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/win_lib/lib/libcurl.a b/win_lib/lib/libcurl.a new file mode 100644 index 0000000000000000000000000000000000000000..845b4b26cfc9ddae0768dbe8b714e6e3a5340300 GIT binary patch literal 575990 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�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

{@sKvKGCnrXJUZ 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, et al. +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### + +# This should most probably benefit from getting a "Requires:" field added +# dynamically by configure. +# +prefix=/home/ca/Schreibtisch/supernet/crypto777/curl-7.52.1/win_lib +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include +supported_protocols="DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP LDAPS POP3 POP3S RTSP SMB SMBS SMTP SMTPS TELNET TFTP" +supported_features="SSL IPv6 NTLM TLS-SRP HTTPS-proxy" + +Name: libcurl +URL: https://curl.haxx.se/ +Description: Library to transfer files with ftp, http, etc. +Version: 7.52.1 +Libs: -L${libdir} -lcurl +Libs.private: -lssl -lcrypto -lssl -lcrypto -lgdi32 -lwldap32 -lws2_32 +Cflags: -I${includedir} -DCURL_STATICLIB diff --git a/win_lib/share/aclocal/libcurl.m4 b/win_lib/share/aclocal/libcurl.m4 new file mode 100644 index 000000000..53d694d0a --- /dev/null +++ b/win_lib/share/aclocal/libcurl.m4 @@ -0,0 +1,272 @@ +#*************************************************************************** +# _ _ ____ _ +# Project ___| | | | _ \| | +# / __| | | | |_) | | +# | (__| |_| | _ <| |___ +# \___|\___/|_| \_\_____| +# +# Copyright (C) 2006, David Shaw +# +# This software is licensed as described in the file COPYING, which +# you should have received as part of this distribution. The terms +# are also available at https://curl.haxx.se/docs/copyright.html. +# +# You may opt to use, copy, modify, merge, publish, distribute and/or sell +# copies of the Software, and permit persons to whom the Software is +# furnished to do so, under the terms of the COPYING file. +# +# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# KIND, either express or implied. +# +########################################################################### +# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION], +# [ACTION-IF-YES], [ACTION-IF-NO]) +# ---------------------------------------------------------- +# David Shaw May-09-2006 +# +# Checks for libcurl. DEFAULT-ACTION is the string yes or no to +# specify whether to default to --with-libcurl or --without-libcurl. +# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the +# minimum version of libcurl to accept. Pass the version as a regular +# version number like 7.10.1. If not supplied, any version is +# accepted. ACTION-IF-YES is a list of shell commands to run if +# libcurl was successfully found and passed the various tests. +# ACTION-IF-NO is a list of shell commands that are run otherwise. +# Note that using --without-libcurl does run ACTION-IF-NO. +# +# This macro #defines HAVE_LIBCURL if a working libcurl setup is +# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary +# values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are +# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy +# where yyy are the various protocols supported by libcurl. Both xxx +# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of +# the macro for the complete list of possible defines. Shell +# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also +# defined to 'yes' for those features and protocols that were found. +# Note that xxx and yyy keep the same capitalization as in the +# curl-config list (e.g. it's "HTTP" and not "http"). +# +# Users may override the detected values by doing something like: +# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure +# +# For the sake of sanity, this macro assumes that any libcurl that is +# found is after version 7.7.2, the first version that included the +# curl-config script. Note that it is very important for people +# packaging binary versions of libcurl to include this script! +# Without curl-config, we can only guess what protocols are available, +# or use curl_version_info to figure it out at runtime. + +AC_DEFUN([LIBCURL_CHECK_CONFIG], +[ + AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL]) + AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4]) + AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6]) + AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz]) + AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS]) + AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN]) + AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI]) + AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM]) + + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS]) + AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET]) + AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT]) + AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3]) + AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP]) + AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP]) + + AC_ARG_WITH(libcurl, + AS_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]), + [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])]) + + if test "$_libcurl_with" != "no" ; then + + AC_PROG_AWK + + _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'" + + _libcurl_try_link=yes + + if test -d "$_libcurl_with" ; then + LIBCURL_CPPFLAGS="-I$withval/include" + _libcurl_ldflags="-L$withval/lib" + AC_PATH_PROG([_libcurl_config],[curl-config],[], + ["$withval/bin"]) + else + AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH]) + fi + + if test x$_libcurl_config != "x" ; then + AC_CACHE_CHECK([for the version of libcurl], + [libcurl_cv_lib_curl_version], + [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`]) + + _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` + _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse` + + if test $_libcurl_wanted -gt 0 ; then + AC_CACHE_CHECK([for libcurl >= version $2], + [libcurl_cv_lib_version_ok], + [ + if test $_libcurl_version -ge $_libcurl_wanted ; then + libcurl_cv_lib_version_ok=yes + else + libcurl_cv_lib_version_ok=no + fi + ]) + fi + + if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then + if test x"$LIBCURL_CPPFLAGS" = "x" ; then + LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` + fi + if test x"$LIBCURL" = "x" ; then + LIBCURL=`$_libcurl_config --libs` + + # This is so silly, but Apple actually has a bug in their + # curl-config script. Fixed in Tiger, but there are still + # lots of Panther installs around. + case "${host}" in + powerpc-apple-darwin7*) + LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` + ;; + esac + fi + + # All curl-config scripts support --feature + _libcurl_features=`$_libcurl_config --feature` + + # Is it modern enough to have --protocols? (7.12.4) + if test $_libcurl_version -ge 461828 ; then + _libcurl_protocols=`$_libcurl_config --protocols` + fi + else + _libcurl_try_link=no + fi + + unset _libcurl_wanted + fi + + if test $_libcurl_try_link = yes ; then + + # we didn't find curl-config, so let's see if the user-supplied + # link line (or failing that, "-lcurl") is enough. + LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} + + AC_CACHE_CHECK([whether libcurl is usable], + [libcurl_cv_lib_curl_usable], + [ + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBCURL $LIBS" + + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ +/* Try and use a few common options to force a failure if we are + missing symbols or can't link. */ +int x; +curl_easy_setopt(NULL,CURLOPT_URL,NULL); +x=CURL_ERROR_SIZE; +x=CURLOPT_WRITEFUNCTION; +x=CURLOPT_WRITEDATA; +x=CURLOPT_ERRORBUFFER; +x=CURLOPT_STDERR; +x=CURLOPT_VERBOSE; +if (x) {;} +]])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + ]) + + if test $libcurl_cv_lib_curl_usable = yes ; then + + # Does curl_free() exist in this version of libcurl? + # If not, fake it with free() + + _libcurl_save_cppflags=$CPPFLAGS + CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" + _libcurl_save_libs=$LIBS + LIBS="$LIBS $LIBCURL" + + AC_CHECK_FUNC(curl_free,, + AC_DEFINE(curl_free,free, + [Define curl_free() as free() if our version of curl lacks curl_free.])) + + CPPFLAGS=$_libcurl_save_cppflags + LIBS=$_libcurl_save_libs + unset _libcurl_save_cppflags + unset _libcurl_save_libs + + AC_DEFINE(HAVE_LIBCURL,1, + [Define to 1 if you have a functional curl library.]) + AC_SUBST(LIBCURL_CPPFLAGS) + AC_SUBST(LIBCURL) + + for _libcurl_feature in $_libcurl_features ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1]) + eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes + done + + if test "x$_libcurl_protocols" = "x" ; then + + # We don't have --protocols, so just assume that all + # protocols are available + _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" + + if test x$libcurl_feature_SSL = xyes ; then + _libcurl_protocols="$_libcurl_protocols HTTPS" + + # FTPS wasn't standards-compliant until version + # 7.11.0 (0x070b00 == 461568) + if test $_libcurl_version -ge 461568; then + _libcurl_protocols="$_libcurl_protocols FTPS" + fi + fi + + # RTSP, IMAP, POP3 and SMTP were added in + # 7.20.0 (0x071400 == 463872) + if test $_libcurl_version -ge 463872; then + _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" + fi + fi + + for _libcurl_protocol in $_libcurl_protocols ; do + AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1]) + eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes + done + else + unset LIBCURL + unset LIBCURL_CPPFLAGS + fi + fi + + unset _libcurl_try_link + unset _libcurl_version_parse + unset _libcurl_config + unset _libcurl_feature + unset _libcurl_features + unset _libcurl_protocol + unset _libcurl_protocols + unset _libcurl_version + unset _libcurl_ldflags + fi + + if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then + # This is the IF-NO path + ifelse([$4],,:,[$4]) + else + # This is the IF-YES path + ifelse([$3],,:,[$3]) + fi + + unset _libcurl_with +])dnl diff --git a/win_lib/share/man/man1/curl-config.1 b/win_lib/share/man/man1/curl-config.1 new file mode 100644 index 000000000..4c1e323c6 --- /dev/null +++ b/win_lib/share/man/man1/curl-config.1 @@ -0,0 +1,98 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.TH curl-config 1 "25 Oct 2007" "Curl 7.17.1" "curl-config manual" +.SH NAME +curl-config \- Get information about a libcurl installation +.SH SYNOPSIS +.B curl-config [options] +.SH DESCRIPTION +.B curl-config +displays information about the curl and libcurl installation. +.SH OPTIONS +.IP "--ca" +Displays the built-in path to the CA cert bundle this libcurl uses. +.IP "--cc" +Displays the compiler used to build libcurl. +.IP "--cflags" +Set of compiler options (CFLAGS) to use when compiling files that use +libcurl. Currently that is only the include path to the curl include files. +.IP "--checkfor [version]" +Specify the oldest possible libcurl version string you want, and this +script will return 0 if the current installation is new enough or it +returns 1 and outputs a text saying that the current version is not new +enough. (Added in 7.15.4) +.IP "--configure" +Displays the arguments given to configure when building curl. +.IP "--feature" +Lists what particular main features the installed libcurl was built with. At +the time of writing, this list may include SSL, KRB4 or IPv6. Do not assume +any particular order. The keywords will be separated by newlines. There may be +none, one, or several keywords in the list. +.IP "--help" +Displays the available options. +.IP "--libs" +Shows the complete set of libs and other linker options you will need in order +to link your application with libcurl. +.IP "--prefix" +This is the prefix used when libcurl was installed. Libcurl is then installed +in $prefix/lib and its header files are installed in $prefix/include and so +on. The prefix is set with "configure --prefix". +.IP "--protocols" +Lists what particular protocols the installed libcurl was built to support. At +the time of writing, this list may include HTTP, HTTPS, FTP, FTPS, FILE, +TELNET, LDAP, DICT. Do not assume any particular order. The protocols will +be listed using uppercase and are separated by newlines. There may be none, +one, or several protocols in the list. (Added in 7.13.0) +.IP "--static-libs" +Shows the complete set of libs and other linker options you will need in order +to link your application with libcurl statically. (Added in 7.17.1) +.IP "--version" +Outputs version information about the installed libcurl. +.IP "--vernum" +Outputs version information about the installed libcurl, in numerical mode. +This outputs the version number, in hexadecimal, with 8 bits for each part; +major, minor, patch. So that libcurl 7.7.4 would appear as 070704 and libcurl +12.13.14 would appear as 0c0d0e... Note that the initial zero might be +omitted. (This option was broken in the 7.15.0 release.) +.SH "EXAMPLES" +What linker options do I need when I link with libcurl? + + $ curl-config --libs + +What compiler options do I need when I compile using libcurl functions? + + $ curl-config --cflags + +How do I know if libcurl was built with SSL support? + + $ curl-config --feature | grep SSL + +What's the installed libcurl version? + + $ curl-config --version + +How do I build a single file with a one-line command? + + $ `curl-config --cc --cflags` -o example example.c `curl-config --libs` +.SH "SEE ALSO" +.BR curl (1) diff --git a/win_lib/share/man/man1/curl.1 b/win_lib/share/man/man1/curl.1 new file mode 100644 index 000000000..5866ba908 --- /dev/null +++ b/win_lib/share/man/man1/curl.1 @@ -0,0 +1,2668 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +.\" * +.\" * This software is licensed as described in the file COPYING, which +.\" * you should have received as part of this distribution. The terms +.\" * are also available at https://curl.haxx.se/docs/copyright.html. +.\" * +.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell +.\" * copies of the Software, and permit persons to whom the Software is +.\" * furnished to do so, under the terms of the COPYING file. +.\" * +.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +.\" * KIND, either express or implied. +.\" * +.\" ************************************************************************** +.\" +.\" DO NOT EDIT. Generated by the curl project gen.pl man page generator. +.\" +.TH curl 1 "16 Dec 2016" "Curl 7.52.0" "Curl Manual" +.SH NAME +curl \- transfer a URL +.SH SYNOPSIS +.B curl [options] +.I [URL...] +.SH DESCRIPTION +.B curl +is a tool to transfer data from or to a server, using one of the supported +protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, +LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET +and TFTP). The command is designed to work without user interaction. + +curl offers a busload of useful tricks like proxy support, user +authentication, FTP upload, HTTP post, SSL connections, cookies, file transfer +resume, Metalink, and more. As you will see below, the number of features will +make your head spin! + +curl is powered by libcurl for all transfer-related features. See +\fIlibcurl(3)\fP for details. +.SH URL +The URL syntax is protocol-dependent. You'll find a detailed description in +RFC 3986. + +You can specify multiple URLs or parts of URLs by writing part sets within +braces as in: + + http://site.{one,two,three}.com + +or you can get sequences of alphanumeric series by using [] as in: + + ftp://ftp.example.com/file[1-100].txt + + ftp://ftp.example.com/file[001-100].txt (with leading zeros) + + ftp://ftp.example.com/file[a-z].txt + +Nested sequences are not supported, but you can use several ones next to each +other: + + http://example.com/archive[1996-1999]/vol[1-4]/part{a,b,c}.html + +You can specify any amount of URLs on the command line. They will be fetched +in a sequential manner in the specified order. + +You can specify a step counter for the ranges to get every Nth number or +letter: + + http://example.com/file[1-100:10].txt + + http://example.com/file[a-z:2].txt + +When using [] or {} sequences when invoked from a command line prompt, you +probably have to put the full URL within double quotes to avoid the shell from +interfering with it. This also goes for other characters treated special, like +for example '&', '?' and '*'. + +Provide the IPv6 zone index in the URL with an escaped percentage sign and the +interface name. Like in + + http://[fe80::3%25eth0]/ + +If you specify URL without protocol:// prefix, curl will attempt to guess what +protocol you might want. It will then default to HTTP but try other protocols +based on often-used host name prefixes. For example, for host names starting +with "ftp." curl will assume you want to speak FTP. + +curl will do its best to use what you pass to it as a URL. It is not trying to +validate it as a syntactically correct URL by any means but is instead +\fBvery\fP liberal with what it accepts. + +curl will attempt to re-use connections for multiple file transfers, so that +getting many files from the same server will not do multiple connects / +handshakes. This improves speed. Of course this is only done on files +specified on a single command line and cannot be used between separate curl +invokes. +.SH "PROGRESS METER" +curl normally displays a progress meter during operations, indicating the +amount of transferred data, transfer speeds and estimated time left, etc. The +progress meter displays number of bytes and the speeds are in bytes per +second. The suffixes (k, M, G, T, P) are 1024 based. For example 1k is 1024 +bytes. 1M is 1048576 bytes. + +curl displays this data to the terminal by default, so if you invoke curl to +do an operation and it is about to write data to the terminal, it +\fIdisables\fP the progress meter as otherwise it would mess up the output +mixing progress meter and response data. + +If you want a progress meter for HTTP POST or PUT requests, you need to +redirect the response output to a file, using shell redirect (>), -o [file] or +similar. + +It is not the same case for FTP upload as that operation does not spit out +any response data to the terminal. + +If you prefer a progress "bar" instead of the regular meter, \fI-#, --progress-bar\fP is +your friend. +.SH OPTIONS +Options start with one or two dashes. Many of the options require an +additional value next to them. + +The short "single-dash" form of the options, -d for example, may be used with +or without a space between it and its value, although a space is a recommended +separator. The long "double-dash" form, \fI-d, --data\fP for example, requires a space +between it and its value. + +Short version options that don't need any additional values can be used +immediately next to each other, like for example you can specify all the +options -O, -L and -v at once as -OLv. + +In general, all boolean options are enabled with --\fBoption\fP and yet again +disabled with --\fBno-\fPoption. That is, you use the exact same option name +but prefix it with "no-". However, in this list we mostly only list and show +the --option version of them. (This concept with --no options was added in +7.19.0. Previously most options were toggled on/off on repeated use of the +same command line option.) +.IP "--anyauth" +(HTTP) Tells curl to figure out authentication method by itself, and use the most +secure one the remote site claims to support. This is done by first doing a +request and checking the response-headers, thus possibly inducing an extra +network round-trip. This is used instead of setting a specific authentication +method, which you can do with \fI--basic\fP, \fI--digest\fP, \fI--ntlm\fP, and \fI--negotiate\fP. + +Using \fI--anyauth\fP is not recommended if you do uploads from stdin, since it may +require data to be sent twice and then the client must be able to rewind. If +the need should arise when uploading from stdin, the upload operation will +fail. + +Used together with \fI-u, --user\fP. + +See also \fI--proxy-anyauth\fP and \fI--basic\fP and \fI--digest\fP. +.IP "-a, --append" +(FTP SFTP) When used in an upload, this makes curl append to the target file instead of +overwriting it. If the remote file doesn't exist, it will be created. Note +that this flag is ignored by some SFTP servers (including OpenSSH). +.IP "--basic" +(HTTP) Tells curl to use HTTP Basic authentication with the remote host. This is the +default and this option is usually pointless, unless you use it to override a +previously set option that sets a different authentication method (such as +\fI--ntlm\fP, \fI--digest\fP, or \fI--negotiate\fP). + +Used together with \fI-u, --user\fP. + +See also \fI--proxy-basic\fP. +.IP "--cacert " +(TLS) Tells curl to use the specified certificate file to verify the peer. The file +may contain multiple CA certificates. The certificate(s) must be in PEM +format. Normally curl is built to use a default file for this, so this option +is typically used to alter that default file. + +curl recognizes the environment variable named 'CURL_CA_BUNDLE' if it is +set, and uses the given path as a path to a CA cert bundle. This option +overrides that variable. + +The windows version of curl will automatically look for a CA certs file named +\'curl-ca-bundle.crt\', either in the same directory as curl.exe, or in the +Current Working Directory, or in any folder along your PATH. + +If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module +(libnsspem.so) needs to be available for this option to work properly. + +(iOS and macOS only) If curl is built against Secure Transport, then this +option is supported for backward compatibility with other SSL engines, but it +should not be set. If the option is not set, then curl will use the +certificates in the system and user Keychain to verify the peer, which is the +preferred method of verifying the peer's certificate chain. + +If this option is used several times, the last one will be used. +.IP "--capath

" +(TLS) Tells curl to use the specified certificate directory to verify the +peer. Multiple paths can be provided by separating them with ":" (e.g. +\&"path1:path2:path3"). The certificates must be in PEM format, and if curl is +built against OpenSSL, the directory must have been processed using the +c_rehash utility supplied with OpenSSL. Using \fI--capath\fP can allow +OpenSSL-powered curl to make SSL-connections much more efficiently than using +\fI--cacert\fP if the --cacert file contains many CA certificates. + +If this option is set, the default capath value will be ignored, and if it is +used several times, the last one will be used. +.IP "--cert-status" +(TLS) Tells curl to verify the status of the server certificate by using the +Certificate Status Request (aka. OCSP stapling) TLS extension. + +If this option is enabled and the server sends an invalid (e.g. expired) +response, if the response suggests that the server certificate has been revoked, +or no response at all is received, the verification fails. + +This is currently only implemented in the OpenSSL, GnuTLS and NSS backends. + +Added in 7.41.0. +.IP "--cert-type " +(TLS) Tells curl what certificate type the provided certificate is in. PEM, DER and +ENG are recognized types. If not specified, PEM is assumed. + +If this option is used several times, the last one will be used. + +See also \fI-E, --cert\fP and \fI--key\fP and \fI--key-type\fP. +.IP "-E, --cert " +(TLS) Tells curl to use the specified client certificate file when getting a file +with HTTPS, FTPS or another SSL-based protocol. The certificate must be in +PKCS#12 format if using Secure Transport, or PEM format if using any other +engine. If the optional password isn't specified, it will be queried for on +the terminal. Note that this option assumes a \&"certificate" file that is the +private key and the client certificate concatenated! See \fI-E, --cert\fP and \fI--key\fP to +specify them independently. + +If curl is built against the NSS SSL library then this option can tell +curl the nickname of the certificate to use within the NSS database defined +by the environment variable SSL_DIR (or by default /etc/pki/nssdb). If the +NSS PEM PKCS#11 module (libnsspem.so) is available then PEM files may be +loaded. If you want to use a file from the current directory, please precede +it with "./" prefix, in order to avoid confusion with a nickname. If the +nickname contains ":", it needs to be preceded by "\\" so that it is not +recognized as password delimiter. If the nickname contains "\\", it needs to +be escaped as "\\\\" so that it is not recognized as an escape character. + +(iOS and macOS only) If curl is built against Secure Transport, then the +certificate string can either be the name of a certificate/private key in the +system or user keychain, or the path to a PKCS#12-encoded certificate and +private key. If you want to use a file from the current directory, please +precede it with "./" prefix, in order to avoid confusion with a nickname. + +If this option is used several times, the last one will be used. + +See also \fI--cert-type\fP and \fI--key\fP and \fI--key-type\fP. +.IP "--ciphers " +(TLS) Specifies which ciphers to use in the connection. The list of ciphers must +specify valid ciphers. Read up on SSL cipher list details on this URL: + + https://www.openssl.org/docs/apps/ciphers.html + +NSS ciphers are done differently than OpenSSL and GnuTLS. The full list of NSS +ciphers is in the NSSCipherSuite entry at this URL: + + https://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html#Directives + +If this option is used several times, the last one will be used. +.IP "--compressed" +(HTTP) Request a compressed response using one of the algorithms curl supports, and +save the uncompressed document. If this option is used and the server sends +an unsupported encoding, curl will report an error. +.IP "-K, --config " +Specify which config file to read curl arguments from. The config file is a +text file in which command line arguments can be written which then will be +used as if they were written on the actual command line. + +Options and their parameters must be specified on the same config file line, +separated by whitespace, colon, or the equals sign. Long option names can +optionally be given in the config file without the initial double dashes and +if so, the colon or equals characters can be used as separators. If the option +is specified with one or two dashes, there can be no colon or equals character +between the option and its parameter. + +If the parameter is to contain whitespace, the parameter must be enclosed +within quotes. Within double quotes, the following escape sequences are +available: \\\\, \\", \\t, \\n, \\r and \\v. A backslash preceding any other +letter is ignored. If the first column of a config line is a '#' character, +the rest of the line will be treated as a comment. Only write one option per +physical line in the config file. + +Specify the filename to \fI-K, --config\fP as '-' to make curl read the file from stdin. + +Note that to be able to specify a URL in the config file, you need to specify +it using the \fI--url\fP option, and not by simply writing the URL on its own +line. So, it could look similar to this: + +url = "https://curl.haxx.se/docs/" + +When curl is invoked, it always (unless \fI-q, --disable\fP is used) checks for a +default config file and uses it if found. The default config file is checked +for in the following places in this order: + +1) curl tries to find the "home dir": It first checks for the CURL_HOME and +then the HOME environment variables. Failing that, it uses getpwuid() on +Unix-like systems (which returns the home dir given the current user in your +system). On Windows, it then checks for the APPDATA variable, or as a last +resort the '%USERPROFILE%\\Application Data'. + +2) On windows, if there is no _curlrc file in the home dir, it checks for one +in the same dir the curl executable is placed. On Unix-like systems, it will +simply try to load .curlrc from the determined home dir. + +.nf +# --- Example file --- +# this is a comment +url = "example.com" +output = "curlhere.html" +user-agent = "superagent/1.0" + +# and fetch another URL too +url = "example.com/docs/manpage.html" +-O +referer = "http://nowhereatall.example.com/" +# --- End of example file --- +.fi + +This option can be used multiple times to load multiple config files. +.IP "--connect-timeout " +Maximum time in seconds that you allow curl's connection to take. This only +limits the connection phase, so if curl connects within the given period it +will continue - if not it will exit. Since version 7.32.0, this option +accepts decimal values. + +If this option is used several times, the last one will be used. + +See also \fI-m, --max-time\fP. +.IP "--connect-to " + +For a request to the given HOST:PORT pair, connect to +CONNECT-TO-HOST:CONNECT-TO-PORT instead. This option is suitable to direct +requests at a specific server, e.g. at a specific cluster node in a cluster of +servers. This option is only used to establish the network connection. It +does NOT affect the hostname/port that is used for TLS/SSL (e.g. SNI, +certificate verification) or for the application protocols. "host" and "port" +may be the empty string, meaning "any host/port". "connect-to-host" and +"connect-to-port" may also be the empty string, meaning "use the request's +original host/port". + +This option can be used many times to add many connect rules. + +See also \fI--resolve\fP and \fI-H, --header\fP. Added in 7.49.0. +.IP "-C, --continue-at " +Continue/Resume a previous file transfer at the given offset. The given offset +is the exact number of bytes that will be skipped, counting from the beginning +of the source file before it is transferred to the destination. If used with +uploads, the FTP server command SIZE will not be used by curl. + +Use "-C -" to tell curl to automatically find out where/how to resume the +transfer. It then uses the given output/input files to figure that out. + +If this option is used several times, the last one will be used. + +See also \fI-r, --range\fP. +.IP "-c, --cookie-jar " +(HTTP) Specify to which file you want curl to write all cookies after a completed +operation. Curl writes all cookies from its in-memory cookie storage to the +given file at the end of operations. If no cookies are known, no data will be +written. The file will be written using the Netscape cookie file format. If +you set the file name to a single dash, "-", the cookies will be written to +stdout. + +This command line option will activate the cookie engine that makes curl +record and use cookies. Another way to activate it is to use the \fI-b, --cookie\fP +option. + +If the cookie jar can't be created or written to, the whole curl operation +won't fail or even report an error clearly. Using \fI-v, --verbose\fP will get a warning +displayed, but that is the only visible feedback you get about this possibly +lethal situation. + +If this option is used several times, the last specified file name will be +used. +.IP "-b, --cookie " +(HTTP) Pass the data to the HTTP server in the Cookie header. It is supposedly +the data previously received from the server in a "Set-Cookie:" line. The +data should be in the format "NAME1=VALUE1; NAME2=VALUE2". + +If no '=' symbol is used in the argument, it is instead treated as a filename +to read previously stored cookie from. This option also activates the cookie +engine which will make curl record incoming cookies, which may be handy if +you're using this in combination with the \fI-L, --location\fP option or do multiple URL +transfers on the same invoke. + +The file format of the file to read cookies from should be plain HTTP headers +(Set-Cookie style) or the Netscape/Mozilla cookie file format. + +The file specified with \fI-b, --cookie\fP is only used as input. No cookies will be +written to the file. To store cookies, use the \fI-c, --cookie-jar\fP option. + +Exercise caution if you are using this option and multiple transfers may +occur. If you use the NAME1=VALUE1; format, or in a file use the Set-Cookie +format and don't specify a domain, then the cookie is sent for any domain +(even after redirects are followed) and cannot be modified by a server-set +cookie. If the cookie engine is enabled and a server sets a cookie of the same +name then both will be sent on a future transfer to that server, likely not +what you intended. To address these issues set a domain in Set-Cookie (doing +that will include sub domains) or use the Netscape format. + +If this option is used several times, the last one will be used. + +Users very often want to both read cookies from a file and write updated +cookies back to a file, so using both \fI-b, --cookie\fP and \fI-c, --cookie-jar\fP in the same +command line is common. +.IP "--create-dirs" +When used in conjunction with the \fI-o, --output\fP option, curl will create the +necessary local directory hierarchy as needed. This option creates the dirs +mentioned with the \fI-o, --output\fP option, nothing else. If the --output file name +uses no dir or if the dirs it mentions already exist, no dir will be created. + +To create remote directories when using FTP or SFTP, try \fI--ftp-create-dirs\fP. +.IP "--crlf" +(FTP SMTP) Convert LF to CRLF in upload. Useful for MVS (OS/390). + +(SMTP added in 7.40.0) +.IP "--crlfile " +(TLS) Provide a file using PEM format with a Certificate Revocation List that may +specify peer certificates that are to be considered revoked. + +If this option is used several times, the last one will be used. + +Added in 7.19.7. +.IP "--data-ascii " +(HTTP) This is just an alias for \fI-d, --data\fP. +.IP "--data-binary " +(HTTP) This posts data exactly as specified with no extra processing whatsoever. + +If you start the data with the letter @, the rest should be a filename. Data +is posted in a similar manner as \fI-d, --data\fP does, except that newlines and +carriage returns are preserved and conversions are never done. + +If this option is used several times, the ones following the first will append +data as described in \fI-d, --data\fP. +.IP "--data-raw " +(HTTP) This posts data similarly to \fI-d, --data\fP but without the special +interpretation of the @ character. + +See also \fI-d, --data\fP. Added in 7.43.0. +.IP "--data-urlencode " +(HTTP) This posts data, similar to the other \fI-d, --data\fP options with the exception +that this performs URL-encoding. + +To be CGI-compliant, the part should begin with a \fIname\fP followed +by a separator and a content specification. The part can be passed to +curl using one of the following syntaxes: +.RS +.IP "content" +This will make curl URL-encode the content and pass that on. Just be careful +so that the content doesn't contain any = or @ symbols, as that will then make +the syntax match one of the other cases below! +.IP "=content" +This will make curl URL-encode the content and pass that on. The preceding = +symbol is not included in the data. +.IP "name=content" +This will make curl URL-encode the content part and pass that on. Note that +the name part is expected to be URL-encoded already. +.IP "@filename" +This will make curl load data from the given file (including any newlines), +URL-encode that data and pass it on in the POST. +.IP "name@filename" +This will make curl load data from the given file (including any newlines), +URL-encode that data and pass it on in the POST. The name part gets an equal +sign appended, resulting in \fIname=urlencoded-file-content\fP. Note that the +name is expected to be URL-encoded already. +.RE + +See also \fI-d, --data\fP and \fI--data-raw\fP. Added in 7.18.0. +.IP "-d, --data " +(HTTP) Sends the specified data in a POST request to the HTTP server, in the same way +that a browser does when a user has filled in an HTML form and presses the +submit button. This will cause curl to pass the data to the server using the +content-type application/x-www-form-urlencoded. Compare to \fI-F, --form\fP. + +\fI--data-raw\fP is almost the same but does not have a special interpretation of +the @ character. To post data purely binary, you should instead use the +\fI--data-binary\fP option. To URL-encode the value of a form field you may use +\fI--data-urlencode\fP. + +If any of these options is used more than once on the same command line, the +data pieces specified will be merged together with a separating +&-symbol. Thus, using '-d name=daniel -d skill=lousy' would generate a post +chunk that looks like \&'name=daniel&skill=lousy'. + +If you start the data with the letter @, the rest should be a file name to +read the data from, or - if you want curl to read the data from +stdin. Multiple files can also be specified. Posting data from a file named +'foobar' would thus be done with \fI-d, --data\fP @foobar. When --data is told to read +from a file like that, carriage returns and newlines will be stripped out. If +you don't want the @ character to have a special interpretation use \fI--data-raw\fP +instead. + +See also \fI--data-binary\fP and \fI--data-urlencode\fP and \fI--data-raw\fP. This option overrides \fI-F, --form\fP and \fI-I, --head\fP and \fI--upload\fP. +.IP "--delegation " +(GSS/kerberos) Set LEVEL to tell the server what it is allowed to delegate when it +comes to user credentials. +.RS +.IP "none" +Don't allow any delegation. +.IP "policy" +Delegates if and only if the OK-AS-DELEGATE flag is set in the Kerberos +service ticket, which is a matter of realm policy. +.IP "always" +Unconditionally allow the server to delegate. +.RE +.IP "--digest" +(HTTP) Enables HTTP Digest authentication. This is an authentication scheme that +prevents the password from being sent over the wire in clear text. Use this in +combination with the normal \fI-u, --user\fP option to set user name and password. + +If this option is used several times, only the first one is used. + +See also \fI-u, --user\fP and \fI--proxy-digest\fP and \fI--anyauth\fP. This option overrides \fI--basic\fP and \fI--ntlm\fP and \fI--negotiate\fP. +.IP "--disable-eprt" +(FTP) Tell curl to disable the use of the EPRT and LPRT commands when doing active +FTP transfers. Curl will normally always first attempt to use EPRT, then LPRT +before using PORT, but with this option, it will use PORT right away. EPRT and +LPRT are extensions to the original FTP protocol, and may not work on all +servers, but they enable more functionality in a better way than the +traditional PORT command. + +--eprt can be used to explicitly enable EPRT again and --no-eprt is an alias +for \fI--disable-eprt\fP. + +If the server is accessed using IPv6, this option will have no effect as EPRT +is necessary then. + +Disabling EPRT only changes the active behavior. If you want to switch to +passive mode you need to not use \fI-P, --ftp-port\fP or force it with \fI--ftp-pasv\fP. +.IP "--disable-epsv" +(FTP) (FTP) Tell curl to disable the use of the EPSV command when doing passive FTP +transfers. Curl will normally always first attempt to use EPSV before PASV, +but with this option, it will not try using EPSV. + +--epsv can be used to explicitly enable EPSV again and --no-epsv is an alias +for \fI--disable-epsv\fP. + +If the server is an IPv6 host, this option will have no effect as EPSV is +necessary then. + +Disabling EPSV only changes the passive behavior. If you want to switch to +active mode you need to use \fI-P, --ftp-port\fP. +.IP "-q, --disable" +If used as the first parameter on the command line, the \fIcurlrc\fP config +file will not be read and used. See the \fI-K, --config\fP for details on the default +config file search path. +.IP "--dns-interface " +(DNS) Tell curl to send outgoing DNS requests through . This option is a +counterpart to \fI--interface\fP (which does not affect DNS). The supplied string +must be an interface name (not an address). + +See also \fI--dns-ipv4-addr\fP and \fI--dns-ipv6-addr\fP. \fI--dns-interface\fP requires that the underlying libcurl was built to support c-ares. Added in 7.33.0. +.IP "--dns-ipv4-addr
" +(DNS) Tell curl to bind to when making IPv4 DNS requests, so that +the DNS requests originate from this address. The argument should be a +single IPv4 address. + +See also \fI--dns-interface\fP and \fI--dns-ipv6-addr\fP. \fI--dns-ipv4-addr\fP requires that the underlying libcurl was built to support c-ares. Added in 7.33.0. +.IP "--dns-ipv6-addr
" +(DNS) Tell curl to bind to when making IPv6 DNS requests, so that +the DNS requests originate from this address. The argument should be a +single IPv6 address. + +See also \fI--dns-interface\fP and \fI--dns-ipv4-addr\fP. \fI--dns-ipv6-addr\fP requires that the underlying libcurl was built to support c-ares. Added in 7.33.0. +.IP "--dns-servers " +Set the list of DNS servers to be used instead of the system default. +The list of IP addresses should be separated with commas. Port numbers +may also optionally be given as \fI:\fP after each IP +address. + +\fI--dns-servers\fP requires that the underlying libcurl was built to support c-ares. Added in 7.33.0. +.IP "-D, --dump-header " +(HTTP FTP) Write the received protocol headers to the specified file. + +This option is handy to use when you want to store the headers that an HTTP +site sends to you. Cookies from the headers could then be read in a second +curl invocation by using the \fI-b, --cookie\fP option! The \fI-c, --cookie-jar\fP option is a +better way to store cookies. + +When used in FTP, the FTP server response lines are considered being "headers" +and thus are saved there. + +If this option is used several times, the last one will be used. + +See also \fI-o, --output\fP. +.IP "--egd-file " +(TLS) Specify the path name to the Entropy Gathering Daemon socket. The socket is +used to seed the random engine for SSL connections. + +See also \fI--random-file\fP. +.IP "--engine " +(TLS) Select the OpenSSL crypto engine to use for cipher operations. Use \fI--engine\fP +list to print a list of build-time supported engines. Note that not all (or +none) of the engines may be available at run-time. +.IP "--environment" +Sets a range of environment variables, using the names the \fI-w, --write-out\fP option +supports, to allow easier extraction of useful information after having run +curl. + +\fI--environment\fP requires that the underlying libcurl was built to support RISC OS. +.IP "--expect100-timeout " +(HTTP) Maximum time in seconds that you allow curl to wait for a 100-continue +response when curl emits an Expects: 100-continue header in its request. By +default curl will wait one second. This option accepts decimal values! When +curl stops waiting, it will continue as if the response has been received. + +See also \fI--connect-timeout\fP. Added in 7.47.0. +.IP "--fail-early" +Fail and exit on first detected error. + +When curl is used to do multiple transfers on the command line, it will +attempt to operate on each given URL, one by one. By default, it will ignore +errors if there are more URLs given and the last URL's success will determine +the error code curl returns. So early failures will be "hidden" by subsequent +successful transfers. + +Using this option, curl will instead return an error on the first transfers +that fails, independent on the amount of more URLs that are given on the +command line. This way, no transfer failures go undetected by scripts and +similar. + +This option will apply for all given URLs even if you use \fI-:, --next\fP. + +Added in 7.52.0. +.IP "-f, --fail" +(HTTP) Fail silently (no output at all) on server errors. This is mostly done to +better enable scripts etc to better deal with failed attempts. In normal cases +when an HTTP server fails to deliver a document, it returns an HTML document +stating so (which often also describes why and more). This flag will prevent +curl from outputting that and return error 22. + +This method is not fail-safe and there are occasions where non-successful +response codes will slip through, especially when authentication is involved +(response codes 401 and 407). +.IP "--false-start" +(TLS) Tells curl to use false start during the TLS handshake. False start is a mode +where a TLS client will start sending application data before verifying the +server's Finished message, thus saving a round trip when performing a full +handshake. + +This is currently only implemented in the NSS and Secure Transport (on iOS 7.0 +or later, or OS X 10.9 or later) backends. + +Added in 7.42.0. +.IP "--form-string " +(HTTP) Similar to \fI-F, --form\fP except that the value string for the named parameter is used +literally. Leading \&'@' and \&'<' characters, and the \&';type=' string in +the value have no special meaning. Use this in preference to \fI-F, --form\fP if +there's any possibility that the string value may accidentally trigger the +\&'@' or \&'<' features of \fI-F, --form\fP. + +See also \fI-F, --form\fP. +.IP "-F, --form " +(HTTP) This lets curl emulate a filled-in form in which a user has pressed the submit +button. This causes curl to POST data using the Content-Type +multipart/form-data according to RFC 2388. This enables uploading of binary +files etc. To force the 'content' part to be a file, prefix the file name with +an @ sign. To just get the content part from a file, prefix the file name with +the symbol <. The difference between @ and < is then that @ makes a file get +attached in the post as a file upload, while the < makes a text field and just +get the contents for that text field from a file. + +Example: to send an image to a server, where \&'profile' is the name of the +form-field to which portrait.jpg will be the input: + + curl -F profile=@portrait.jpg https://example.com/upload.cgi + +To read content from stdin instead of a file, use - as the filename. This goes +for both @ and < constructs. Unfortunately it does not support reading the +file from a named pipe or similar, as it needs the full size before the +transfer starts. + +You can also tell curl what Content-Type to use by using 'type=', in a manner +similar to: + + curl -F "web=@index.html;type=text/html" example.com + +or + + curl -F "name=daniel;type=text/foo" example.com + +You can also explicitly change the name field of a file upload part by setting +filename=, like this: + + curl -F "file=@localfile;filename=nameinpost" example.com + +If filename/path contains ',' or ';', it must be quoted by double-quotes like: + + curl -F "file=@\\"localfile\\";filename=\\"nameinpost\\"" example.com + +or + + curl -F 'file=@"localfile";filename="nameinpost"' example.com + +Note that if a filename/path is quoted by double-quotes, any double-quote +or backslash within the filename must be escaped by backslash. + +See further examples and details in the MANUAL. + +This option can be used multiple times. + +This option overrides \fI-d, --data\fP and \fI-I, --head\fP and \fI--upload\fP. +.IP "--ftp-account " +(FTP) When an FTP server asks for "account data" after user name and password has +been provided, this data is sent off using the ACCT command. + +If this option is used several times, the last one will be used. + +Added in 7.13.0. +.IP "--ftp-alternative-to-user " +(FTP) If authenticating with the USER and PASS commands fails, send this command. +When connecting to Tumbleweed's Secure Transport server over FTPS using a +client certificate, using "SITE AUTH" will tell the server to retrieve the +username from the certificate. + +Added in 7.15.5. +.IP "--ftp-create-dirs" +(FTP SFTP) When an FTP or SFTP URL/operation uses a path that doesn't currently exist on +the server, the standard behavior of curl is to fail. Using this option, curl +will instead attempt to create missing directories. + +See also \fI--create-dirs\fP. +.IP "--ftp-method " +(FTP) Control what method curl should use to reach a file on an FTP(S) +server. The method argument should be one of the following alternatives: +.RS +.IP multicwd +curl does a single CWD operation for each path part in the given URL. For deep +hierarchies this means very many commands. This is how RFC 1738 says it should +be done. This is the default but the slowest behavior. +.IP nocwd +curl does no CWD at all. curl will do SIZE, RETR, STOR etc and give a full +path to the server for all these commands. This is the fastest behavior. +.IP singlecwd +curl does one CWD with the full target directory and then operates on the file +\&"normally" (like in the multicwd case). This is somewhat more standards +compliant than 'nocwd' but without the full penalty of 'multicwd'. +.RE + +Added in 7.15.1. +.IP "--ftp-pasv" +(FTP) Use passive mode for the data connection. Passive is the internal default +behavior, but using this option can be used to override a previous \fI-P, --ftp-port\fP +option. + +If this option is used several times, only the first one is used. Undoing an +enforced passive really isn't doable but you must then instead enforce the +correct \fI-P, --ftp-port\fP again. + +Passive mode means that curl will try the EPSV command first and then PASV, +unless \fI--disable-epsv\fP is used. + +See also \fI--disable-epsv\fP. Added in 7.11.0. +.IP "-P, --ftp-port
" +(FTP) Reverses the default initiator/listener roles when connecting with FTP. This +option makes curl use active mode. curl then tells the server to connect back +to the client's specified address and port, while passive mode asks the server +to setup an IP address and port for it to connect to.
should be one +of: +.RS +.IP interface +i.e "eth0" to specify which interface's IP address you want to use (Unix only) +.IP "IP address" +i.e "192.168.10.1" to specify the exact IP address +.IP "host name" +i.e "my.host.domain" to specify the machine +.IP "-" +make curl pick the same IP address that is already used for the control +connection +.RE + +If this option is used several times, the last one will be used. Disable the +use of PORT with \fI--ftp-pasv\fP. Disable the attempt to use the EPRT command +instead of PORT by using \fI--disable-eprt\fP. EPRT is really PORT++. + +Since 7.19.5, you can append \&":[start]-[end]\&" to the right of the address, +to tell curl what TCP port range to use. That means you specify a port range, +from a lower to a higher number. A single number works as well, but do note +that it increases the risk of failure since the port may not be available. + +See also \fI--ftp-pasv\fP and \fI--disable-eprt\fP. +.IP "--ftp-pret" +(FTP) Tell curl to send a PRET command before PASV (and EPSV). Certain FTP servers, +mainly drftpd, require this non-standard command for directory listings as +well as up and downloads in PASV mode. + +Added in 7.20.0. +.IP "--ftp-skip-pasv-ip" +(FTP) Tell curl to not use the IP address the server suggests in its response +to curl's PASV command when curl connects the data connection. Instead curl +will re-use the same IP address it already uses for the control +connection. + +This option has no effect if PORT, EPRT or EPSV is used instead of PASV. + +See also \fI--ftp-pasv\fP. Added in 7.14.2. +.IP "--ftp-ssl-ccc-mode " +(FTP) Sets the CCC mode. The passive mode will not initiate the shutdown, but +instead wait for the server to do it, and will not reply to the shutdown from +the server. The active mode initiates the shutdown and waits for a reply from +the server. + +See also \fI--ftp-ssl-ccc\fP. Added in 7.16.2. +.IP "--ftp-ssl-ccc" +(FTP) Use CCC (Clear Command Channel) Shuts down the SSL/TLS layer after +authenticating. The rest of the control channel communication will be +unencrypted. This allows NAT routers to follow the FTP transaction. The +default mode is passive. + +See also \fI--ssl\fP and \fI--ftp-ssl-ccc-mode\fP. Added in 7.16.1. +.IP "--ftp-ssl-control" +(FTP) Require SSL/TLS for the FTP login, clear for transfer. Allows secure +authentication, but non-encrypted data transfers for efficiency. Fails the +transfer if the server doesn't support SSL/TLS. + +Added in 7.16.0. +.IP "-G, --get" +When used, this option will make all data specified with \fI-d, --data\fP, \fI--data-binary\fP +or \fI--data-urlencode\fP to be used in an HTTP GET request instead of the POST +request that otherwise would be used. The data will be appended to the URL +with a '?' separator. + +If used in combination with \fI-I, --head\fP, the POST data will instead be appended to +the URL with a HEAD request. + +If this option is used several times, only the first one is used. This is +because undoing a GET doesn't make sense, but you should then instead enforce +the alternative method you prefer. +.IP "-g, --globoff" +This option switches off the "URL globbing parser". When you set this option, +you can specify URLs that contain the letters {}[] without having them being +interpreted by curl itself. Note that these letters are not normal legal URL +contents but they should be encoded according to the URI standard. +.IP "-I, --head" +(HTTP FTP FILE) Fetch the headers only! HTTP-servers feature the command HEAD which this uses +to get nothing but the header of a document. When used on an FTP or FILE file, +curl displays the file size and last modification time only. +.IP "-H, --header
" +(HTTP) +Extra header to include in the request when sending HTTP to a server. You may +specify any number of extra headers. Note that if you should add a custom +header that has the same name as one of the internal ones curl would use, your +externally set header will be used instead of the internal one. This allows +you to make even trickier stuff than curl would normally do. You should not +replace internally set headers without knowing perfectly well what you're +doing. Remove an internal header by giving a replacement without content on +the right side of the colon, as in: -H \&"Host:". If you send the custom +header with no-value then its header must be terminated with a semicolon, such +as \-H \&"X-Custom-Header;" to send "X-Custom-Header:". + +curl will make sure that each header you add/replace is sent with the proper +end-of-line marker, you should thus \fBnot\fP add that as a part of the header +content: do not add newlines or carriage returns, they will only mess things up +for you. + +See also the \fI-A, --user-agent\fP and \fI-e, --referer\fP options. + +Starting in 7.37.0, you need \fI--proxy-header\fP to send custom headers intended +for a proxy. + +Example: + + curl -H "X-First-Name: Joe" http://example.com/ + +\fBWARNING\fP: headers set with this option will be set in all requests - even +after redirects are followed, like when told with \fI-L, --location\fP. This can lead to +the header being sent to other hosts than the original host, so sensitive +headers should be used with caution combined with following redirects. + +This option can be used multiple times to add/replace/remove multiple headers. +.IP "-h, --help" +Usage help. This lists all current command line options with a short +description. +.IP "--hostpubmd5 " +(SFTP SCP) Pass a string containing 32 hexadecimal digits. The string should +be the 128 bit MD5 checksum of the remote host's public key, curl will refuse +the connection with the host unless the md5sums match. + +Added in 7.17.1. +.IP "-0, --http1.0" +(HTTP) Tells curl to use HTTP version 1.0 instead of using its internally preferred +HTTP version. + +This option overrides \fI--http1.1\fP and \fI--http2\fP. +.IP "--http1.1" +(HTTP) Tells curl to use HTTP version 1.1. + +This option overrides \fI-0, --http1.0\fP and \fI--http2\fP. Added in 7.33.0. +.IP "--http2-prior-knowledge" +(HTTP) Tells curl to issue its non-TLS HTTP requests using HTTP/2 without HTTP/1.1 +Upgrade. It requires prior knowledge that the server supports HTTP/2 straight +away. HTTPS requests will still do HTTP/2 the standard way with negotiated +protocol version in the TLS handshake. + +\fI--http2-prior-knowledge\fP requires that the underlying libcurl was built to support HTTP/2. This option overrides \fI--http1.1\fP and \fI-0, --http1.0\fP and \fI--http2\fP. Added in 7.49.0. +.IP "--http2" +(HTTP) Tells curl to use HTTP version 2. + +See also \fI--no-alpn\fP. \fI--http2\fP requires that the underlying libcurl was built to support HTTP/2. This option overrides \fI--http1.1\fP and \fI-0, --http1.0\fP and \fI--http2-prior-knowledge\fP. Added in 7.33.0. +.IP "--ignore-content-length" +(FTP HTTP) For HTTP, Ignore the Content-Length header. This is particularly useful for +servers running Apache 1.x, which will report incorrect Content-Length for +files larger than 2 gigabytes. + +For FTP (since 7.46.0), skip the RETR command to figure out the size before +downloading a file. +.IP "-i, --include" +Include the HTTP-header in the output. The HTTP-header includes things like +server-name, date of the document, HTTP-version and more... + +See also \fI-v, --verbose\fP. +.IP "-k, --insecure" +(TLS) This option explicitly allows curl to perform "insecure" SSL connections and +transfers. All SSL connections are attempted to be made secure by using the CA +certificate bundle installed by default. This makes all connections considered +\&"insecure" fail unless \fI-k, --insecure\fP is used. + +See this online resource for further details: + https://curl.haxx.se/docs/sslcerts.html +.IP "--interface " + +Perform an operation using a specified interface. You can enter interface +name, IP address or host name. An example could look like: + + curl --interface eth0:1 https://www.example.com/ + +If this option is used several times, the last one will be used. + +See also \fI--dns-interface\fP. +.IP "-4, --ipv4" +This option tells curl to resolve names to IPv4 addresses only, and not for +example try IPv6. + +See also \fI--http1.1\fP and \fI--http2\fP. This option overrides \fI-6, --ipv6\fP. +.IP "-6, --ipv6" +This option tells curl to resolve names to IPv6 addresses only, and not for +example try IPv4. + +See also \fI--http1.1\fP and \fI--http2\fP. This option overrides \fI-6, --ipv6\fP. +.IP "-j, --junk-session-cookies" +(HTTP) When curl is told to read cookies from a given file, this option will make it +discard all "session cookies". This will basically have the same effect as if +a new session is started. Typical browsers always discard session cookies when +they're closed down. + +See also \fI-b, --cookie\fP and \fI-c, --cookie-jar\fP. +.IP "--keepalive-time " +This option sets the time a connection needs to remain idle before sending +keepalive probes and the time between individual keepalive probes. It is +currently effective on operating systems offering the TCP_KEEPIDLE and +TCP_KEEPINTVL socket options (meaning Linux, recent AIX, HP-UX and more). This +option has no effect if \fI--no-keepalive\fP is used. + +If this option is used several times, the last one will be used. If +unspecified, the option defaults to 60 seconds. + +Added in 7.18.0. +.IP "--key-type " +(TLS) Private key file type. Specify which type your \fI--key\fP provided private key +is. DER, PEM, and ENG are supported. If not specified, PEM is assumed. + +If this option is used several times, the last one will be used. +.IP "--key " +(TLS SSH) Private key file name. Allows you to provide your private key in this separate +file. For SSH, if not specified, curl tries the following candidates in order: +'~/.ssh/id_rsa', '~/.ssh/id_dsa', './id_rsa', './id_dsa'. + +If this option is used several times, the last one will be used. +.IP "--krb " +(FTP) Enable Kerberos authentication and use. The level must be entered and should +be one of 'clear', 'safe', 'confidential', or 'private'. Should you use a +level that is not one of these, 'private' will instead be used. + +If this option is used several times, the last one will be used. + +\fI--krb\fP requires that the underlying libcurl was built to support Kerberos. +.IP "--libcurl " +Append this option to any ordinary curl command line, and you will get a +libcurl-using C source code written to the file that does the equivalent +of what your command-line operation does! + +If this option is used several times, the last given file name will be +used. + +Added in 7.16.1. +.IP "--limit-rate " +Specify the maximum transfer rate you want curl to use - for both downloads +and uploads. This feature is useful if you have a limited pipe and you'd like +your transfer not to use your entire bandwidth. To make it slower than it +otherwise would be. + +The given speed is measured in bytes/second, unless a suffix is appended. +Appending 'k' or 'K' will count the number as kilobytes, 'm' or M' makes it +megabytes, while 'g' or 'G' makes it gigabytes. Examples: 200K, 3m and 1G. + +If you also use the \fI-Y, --speed-limit\fP option, that option will take precedence and +might cripple the rate-limiting slightly, to help keeping the speed-limit +logic working. + +If this option is used several times, the last one will be used. +.IP "-l, --list-only" +(FTP POP3) (FTP) +When listing an FTP directory, this switch forces a name-only view. This is +especially useful if the user wants to machine-parse the contents of an FTP +directory since the normal directory view doesn't use a standard look or +format. When used like this, the option causes a NLST command to be sent to +the server instead of LIST. + +Note: Some FTP servers list only files in their response to NLST; they do not +include sub-directories and symbolic links. + +(POP3) +When retrieving a specific email from POP3, this switch forces a LIST command +to be performed instead of RETR. This is particularly useful if the user wants +to see if a specific message id exists on the server and what size it is. + +Note: When combined with \fI-X, --request\fP, this option can be used to send an UIDL +command instead, so the user may use the email's unique identifier rather than +it's message id to make the request. + +Added in 7.21.5. +.IP "--local-port " +Set a preferred single number or range (FROM-TO) of local port numbers to use +for the connection(s). Note that port numbers by nature are a scarce resource +that will be busy at times so setting this range to something too narrow might +cause unnecessary connection setup failures. + +Added in 7.15.2. +.IP "--location-trusted" +(HTTP) Like \fI-L, --location\fP, but will allow sending the name + password to all hosts that +the site may redirect to. This may or may not introduce a security breach if +the site redirects you to a site to which you'll send your authentication info +(which is plaintext in the case of HTTP Basic authentication). + +See also \fI-u, --user\fP. +.IP "-L, --location" +(HTTP) If the server reports that the requested page has moved to a different +location (indicated with a Location: header and a 3XX response code), this +option will make curl redo the request on the new place. If used together with +\fI-i, --include\fP or \fI-I, --head\fP, headers from all requested pages will be shown. When +authentication is used, curl only sends its credentials to the initial +host. If a redirect takes curl to a different host, it won't be able to +intercept the user+password. See also \fI--location-trusted\fP on how to change +this. You can limit the amount of redirects to follow by using the +\fI--max-redirs\fP option. + +When curl follows a redirect and the request is not a plain GET (for example +POST or PUT), it will do the following request with a GET if the HTTP response +was 301, 302, or 303. If the response code was any other 3xx code, curl will +re-send the following request using the same unmodified method. + +You can tell curl to not change the non-GET request method to GET after a 30x +response by using the dedicated options for that: \fI--post301\fP, \fI--post302\fP and +\fI--post303\fP. +.IP "--login-options " +(IMAP POP3 SMTP) Specify the login options to use during server authentication. + +You can use the login options to specify protocol specific options that may +be used during authentication. At present only IMAP, POP3 and SMTP support +login options. For more information about the login options please see +RFC 2384, RFC 5092 and IETF draft draft-earhart-url-smtp-00.txt + +If this option is used several times, the last one will be used. + +Added in 7.34.0. +.IP "--mail-auth
" +(SMTP) Specify a single address. This will be used to specify the authentication +address (identity) of a submitted message that is being relayed to another +server. + +See also \fI--mail-rcpt\fP and \fI--mail-from\fP. Added in 7.25.0. +.IP "--mail-from
" +(SMTP) Specify a single address that the given mail should get sent from. + +See also \fI--mail-rcpt\fP and \fI--mail-auth\fP. Added in 7.20.0. +.IP "--mail-rcpt
" +(SMTP) Specify a single address, user name or mailing list name. Repeat this +option several times to send to multiple recipients. + +When performing a mail transfer, the recipient should specify a valid email +address to send the mail to. + +When performing an address verification (VRFY command), the recipient should be +specified as the user name or user name and domain (as per Section 3.5 of +RFC5321). (Added in 7.34.0) + +When performing a mailing list expand (EXPN command), the recipient should be +specified using the mailing list name, such as "Friends" or "London-Office". +(Added in 7.34.0) + +Added in 7.20.0. +.IP "-M, --manual" +Manual. Display the huge help text. +.IP "--max-filesize " +Specify the maximum size (in bytes) of a file to download. If the file +requested is larger than this value, the transfer will not start and curl will +return with exit code 63. + +\fBNOTE:\fP The file size is not always known prior to download, and for such +files this option has no effect even if the file transfer ends up being larger +than this given limit. This concerns both FTP and HTTP transfers. + +See also \fI--limit-rate\fP. +.IP "--max-redirs " +(HTTP) Set maximum number of redirection-followings allowed. When \fI-L, --location\fP is used, +is used to prevent curl from following redirections \&"in absurdum". By +default, the limit is set to 50 redirections. Set this option to -1 to make it +unlimited. + +If this option is used several times, the last one will be used. +.IP "-m, --max-time