diff --git a/.gitignore b/.gitignore
index 593be70c7..4f2ba20d2 100755
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,17 @@ deprecated/.DS_Store
.DS_Store
+
+iguana/help/.tmpmarker
+
+iguana/genesis/.tmpmarker
+
+iguana/help.json
+
+iguana/autoAPI.md
+
+iguana/basilisk.o-2ad8cb38
+=======
*.pbxproj
iguana/tmp/.tmpmarker
@@ -208,3 +219,270 @@ iguana/DB/SWAPS/467927158-3437055573
iguana/DB/SWAPS/270159951-1269722638
iguana/DB/SWAPS/244991424-1008712592
+
+iguana/confs/1cc0270abba7f4463a3dcb9908b9d875691a6773fe3cc1b4302233ed76665300
+
+iguana/autoAPI.md
+
+iguana/confs/5228bcea7ae2515a29c3844673de6ee2acba53bf45724744a00ff4306f192912
+
+iguana/confs/630929d976025fafde221c7358eb5805f4359bad3c6b8bd50ad3f6e0a9b5ce78
+
+iguana/confs/5f3283a017c31e52443d61cb43944e2157f7c03eb12d701ebf4a35a695688e1f
+
+
+iguana/DB/SWAPS/1313603851-3952777544
+
+iguana/DB/SWAPS/1923456555-3815385469
+
+iguana/DB/SWAPS/897416195-4050269921
+
+iguana/DB/SWAPS/2465996447-4202128826
+
+iguana/DB/SWAPS/3078036996-3700749298
+
+iguana/DB/SWAPS/1061498231-3266306388
+
+iguana/DB/SWAPS/1060082251-3390546616
+
+iguana/SVM/rawfeatures/BTCD_BTC
+
+iguana/DB/SWAPS/1032184933-1028220623
+
+iguana/DB/SWAPS/771249356-2746947221
+
+iguana/DB/SWAPS/2311778512-3235676199
+
+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
+
+iguana/DB/SWAPS/2510768478-2766365035
+
+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
+
+iguana/DB/SWAPS/2050938501-203733478
+
+iguana/DB/SWAPS/3434672913-3981690962
+
+iguana/DB/SWAPS/2840127595-1174059534
+
+iguana/DB/SWAPS/2448551545-1211445977
+
+*.alicepayment
+
+*.myfee
+
+iguana/DB/SWAPS/1313312572-123661666
+
+iguana/DB/SWAPS/3408402932-4088991610
+
+iguana/DB/SWAPS/3772541120-2007204891
+
+iguana/DB/SWAPS/784303571-1929722462
+
+iguana/DB/SWAPS/3221116355-3522779294
+
+iguana/DB/SWAPS/1703578312-1139459191
+
+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
+
+iguana/DB/SWAPS/1505015888-2633757068
+
+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
+
+iguana/DB/SWAPS/1914406677-1452353494
+
+iguana/DB/SWAPS/3193054754-2514575257
+
+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
+
+iguana/DB/SWAPS/246664144-1570119145
+
+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
+
+iguana/DB/SWAPS/61119357-1960547076
+
+iguana/DB/SWAPS/26534791-3105729230
+
+*.finished
+
+iguana/DB/SWAPS/2279906047-2580050792
+
+iguana/DB/SWAPS/1672096208-4211948211
+
+iguana/DB/SWAPS/3062665554-3128383014
+
+iguana/DB/SWAPS/2668150969-2698996317
+
+iguana/DB/SWAPS/3462690702-2419919594
+
+iguana/DB/SWAPS/543051861-1532200070
+
+iguana/DB/SWAPS/442294237-2721246052
+
+iguana/DB/SWAPS/1247864366-3828803132
+
+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
+
+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
+
+iguana/3193054754-2514575257
+
+iguana/DB/SWAPS/2723832060-1788071166
+
+
+
+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
+
+iguana/DB/SWAPS/1238069553-2363573428
+
+iguana/DB/SWAPS/2895470622-2170247626
+
+iguana/confs/ed476386688e486f359ce67e44ce4268a875125527e122ea9126ebc54f473d31
+
+iguana/confs/f6e8e8ab82ed33b2de063d6820dcaefb99b95cf1aef6527b8f27e1e5b1fe882d
+
+iguana/e
+
+iguana/a
+
+iguana/t
+
+iguana/stats
+
+iguana/DEXstats
+
+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
+
+iguana/DB/LTC/.tmpmarker
+
+iguana/DB/purgeable/LTC/.tmpmarker
+
+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
+
+iguana/marketmaker.dSYM/Contents/Info.plist
+
+iguana/client
+
+iguana/marketmaker.dSYM/Contents/Resources/DWARF/marketmaker
+
+iguana/confs/97f18454bb61e9eb7a827cfbefe42fbf7ae2832dc74c4812bdaef8bcf5c10474
+
+iguana/DB/PRICES/.tmpmarker
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/OSlibs/win/libcrypto-1_1.dll b/OSlibs/win/libcrypto-1_1.dll
new file mode 100644
index 000000000..4b16b67be
Binary files /dev/null and b/OSlibs/win/libcrypto-1_1.dll differ
diff --git a/OSlibs/win/libcurl.dll b/OSlibs/win/libcurl.dll
new file mode 100644
index 000000000..8c80e23eb
Binary files /dev/null and b/OSlibs/win/libcurl.dll differ
diff --git a/OSlibs/win/libcurl.exp b/OSlibs/win/libcurl.exp
new file mode 100644
index 000000000..a2b9da989
Binary files /dev/null and b/OSlibs/win/libcurl.exp differ
diff --git a/OSlibs/win/libcurl.lib b/OSlibs/win/libcurl.lib
new file mode 100644
index 000000000..c2b00f3c8
Binary files /dev/null and b/OSlibs/win/libcurl.lib differ
diff --git a/OSlibs/win/libssl-1_1.dll b/OSlibs/win/libssl-1_1.dll
new file mode 100644
index 000000000..dee38788d
Binary files /dev/null and b/OSlibs/win/libssl-1_1.dll differ
diff --git a/OSlibs/win/x64/libcurl.dll b/OSlibs/win/x64/libcurl.dll
new file mode 100644
index 000000000..c77ec1f0f
Binary files /dev/null and b/OSlibs/win/x64/libcurl.dll differ
diff --git a/OSlibs/win/x64/libcurl.lib b/OSlibs/win/x64/libcurl.lib
new file mode 100644
index 000000000..92f23798c
Binary files /dev/null and b/OSlibs/win/x64/libcurl.lib differ
diff --git a/OSlibs/win/x64/release/libcurl.dll b/OSlibs/win/x64/release/libcurl.dll
new file mode 100644
index 000000000..c77ec1f0f
Binary files /dev/null and b/OSlibs/win/x64/release/libcurl.dll differ
diff --git a/OSlibs/win/x64/release/libcurl.exp b/OSlibs/win/x64/release/libcurl.exp
new file mode 100644
index 000000000..fc2bcb28c
Binary files /dev/null and b/OSlibs/win/x64/release/libcurl.exp differ
diff --git a/OSlibs/win/x64/release/libcurl.lib b/OSlibs/win/x64/release/libcurl.lib
new file mode 100644
index 000000000..92f23798c
Binary files /dev/null and b/OSlibs/win/x64/release/libcurl.lib differ
diff --git a/README.md b/README.md
index 2d49a0b55..2d172e790 100755
--- a/README.md
+++ b/README.md
@@ -12,6 +12,28 @@ docs.supernet.org | [![Build Status](https://jenkinsmaster.sprnt.pw/buildStatus/
---
+
+## Crosscompile iguana/marketmaker (barterDEX):
+System requirements: Crossbuilding was tested on debian 7 and 8.
+
+Install mingw-w64:
+
+`sudo apt-get install mingw-w64`
+
+Clone the windows-crossbuild branch:
+`git clone https://github.com/ca333/supernet && cd supernet && git checkout windows-cross`
+
+Build iguana (LP) and marketmaker:
+```
+cd iguana
+./m_LP_win_cross
+./m_mm_win_cross
+```
+
+`iguana.exe` is built into `supernet/agents/` and `marketmaker.exe` into `supernet/iguana/`
+
+---
+
Codebase is going under radical changes now and versions from mid-May should be used unless you are doing advanced testing. There will be four layers:
gecko: abstracted bitcoin compatible blockchains that run via basilisk lite mode or as iguana core full network peers. I will try to get a geckochain to simultaneously have both virtual basilisk nodes and private iguana nodes, but at first will probably need to choose which mode a new chain will be and transition between the two via special suspend and resume functions that allow migration from virtual to physical. Each specific geckochain will be able to be enhanced into a datachain.
@@ -35,7 +57,7 @@ komodo: this is the top secret project I cant talk about publicly yet
*** all external dependencies have been removed, except for -lpthread and -lm
-##For native (win32, win64)##
+## For native (win32, win64)
TOOL_DIR := /usr/local/gcc-4.8.0-qt-4.8.4-for-mingw32/win32-gcc/bin
MINGW := i586-mingw32
The above two definitions need to be changed to match the mingw install on your system. m_win32 and m_win64 just invokes the makefile in mingw32 and mingw64
@@ -223,3 +245,35 @@ 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/basilisk/basilisk.c b/basilisk/basilisk.c
index ba880e2e6..a2a6d2200 100755
--- a/basilisk/basilisk.c
+++ b/basilisk/basilisk.c
@@ -33,6 +33,55 @@ int32_t basilisk_notarycmd(char *cmd)
else return(0);
}*/
+cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *satoshis,uint64_t limit,int32_t maxvins,char *coinaddr)
+{
+ 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 )
+ {
+ //printf("(%s)\n",retstr);
+ if ( (array= cJSON_Parse(retstr)) != 0 )
+ {
+ n = cJSON_GetArraySize(array);
+ for (i=0; i biggest )
+ {
+ //fprintf(stderr,"biggest! ");
+ if ( biggestitem != 0 )
+ free_json(biggestitem);
+ biggestitem = jduplicate(item);
+ *satoshis = biggest = value;
+ } //else fprintf(stderr,"> ");
+ }
+ }
+ free_json(array);
+ if ( utxos == 0 && biggestitem != 0 )
+ {
+ fprintf(stderr,"add biggest.(%s)\n",jprint(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;
@@ -872,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");
@@ -925,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 )
@@ -942,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);
@@ -1071,6 +1123,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;
@@ -1130,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 )
@@ -1150,7 +1203,15 @@ 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 )
+ {
+ if ( (sobj= jobj(txoutjson,"scriptPubKey")) != 0 && (addrs= jarray(&n,sobj,"addresses")) != 0 && n > 0 )
+ coinaddr = jstri(addrs,0);
+ printf("no address, check addrs %p coinaddr.%p\n",sobj,coinaddr);
+ }
+ if ( coinaddr != 0 && value != 0 )
{
retjson = cJSON_CreateObject();
jaddstr(retjson,"result","success");
@@ -1158,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);
@@ -1167,22 +1228,26 @@ 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\"}"));
}
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 )
@@ -1195,6 +1260,9 @@ HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr)
retjson = cJSON_CreateObject();
jaddstr(retjson,"result","success");
jaddnum(retjson,"numconfirms",jint(txoutjson,"confirmations"));
+ 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));
@@ -1293,16 +1361,16 @@ 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 )
+ 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
{
safecopy(myinfo->jumblr_passphrase,passphrase,sizeof(myinfo->jumblr_passphrase));
retjson = cJSON_CreateObject();
jaddstr(retjson,"result","success");
- privkey = jumblr_privkey(myinfo,BTCaddr,KMDaddr,JUMBLR_DEPOSITPREFIX);
- smartaddress_add(myinfo,privkey,BTCaddr,KMDaddr);
+ privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX);
+ 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 )
@@ -1316,17 +1384,35 @@ 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,"");
- smartaddress_add(myinfo,privkey,BTCaddr,KMDaddr);
+ privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,"");
+ smartaddress_add(myinfo,privkey,"jumblr","KMD",0.,0.);
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));
}
}
+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;
@@ -1335,14 +1421,15 @@ 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,"mode",myinfo->runsilent == 0 ? "totransparent" : "runsilent");
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 )
@@ -1603,7 +1690,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,11 +1699,33 @@ 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,0));
}
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 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,maxvins,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)
@@ -1699,21 +1808,21 @@ 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);
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 )
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 )
@@ -1748,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 )
@@ -1787,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;
@@ -1795,11 +1906,15 @@ 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);
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 )
@@ -1811,7 +1926,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,pubkey),msgid);
}
return(jprint(retjson,1));
}
@@ -1862,6 +1977,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.h b/basilisk/basilisk.h
index b15b9032f..8d0c3da9d 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"
@@ -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
@@ -60,7 +64,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];
};
@@ -79,6 +83,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_DEX.c b/basilisk/basilisk_DEX.c
index 5ec6fcaed..17ed0816e 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 )
@@ -159,11 +161,16 @@ 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);
+ //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 )
@@ -192,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));
@@ -212,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 )
@@ -231,14 +239,15 @@ 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);
+ 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,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++)
@@ -273,12 +282,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.;
- if ( myinfo->IAMNOTARY != 0 || time(NULL) < lastpoll+20 || (myinfo->IAMLP == 0 && myinfo->DEXactive < time(NULL)) )
- return;
+ 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+5 || (myinfo->IAMLP == 0 && myinfo->DEXactive < time(NULL)) )
+ return(retval);
lastpoll = (uint32_t)time(NULL);
memset(&issueR,0,sizeof(issueR));
memset(&myinfo->DEXaccept,0,sizeof(myinfo->DEXaccept));
@@ -290,6 +299,7 @@ void basilisk_requests_poll(struct supernet_info *myinfo)
{
if ( (outerarray= jarray(&n,retjson,"responses")) != 0 )
{
+ retval++;
for (i=0; i 0. )
{
myinfo->DEXaccept = issueR;
- if ( smartaddress_pubkey(myinfo,&privkey,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
- 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 )
+ else if ( myinfo->IAMLP != 0 && issueR.requestid != myinfo->lastdexrequestid )//if ( issueR.quoteid == 0 )
{
issueR.quoteid = basilisk_quoteid(&issueR);
issueR.desthash = myinfo->myaddr.persistent;
@@ -324,6 +336,7 @@ void basilisk_requests_poll(struct supernet_info *myinfo)
free(retstr);
} //else printf("basilisk_requests_poll unexpected hwm issueR\n");
}
+ return(retval);
}
struct basilisk_relay *basilisk_request_ensure(struct supernet_info *myinfo,uint32_t senderipbits,int32_t numrequests)
@@ -471,9 +484,10 @@ 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;
+ cJSON *unspents=0,*array=0,*json,*ismine; char *retstr; int32_t valid = 0;
if ( coin->FULLNODE > 0 )
{
array = cJSON_CreateArray();
@@ -481,15 +495,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_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 duplicates/4 )
+ if ( strcmp(coin->chain->symbol,"BTC") == 0 && cJSON_GetArraySize(vins) > duplicates/2 )
{
free(rawtx);
rawtx = 0;
@@ -602,7 +602,7 @@ char *iguana_utxoduplicates(struct supernet_info *myinfo,struct iguana_info *coi
free_json(vins);
return(rawtx);
}
- //printf("duplicatesTX.(%s)\n",rawtx);
+ printf("splitfunds tx.(%s) vins.(%s)\n",rawtx,jprint(vins,0));
if ( signedtxidp != 0 )
{
if ( (signedtx= iguana_signrawtx(myinfo,coin,0,signedtxidp,completedp,vins,rawtx,0,0)) != 0 )
@@ -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,cJSON *privkeys)
{
- 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,15 +687,17 @@ 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);
- 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 )
{
@@ -703,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");
@@ -740,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));
}
@@ -774,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 9b3abc4d5..a142f8a12 100755
--- a/basilisk/basilisk_swap.c
+++ b/basilisk/basilisk_swap.c
@@ -18,7 +18,8 @@
make sure to broadcast deposit before claiming refund, or to just skip it if neither is done
*/
-#define DEX_SLEEP 1
+#define DEX_SLEEP 10
+#define BASILISK_DEFAULT_NUMCONFIRMS 5
// Todo: monitor blockchains, ie complete extracting scriptsig
// mode to autocreate required outputs
@@ -105,6 +106,45 @@ 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);
+}
+
+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;
@@ -139,30 +179,28 @@ 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[20],secret256[32];
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;
+ memcpy(secret160,secretBn,20);
+ memcpy(secret256,secretBn256,32);
}
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;
+ memcpy(secret160,secretAm,20);
+ memcpy(secret256,secretAm256,32);
}
//for (i=0; i<32; i++)
// printf("%02x",secret256[i]);
- //printf(" <- secret256 depositflag.%d\n",depositflag);
+ //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++)
@@ -173,7 +211,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
@@ -217,12 +255,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;
+ *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 && numconfirms >= 0 )
return(numconfirms);
+ printf("basilisk_confirmsobj height.%d numconfirms.%d (%s)\n",height,numconfirms,jprint(item,0));
return(-1);
}
@@ -264,14 +314,17 @@ 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 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 )
+ if ( valstr[0] == '[' && is_cJSON_Array(valuearray) != 0 )
{
n = cJSON_GetArraySize(valuearray);
for (i=0; i= 0 )
break;
}
@@ -281,12 +334,13 @@ int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_swap *
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;
+ bits256 txid; char *signedtx,*retstr; int32_t i;
memset(txid.bytes,0,sizeof(txid));
if ( data != 0 && datalen != 0 )
{
@@ -298,20 +352,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);
@@ -389,7 +447,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");
@@ -412,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 )
@@ -442,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,typestr,bidasks,&privkey,coin->symbol,coinaddr) >= 0 )
{
bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype);
jaddistr(privkeyarray,wifstr);
@@ -506,8 +564,12 @@ 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 )
+ locktime = (uint32_t)time(NULL) - 777;
jaddnum(valsobj,"locktime",locktime);
jaddnum(valsobj,"timeout",30000);
jaddnum(valsobj,"timestamp",swapstarted+delay);
@@ -516,11 +578,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) txfee %.8f\n",rawtx->name,str,retstr,dstr(txfee));
flag = 0;
if ( (retarray= cJSON_Parse(retstr)) != 0 )
{
@@ -550,7 +612,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);
@@ -643,6 +705,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;
@@ -654,6 +717,31 @@ 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,*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;
@@ -679,12 +767,215 @@ 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);
+ 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++)
@@ -705,6 +996,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++)
@@ -728,6 +1021,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++)
@@ -745,9 +1040,15 @@ 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.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 )
{
@@ -777,6 +1078,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++)
@@ -790,101 +1101,17 @@ 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;
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);
}
@@ -917,6 +1144,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.redeemscript,swap->bobpayment.I.redeemlen);
//for (i=0; ibobpayment.redeemlen; i++)
// printf("%02x",swap->bobpayment.redeemscript[i]);
//printf(" <- bobpayment.%d\n",i);
@@ -952,6 +1180,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.redeemscript,swap->bobdeposit.I.redeemlen);
if ( genflag != 0 && (swap->bobdeposit.I.datalen == 0 || swap->bobrefund.I.datalen == 0) )
{
for (i=0; i<3; i++)
@@ -1013,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);
}
@@ -1034,7 +1264,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;
@@ -1055,7 +1285,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 )
{
@@ -1070,7 +1300,7 @@ FILE *basilisk_swap_save(struct supernet_info *myinfo,struct basilisk_swap *swap
}
else if ( reinit != 0 )
{
- }
+ }*/
return(fp);
}
@@ -1120,20 +1350,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;
}
}
@@ -1144,7 +1376,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);
@@ -1165,12 +1397,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;
}
@@ -1185,12 +1428,12 @@ 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 )
+ if ( swap->pushsock >= 0 ) //
nn_close(swap->pushsock), swap->pushsock = -1;
- if ( swap->subsock >= 0 )
+ 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 )
@@ -1222,10 +1465,11 @@ 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->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;
+ swap->aborted = (uint32_t)time(NULL);
}
}
//else printf("send.[%d] %x offset.%d datalen.%d [%llx]\n",sentbytes,msgbits,offset,datalen,*(long long *)data);
@@ -1233,26 +1477,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)
@@ -1261,13 +1502,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("got privBn.%s\n",bits256_str(str,swap->I.privBn));
+ return(basilisk_alicepayment_spend(myinfo,swap,&swap->alicereclaim));
}
return(-1);
}
@@ -1276,11 +1517,11 @@ 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 )
{
- 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);
@@ -1363,12 +1604,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 )
@@ -1456,14 +1694,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 +1721,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);
}
@@ -1535,23 +1777,37 @@ 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 ( swap->I.bobconfirms == 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;
+ 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_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);
@@ -1567,13 +1823,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
@@ -1613,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; iI.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;
@@ -1733,39 +2004,20 @@ int32_t basilisk_verify_privkeys(struct supernet_info *myinfo,void *ptr,uint8_t
return(errs);
}
-void basilisk_dontforget(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx,int32_t locktime,bits256 triggertxid)
+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)
{
- char fname[512],str[65]; FILE *fp; int32_t i;
- 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 )
+ uint8_t sendbuf[32768]; int32_t sendlen;
+ if ( basilisk_swapdata_rawtx(myinfo,swap,data,maxlen,rawtx) != 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)));
- }
- fprintf(fp,",\"lock\":%u",locktime);
- if ( bits256_nonz(triggertxid) != 0 )
- fprintf(fp,",\"trigger\":\"%s\"",bits256_str(str,triggertxid));
- 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;
- if ( basilisk_swapdata_rawtx(myinfo,swap,data,maxlen,rawtx) != 0 )
- {
- if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 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;
@@ -1778,35 +2030,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 ( swap->I.iambob != 0 )
- {
- if ( rawtx == &swap->bobdeposit )
- {
- basilisk_dontforget(myinfo,swap,&swap->bobdeposit,0,triggertxid);
- basilisk_dontforget(myinfo,swap,&swap->bobrefund,0,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->bobspend,0,triggertxid);
- }
- else
- {
- if ( rawtx == &swap->alicepayment )
- {
- basilisk_dontforget(myinfo,swap,&swap->alicepayment,0,triggertxid);
- }
- 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);
- }
- }
+ 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));
@@ -1818,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);
}
@@ -1941,13 +2166,15 @@ 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;
- while ( ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration )
+ 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\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 )
{
@@ -1956,24 +2183,29 @@ 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 )
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 )
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");
@@ -1994,7 +2226,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");
@@ -2018,13 +2250,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;
@@ -2071,7 +2303,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 || (swap->I.bobconfirms == 0 && swap->depositunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobdeposit) >= swap->I.bobconfirms )
{
printf("bobdeposit confirmed\n");
swap->I.statebits |= 0x400;
@@ -2095,7 +2327,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 || (swap->I.bobconfirms == 0 && swap->paymentunconf != 0) || basilisk_numconfirms(myinfo,swap,&swap->bobpayment) >= swap->I.bobconfirms )
{
printf("bobpayment confirmed\n");
swap->I.statebits |= 0x10000;
@@ -2104,22 +2336,23 @@ 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 )
{
- 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;
+ 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 )
{
@@ -2132,7 +2365,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;
@@ -2147,7 +2380,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);
}
@@ -2169,12 +2405,12 @@ 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 )
{
- 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));
@@ -2182,13 +2418,13 @@ 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;
}
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 )
{
@@ -2211,13 +2447,15 @@ 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) amlp.%d\n",keystr,retstr,swap->connected,swap->pushsock,swap->subsock,amlp);
free(retstr);
}
- if ( swap->connected == 0 && amlp != 0 )
+ 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 )
{
@@ -2225,44 +2463,98 @@ 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\"}",pushaddr,subaddr);
- 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;
+ 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; 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,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) + 600;
+ expiration = (uint32_t)time(NULL) + 300;
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 )
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);
@@ -2273,14 +2565,17 @@ 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 )
{
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 )
{
if ( swap->connected == 0 )
basilisk_psockinit(myinfo,swap,swap->I.iambob != 0);
@@ -2293,7 +2588,12 @@ 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;
+ if ( time(NULL) > expiration )
+ break;
}
myinfo->DEXactive = swap->I.expiration;
if ( time(NULL) >= expiration )
@@ -2301,9 +2601,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);
@@ -2312,7 +2617,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 )
{
/*for (i=0; i<20; i++)
printf("%02x",swap->secretAm[i]);
@@ -2344,63 +2659,14 @@ 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 )
- {
- 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
+ if ( (retval= basilisk_alicetxs(myinfo,swap,data,maxlen)) != 0 )
{
- printf("error creating myfee\n");
- retval = -6;
+ printf("basilisk_alicetxs error\n");
+ break;
}
}
}
- if ( (swap->I.statebits & 0x40) == 0 )
+ if ( swap->I.iambob == 0 && (swap->I.statebits & 0x40) == 0 )
{
printf("couldnt send fee\n");
retval = -8;
@@ -2412,22 +2678,25 @@ 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->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 ( 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);
+ 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 )
+ 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
@@ -2446,6 +2715,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
{
@@ -2458,10 +2729,34 @@ 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;
+ 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 )
@@ -2485,7 +2780,19 @@ 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<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 )
@@ -2498,12 +2805,17 @@ 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 )
{
+ 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 )
@@ -2527,25 +2839,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 )
@@ -2553,7 +2866,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);
+ }
}
}
}
@@ -2561,25 +2885,1152 @@ struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,bits256
return(swap);
}
-char *basilisk_swaplist(struct supernet_info *myinfo)
+/////////////// remember functions
+
+cJSON *basilisk_nullretjson(cJSON *retjson)
{
- char fname[512]; FILE *fp; struct basilisk_request R; int32_t optionduration; uint32_t quoteid,requestid,statebits; cJSON *retjson,*array; bits256 privkey;
- retjson = cJSON_CreateObject();
- array = cJSON_CreateArray();
- sprintf(fname,"%s/SWAPS/list",GLOBAL_DBDIR), OS_compatible_path(fname);
- if ( (fp= fopen(fname,"rb")) != 0 )
+ char *outstr;
+ if ( retjson != 0 )
{
- while ( fread(&requestid,1,sizeof(requestid),fp) == sizeof(requestid) && fread("eid,1,sizeof(quoteid),fp) == sizeof(quoteid) )
+ 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 )
{
- if ( basilisk_swap_load(requestid,quoteid,&privkey,&R,&statebits,&optionduration) == 0 )
+ item = jitem(addresses,0);
+ if ( (addr= jstr(item,0)) != 0 )
{
- jaddi(array,basilisk_requestjson(&R));
+ safecopy(destaddr,addr,64);
+ retval = 0;
}
+ //printf("item.(%s) -> dest.(%s)\n",jprint(item,0),destaddr);
}
- fclose(fp);
}
- jaddstr(retjson,"result","success");
- jadd(retjson,"swaps",array);
+ 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/basilisk/basilisk_tradebot.c b/basilisk/basilisk_tradebot.c
index 5d16548dc..2635cde97 100755
--- a/basilisk/basilisk_tradebot.c
+++ b/basilisk/basilisk_tradebot.c
@@ -228,7 +228,9 @@ 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");
+ //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 )
@@ -279,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);
@@ -289,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,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 )
@@ -305,6 +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);
maxi = i;
}
}
@@ -313,28 +316,39 @@ 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 )
{
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);
+ } // 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.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);
+ 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("aveprice %f dest %.8f avebid %f bidvol %f, aveask %f askvol %f\n",aveprice,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 )
+ destamount = (1.0 - profitmargin) * aveprice * list[0].srcamount;
+ 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 ( (coin= iguana_coinfind(list[0].dest)) != 0 )
+ {
+ bitcoin_address(coinaddr,coin->chain->pubtype,myinfo->persistent_pubkey33,33);
+ 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 )
{
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
@@ -342,9 +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?
{
metric = 1.;
@@ -357,12 +369,12 @@ 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; 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.;
diff --git a/basilisk/jumblr.c b/basilisk/jumblr.c
index 0710007c6..9618a9421 100755
--- a/basilisk/jumblr.c
+++ b/basilisk/jumblr.c
@@ -27,19 +27,19 @@
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)
{
- 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)
@@ -170,10 +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];
- sprintf(params,"[1, 99999999, [\"%s\"]]",addr);
+ if ( coin->FULLNODE == 0 )
+ 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));
}
@@ -193,10 +195,11 @@ 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 )
{
+ printf("jumblr.[%s].(%s)\n",coin->symbol,retstr);
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (n= cJSON_GetArraySize(retjson)) > 0 )
@@ -209,10 +212,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("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,dstr(balance));
free_json(retjson);
}
free(retstr);
@@ -289,8 +293,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,79 +368,309 @@ void jumblr_opidsupdate(struct supernet_info *myinfo,struct iguana_info *coin)
}
}
-bits256 jumblr_privkey(struct supernet_info *myinfo,char *BTCaddr,char *KMDaddr,char *prefix)
+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;
+ total = 0;
+ estfee = SATOSHIDEN * esttxfee;
+ 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 )
+ {
+ n = 0;
+ while ( n < 10 && remaining > value && numoutputs < sizeof(outputs)/sizeof(*outputs) )
+ {
+ outputs[numoutputs++] = value;
+ remaining -= value;
+ total += 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);
+ if ( numoutputs > 1 ) // no point to make just one
+ {
+ 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));
+ if ( (retstr= iguana_utxorawtx(myinfo,coin,0,coinaddr,coinaddr,outputs,numoutputs,0,&completed,sendflag,utxo,privkeys)) != 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);
+}
+
+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 * 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);
+}
+
+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 >= targetvolB )
+ {
+ if ( amount > margin * (targetvolB + targetvolS) )
+ *shouldsplitp = 1;
+ return(0);
+ }
+ else
+ {
+ if ( amount >= targetvolM )
+ {
+ if ( amount > margin * (targetvolM + targetvolS) )
+ *shouldsplitp = 1;
+ return(1);
+ }
+ else
+ {
+ if ( amount >= targetvolS )
+ {
+ if ( amount > margin * targetvolS )
+ *shouldsplitp = 1;
+ return(2);
+ }
+ else if ( amount >= targetvolB/dexfeeratio )
+ {
+ if ( amount > margin * targetvolB/dexfeeratio )
+ *shouldsplitp = 1;
+ return(3);
+ }
+ else if ( amount >= targetvolM/dexfeeratio )
+ {
+ if ( amount > margin * targetvolM/dexfeeratio )
+ *shouldsplitp = 1;
+ return(4);
+ }
+ else if ( amount >= targetvolS/dexfeeratio )
+ {
+ if ( amount > margin * targetvolS/dexfeeratio )
+ *shouldsplitp = 1;
+ return(5);
+ }
+ else if ( amount >= esttxfee )
+ {
+ if ( amount > esttxfee*4 )
+ *shouldsplitp = 1;
+ return(6);
+ }
+ else return(-1);
+ }
+ }
+}
+
+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)
{
- 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(KMDaddr,60,pubkey33,33);
- return(privkey);
+ 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.;
+ 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] = (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 )
+ fees[i] = 10000;
+ if ( (ind= jumblr_DEXutxoind(shouldsplitp,targetvolB,targetvolM,targetvolS,amount,margin,dexfeeratio,fees[3])) >= 0 )
+ {
+ printf("shouldsplit.%d ind.%d\n",*shouldsplitp,ind);
+ if ( *shouldsplitp != 0 )
+ {
+ privkeys = cJSON_CreateArray();
+ bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype);
+ jaddistr(privkeys,wifstr);
+ 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);
+ }
+ } // else printf("negative ind\n");
+ return(ind);
}
-void jumblr_DEXcheck(struct supernet_info *myinfo,struct iguana_info *coinkmd,char *BTCaddr,char *KMDaddr,bits256 privkey)
+/*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,int32_t *indp,struct iguana_info *coin,bits256 txid,int32_t vout)
{
- 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 )
+ int32_t i;
+ memset(splittxidp,0,sizeof(*splittxidp));
+ for (i=0; iDEXinfo.numpending; i++)
{
- 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 ( 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);
+ }
}
- if ( kmdprice > SMALLVAL )
+ // printf("jumblr_utxotxidpending cant find txid\n");
+ 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,int32_t shouldsplit)
+{
+ struct jumblr_pending pend; cJSON *vals,*retjson; bits256 hash; char *retstr;
+ memset(&pend,0,sizeof(pend));
+ pend.splittxid = splittxid;
+ pend.txid = txid;
+ pend.vout = vout;
+ pend.ind = ind;
+ if ( 0 && myinfo->IAMLP == 0 && shouldsplit == 0 && ind < 3 )
{
- 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 )
+ static uint32_t num;
+ if ( num == 0 && price > SMALLVAL )
{
- printf("BTC deposits %.8f, min %.8f\n",btcavail,minbtc);
+ num++;
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);
+ jaddstr(vals,"source",coin->symbol);
+ jaddstr(vals,"dest",dest);
+ jaddnum(vals,"amount",price * 100);//dstr(value) - estfee);
+ jaddnum(vals,"minprice",price);
jaddnum(vals,"usejumblr",1);
memset(hash.bytes,0,sizeof(hash));
- pending = btcavail;
- if ( (retstr= InstantDEX_request(myinfo,coinbtc,0,0,hash,vals,"")) != 0 )
+ if ( (retstr= InstantDEX_request(myinfo,coin,0,0,hash,vals,"")) != 0 )
{
- printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr);
+ if ( (retjson= cJSON_Parse(retstr)) != 0 )
+ {
+ printf("request.(%s) -> (%s)\n",jprint(vals,0),retstr);
+ free_json(retjson);
+ }
free(retstr);
}
- // 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);
+ 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)
+{
+ 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);
+ if ( (array= cJSON_Parse(retstr)) != 0 )
+ {
+ if ( (n= cJSON_GetArraySize(array)) > 0 )
+ {
+ for (i=0; iIAMLP,price,estfee);
+ jumblr_utxotxidpendingadd(myinfo,dest,coin,txid,vout,value,splittxid,ind,price,estfee,shouldsplit);
+ }
+ else
+ {
+ // update status of utxo
+ }
+ }
+ }
+ free_json(array);
+ }
+ free(retstr);
+ }
}
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; 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;
OS_randombytes(&r,sizeof(r));
//r = 0;
+ // 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,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 )
{
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);
@@ -448,43 +682,86 @@ 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;
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);
+ chosen_one = -1;
+ for (iter=0; iter<2; iter++)
{
- if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN )
+ counter = n = 0;
+ HASH_ITER(hh,myinfo->jumblrs,ptr,tmp)
{
- privkey = jumblr_privkey(myinfo,BTCaddr,KMDaddr,"");
- if ( (retstr= jumblr_sendz_to_t(myinfo,coin,ptr->dest,KMDaddr,dstr(total))) != 0 )
+ if ( jumblr_addresstype(myinfo,coin,ptr->src) == 'z' && jumblr_addresstype(myinfo,coin,ptr->dest) == 'z' )
{
- printf("sendz_to_t.(%s)\n",retstr);
- free(retstr);
+ if ( (r & 1) == 0 && ptr->spent == 0 && (total= jumblr_balance(myinfo,coin,ptr->dest)) >= (fee + JUMBLR_FEE)*SATOSHIDEN )
+ {
+ 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);
+ 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/basilisk/smartaddress.c b/basilisk/smartaddress.c
index ff9707b0c..727a54709 100755
--- a/basilisk/smartaddress.c
+++ b/basilisk/smartaddress.c
@@ -15,21 +15,206 @@
// 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 && 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);
+}
+
+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_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],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);
+ if ( (dest= iguana_coinfind(symbol)) != 0 )
+ desttype = dest->chain->pubtype;
+ else desttype = 60;
+ if ( (n= ap->numsymbols) > 0 )
+ {
+ array = cJSON_CreateArray();
+ for (j=0; jsymbols[j].symbol)) != 0 )
+ {
+ bitcoin_address(coinaddr,coin->chain->pubtype,ap->pubkey33,33);
+ 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);
+ 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);
+ }
+ jadd(item,"extra",smartaddress_extrajson(ap));
+ jaddi(array,item);
+ }
+ }
+ jadd(retjson,"coins",array);
+ }
+ return(retjson);
+}
+
+void smartaddress_symboladd(struct smartaddress *ap,char *symbol,double maxbid,double 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;
+ printf("symboladd.%d (%s) <- (%s %f %f)\n",ap->numsymbols,ap->typestr,symbol,maxbid,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++)
+ {
+ ap = &myinfo->smartaddrs[i];
+ if ( strcmp(type,ap->typestr) == 0 )
+ {
+ n = ap->numsymbols;
+ for (j=0; jsymbols[j].symbol,symbol) == 0 )
+ {
+ 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;
- int32_t i;
+ 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)
+{
+ 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 ( strcmp(type,ap->typestr) == 0 && bits256_cmp(ap->privkey,privkey) == 0 )
+ {
+ n = ap->numsymbols;
+ for (j=0; jsymbols[j].symbol,symbol) == 0 )
+ {
+ 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);
+ }
+ }
+ smartaddress_symboladd(ap,symbol,maxbid,minask);
+ return(i+1);
+ }
+ }
+ ap = &myinfo->smartaddrs[myinfo->numsmartaddrs];
+ if ( smartaddress_type(symbol) < 0 )
+ return(-1);
+ 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);
ap->pubkey = curve25519(privkey,curve25519_basepoint9());
- char coinaddr[64]; uint8_t addrtype,rmd160[20];
+ 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]);
@@ -37,54 +222,464 @@ 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_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,type,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;
+ strcpy(typestr,ap->typestr);
+ if ( (n= ap->numsymbols) > 0 )
+ {
+ for (j=0; jsymbols[j].symbol,symbol) == 0 )
+ {
+ bidaskp[0] = ap->symbols[j].maxbid;
+ bidaskp[1] = ap->symbols[j].minask;
+ return(j);
+ }
+ }
+ }
+ return(-1);
+}
+
+int32_t smartaddress(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,char *coinaddr)
{
- int32_t i; uint8_t addrtype,rmd160[20];
+ 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 )
{
- *privkeyp = myinfo->smartaddrs[i].privkey;
- printf("MATCHED %s\n",coinaddr);
- return(i);
+ ap = &myinfo->smartaddrs[i];
+ *privkeyp = ap->privkey;
+ 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,bits256 pubkey)
+int32_t smartaddress_pubkey(struct supernet_info *myinfo,char *typestr,double *bidaskp,bits256 *privkeyp,char *symbol,bits256 pubkey)
{
- int32_t i;
+ int32_t i,j,retval = -1; struct smartaddress *ap;
memset(privkeyp,0,sizeof(*privkeyp));
+ memset(bidaskp,0,sizeof(*bidaskp) * 2);
+ if ( bits256_cmp(myinfo->myaddr.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 )
{
- *privkeyp = myinfo->smartaddrs[i].privkey;
- return(i);
+ ap = &myinfo->smartaddrs[i];
+ *privkeyp = ap->privkey;
+ if ( (j= smartaddress_symbolmatch(typestr,bidaskp,ap,symbol)) >= 0 )
+ retval = 0;
+ else retval = (i+1);
+ break;
}
- return(-1);
+ 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);
}
-int32_t smartaddress_pubkey33(struct supernet_info *myinfo,bits256 *privkeyp,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;
+ 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 )
{
- *privkeyp = myinfo->smartaddrs[i].privkey;
- return(i);
+ ap = &myinfo->smartaddrs[i];
+ *privkeyp = ap->privkey;
+ if ( (j= smartaddress_symbolmatch(typestr,bidaskp,ap,symbol)) >= 0 )
+ retval = 0;
+ else retval = (i+1);
+ break;
}
- return(0);
+ portable_mutex_unlock(&myinfo->smart_mutex);
+ 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,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; struct smartaddress *ap;
+ 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 ( myinfo->DEXratio < .95 || myinfo->DEXratio > 1.01 )
+ myinfo->DEXratio = 0.995;
+ 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 = myinfo->DEXratio * (basebtc / relbtc);
+ minbtc = btc2kmd * (JUMBLR_INCR + 3*(JUMBLR_INCR * JUMBLR_FEE + JUMBLR_TXFEE));
+ if ( minamount == 0. && basebtc > SMALLVAL )
+ minamount = (minbtc / basebtc);
+ 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 - 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 ( (ap= smartaddressptr(0,myinfo,type,basecoin->symbol)) != 0 )
+ jaddbits256(vals,"srchash",ap->pubkey);
+ 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);
+ } 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));
+ 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,"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);
+ }
+}
+
+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,"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);
+ }
+}
+
+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_availupdate(myinfo,typestr,symbol,avail,SMALLVAL*0.99);
+ smartaddress_dex(myinfo,typestr,0,basecoin,coinaddr,avail,relcoin,maxbid,minask,extraobj,0.);
+ }
+ }
+ }
+ }
+}
+
+void smartaddress_update(struct supernet_info *myinfo,int32_t selector)
+{
+ 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;
+ 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
+ {
+ printf("Action.%s (%s)\n",typestr,jprint(coinitem,0));
+ if ( (address= jstr(coinitem,"address")) != 0 )
+ {
+ 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");
+ smartaddress_action(myinfo,selector,typestr,symbol,coinaddr,maxbid,minask,extraobj);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ free_json(smartarray);
+ }
+ free(smartstr);
+ }
+ }
+}
+
+#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();
+ 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_AND_TWO_DOUBLES(InstantDEX,smartaddress,type,symbol,maxbid,minask)
+{
+ 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,typestr,bidask,&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,type,symbol,maxbid,minask);
+ 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 7e21127aa..b044accd4 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;
@@ -984,17 +984,28 @@ 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;
}
}
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 %.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);
}
@@ -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;
@@ -1131,7 +1142,24 @@ 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");
+ if ( swap->bobcoin != 0 && swap->alicecoin != 0 )
+ {
+ 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;
if ( swap->balancingtrade == 0 )
_default_swap_balancingtrade(myinfo,swap,iambob);
diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h
index 040436d1a..84ba44794 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
@@ -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;
@@ -197,6 +198,8 @@ int32_t OS_nonportable_init();
void OS_portable_init();
void OS_init();
+int32_t sortds(double *buf,uint32_t num,int32_t size);
+int32_t revsortds(double *buf,uint32_t num,int32_t size);
double OS_portable_milliseconds();
void OS_portable_randombytes(uint8_t *x,long xlen);
@@ -347,7 +350,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);
@@ -358,6 +361,8 @@ 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);
+double dxblend(double *destp,double val,double decay);
uint64_t calc_ipbits(char *ip_port);
void expand_ipbits(char *ipaddr,uint64_t ipbits);
@@ -384,6 +389,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/OS_time.c b/crypto777/OS_time.c
index e930424f6..03489f03e 100755
--- a/crypto777/OS_time.c
+++ b/crypto777/OS_time.c
@@ -578,8 +578,8 @@ int32_t OS_conv_unixtime(struct tai *tp,int32_t *secondsp,time_t timestamp) // g
int32_t conv_date(int32_t *secondsp,char *date)
{
- char origdate[64],tmpdate[64]; int32_t year,month,day,hour,min,sec,len;
- strcpy(origdate,date), strcpy(tmpdate,date), tmpdate[8 + 2] = 0;
+ char origdate[512],tmpdate[512]; int32_t year,month,day,hour,min,sec,len;
+ safecopy(origdate,date,sizeof(origdate)), safecopy(tmpdate,date,sizeof(tmpdate)), tmpdate[8 + 2] = 0;
year = atoi(tmpdate), month = atoi(tmpdate+5), day = atoi(tmpdate+8);
*secondsp = 0;
if ( (len= (int32_t)strlen(date)) <= 10 )
@@ -591,8 +591,8 @@ int32_t conv_date(int32_t *secondsp,char *date)
if ( hour >= 0 && hour < 24 && min >= 0 && min < 60 && sec >= 0 && sec < 60 )
*secondsp = (3600*hour + 60*min + sec);
else printf("ERROR: seconds.%d %d %d %d, len.%d\n",*secondsp,hour,min,sec,len);
- }
- //printf("(%s) -> Y.%d M.%d D.%d %d:%d:%d\n",date,year,month,day,hour,min,sec);
+ //printf("(%s) -> Y.%d M.%d D.%d %d:%d:%d\n",date,year,month,day,hour,min,sec);
+ } //else printf("short len.(%s) from (%s)\n",date,origdate);
sprintf(origdate,"%d-%02d-%02d",year,month,day); //2015-07-25T22:34:31Z
if ( strcmp(tmpdate,origdate) != 0 )
{
diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c
index e0d7fca85..fd27643d3 100755
--- a/crypto777/bitcoind_RPC.c
+++ b/crypto777/bitcoind_RPC.c
@@ -17,13 +17,8 @@
#define LIQUIDITY_PROVIDER 1
#if LIQUIDITY_PROVIDER
-#ifdef _WIN32
-#include
-#include
-#else
#include
#include
-#endif
// return data from the server
#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
@@ -62,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);
}
@@ -90,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;
@@ -120,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;
@@ -142,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;
@@ -158,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);
+ 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);
@@ -206,9 +202,9 @@ 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);
+ //printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res);
free(s.ptr);
return(0);
}
diff --git a/crypto777/cJSON.c b/crypto777/cJSON.c
index 13cc6567e..8bce48b19 100755
--- a/crypto777/cJSON.c
+++ b/crypto777/cJSON.c
@@ -546,7 +546,7 @@ static char *print_object(cJSON *item,int32_t depth,int32_t fmt)
/* Get Array size/item / object item. */
int32_t cJSON_GetArraySize(cJSON *array) {cJSON *c; if ( array == 0 ) return(0); c=array->child;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/crypto777/hmac/sha224.c b/crypto777/hmac/sha224.c
index 78a0bfb84..683440d70 100755
--- a/crypto777/hmac/sha224.c
+++ b/crypto777/hmac/sha224.c
@@ -26,7 +26,7 @@ const struct ltc_hash_descriptor sha224_desc =
9,
&sha224_init,
- &sha256_process,
+ &sha256i_process,
&sha224_done,
&sha224_test,
NULL
@@ -69,7 +69,7 @@ int sha224_done(hash_state * md, unsigned char *out)
LTC_ARGCHK(md != NULL);
LTC_ARGCHK(out != NULL);
- err = sha256_done(md, buf);
+ err = sha256i_done(md, buf);
XMEMCPY(out, buf, 28);
#ifdef LTC_CLEAN_STACK
zeromem(buf, sizeof(buf));
diff --git a/crypto777/hmac/sha256.c b/crypto777/hmac/sha256.c
index 29dceaa2e..e3b6a27b9 100755
--- a/crypto777/hmac/sha256.c
+++ b/crypto777/hmac/sha256.c
@@ -17,24 +17,6 @@
//#ifdef LTC_SHA256
-const struct ltc_hash_descriptor sha256_desc =
-{
- "sha256",
- 0,
- 32,
- 64,
-
- /* OID */
- { 2, 16, 840, 1, 101, 3, 4, 2, 1, },
- 9,
-
- &sha256_init,
- &sha256_process,
- &sha256_done,
- &sha256_test,
- NULL
-};
-
#ifdef LTC_SMALL_CODE
/* the K array */
static const ulong32 K[64] = {
@@ -203,7 +185,7 @@ static int sha256_compress(hash_state * md, unsigned char *buf)
@param md The hash state you wish to initialize
@return CRYPT_OK if successful
*/
-int sha256_init(hash_state * md)
+int sha256i_init(hash_state * md)
{
LTC_ARGCHK(md != NULL);
@@ -227,7 +209,7 @@ int sha256_init(hash_state * md)
@param inlen The length of the data (octets)
@return CRYPT_OK if successful
*/
-HASH_PROCESS(sha256_process, sha256_compress, sha256, 64)
+HASH_PROCESS(sha256i_process, sha256_compress, sha256, 64)
/**
Terminate the hash to get the digest
@@ -235,7 +217,7 @@ HASH_PROCESS(sha256_process, sha256_compress, sha256, 64)
@param out [out] The destination of the hash (32 bytes)
@return CRYPT_OK if successful
*/
-int sha256_done(hash_state * md, unsigned char *out)
+int sha256i_done(hash_state * md, unsigned char *out)
{
int i;
@@ -287,9 +269,9 @@ int sha256_done(hash_state * md, unsigned char *out)
void calc_sha256(char hashstr[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len)
{
hash_state md;
- sha256_init(&md);
- sha256_process(&md,src,len);
- sha256_done(&md,hash);
+ sha256i_init(&md);
+ sha256i_process(&md,src,len);
+ sha256i_done(&md,hash);
if ( hashstr != 0 )
{
int32_t init_hexbytes_noT(char *hexbytes,uint8_t *message,long len);
@@ -300,11 +282,11 @@ void calc_sha256(char hashstr[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t
void calc_sha256cat(uint8_t hash[256 >> 3],uint8_t *src,int32_t len,uint8_t *src2,int32_t len2)
{
hash_state md;
- sha256_init(&md);
- sha256_process(&md,src,len);
+ sha256i_init(&md);
+ sha256i_process(&md,src,len);
if ( src2 != 0 )
- sha256_process(&md,src2,len2);
- sha256_done(&md,hash);
+ sha256i_process(&md,src2,len2);
+ sha256i_done(&md,hash);
}
void update_sha256(uint8_t hash[256 >> 3],struct sha256_state *state,uint8_t *src,int32_t len)
@@ -312,14 +294,14 @@ void update_sha256(uint8_t hash[256 >> 3],struct sha256_state *state,uint8_t *sr
hash_state md;
memset(&md,0,sizeof(md));
if ( src == 0 )
- sha256_init(&md);
+ sha256i_init(&md);
else
{
md.sha256 = *state;
- sha256_process(&md,src,len);
+ sha256i_process(&md,src,len);
}
*state = md.sha256;
- sha256_done(&md,hash);
+ sha256i_done(&md,hash);
}
/*void calc_OP_HASH160(char hexstr[41],uint8_t hash160[20],char *pubkey)
@@ -334,9 +316,9 @@ void update_sha256(uint8_t hash[256 >> 3],struct sha256_state *state,uint8_t *sr
return;
}
decode_hex(buf,len,pubkey);
- sha256_init(&md);
- sha256_process(&md,buf,len);
- sha256_done(&md,sha256);
+ sha256i_init(&md);
+ sha256i_process(&md,buf,len);
+ sha256i_done(&md,sha256);
rmd160_init(&md);
rmd160_process(&md,sha256,256 >> 3);
@@ -389,9 +371,9 @@ int sha256_test(void)
char *str;
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
- sha256_init(&md);
- sha256_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
- sha256_done(&md, tmp);
+ sha256i_init(&md);
+ sha256i_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+ sha256i_done(&md, tmp);
if (XMEMCMP(tmp, tests[i].hash, 32) != 0) {
for (j=0; j<32; j++)
printf("%02x",tmp[j]);
@@ -400,16 +382,16 @@ int sha256_test(void)
strcpy(str,(char*)tests[i].msg);
reverse_hexstr(str);
printf("reversed.(%s)\n",str);
- sha256_init(&md);
- sha256_process(&md, (unsigned char*)str, (unsigned long)strlen(str));
- sha256_done(&md, tmp);
+ sha256i_init(&md);
+ sha256i_process(&md, (unsigned char*)str, (unsigned long)strlen(str));
+ sha256i_done(&md, tmp);
for (j=0; j<32; j++)
printf("%02x",tmp[j]);
printf(" <- sha256(%s)\n",str);
decode_hex(buf,(int)strlen(tests[i].msg),tests[i].msg);
- sha256_init(&md);
- sha256_process(&md, (unsigned char*)buf, (unsigned long)strlen(tests[i].msg)/2);
- sha256_done(&md, tmp);
+ sha256i_init(&md);
+ sha256i_process(&md, (unsigned char*)buf, (unsigned long)strlen(tests[i].msg)/2);
+ sha256i_done(&md, tmp);
for (j=0; j<32; j++)
printf("%02x",tmp[j]);
printf(" <- sha256(binary %s)\n",tests[i].msg);
@@ -436,6 +418,24 @@ int sha256_test(void)
#undef Maj
+const struct ltc_hash_descriptor sha256_desc =
+{
+ "sha256",
+ 0,
+ 32,
+ 64,
+
+ /* OID */
+ { 2, 16, 840, 1, 101, 3, 4, 2, 1, },
+ 9,
+
+ &sha256i_init,
+ &sha256i_process,
+ &sha256i_done,
+ &sha256_test,
+ NULL
+};
+
/* $Source: /cvs/libtom/libtomcrypt/src/hashes/sha2/sha256.c,v $ */
/* $Revision: 1.11 $ */
diff --git a/crypto777/hmac/tomcrypt_hash.h b/crypto777/hmac/tomcrypt_hash.h
index b596c6a37..de5977437 100755
--- a/crypto777/hmac/tomcrypt_hash.h
+++ b/crypto777/hmac/tomcrypt_hash.h
@@ -228,9 +228,9 @@ extern const struct ltc_hash_descriptor sha384_desc;
#endif
#ifdef LTC_SHA256
-int sha256_init(hash_state * md);
-int sha256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
-int sha256_done(hash_state * md, unsigned char *hash);
+int sha256i_init(hash_state * md);
+int sha256i_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha256i_done(hash_state * md, unsigned char *hash);
int sha256_test(void);
extern const struct ltc_hash_descriptor sha256_desc;
@@ -239,7 +239,7 @@ extern const struct ltc_hash_descriptor sha256_desc;
#error LTC_SHA256 is required for LTC_SHA224
#endif
int sha224_init(hash_state * md);
-#define sha224_process sha256_process
+#define sha224_process sha256i_process
int sha224_done(hash_state * md, unsigned char *hash);
int sha224_test(void);
extern const struct ltc_hash_descriptor sha224_desc;
diff --git a/crypto777/hmac_sha512.c b/crypto777/hmac_sha512.c
index e1fe4e523..7df6d978f 100755
--- a/crypto777/hmac_sha512.c
+++ b/crypto777/hmac_sha512.c
@@ -621,4 +621,28 @@ char *hmac_whirlpool_str(char *dest,char *key,int32_t key_size,char *message)
return(dest);
}
+void calc_md2str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
+{
+ bits128 x;
+ calc_md2(hexstr,buf,msg,len);
+ decode_hex(buf,sizeof(x),hexstr);
+ //memcpy(buf,x.bytes,sizeof(x));
+}
+
+void calc_md4str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
+{
+ bits128 x;
+ calc_md4(hexstr,buf,msg,len);
+ decode_hex(buf,sizeof(x),hexstr);
+ //memcpy(buf,x.bytes,sizeof(x));
+}
+
+void calc_md5str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
+{
+ bits128 x;
+ calc_md5(hexstr,msg,len);
+ decode_hex(buf,sizeof(x),hexstr);
+ //memcpy(buf,x.bytes,sizeof(x));
+}
+
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/crypto777/iguana_utils.c b/crypto777/iguana_utils.c
index 80988fa5f..5b0ce5743 100755
--- a/crypto777/iguana_utils.c
+++ b/crypto777/iguana_utils.c
@@ -522,11 +522,24 @@ static int _increasing_double(const void *a,const void *b)
{
#define double_a (*(double *)a)
#define double_b (*(double *)b)
- if ( double_b > double_a )
- return(-1);
- else if ( double_b < double_a )
- return(1);
- return(0);
+ if ( double_b > double_a )
+ return(-1);
+ else if ( double_b < double_a )
+ return(1);
+ return(0);
+#undef double_a
+#undef double_b
+}
+
+static int _decreasing_double(const void *a,const void *b)
+{
+#define double_a (*(double *)a)
+#define double_b (*(double *)b)
+ if ( double_b > double_a )
+ return(1);
+ else if ( double_b < double_a )
+ return(-1);
+ return(0);
#undef double_a
#undef double_b
}
@@ -572,8 +585,14 @@ static int _decreasing_uint32(const void *a,const void *b)
int32_t sortds(double *buf,uint32_t num,int32_t size)
{
- qsort(buf,num,size,_increasing_double);
- return(0);
+ qsort(buf,num,size,_increasing_double);
+ return(0);
+}
+
+int32_t revsortds(double *buf,uint32_t num,int32_t size)
+{
+ qsort(buf,num,size,_decreasing_double);
+ return(0);
}
int32_t sort64s(uint64_t *buf,uint32_t num,int32_t size)
@@ -1086,30 +1105,6 @@ void rmd160ofsha256(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
calc_rmd160(hexstr,buf,sha256,sizeof(sha256));
}
-void calc_md2str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
-{
- bits128 x;
- calc_md2(hexstr,buf,msg,len);
- decode_hex(buf,sizeof(x),hexstr);
- //memcpy(buf,x.bytes,sizeof(x));
-}
-
-void calc_md4str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
-{
- bits128 x;
- calc_md4(hexstr,buf,msg,len);
- decode_hex(buf,sizeof(x),hexstr);
- //memcpy(buf,x.bytes,sizeof(x));
-}
-
-void calc_md5str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
-{
- bits128 x;
- calc_md5(hexstr,msg,len);
- decode_hex(buf,sizeof(x),hexstr);
- //memcpy(buf,x.bytes,sizeof(x));
-}
-
void calc_crc32str(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len)
{
uint32_t crc; uint8_t serialized[sizeof(crc)];
@@ -1279,7 +1274,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 ( (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/crypto777/m_LP_win_cross b/crypto777/m_LP_win_cross
new file mode 100755
index 000000000..483f14aa5
--- /dev/null
+++ b/crypto777/m_LP_win_cross
@@ -0,0 +1,4 @@
+git pull
+rm *.o
+i686-w64-mingw32-gcc -DWIN32 -static-libgcc -c -DLIQUIDITY_PROVIDER=1 -O2 *.c jpeg/*.c jpeg/unix/*.c -DPTW32_STATIC_LIB -lm -DCURL_STATICLIB -L../win_lib/lib/ -I../win_lib/include/ -L../win_lib/ -lcurl
+rm -f ../agents/libcrypto777.a; ar rc ../agents/libcrypto777.a *.o
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);
diff --git a/crypto777/scrypt.c b/crypto777/scrypt.c
index fa482eaf8..1b156a286 100755
--- a/crypto777/scrypt.c
+++ b/crypto777/scrypt.c
@@ -69,7 +69,7 @@ static const uint32_t sha256_k[64] = {
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
-static inline void sha256_init(uint32_t *state)
+static inline void scrypt_sha256_init(uint32_t *state)
{
memcpy(state, sha256_h, 32);
}
@@ -102,7 +102,7 @@ W[i] + sha256_k[i])
#define swab32(x) ((((x) << 24) & 0xff000000u) | (((x) << 8) & 0x00ff0000u) | (((x) >> 8) & 0x0000ff00u) | (((x) >> 24) & 0x000000ffu))
-static inline void sha256_transform(uint32_t *state, const uint32_t *block, int swap)
+static inline void scrypt_sha256_transform(uint32_t *state, const uint32_t *block, int swap)
{
uint32_t W[64];
uint32_t S[8];
@@ -203,29 +203,29 @@ static inline void HMAC_SHA256_80_init(const uint32_t *key,uint32_t *tstate, uin
/* tstate is assumed to contain the midstate of key */
memcpy(pad, key + 16, 16);
memcpy(pad + 4, keypad, 48);
- sha256_transform(tstate, pad, 0);
+ scrypt_sha256_transform(tstate, pad, 0);
memcpy(ihash, tstate, 32);
- sha256_init(ostate);
+ scrypt_sha256_init(ostate);
for (i = 0; i < 8; i++)
pad[i] = ihash[i] ^ 0x5c5c5c5c;
for (; i < 16; i++)
pad[i] = 0x5c5c5c5c;
- sha256_transform(ostate, pad, 0);
+ scrypt_sha256_transform(ostate, pad, 0);
- sha256_init(tstate);
+ scrypt_sha256_init(tstate);
for (i = 0; i < 8; i++)
pad[i] = ihash[i] ^ 0x36363636;
for (; i < 16; i++)
pad[i] = 0x36363636;
- sha256_transform(tstate, pad, 0);
+ scrypt_sha256_transform(tstate, pad, 0);
}
static inline void PBKDF2_SHA256_80_128(const uint32_t *tstate,const uint32_t *ostate, const uint32_t *salt, uint32_t *output)
{
uint32_t istate[8], ostate2[8],ibuf[16], obuf[16]; int i, j;
memcpy(istate, tstate, 32);
- sha256_transform(istate, salt, 0);
+ scrypt_sha256_transform(istate, salt, 0);
memcpy(ibuf, salt + 16, 16);
memcpy(ibuf + 5, innerpad, 44);
memcpy(obuf + 8, outerpad, 32);
@@ -233,9 +233,9 @@ static inline void PBKDF2_SHA256_80_128(const uint32_t *tstate,const uint32_t *o
{
memcpy(obuf, istate, 32);
ibuf[4] = i + 1;
- sha256_transform(obuf, ibuf, 0);
+ scrypt_sha256_transform(obuf, ibuf, 0);
memcpy(ostate2, ostate, 32);
- sha256_transform(ostate2, obuf, 0);
+ scrypt_sha256_transform(ostate2, obuf, 0);
for (j = 0; j < 8; j++)
output[8 * i + j] = swab32(ostate2[j]);
}
@@ -244,12 +244,12 @@ static inline void PBKDF2_SHA256_80_128(const uint32_t *tstate,const uint32_t *o
static inline void PBKDF2_SHA256_128_32(uint32_t *tstate, uint32_t *ostate,const uint32_t *salt, uint32_t *output)
{
uint32_t buf[16]; int i;
- sha256_transform(tstate, salt, 1);
- sha256_transform(tstate, salt + 16, 1);
- sha256_transform(tstate, finalblk, 0);
+ scrypt_sha256_transform(tstate, salt, 1);
+ scrypt_sha256_transform(tstate, salt + 16, 1);
+ scrypt_sha256_transform(tstate, finalblk, 0);
memcpy(buf, tstate, 32);
memcpy(buf + 8, outerpad, 32);
- sha256_transform(ostate, buf, 0);
+ scrypt_sha256_transform(ostate, buf, 0);
for (i = 0; i < 8; i++)
output[i] = swab32(ostate[i]);
}
@@ -363,11 +363,11 @@ void calc_scrypthash(uint32_t *hash,void *data)
uint8_t *scratchbuf; uint32_t midstate[8];
memset(midstate,0,sizeof(midstate));
memset(hash,0,32);
- sha256_init(midstate);
- sha256_transform(midstate,(void *)data,0);
+ scrypt_sha256_init(midstate);
+ scrypt_sha256_transform(midstate,(void *)data,0);
scratchbuf = malloc(1024 * 128 + 64);
scrypt_1024_1_1_256((void *)data,hash,midstate,scratchbuf,1024);
free(scratchbuf);
}
//010000000000000000000000000000000000000000000000000000000000000000000000d9ced4ed1130f7b7faad9be25323ffafa33232a17c3edf6cfd97bee6bafbdd97b9aa8e4ef0ff0f1ecd513f7c
-//010000000000000000000000000000000000000000000000000000000000000000000000d9ced4ed1130f7b7faad9be25323ffafa33232a17c3edf6cfd97bee6bafbdd97b9aa8e4ef0ff0f1ecd513f7c00
\ No newline at end of file
+//010000000000000000000000000000000000000000000000000000000000000000000000d9ced4ed1130f7b7faad9be25323ffafa33232a17c3edf6cfd97bee6bafbdd97b9aa8e4ef0ff0f1ecd513f7c00
diff --git a/iguana.vcxproj b/iguana.vcxproj
index e7a0d7a57..fbdc95c13 100644
--- a/iguana.vcxproj
+++ b/iguana.vcxproj
@@ -73,16 +73,22 @@
true
+ $(ProjectDir)\includes;$(ProjectDir)\includes\curl;$(IncludePath)
+ $(ProjectDir)\OSlibs\win;$(LibraryPath)
true
+ $(SolutionDir)/includes;$(SolutionDir)/includes/curl;$(IncludePath)
false
+ $(ProjectDir)\includes;$(ProjectDir)\includes\curl;$(IncludePath)
+ $(ProjectDir)\OSlibs\win;$(LibraryPath)
false
false
+ $(ProjectDir)\includes;$(ProjectDir)\includes\curl;$(IncludePath)
@@ -97,7 +103,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)
@@ -114,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)
@@ -133,7 +139,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)
@@ -154,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)
diff --git a/iguana/coins/basilisk/coqui b/iguana/coins/basilisk/coqui
new file mode 100755
index 000000000..55730d486
--- /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\":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/basilisk/mesh b/iguana/coins/basilisk/mesh
index 81904b6d7..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\":\"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\":\"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/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..8c10b2475
--- /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\":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/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/coqui_7776 b/iguana/coins/coqui_7776
new file mode 100755
index 000000000..6079fd06e
--- /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\":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/genltc b/iguana/coins/genltc
index df691b5d6..ea034ed80 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: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/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/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/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}"
+
diff --git a/iguana/coins/ltc_7776 b/iguana/coins/ltc_7776
new file mode 100755
index 000000000..d6b5e4e11
--- /dev/null
+++ b/iguana/coins/ltc_7776
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+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}"
+
diff --git a/iguana/coins/mesh_7776 b/iguana/coins/mesh_7776
index 214335788..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\":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\":\"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/revs b/iguana/coins/revs
new file mode 100755
index 000000000..23f4948b2
--- /dev/null
+++ b/iguana/coins/revs
@@ -0,0 +1,3 @@
+~/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\"}"
+
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\"}"
+
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..b43b7f793
--- /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\":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/dPoW.h b/iguana/dPoW.h
index b773104c8..47e9f1642 100755
--- a/iguana/dPoW.h
+++ b/iguana/dPoW.h
@@ -137,7 +137,7 @@ struct dpow_info
int32_t lastheight,maxblocks,SRCHEIGHT,SHORTFLAG,ratifying;
struct pax_transaction *PAX;
portable_mutex_t paxmutex,dexmutex;
- uint32_t ipbits[64],numipbits;
+ uint32_t ipbits[128],numipbits;
struct dpow_block **blocks;
};
uint64_t dpow_notarybestk(uint64_t refmask,struct dpow_block *bp,int8_t *lastkp);
diff --git a/iguana/dexscripts/.marker b/iguana/dexscripts/.marker
new file mode 100644
index 000000000..e69de29bb
diff --git a/iguana/dpow/dpow_network.c b/iguana/dpow/dpow_network.c
index cadc11faa..9899b9cac 100755
--- a/iguana/dpow/dpow_network.c
+++ b/iguana/dpow/dpow_network.c
@@ -88,6 +88,9 @@ 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]);
@@ -140,23 +143,34 @@ 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;
+ int32_t i=0,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++) cant do this!! slows down notary servers, big latency
+ {
+ 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; 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) )
{
vcalc_sha256(0,packethash.bytes,(void *)&sigpacket->nonce,(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
@@ -376,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;
@@ -386,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);
@@ -402,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 )
{
@@ -421,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));
}
}
}
@@ -467,14 +478,14 @@ 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);
}
//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);
@@ -515,7 +526,7 @@ 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);
@@ -550,7 +561,7 @@ void dex_channelsend(struct supernet_info *myinfo,bits256 srchash,bits256 destha
void dpow_randipbits(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *retjson)
{
- int32_t m; uint32_t ipbits; char *coinstr;
+ int32_t m; uint32_t ipbits; char *coinstr; cJSON *infojson;
if ( is_cJSON_Array(retjson) == 0 )
{
if ( (m= myinfo->numdpowipbits) > 0 )
@@ -561,6 +572,11 @@ void dpow_randipbits(struct supernet_info *myinfo,struct iguana_info *coin,cJSON
}
if ( (coinstr= jstr(retjson,"coin")) == 0 )
jaddstr(retjson,"coin",coin->symbol);
+ if ( (infojson= dpow_getinfo(myinfo,coin)) != 0 )
+ {
+ jaddnum(retjson,"notaryheight",juint(infojson,"blocks"));
+ free_json(infojson);
+ }
}
}
@@ -798,7 +814,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\"}"));
}
@@ -813,7 +835,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 )
@@ -1082,11 +1104,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)
@@ -1154,14 +1178,17 @@ 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("_dex_listunspentarg: %s UNSPENTS.(%s)\n",symbol,retstr);
}
return(_dex_arrayreturn(retstr));
}
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)
@@ -1255,9 +1282,9 @@ 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 )
+ if ( myinfo->subsock >= 0 && (size= signed_nn_recv(&freeptr,myinfo,myinfo->notaries,myinfo->numnotaries,myinfo->subsock,&dexp)) >= 0 )
{
if ( dexp != 0 )
{
@@ -1296,7 +1323,7 @@ struct dpow_nanomsghdr
{
bits256 srchash,desthash;
struct dpow_nanoutxo ratify,notarize;
- uint32_t channel,height,size,datalen,crc32,myipbits,numipbits,ipbits[64];
+ uint32_t channel,height,size,datalen,crc32,myipbits,numipbits,ipbits[128];
char symbol[16];
uint8_t senderind,version0,version1,packet[];
} PACKED;
@@ -2004,10 +2031,10 @@ void dpow_send(struct supernet_info *myinfo,struct dpow_info *dp,struct dpow_blo
printf("%d NANOSEND.%d ht.%d channel.%08x (%d) pax.%08x datalen.%d (%d %llx) (%d %llx) recv.%llx\n",i,sentbytes,np->height,np->channel,size,np->notarize.paxwdcrc,datalen,(int8_t)np->notarize.bestk,(long long)np->notarize.bestmask,bp->notaries[bp->myind].bestk,(long long)bp->notaries[bp->myind].bestmask,(long long)bp->recvmask);
}
-void dpow_ipbitsadd(struct supernet_info *myinfo,struct dpow_info *dp,uint32_t *ipbits,int32_t numipbits,int32_t fromid,uint32_t senderipbits)
+void dpow_ipbitsadd(struct supernet_info *myinfo,struct dpow_info *dp,uint32_t *ipbits,int32_t numipbits,int32_t maxipbits,int32_t fromid,uint32_t senderipbits)
{
int32_t i,j,matched,missing,n; char ipaddr[64];
- if ( numipbits >= 64 )
+ if ( numipbits >= maxipbits )
{
static int32_t counter;
if ( counter++ < 100 )
@@ -2063,10 +2090,10 @@ 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 )
+ if ( size >= sizeof(*np) )
{
//fprintf(stderr,"%d ",size);
if ( np->version0 == (DPOW_VERSION & 0xff) && np->version1 == ((DPOW_VERSION >> 8) & 0xff) )
@@ -2090,7 +2117,7 @@ int32_t dpow_nanomsg_update(struct supernet_info *myinfo)
printf("received nnpacket for (%s)\n",np->symbol);
else
{
- dpow_ipbitsadd(myinfo,dp,np->ipbits,np->numipbits,np->senderind,np->myipbits);
+ dpow_ipbitsadd(myinfo,dp,np->ipbits,np->numipbits,sizeof(np->ipbits)/sizeof(*np->ipbits),np->senderind,np->myipbits);
if ( (bp= dpow_heightfind(myinfo,dp,np->height)) != 0 && bp->state != 0xffffffff && bp->myind >= 0 )
{
//char str[65]; printf("%s RECV ht.%d ch.%08x (%d) crc32.%08x:%08x datalen.%d:%d firstz.%d i.%d senderind.%d myind.%d\n",bits256_str(str,np->srchash),np->height,np->channel,size,np->crc32,crc32,np->datalen,(int32_t)(size - sizeof(*np)),firstz,i,np->senderind,bp->myind);
@@ -2117,7 +2144,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++;
@@ -2157,11 +2184,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);
@@ -2183,7 +2210,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/dpow/dpow_prices.c b/iguana/dpow/dpow_prices.c
index 3a8257bb7..d83da8dd1 100755
--- a/iguana/dpow/dpow_prices.c
+++ b/iguana/dpow/dpow_prices.c
@@ -1275,25 +1275,33 @@ int32_t PAX_ecbparse(char *date,double *prices,char *url,int32_t basenum)
printf("(%s)\n",jsonstr);
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
- copy_cJSON(&tmp,jobj(json,"date")), safecopy(date,tmp.buf,64);
- if ( (basestr= jstr(json,"base")) != 0 && strcmp(basestr,CURRENCIES[basenum]) == 0 && (ratesobj= jobj(json,"rates")) != 0 && (item= ratesobj->child) != 0 )
+ if ( jobj(json,"error") != 0 || jobj(json,"date") == 0 )
{
- while ( item != 0 )
+ printf("Got error from fixer.io (%s)\n",jsonstr);
+ sleep(10);
+ }
+ else
+ {
+ copy_cJSON(&tmp,jobj(json,"date")), safecopy(date,tmp.buf,64);
+ if ( (basestr= jstr(json,"base")) != 0 && strcmp(basestr,CURRENCIES[basenum]) == 0 && (ratesobj= jobj(json,"rates")) != 0 && (item= ratesobj->child) != 0 )
{
- if ( (relstr= get_cJSON_fieldname(item)) != 0 && (relnum= PAX_basenum(relstr)) >= 0 )
+ while ( item != 0 )
{
- i = basenum*MAX_CURRENCIES + relnum;
- prices[i] = item->valuedouble;
- //if ( basenum == JPYNUM )
- // prices[i] *= 100.;
- // else if ( relnum == JPYNUM )
- // prices[i] /= 100.;
- count++;
- if ( Debuglevel > 2 )
- printf("(%02d:%02d %f) ",basenum,relnum,prices[i]);
- sprintf(name,"%s%s",CURRENCIES[basenum],CURRENCIES[relnum]);
- } else printf("cant find.(%s)\n",relstr);//, getchar();
- item = item->next;
+ if ( (relstr= get_cJSON_fieldname(item)) != 0 && (relnum= PAX_basenum(relstr)) >= 0 )
+ {
+ i = basenum*MAX_CURRENCIES + relnum;
+ prices[i] = item->valuedouble;
+ //if ( basenum == JPYNUM )
+ // prices[i] *= 100.;
+ // else if ( relnum == JPYNUM )
+ // prices[i] /= 100.;
+ count++;
+ if ( Debuglevel > 2 )
+ printf("(%02d:%02d %f) ",basenum,relnum,prices[i]);
+ sprintf(name,"%s%s",CURRENCIES[basenum],CURRENCIES[relnum]);
+ } else printf("cant find.(%s)\n",relstr);//, getchar();
+ item = item->next;
+ }
}
}
free_json(json);
@@ -1322,12 +1330,13 @@ int32_t PAX_ecbprices(char *date,double *prices,int32_t year,int32_t month,int32
{
for (basenum=0; basenum= MAX_CURRENCIES )
break;
if ( iter == 0 )
{
sprintf(url,"%s%s",baseurl,CURRENCIES[basenum]);
count += PAX_ecbparse(basenum == 0 ? date : tmpdate,prices,url,basenum);
+ usleep(100000);
if ( (basenum != 0 && strcmp(tmpdate,date) != 0) || (checkdate[0] != 0 && strcmp(checkdate,date) != 0) )
{
//printf("date mismatch (%s) != (%s) or checkdate.(%s)\n",tmpdate,date,checkdate);
@@ -1338,7 +1347,7 @@ int32_t PAX_ecbprices(char *date,double *prices,int32_t year,int32_t month,int32
{
for (nonz=i=0; i= MAX_CURRENCIES )
break;
if ( prices[MAX_CURRENCIES*basenum + i] != 0. )
nonz++;
@@ -1358,6 +1367,7 @@ int32_t ecb_matrix(double basevals[MAX_CURRENCIES],double matrix[MAX_CURRENCIES]
FILE *fp=0; double price,bid,ask; int32_t n=0,datenum,relid,baseid,year=0,seconds,month=0,day=0,loaded = 0; char name[16],fname[64],_date[64];
if ( date == 0 )
date = _date, memset(_date,0,sizeof(_date));
+ //printf("ecb_matrix(%s)\n",date);
sprintf(fname,"%s/ECB/%s",GLOBAL_DBDIR,date), OS_compatible_path(fname);
if ( date[0] != 0 && (fp= fopen(fname,"rb")) != 0 )
{
@@ -1365,7 +1375,7 @@ int32_t ecb_matrix(double basevals[MAX_CURRENCIES],double matrix[MAX_CURRENCIES]
loaded = 1;
else printf("fread error\n");
fclose(fp);
- } //else printf("ecb_matrix.(%s) load error fp.%p\n",fname,fp);
+ } else printf("ecb_matrix.(%s) load error fp.%p\n",fname,fp);
datenum = conv_date(&seconds,date);
year = datenum / 10000, month = (datenum / 100) % 100, day = (datenum % 100);
if ( loaded == 0 )
@@ -1428,7 +1438,7 @@ void PAX_update(struct PAX_data *dp,double *btcusdp,double *kmdbtcp)
*kmdbtcp = 0;
bitcoinave = 0;//url_json("https://api.bitcoinaverage.com/ticker/USD/");
//bitcoincharts = url_json("http://api.bitcoincharts.com/v1/weighted_prices.json");
- blockchaininfo = 0;//url_json("https://blockchain.info/ticker");
+ blockchaininfo = url_json("https://blockchain.info/ticker");
coindesk = 0;//url_json("http://api.coindesk.com/v1/bpi/historical/close.json");
sprintf(url,"https://poloniex.com/public?command=returnChartData¤cyPair=BTC_KMD&start=%ld&end=9999999999&period=86400",(long)(time(NULL)-3600*24));
sprintf(url2,"https://poloniex.com/public?command=returnChartData¤cyPair=BTC_BTCD&start=%ld&end=9999999999&period=86400",(long)(time(NULL)-3600*24));
@@ -1531,7 +1541,7 @@ void PAX_update(struct PAX_data *dp,double *btcusdp,double *kmdbtcp)
if ( (item= jobj(blockchaininfo,"USD")) != 0 && item != 0 && (price= jdouble(item,"15m")) > SMALLVAL )
{
dpow_price("blockchain.info","BTCUSD",price,price);
- //printf("blockchaininfo %f %f\n",btcusd,price);
+ printf("blockchaininfo %f %f\n",btcusd,price);
dxblend(&btcusd,price,0.5);
}
free_json(blockchaininfo);
@@ -1779,13 +1789,20 @@ double PAX_val(uint32_t pval,int32_t baseid)
void PAX_genecbsplines(struct PAX_data *dp)
{
+ static portable_mutex_t mutex; static int32_t initflag;
int32_t i,j,datenum,seconds,numsamples; double prices[128][MAX_SPLINES],splineval,diff; uint32_t pvals[MAX_CURRENCIES],utc32[MAX_SPLINES],timestamp; struct tai t;
+ if ( initflag == 0 )
+ {
+ portable_mutex_init(&mutex);
+ initflag = 1;
+ }
+ portable_mutex_lock(&mutex);
for (i=numsamples=0; i<28; i++)
{
datenum = OS_conv_unixtime(&t,&seconds,(uint32_t)time(NULL)-(28-i+1)*24*3600);
expand_datenum(dp->edate,datenum);
timestamp = OS_conv_datenum(datenum,12,0,0);
- //printf("i.%d datenum.%d %s t%u\n",i,datenum,dp->edate,timestamp);
+ printf("i.%d datenum.%d %s t%u\n",i,datenum,dp->edate,timestamp);
if ( (datenum= ecb_matrix(dp->basevals,dp->ecbmatrix,dp->edate)) > 0 )
{
utc32[numsamples] = timestamp;
@@ -1812,15 +1829,19 @@ void PAX_genecbsplines(struct PAX_data *dp)
//printf("%s splineval %f vs %f %f %f\n",CURRENCIES[j],prices[j][numsamples-1],prices[j][numsamples],prices[j][numsamples+1],prices[j][numsamples+2]);
PAX_genspline(&dp->splines[j],j,CURRENCIES[j],utc32,prices[j],numsamples+3,prices[j]);
}
+ portable_mutex_unlock(&mutex);
}
+#define BTCFACTOR_TIMESTAMP 1503746319
+#define BTCFACTOR_HEIGHT 466266
+
int32_t PAX_idle(struct supernet_info *myinfo)//struct PAX_data *argdp,int32_t idlegap)
{
- static double lastupdate,lastdayupdate; static int32_t didinit; static char *userhome; int32_t idlegap = 10;
+ static double lastupdate,lastdayupdate; static uint32_t didinit; static char *userhome; int32_t idlegap = 10;
FILE *fp; long filesize; char fname[512]; double splineval; uint32_t pvals[128],timestamp; int32_t i,datenum,seconds,c; struct tai t; struct PAX_data *dp; uint8_t data[512];
if ( Currencymasks[0] == 0 )
return(0);
- if ( didinit == 0 )
+ if ( time(NULL) > didinit+12*3600 )
{
if ( (userhome= OS_filestr(&filesize,"userhome.txt")) == 0 )
userhome = "root";
@@ -1831,15 +1852,15 @@ int32_t PAX_idle(struct supernet_info *myinfo)//struct PAX_data *argdp,int32_t i
userhome[strlen(userhome)-1] = 0;
}
}
- myinfo->PAXDATA = calloc(1,sizeof(*dp));
- didinit = 1;
+ if ( myinfo->PAXDATA == 0 )
+ myinfo->PAXDATA = calloc(1,sizeof(*dp));
dp = myinfo->PAXDATA;
PAX_genecbsplines(dp);
printf("generated splines\n");
- datenum = OS_conv_unixtime(&t,&seconds,(uint32_t)time(NULL));
+ didinit = (uint32_t)time(NULL);
+ datenum = OS_conv_unixtime(&t,&seconds,didinit);
expand_datenum(dp->edate,datenum);
}
-
dp = myinfo->PAXDATA;
/*if ( 0 && time(NULL) > dp->lastupdate+10 )
{
@@ -1886,8 +1907,9 @@ int32_t PAX_idle(struct supernet_info *myinfo)//struct PAX_data *argdp,int32_t i
PAX_emitprices(pvals,dp);
}
timestamp = (uint32_t)time(NULL);
- int32_t dispflag = ((rand() % 64) == 0);
- if ( dp->kmdbtc == 0 || dispflag != 0 )
+ int32_t dispflag = ((rand() % 6) == 0);
+ //printf("PAX_IDLE.%d %.8f %.8f\n",dispflag,dp->kmdbtc,dp->btcusd);
+ if ( dp->kmdbtc == 0 || dp->btcusd == 0 || dispflag != 0 )
{
PAX_update(dp,&dp->btcusd,&dp->kmdbtc);
for (i=0; ikmdbtc * 1000);
- pvals[4] = PAX_val32(dp->btcusd * .001);
+ double btcfactor;
+ //if ( time(NULL) > BTCFACTOR_TIMESTAMP )
+ btcfactor = .00001;
+ //else btcfactor = .001;
+ pvals[4] = PAX_val32(dp->btcusd * btcfactor);
pvals[5] = PAX_val32(dp->CNYUSD);
- if ( dispflag != 0 )
- printf("KMD %.8f BTC %f CNY %f (%f)\n",dp->kmdbtc,dp->btcusd,dp->CNYUSD,1./dp->CNYUSD);
sprintf(fname,"/%s/.komodo/komodofeed",userhome);
if ( (fp= fopen(fname,"wb")) != 0 )
{
@@ -1921,7 +1945,7 @@ int32_t PAX_idle(struct supernet_info *myinfo)//struct PAX_data *argdp,int32_t i
{
for (i=0; i<6; i++)
printf("%u ",pvals[i]);
- printf("pvals -> %s\n",fname);
+ printf("KMD %.8f BTC %f CNY %f (%f) btcusd pval.%u\n",dp->kmdbtc,dp->btcusd,dp->CNYUSD,1./dp->CNYUSD,pvals[4]);
}
}
}
diff --git a/iguana/dpow/dpow_rpc.c b/iguana/dpow/dpow_rpc.c
index f8ffded08..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)
{
@@ -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);
}
@@ -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,13 +788,15 @@ 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; jdestcoin->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; iprice = price;
+ ptr->volume = volume;
+ ptr->height = height;
+ ptr->hour = hour;
+ ptr->dir = dir;
+ ptr->seconds = seconds;
+}
+
+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 )
+ {
+ 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 )
+ {
+ pair = &date->pairs[i];
+ break;
+ }
+ if ( date->pairs == 0 || 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);
+ 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(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(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 )
+ {
+ printf("illegal datenum.%d for %s when 1st.%d\n",datenum,pp->symbol,pp->firstdatenum);
+ return;
+ }
+ if ( offset == 0 || offset > pp->numdates )
+ {
+ 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];
+ if ( date->datenum != pp->firstdatenum + pp->numdates + i )
+ {
+ memset(date,0,sizeof(*date));
+ date->datenum = pp->firstdatenum + pp->numdates + i;
+ }
+ }
+ pp->numdates = offset;
+ }
+ 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)
+{
+ 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)
+{
+ 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 )
+ {
+ 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 ( 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 )
+ 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.;
+ 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);
+ }
+}
+
+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;
+ //printf("(%d, %d) <- %x, ",x,y,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 %f) ",val,yval);
+ if ( fabs(yval) > .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,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,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++)
+ {
+ 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];
+ 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 offset.%d (%.8f %.6f)\n",dest,pair->numprices,offset,ptr->price,ptr->volume);
+ stats_updatedisp(&prices[offset],ptr->price,ptr->volume);
+ }
+ }
+ break;
+ }
+ }
+}
+
+#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)
+{
+ 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);
+ return;
+ }
+ 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,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);
+ 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);
+ 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;
+ }
+ 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 (total=i=n=0; i 3 )
+ {
+ 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> 8) & 0xff;
+ blue = (val >> 16) & 0xff;
+ *tmpptr++ = red;
+ *tmpptr++ = green;
+ *tmpptr++ = blue;
+ }
+ sprintf(fname,"%s/bitmaps/%s_%s.jpg",STATS_DESTDIR,symbol,dest), OS_portable_path(fname);
+ gen_jpegfile(fname,100,bytemap,numdates*24,height);
+ free(bitmap), free(bytemap);
+ jaddstr(retjson,"bitmap",fname);
+ jadd(retjson,"hourly",array);
+ jaddnum(retjson,"average",sum);
+ }
+ free(utc32);
+ free(splinevals);
+ return(jprint(retjson,1));
+}
+
+#ifndef FROM_MARKETMAKER
+char *stats_JSON(void *ctx,char *myipaddr,int32_t mypubsock,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 )
+ return(clonestr("{\"error\":\"need method in request\"}"));
+ if ( (agent= jstr(argjson,"agent")) == 0 )
+ agent = "stats";
+ if ( strcmp(method,"bitmap") == 0 )
+ {
+ if ( (endtimestamp= 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";
+ 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);
+ memset(prices,0,sizeof(prices));
+ if ( (retstr= stats_prices(source,dest,prices,leftdatenum,numdates+1)) != 0 )
+ return(retstr);
+ }
+ return(clonestr(jprint(argjson,0)));
+}
+#endif
+
+#endif /* DEXstats_h */
diff --git a/iguana/exchanges/LP_bitcoin.c b/iguana/exchanges/LP_bitcoin.c
new file mode 100644
index 000000000..ba6a5b63f
--- /dev/null
+++ b/iguana/exchanges/LP_bitcoin.c
@@ -0,0 +1,3627 @@
+
+/******************************************************************************
+ * 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
+//
+
+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])
+{
+ int32_t i; static bits256 zero;
+ for (i=0; i no privkey\n");
+ return(zero);
+}
+
+int32_t LP_privkeyadd(bits256 privkey,uint8_t rmd160[20])
+{
+ bits256 tmpkey;
+ tmpkey = LP_privkeyfind(rmd160);
+ 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(" -> add privkey.(%s)\n",bits256_str(str,privkey));
+ LP_numprivkeys++;
+ return(LP_numprivkeys);
+}
+
+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 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;
+ 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; jstack[--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 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));
+ }
+ if ( numargs > 0 )
+ {
+ for (i=0; i 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);
+}
+
+char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params)
+{
+ return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params,4));
+}
+
+char *bitcoind_passthrut(char *coinstr,char *serverport,char *userpass,char *method,char *params,int32_t timeout)
+{
+ return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params,timeout));
+}
+
+int32_t bitcoin_addr2rmd160(uint8_t taddr,uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr)
+{
+ 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,20+offset);
+ *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] )
+ {
+ //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; i ");
+ 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+offset] = hash.bytes[31-i];
+ return(data_len + 4 + offset);
+}
+
+int32_t bitcoin_wif2priv(uint8_t wiftaddr,uint8_t *addrtypep,bits256 *privkeyp,char *wifstr)
+{
+ int32_t offset,len = -1; bits256 hash; uint8_t buf[256];
+ offset = 1 + (wiftaddr != 0);
+ 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 = (wiftaddr == 0) ? *buf : buf[1];
+ memcpy(privkeyp,buf+offset,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] )
+ {
+ //int32_t i; 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 bitcoin_priv2wiflong(uint8_t wiftaddr,char *wifstr,bits256 privkey,uint8_t addrtype)
+{
+ uint8_t data[128]; int32_t offset,len = 32;
+ offset = 1 + (wiftaddr != 0);
+ memcpy(data+offset,privkey.bytes,sizeof(privkey));
+ len = base58encode_checkbuf(wiftaddr,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(wiftaddr,&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));
+}
+
+bits256 LP_privkey(char *coinaddr,uint8_t taddr)
+{
+ bits256 privkey; uint8_t addrtype,rmd160[20];
+ bitcoin_addr2rmd160(taddr,&addrtype,rmd160,coinaddr);
+ privkey = LP_privkeyfind(rmd160);
+ return(privkey);
+}
+
+bits256 LP_pubkey(bits256 privkey)
+{
+ bits256 pubkey;
+ pubkey = curve25519(privkey,curve25519_basepoint9());
+ return(pubkey);
+}
+
+char *_setVsigner(uint8_t wiftaddr,uint8_t pubtype,struct vin_info *V,int32_t ind,char *pubstr,char *wifstr)
+{
+ uint8_t addrtype;
+ decode_hex(V->signers[ind].pubkey,(int32_t)strlen(pubstr)/2,pubstr);
+ bitcoin_wif2priv(wiftaddr,&addrtype,&V->signers[ind].privkey,wifstr);
+ if ( addrtype != pubtype )
+ return(clonestr("{\"error\":\"invalid wifA\"}"));
+ else return(0);
+}
+
+uint8_t iguana_addrtype(uint8_t pubtype,uint8_t p2shtype,uint8_t script_type)
+{
+ 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);
+ }
+}
+
+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;
+ 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 )
+ {
+ init_hexbytes_noT(rmd160str,rmd160,20);
+ bitcoin_address(coinaddr,taddr,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,taddr,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,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,taddr,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,taddr,p2shtype,script,scriptlen);
+ if ( asmstr != 0 )
+ {
+ sprintf(asmstr,"%d ",m);
+ for (i=0; isigners[i].pubkey)) > 0 )
+ {
+ init_hexbytes_noT(asmstr + strlen(asmstr),(uint8_t *)vp->signers[i].pubkey,plen);
+ if ( asmstr != 0 )
+ strcat(asmstr," ");
+ }
+ 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 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;
+ *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;
+ }
+ vp->numsigs = j;
+ vp->type = spendtype;
+ if ( j == 0 )
+ {
+ //*userdatalenp = len;
+ vp->spendlen = len;
+ return(vp->spendlen);
+ }
+ j = 0;
+ while ( ((plen= scriptsig[n]) == 33 || plen == 65) && j < 16 && plen+n <= len )
+ {
+ memcpy(vp->signers[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) )
+ {
+ 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 )
+ {
+ p2shscript = &scriptsig[n];
+ memcpy(vp->p2shscript,&scriptsig[n],vp->p2shlen);
+ n += vp->p2shlen;
+ vp->type = IGUANA_SCRIPT_P2SH;
+ } else vp->p2shlen = 0;
+ }
+ }
+ 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(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 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;
+ 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 )
+ {
+ 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; isigners[i].pubkey,script,plen);
+ calc_rmd160_sha256(vp->signers[i].rmd160,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 )
+ {
+ 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));
+ }
+ calc_rmd160_sha256(vp->rmd160,vp->spendscript,vp->spendlen);
+ return(type);
+}
+
+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));
+ 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(taddr,pubtype,p2shtype,vp)) >= 0 )
+ {
+ 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;
+ 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 )
+ {
+ int32_t i;
+ printf("\n--------------------\n");
+ for (i=0; itype,scriptlen,pk_scriptlen);
+ }
+ }
+ }
+ 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 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"));
+ 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(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);
+ 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 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(taddr,pubtype,p2shtype,destaddress) == 0 && satoshis != 0 )
+ {
+ bitcoin_addr2rmd160(taddr,&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);
+ }
+ 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 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;
+ 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(taddr,pubtype,p2shtype,asmstr,vp,vout->pk_script,vout->pk_scriptlen,txid,txi,0xffffffff)) >= 0 )
+ {
+ skey = cJSON_CreateObject();
+ 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();
+ 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(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);
+ /*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(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));
+ 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 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(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);
+ }
+ 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 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 )
+ 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(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);
+ 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 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 )
+ 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(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
new file mode 100644
index 000000000..a5fd82434
--- /dev/null
+++ b/iguana/exchanges/LP_coins.c
@@ -0,0 +1,381 @@
+
+/******************************************************************************
+ * 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 *portstrs[][3] = { { "BTC", "8332" }, { "KMD", "7771" } };
+
+uint16_t LP_rpcport(char *symbol)
+{
+ int32_t i;
+ for (i=0; isymbol);
+ if ( showwif != 0 )
+ {
+ bitcoin_priv2wif(coin->wiftaddr,wifstr,LP_mypriv25519,coin->wiftype);
+ bitcoin_wif2priv(coin->wiftaddr,&tmptype,&checkkey,wifstr);
+ if ( bits256_cmp(LP_mypriv25519,checkkey) == 0 )
+ jaddstr(item,"wif",wifstr);
+ else jaddstr(item,"wif","error creating wif");
+ }
+ 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);
+ jaddstr(item,"rpc",coin->serverport);
+ jaddnum(item,"pubtype",coin->pubtype);
+ jaddnum(item,"p2shtype",coin->p2shtype);
+ jaddnum(item,"wiftype",coin->wiftype);
+ jaddnum(item,"txfee",coin->txfee);
+ return(item);
+}
+
+cJSON *LP_coinsjson(int32_t showwif)
+{
+ struct iguana_info *coin,*tmp; cJSON *array = cJSON_CreateArray();
+ HASH_ITER(hh,LP_coins,coin,tmp)
+ {
+ jaddi(array,LP_coinjson(coin,showwif));
+ }
+ return(array);
+}
+
+char *LP_getcoin(char *symbol)
+{
+ int32_t numenabled,numdisabled; struct iguana_info *coin,*tmp; cJSON *item=0,*retjson;
+ numenabled = numdisabled = 0;
+ retjson = cJSON_CreateObject();
+ HASH_ITER(hh,LP_coins,coin,tmp)
+ {
+ if ( strcmp(symbol,coin->symbol) == 0 )
+ item = LP_coinjson(coin,0);
+ if ( coin->inactive == 0 )
+ numenabled++;
+ else numdisabled++;
+ }
+ jaddstr(retjson,"result","success");
+ jaddnum(retjson,"enabled",numenabled);
+ jaddnum(retjson,"disabled",numdisabled);
+ if ( item == 0 )
+ item = cJSON_CreateObject();
+ jadd(retjson,"coin",item);
+ return(jprint(retjson,1));
+}
+
+struct iguana_info *LP_coinsearch(char *symbol)
+{
+ struct iguana_info *coin;
+ portable_mutex_lock(&LP_coinmutex);
+ HASH_FIND(hh,LP_coins,symbol,strlen(symbol),coin);
+ portable_mutex_unlock(&LP_coinmutex);
+ return(coin);
+}
+
+struct iguana_info *LP_coinadd(struct iguana_info *cdata)
+{
+ struct iguana_info *coin = calloc(1,sizeof(*coin));
+ //printf("%s: (%s) (%s)\n",symbol,cdata.serverport,cdata.userpass);
+ *coin = *cdata;
+ portable_mutex_init(&coin->txmutex);
+ 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 wiftaddr,uint8_t taddr,uint16_t busport,char *confpath)
+{
+ char *name2;
+ 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->wiftaddr = wiftaddr;
+ coin->longestchain = longestchain;
+ coin->txfee = txfee;
+ coin->pubtype = pubtype;
+ coin->p2shtype = p2shtype;
+ coin->wiftype = wiftype;
+ coin->inactive = (uint32_t)time(NULL);
+ coin->bussock = LP_coinbus(busport);
+ if ( strcmp(symbol,"KMD") == 0 || (assetname != 0 && assetname[0] != 0) )
+ name2 = 0;
+ else name2 = name;
+ if ( strcmp(symbol,"XVG") == 0 || strcmp(symbol,"CLOAK") == 0 || strcmp(symbol,"PPC") == 0 || strcmp(symbol,"BCC") == 0 || strcmp(symbol,"ORB") == 0 )
+ {
+ coin->noimportprivkey_flag = 1;
+ printf("truncate importprivkey for %s\n",symbol);
+ }
+ return(LP_userpass(coin->userpass,symbol,assetname,name,name2,confpath));
+}
+
+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 isinactive,isPoS,longestchain = 1; uint16_t port,busport; 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);
+ if ( (busport= LP_busport(port)) == 0 )
+ return(0);
+ isPoS = 0;
+ txfee = LP_MIN_TXFEE;
+ estimatedrate = 20;
+ pubtype = 60;
+ p2shtype = 85;
+ wiftype = 188;
+ assetname = "";
+ if ( strcmp(symbol,"BTC") == 0 )
+ {
+ txfee = 0;
+ estimatedrate = 300;
+ pubtype = 0;
+ p2shtype = 5;
+ wiftype = 128;
+ name = "bitcoin";
+ }
+ else if ( strcmp(symbol,"KMD") == 0 )
+ name = "komodo";
+ else return(0);
+ isinactive = LP_coininit(&cdata,symbol,name,assetname,isPoS,port,pubtype,p2shtype,wiftype,txfee,estimatedrate,longestchain,0,0,busport,0) < 0;
+ if ( (coin= LP_coinadd(&cdata)) != 0 )
+ {
+ coin->inactive = isinactive * (uint32_t)time(NULL);
+ if ( strcmp(symbol,"KMD") == 0 )
+ coin->inactive = 0;
+ else if ( strcmp(symbol,"BTC") == 0 )
+ {
+ coin->inactive = (uint32_t)time(NULL) * !IAMLP;
+ printf("BTC inactive.%u\n",coin->inactive);
+ }
+ }
+ return(coin);
+}
+
+// "coins":[{"coin":"", "rpcport":pppp}, {"coin":"LTC", "name":"litecoin", "rpcport":9332, "pubtype":48, "p2shtype":5, "wiftype":176, "txfee":100000 }]
+// {"coin":"HUSH", "name":"hush", "rpcport":8822, "taddr":28, "pubtype":184, "p2shtype":189, "wiftype":128, "txfee":10000 }
+
+struct iguana_info *LP_coincreate(cJSON *item)
+{
+ 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");
+ txfee = j64bits(item,"txfee");
+ if ( (estimatedrate= jdouble(item,"estimatedrate")) == 0. )
+ estimatedrate = 20;
+ pubtype = juint(item,"pubtype");
+ if ( (p2shtype= juint(item,"p2shtype")) == 0 )
+ p2shtype = 85;
+ if ( (wiftype= juint(item,"wiftype")) == 0 )
+ wiftype = 188;
+ if ( (assetname= jstr(item,"asset")) != 0 )
+ {
+ name = assetname;
+ pubtype = 60;
+ }
+ 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,juint(item,"wiftaddr"),juint(item,"taddr"),LP_busport(port),jstr(item,"confpath")) < 0 )
+ {
+ coin = LP_coinadd(&cdata);
+ coin->inactive = (uint32_t)time(NULL);
+ } else coin = LP_coinadd(&cdata);
+ } else if ( symbol != 0 && jobj(item,"rpcport") == 0 )
+ printf("SKIP %s, missing rpcport field in coins array\n",symbol);
+ if ( coin != 0 && item != 0 )
+ {
+ if ( strcmp("KMD",coin->symbol) != 0 )
+ {
+ if ( jobj(item,"active") != 0 )
+ coin->inactive = !jint(item,"active");
+ else
+ {
+ if ( IAMLP == 0 || assetname != name )
+ coin->inactive = (uint32_t)time(NULL);
+ else coin->inactive = 0;
+ }
+ } else coin->inactive = 0;
+ }
+ if ( coin != 0 && coin->inactive != 0 )
+ 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_commands.c b/iguana/exchanges/LP_commands.c
new file mode 100644
index 000000000..ad0a07be4
--- /dev/null
+++ b/iguana/exchanges/LP_commands.c
@@ -0,0 +1,431 @@
+
+/******************************************************************************
+ * 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
+//
+
+char *LP_numutxos()
+{
+ cJSON *retjson = cJSON_CreateObject();
+ if ( LP_mypeer != 0 )
+ {
+ jaddstr(retjson,"ipaddr",LP_mypeer->ipaddr);
+ jaddnum(retjson,"port",LP_mypeer->port);
+ jaddnum(retjson,"numutxos",LP_mypeer->numutxos);
+ jaddnum(retjson,"numpeers",LP_mypeer->numpeers);
+ jaddnum(retjson,"session",LP_sessionid);
+ } else jaddstr(retjson,"error","client node");
+ return(jprint(retjson,1));
+}
+
+char *stats_JSON(void *ctx,char *myipaddr,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=0,pushport,subport; int32_t changed,otherpeers,othernumutxos,flag = 0; struct LP_peerinfo *peer; cJSON *retjson,*reqjson = 0; 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 )
+ {
+ 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;
+ }
+ if ( peer->sessionid == 0 )
+ peer->sessionid = juint(argjson,"session");
+ //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,jint(argjson,"numpeers"),jint(argjson,"numutxos"),juint(argjson,"session"));
+ }
+ }
+ if ( (method= jstr(argjson,"method")) == 0 )
+ {
+ if ( flag == 0 || jobj(argjson,"result") != 0 )
+ printf("stats_JSON no method: (%s) (%s:%u)\n",jprint(argjson,0),ipaddr,argport);
+ return(0);
+ }
+ /*if ( strcmp(method,"hello") == 0 )
+ {
+ //printf("got hello from %s:%u\n",ipaddr!=0?ipaddr:"",argport);
+ return(0);
+ }
+ else*/ if ( strcmp(method,"sendmessage") == 0 && jobj(argjson,"userpass") == 0 )
+ {
+ static char *laststr;
+ char *newstr; bits256 pubkey = jbits256(argjson,"pubkey");
+ if ( bits256_nonz(pubkey) == 0 || bits256_cmp(pubkey,LP_mypub25519) == 0 )
+ {
+ newstr = jprint(argjson,0);
+ if ( laststr == 0 || strcmp(laststr,newstr) != 0 )
+ {
+ printf("got message.(%s) from %s:%u\n",newstr,ipaddr!=0?ipaddr:"",argport);
+ if ( laststr != 0 )
+ free(laststr);
+ laststr = newstr;
+ LP_gotmessage(argjson);
+ retstr = clonestr(laststr);
+ }
+ } else retstr = clonestr("{\"error\":\"duplicate message\"}");
+ }
+ //else if ( strcmp(method,"nn_tests") == 0 )
+ // return(clonestr("{\"result\":\"success\"}"));
+ else if ( strcmp(method,"help") == 0 )
+ return(clonestr("{\"result\":\" \
+available localhost RPC commands:\n \
+pricearray(base, rel, firsttime=0, lasttime=-1, timescale=60) -> [timestamp, avebid, aveask, highbid, lowask]\n\
+setprice(base, rel, price)\n\
+autoprice(base, rel, price, margin, type)\n\
+goal(coin=*, val=)\n\
+myprice(base, rel)\n\
+enable(coin)\n\
+disable(coin)\n\
+inventory(coin)\n\
+bestfit(rel, relvolume)\n\
+ordermatch(base, txfee=0, rel, desttxfee=0, price, relvolume=0, txid, vout, feetxid, feevout, duration=3600)\n\
+trade(price, timeout=10, duration=3600, )\n\
+autotrade(base, rel, price, relvolume, timeout=10, duration=3600)\n\
+swapstatus()\n\
+swapstatus(requestid, quoteid)\n\
+public API:\n \
+getcoins()\n\
+getcoin(coin)\n\
+portfolio()\n\
+getpeers()\n\
+getutxos()\n\
+getutxos(coin, lastn)\n\
+orderbook(base, rel, duration=3600)\n\
+getprices(base, rel)\n\
+sendmessage(base=coin, rel="", pubkey=zero, )\n\
+getmessages(firsti=0, num=100)\n\
+clearmessages(firsti=0, num=100)\n\
+secretaddresses(passphrase, num=10, pubtype=60, taddr=0)\n\
+snapshot(coin, height)\n\
+snapshot_balance(coin, height, addresses[])\n\
+dividends(coin, height, )\n\
+\"}"));
+
+ 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 )
+ {
+ USERPASS_COUNTER = 1;
+ retjson = cJSON_CreateObject();
+ jaddstr(retjson,"userpass",USERPASS);
+ jaddbits256(retjson,"mypubkey",LP_mypub25519);
+ jadd(retjson,"coins",LP_coinsjson(LP_showwif));
+ return(jprint(retjson,1));
+ }
+ if ( (userpass= jstr(argjson,"userpass")) == 0 || strcmp(userpass,USERPASS) != 0 )
+ return(clonestr("{\"error\":\"authentication error\"}"));
+ jdelete(argjson,"userpass");
+ if ( strcmp(method,"sendmessage") == 0 )
+ {
+ if ( jobj(argjson,"method2") == 0 )
+ {
+ printf("broadcast message\n");
+ LP_broadcast_message(LP_mypubsock,base!=0?base:jstr(argjson,"coin"),rel,jbits256(argjson,"pubkey"),jprint(argjson,0));
+ }
+ return(clonestr("{\"result\":\"success\"}"));
+ }
+ else if ( strcmp(method,"getmessages") == 0 )
+ {
+ if ( (retjson= LP_getmessages(jint(argjson,"firsti"),jint(argjson,"num"))) != 0 )
+ return(jprint(retjson,1));
+ else return(clonestr("{\"error\":\"null messages\"}"));
+ }
+ else if ( strcmp(method,"deletemessages") == 0 )
+ {
+ LP_deletemessages(jint(argjson,"firsti"),jint(argjson,"num"));
+ return(clonestr("{\"result\":\"success\"}"));
+ }
+ else if ( strcmp(method,"portfolio") == 0 )
+ {
+ return(LP_portfolio());
+ }
+ else if ( strcmp(method,"secretaddresses") == 0 )
+ {
+ uint8_t taddr,pubtype;
+ pubtype = (jobj(argjson,"pubtype") == 0) ? 60 : juint(argjson,"pubtype");
+ taddr = (jobj(argjson,"taddr") == 0) ? 0 : juint(argjson,"taddr");
+ return(LP_secretaddresses(ctx,jstr(argjson,"passphrase"),juint(argjson,"num"),taddr,pubtype));
+ }
+ if ( base != 0 && rel != 0 )
+ {
+ double price,bid,ask;
+ if ( IAMLP == 0 && 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 > SMALLVAL )
+ {
+ if ( LP_mypriceset(&changed,base,rel,price) < 0 )
+ return(clonestr("{\"error\":\"couldnt set price\"}"));
+ //else if ( LP_mypriceset(&changed,rel,base,1./price) < 0 )
+ // return(clonestr("{\"error\":\"couldnt set price\"}"));
+ else return(LP_pricepings(ctx,myipaddr,LP_mypubsock,base,rel,price * LP_profitratio));
+ } else return(clonestr("{\"error\":\"no price\"}"));
+ }
+ else if ( strcmp(method,"autoprice") == 0 )
+ {
+ if ( LP_autoprice(base,rel,price,jdouble(argjson,"margin"),jstr(argjson,"type")) < 0 )
+ return(clonestr("{\"error\":\"couldnt set autoprice\"}"));
+ else return(clonestr("{\"result\":\"success\"}"));
+ }
+ else if ( strcmp(method,"pricearray") == 0 )
+ {
+ return(jprint(LP_pricearray(base,rel,juint(argjson,"firsttime"),juint(argjson,"lasttime"),jint(argjson,"timescale")),1));
+ }
+ else if ( strcmp(method,"myprice") == 0 )
+ {
+ if ( LP_myprice(&bid,&ask,base,rel) > SMALLVAL )
+ {
+ 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 ( strcmp(method,"ordermatch") == 0 )
+ {
+ if ( price > SMALLVAL )
+ return(LP_ordermatch(base,j64bits(argjson,"txfee"),price,jdouble(argjson,"relvolume"),rel,jbits256(argjson,"txid"),jint(argjson,"vout"),jbits256(argjson,"feetxid"),jint(argjson,"feevout"),j64bits(argjson,"desttxfee"),jint(argjson,"duration")));
+ else return(clonestr("{\"error\":\"no price set\"}"));
+ }
+ else if ( strcmp(method,"trade") == 0 )
+ {
+ struct LP_quoteinfo Q;
+ if ( price > SMALLVAL || jobj(argjson,"quote") != 0 )
+ {
+ LP_quoteparse(&Q,jobj(argjson,"quote"));
+ return(LP_trade(ctx,myipaddr,pubsock,&Q,price,jint(argjson,"timeout"),jint(argjson,"duration")));
+ } else return(clonestr("{\"error\":\"no price set or no quote object\"}"));
+ }
+ else if ( strcmp(method,"autotrade") == 0 )
+ {
+ if ( price > SMALLVAL )
+ {
+ return(LP_autotrade(ctx,myipaddr,pubsock,base,rel,price,jdouble(argjson,"relvolume"),jint(argjson,"timeout"),jint(argjson,"duration")));
+ } else return(clonestr("{\"error\":\"no price set\"}"));
+ }
+ }
+ else if ( rel != 0 && strcmp(method,"bestfit") == 0 )
+ {
+ double relvolume;
+ if ( (relvolume= jdouble(argjson,"relvolume")) > SMALLVAL )
+ return(LP_bestfit(rel,relvolume));
+ else return(clonestr("{\"error\":\"no relvolume set\"}"));
+ }
+ else if ( (coin= jstr(argjson,"coin")) != 0 )
+ {
+ if ( strcmp(method,"enable") == 0 )
+ {
+ if ( (ptr= LP_coinsearch(coin)) != 0 )
+ ptr->inactive = 0;
+ return(jprint(LP_coinsjson(0),1));
+ }
+ else if ( strcmp(method,"disable") == 0 )
+ {
+ if ( (ptr= LP_coinsearch(coin)) != 0 )
+ ptr->inactive = (uint32_t)time(NULL);
+ return(jprint(LP_coinsjson(0),1));
+ }
+ else if ( strcmp(method,"snapshot") == 0 )
+ {
+ if ( (ptr= LP_coinsearch(coin)) != 0 )
+ return(jprint(LP_snapshot(ptr,juint(argjson,"height")),1));
+ else return(clonestr("{\"error\":\"cant find coind\"}"));
+ }
+ else if ( strcmp(method,"dividends") == 0 )
+ {
+ if ( (ptr= LP_coinsearch(coin)) != 0 )
+ return(LP_dividends(ptr,juint(argjson,"height"),argjson));
+ else return(clonestr("{\"error\":\"cant find coind\"}"));
+ }
+ else if ( strcmp(method,"snapshot_balance") == 0 )
+ {
+ if ( (ptr= LP_coinsearch(coin)) != 0 )
+ return(LP_snapshot_balance(ptr,juint(argjson,"height"),argjson));
+ else return(clonestr("{\"error\":\"cant find coind\"}"));
+ }
+ if ( LP_isdisabled(coin,0) != 0 )
+ return(clonestr("{\"error\":\"coin is disabled\"}"));
+ if ( strcmp(method,"inventory") == 0 )
+ {
+ struct iguana_info *ptr;
+ if ( (ptr= LP_coinfind(coin)) != 0 )
+ {
+ //privkey = LP_privkeycalc(ctx,pubkey33,&pubkey,ptr,"",USERPASS_WIFSTR);
+ //LP_utxopurge(0);
+ if ( bits256_nonz(LP_mypriv25519) != 0 )
+ LP_privkey_init(-1,ptr,LP_mypriv25519,LP_mypub25519);
+ 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));
+ }
+ }
+ else if ( strcmp(method,"goal") == 0 )
+ return(LP_portfolio_goal(coin,jdouble(argjson,"val")));
+ else if ( strcmp(method,"getcoin") == 0 )
+ return(LP_getcoin(coin));
+ }
+ else if ( strcmp(method,"goal") == 0 )
+ return(LP_portfolio_goal("*",100.));
+ else if ( strcmp(method,"swapstatus") == 0 )
+ {
+ uint32_t requestid,quoteid;
+ if ( (requestid= juint(argjson,"requestid")) != 0 && (quoteid= juint(argjson,"quoteid")) != 0 )
+ return(basilisk_swapentry(requestid,quoteid));
+ else return(basilisk_swaplist());
+ }
+ 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 ( IAMLP == 0 )
+ {
+ if ( (reqjson= LP_dereference(argjson,"broadcast")) != 0 )
+ {
+ if ( jobj(reqjson,"method2") != 0 )
+ {
+ jdelete(reqjson,"method");
+ method = jstr(reqjson,"method2");
+ jaddstr(reqjson,"method",method);
+ }
+ argjson = reqjson;
+ }
+ }
+ if ( IAMLP == 0 && LP_isdisabled(base,rel) != 0 )
+ return(clonestr("{\"result\":\"at least one of coins disabled\"}"));
+ else if ( IAMLP == 0 && LP_isdisabled(jstr(argjson,"coin"),0) != 0 )
+ retstr = clonestr("{\"result\":\"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 )
+ return(jprint(LP_coinsjson(0),1));
+ else if ( strcmp(method,"numutxos") == 0 )
+ return(LP_numutxos());
+ else if ( strcmp(method,"postprice") == 0 )
+ retstr = LP_postedprice(argjson);
+ else if ( strcmp(method,"encrypted") == 0 )
+ retstr = clonestr("{\"result\":\"success\"}");
+ else if ( strcmp(method,"getprices") == 0 )
+ return(LP_prices());
+ else if ( strcmp(method,"orderbook") == 0 )
+ return(LP_orderbook(base,rel,jint(argjson,"duration")));
+ else if ( strcmp(method,"registerall") == 0 )
+ return(clonestr("{\"error\":\"you are running an obsolete version, update\"}"));
+ else if ( strcmp(method,"forward") == 0 )
+ return(clonestr("{\"error\":\"you are running an obsolete version, update\"}"));
+ else if ( strcmp(method,"keepalive") == 0 )
+ return(clonestr("{\"error\":\"you are running an obsolete version, update\"}"));
+ else if ( strcmp(method,"getpeers") == 0 )
+ return(LP_peers());
+ else if ( strcmp(method,"getutxos") == 0 )
+ return(LP_utxos(1,LP_mypeer,jstr(argjson,"coin"),jint(argjson,"lastn")));
+ else if ( strcmp(method,"utxo") == 0 )
+ {
+ if ( LP_utxoaddjson(1,LP_mypubsock,argjson) != 0 )
+ retstr = clonestr("{\"result\":\"success\",\"utxo\":\"received\"}");
+ else retstr = clonestr("{\"result\":\"couldnt add utxo\"}");
+ }
+ else
+ {
+ if ( IAMLP != 0 )
+ {
+ if ( strcmp(method,"register") == 0 )
+ return(clonestr("{\"error\":\"you are running an obsolete version, update\"}"));
+ else if ( strcmp(method,"lookup") == 0 )
+ return(clonestr("{\"error\":\"you are running an obsolete version, update\"}"));
+ if ( strcmp(method,"broadcast") == 0 )
+ {
+ bits256 zero; char *cipherstr; int32_t cipherlen; uint8_t cipher[LP_ENCRYPTED_MAXSIZE];
+ if ( (reqjson= LP_dereference(argjson,"broadcast")) != 0 )
+ {
+ if ( (cipherstr= jstr(reqjson,"cipher")) != 0 )
+ {
+ cipherlen = (int32_t)strlen(cipherstr) >> 1;
+ if ( cipherlen <= sizeof(cipher) )
+ {
+ decode_hex(cipher,cipherlen,cipherstr);
+ LP_queuesend(calc_crc32(0,&cipher[2],cipherlen-2),LP_mypubsock,base,rel,cipher,cipherlen);
+ } else retstr = clonestr("{\"error\":\"cipher too big\"}");
+ }
+ else
+ {
+ memset(zero.bytes,0,sizeof(zero));
+ LP_broadcast_message(LP_mypubsock,base!=0?base:jstr(argjson,"coin"),rel,zero,jprint(reqjson,0));
+ }
+ retstr = clonestr("{\"result\":\"success\"}");
+ } else retstr = clonestr("{\"error\":\"couldnt dereference sendmessage\"}");
+ }
+ 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");
+ }
+ if ( jint(argjson,"ispaired") != 0 )
+ return(LP_psock(myipaddr,jint(argjson,"ispaired")));
+ else return(clonestr("{\"error\":\"you are running an obsolete version, update\"}"));
+ }
+ else if ( strcmp(method,"notify") == 0 )
+ retstr = clonestr("{\"result\":\"success\",\"notify\":\"received\"}");
+ }
+ else
+ {
+ if ( strcmp(method,"psock") == 0 )
+ {
+ //printf("nonLP got (%s)\n",jprint(argjson,0));
+ retstr = clonestr("{\"result\":\"success\"}");
+ }
+ }
+ }
+ if ( retstr == 0 )
+ printf("ERROR.(%s)\n",jprint(argjson,0));
+ if ( reqjson != 0 )
+ free_json(reqjson);
+ if ( retstr != 0 )
+ {
+ free(retstr);
+ return(0);
+ }
+ return(0);
+}
diff --git a/iguana/exchanges/LP_forwarding.c b/iguana/exchanges/LP_forwarding.c
new file mode 100644
index 000000000..749cf2f2e
--- /dev/null
+++ b/iguana/exchanges/LP_forwarding.c
@@ -0,0 +1,351 @@
+
+/******************************************************************************
+ * 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
+//
+
+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);
+}
+
+/*
+struct LP_forwardinfo
+{
+ UT_hash_handle hh;
+ bits256 pubkey;
+ char pushaddr[64];
+ int32_t pushsock;
+ uint32_t lasttime,hello;
+} *LP_forwardinfos;
+#define LP_KEEPALIVE (3600 * 24)
+
+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 ( bits256_nonz(pubkey) == 0 )
+ return(clonestr("{\"result\":\"illegal pubkey\"}"));
+ if ( LP_forwardfind(pubkey) != 0 )
+ return(clonestr("{\"result\":\"success\",\"forwarding\":1}"));
+ else return(clonestr("{\"result\":\"notfound\"}"));
+}
+
+int32_t LP_hello(struct LP_forwardinfo *ptr)
+{
+ int32_t i,n=10; char msg[512]; struct nn_pollfd pfd;
+ if ( bits256_cmp(ptr->pubkey,LP_mypubkey) != 0 )
+ {
+ 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);
+ }
+ return(0);
+}
+
+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,LP_COMMAND_SENDSOCK)) < 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));
+ 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 *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("{\"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 )
+ {
+ ptr->lasttime = (uint32_t)time(NULL);
+ if ( ptr->pushsock >= 0 )
+ {
+ if ( strcmp(pushaddr,ptr->pushaddr) != 0 )
+ {
+ nn_close(ptr->pushsock);
+ if ( LP_psockmark(ptr->pushaddr) < 0 )
+ {
+ //printf("cant mark (%s)\n",ptr->pushaddr);
+ }
+ char str[65]; printf("%u recreate pushsock for %s <- %s %s\n",(uint32_t)time(NULL),ptr->pushaddr,pushaddr,bits256_str(str,pubkey));
+ strcpy(ptr->pushaddr,pushaddr);
+ if ( (ptr->pushsock= LP_pushsock_create(ptr,pushaddr)) < 0 )
+ return(clonestr("{\"result\":\"success\",\"status\":\"couldnt recreate pushsock\",\"registered\":0}"));
+ } //else printf("no need to create identical endpoint\n");
+ }
+ return(clonestr("{\"result\":\"success\",\"status\":\"already registered\",\"registered\":1}"));
+ }
+ else if ( (pushsock= LP_pushsock_create(0,pushaddr)) < 0 )
+ return(clonestr("{\"result\":\"success\",\"status\":\"couldnt create pushsock\"}"));
+ 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);
+ //char str[65]; printf("registered (%s) -> (%s) pushsock.%d\n",bits256_str(str,pubkey),pushaddr,ptr->pushsock);
+ LP_hello(ptr);
+ return(LP_lookup(pubkey));
+ }
+}
+
+int32_t LP_forwarding_register(bits256 pubkey,char *publicaddr,uint16_t publicport,int32_t max)
+{
+ char *argstr,ipaddr[64]; cJSON *argjson; struct LP_peerinfo *peer,*tmp; int32_t j,n=0,arglen;
+ if ( publicaddr == 0 || publicaddr[0] == 0 || bits256_nonz(pubkey) == 0 )
+ {
+ 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++)
+ if ( publicaddr[j] >= '0' && publicaddr[j] <= '9' )
+ break;
+ parse_ipaddr(ipaddr,publicaddr+j);
+ argjson = cJSON_CreateObject();
+ jaddstr(argjson,"agent","stats");
+ jaddstr(argjson,"method","register");
+ jaddbits256(argjson,"client",pubkey);
+ jaddstr(argjson,"pushaddr",ipaddr);
+ jaddnum(argjson,"pushport",publicport);
+ argstr = jprint(argjson,1);
+ arglen = (int32_t)strlen(argstr) + 1;
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ if ( strcmp(LP_myipaddr,peer->ipaddr) == 0 )
+ continue;
+ if ( peer->pushsock >= 0 )
+ {
+ if ( LP_send(peer->pushsock,argstr,arglen,0) != arglen )
+ {
+ if ( strncmp(peer->ipaddr,"5.9.253",strlen("5.9.253")) == 0 )
+ printf("error registering with %s:%u\n",peer->ipaddr,peer->port);
+ }
+ n++;
+ }
+ //printf("register.(%s) %s %u with (%s)\n",publicaddr,ipaddr,publicport,peer->ipaddr);
+ }
+ free(argstr);
+ 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);
+ jaddnum(retjson,"iters",i);
+ return(jprint(retjson,1));
+}
+
+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("{\"result\":\"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 )
+ {
+ 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:"");
+ if ( pubsock >= 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 )
+ {
+ if ( ptr->pushsock >= 0 )
+ {
+ printf("%s forwardhex.(%s)\n",ptr->pushaddr,(char *)data);
+ sentbytes = LP_send(ptr->pushsock,(char *)data,datalen,0);
+ }
+ retjson = cJSON_CreateObject();
+ if ( sentbytes >= 0 )
+ {
+ jaddstr(retjson,"result","success");
+ if ( sentbytes == datalen )
+ jaddnum(retjson,"forwarded",sentbytes);
+ else if ( sentbytes == 0 )
+ jaddnum(retjson,"queued",sentbytes);
+ else jaddnum(retjson,"mismatch",sentbytes);
+ retstr = jprint(retjson,1);
+ }
+ else
+ {
+ jaddstr(retjson,"error","send error");
+ jaddnum(retjson,"sentbytes",sentbytes);
+ jaddnum(retjson,"datalen",datalen);
+ jaddnum(retjson,"hello",ptr->hello);
+ retstr = jprint(retjson,1);
+ }
+ }
+ else
+ {
+ char str[65]; printf("couldnt find %s to forward to\n",bits256_str(str,pubkey));
+ if ( pubsock >= 0 )
+ {
+ msg = jprint(reqjson,0);
+ LP_send(pubsock,msg,(int32_t)strlen(msg)+1,1);
+ }
+ retstr = clonestr("{\"result\":\"notfound\"}");
+ }
+ free(data);
+ if ( reqjson != 0 )
+ free_json(reqjson);
+ if ( argjson != 0 )
+ free_json(argjson);
+ return(retstr);
+}
+
+int32_t LP_forward(void *ctx,char *myipaddr,int32_t pubsock,bits256 pubkey,char *jsonstr,int32_t freeflag)
+{
+ struct LP_forwardinfo *ptr; struct LP_peerinfo *peer,*tmp; char *msg,*hexstr,*retstr; int32_t len,n=0,mlen; cJSON *reqjson,*argjson;
+ if ( jsonstr == 0 || jsonstr[0] == 0 )
+ return(-1);
+ len = (int32_t)strlen(jsonstr) + 1;
+ if ( bits256_nonz(pubkey) != 0 )
+ {
+ if ( bits256_cmp(pubkey,LP_mypubkey) == 0 )
+ {
+ printf("GOT FORWARDED.(%s)\n",myipaddr);
+ if ( (argjson= cJSON_Parse(jsonstr)) != 0 )
+ {
+ if ( (retstr= LP_command_process(ctx,myipaddr,pubsock,argjson,0,0)) != 0 )
+ free(retstr);
+ free_json(argjson);
+ }
+ if ( freeflag != 0 )
+ free(jsonstr);
+ return(1);
+ }
+ else if ( IAMLP != 0 && (ptr= LP_forwardfind(pubkey)) != 0 && ptr->pushsock >= 0 )
+ {
+ printf("GOT FORWARDED.(%s) -> pushsock.%d\n",jsonstr,ptr->pushsock);
+ if ( LP_send(ptr->pushsock,jsonstr,len,freeflag) == len )
+ return(1);
+ }
+ }
+ hexstr = malloc(len*2 + 1);
+ init_hexbytes_noT(hexstr,(uint8_t *)jsonstr,len);
+ if ( freeflag != 0 )
+ free(jsonstr);
+ reqjson = cJSON_CreateObject();
+ jaddstr(reqjson,"method","forwardhex");
+ jaddstr(reqjson,"hex",hexstr);
+ free(hexstr);
+ msg = jprint(reqjson,1);
+ mlen = (int32_t)strlen(msg) + 1;
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ //printf("found LPnode.(%s) forward.(%s)\n",peer->ipaddr,msg);
+ if ( LP_send(peer->pushsock,msg,mlen,0) == mlen )
+ n++;
+ if ( n >= 8 )//sizeof(default_LPnodes)/sizeof(*default_LPnodes) )
+ break;
+ }
+ if ( msg != 0 )
+ free(msg);
+ if ( n == 0 )
+ return(-1);
+ else return(n-1);
+}
+
+
+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_include.h b/iguana/exchanges/LP_include.h
new file mode 100644
index 000000000..e630c13ea
--- /dev/null
+++ b/iguana/exchanges/LP_include.h
@@ -0,0 +1,289 @@
+
+/******************************************************************************
+ * 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 LP_STRICTPEERS
+
+#define LP_COMMAND_SENDSOCK NN_PUSH
+#define LP_COMMAND_RECVSOCK NN_PULL
+
+#define LP_ENCRYPTED_MAXSIZE (4096 + 2 + crypto_box_NONCEBYTES + crypto_box_ZEROBYTES)
+
+#define LP_MAXPUBKEY_ERRORS 3
+#define PSOCK_KEEPALIVE 3600
+#define MAINLOOP_PERSEC 100
+#define MAX_PSOCK_PORT 60000
+#define MIN_PSOCK_PORT 10000
+#define LP_MEMPOOL_TIMEINCR 10
+#define LP_GETINFO_INCR 30
+#define LP_ORDERBOOK_DURATION 3600
+
+#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 20
+#define LP_PEERGOOD_ERRORDECAY 0.9
+
+#define LP_SWAPSTEP_TIMEOUT 30
+#define LP_AUTOTRADE_TIMEOUT 60
+#define LP_MIN_TXFEE 10000
+#define LP_MINVOL 10
+#define LP_MINCLIENTVOL 20
+#define LP_MINSIZE_TXFEEMULT 10
+#define LP_REQUIRED_TXFEE 0.95
+
+#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
+#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 100 // txid ordering is not enforced, so getting extra recent txid
+#define LP_RESERVETIME 60
+#define LP_AVETXSIZE 256
+#define LP_CACHEDURATION 60
+#define BASILISK_DEFAULT_NUMCONFIRMS 1
+#define DEX_SLEEP 3
+#define BASILISK_KEYSIZE ((int32_t)(2*sizeof(bits256)+sizeof(uint32_t)*2))
+
+extern char GLOBAL_DBDIR[],USERPASS[],USERPASS_WIFSTR[];
+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; };
+
+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[10000],p2shscript[10000],userdata[10000];
+};
+
+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,Atxfee,Btxfee;
+
+ 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 LP_outpoint { bits256 spendtxid; uint64_t value,interest; int32_t spendvini,spendheight; char coinaddr[40]; };
+
+struct LP_transaction
+{
+ UT_hash_handle hh;
+ bits256 txid; int32_t height,numvouts,numvins; uint32_t timestamp;
+ struct LP_outpoint outpoints[];
+};
+
+struct LP_address
+{
+ UT_hash_handle hh;
+ int64_t balance;
+ char coinaddr[40];
+};
+
+struct iguana_info
+{
+ UT_hash_handle hh;
+ portable_mutex_t txmutex; struct LP_transaction *transactions; struct LP_address *addresses;
+ uint64_t txfee;
+ int32_t longestchain,firstrefht,firstscanht,lastscanht,bussock; uint16_t busport;
+ uint32_t counter,inactive,lastmempool,lastgetinfo;
+ uint8_t pubtype,p2shtype,isPoS,wiftype,wiftaddr,taddr,noimportprivkey_flag;
+ char symbol[16],smartaddr[64],userpass[1024],serverport[128];
+ // portfolio
+ double price_kmd,force,perc,goal,goalperc,relvolume;
+ uint64_t maxamount,kmd_equiv,balanceA,balanceB,valuesumA,valuesumB;
+ uint8_t pubkey33[33];
+};
+
+struct _LP_utxoinfo { bits256 txid; uint64_t value; int32_t vout; };
+
+struct LP_utxostats { uint32_t sessionid,lasttime,errors,swappending,spentflag,lastspentcheck,bestflag; };
+
+struct LP_utxobob { struct _LP_utxoinfo utxo,deposit; };
+
+struct LP_utxoalice { struct _LP_utxoinfo utxo,fee; };
+
+struct LP_utxoswap { bits256 otherpubkey; void *swap; uint64_t satoshis; };
+
+struct LP_utxoinfo
+{
+ UT_hash_handle hh,hh2;
+ 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)];
+ char coin[16],coinaddr[64],spendscript[256],gui[16];
+};
+
+struct LP_peerinfo
+{
+ UT_hash_handle hh;
+ uint64_t ip_port;
+ uint32_t ipbits,errortime,errors,numpeers,numutxos,lasttime,connected,lastutxos,lastpeers,diduquery,good,sessionid;
+ int32_t pushsock,subsock;
+ uint16_t port;
+ char ipaddr[64];
+};
+
+struct LP_quoteinfo
+{
+ struct basilisk_request R;
+ bits256 srchash,desthash,txid,txid2,desttxid,feetxid,privkey;
+ 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];
+};
+
+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,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];
+
+};
+
+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 *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(void *ctx,char *myipaddr,int32_t pubsock,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(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen);
+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);
+int32_t LP_pullsock_check(void *ctx,char **retstrp,char *myipaddr,int32_t pubsock,int32_t pullsock);
+uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired);
+void LP_utxo_clientpublish(struct LP_utxoinfo *utxo);
+int32_t LP_coinbus(uint16_t coin_busport);
+struct iguana_info *LP_coinfind(char *symbol);
+int32_t LP_crc32find(int32_t *duplicatep,int32_t ind,uint32_t crc32);
+char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,char *base,char *rel,double price);
+uint64_t LP_txfeecalc(char *symbol,uint64_t txfee);
+
+
+#endif
diff --git a/iguana/exchanges/LP_messages.c b/iguana/exchanges/LP_messages.c
new file mode 100644
index 000000000..80847ee5c
--- /dev/null
+++ b/iguana/exchanges/LP_messages.c
@@ -0,0 +1,97 @@
+
+/******************************************************************************
+ * 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_messages.c
+// marketmaker
+//
+
+struct LP_messageinfo { struct LP_messageinfo *next,*prev; cJSON *msgjson; int32_t ind; } *LP_MSGS;
+int32_t Num_messages;
+
+void LP_gotmessage(cJSON *argjson)
+{
+ struct LP_messageinfo *msg = calloc(1,sizeof(*msg));
+ msg->msgjson = jduplicate(argjson);
+ msg->ind = Num_messages++;
+ portable_mutex_lock(&LP_messagemutex);
+ DL_APPEND(LP_MSGS,msg);
+ portable_mutex_unlock(&LP_messagemutex);
+}
+
+void LP_deletemessages(int32_t firsti,int32_t num)
+{
+ struct LP_messageinfo *msg,*tmp; int32_t lasti;
+ if ( num == 0 )
+ num = 100;
+ if ( firsti < 0 )
+ firsti = 0;
+ else if ( firsti >= Num_messages )
+ return;
+ lasti = firsti + num - 1;
+ if ( lasti < Num_messages-1 )
+ lasti = Num_messages - 1;
+ DL_FOREACH_SAFE(LP_MSGS,msg,tmp)
+ {
+ if ( msg->ind >= firsti && msg->ind <= lasti )
+ {
+ portable_mutex_lock(&LP_messagemutex);
+ DL_DELETE(LP_MSGS,msg);
+ portable_mutex_unlock(&LP_messagemutex);
+ free_json(msg->msgjson);
+ free(msg);
+ }
+ }
+}
+
+cJSON *LP_getmessages(int32_t firsti,int32_t num)
+{
+ struct LP_messageinfo *msg,*tmp; int32_t lasti,n=0,maxi=-1,mini=-1; cJSON *retjson,*item,*array = cJSON_CreateArray();
+ retjson = cJSON_CreateObject();
+ if ( num == 0 )
+ num = 100;
+ if ( firsti < 0 )
+ firsti = 0;
+ else if ( firsti >= Num_messages )
+ {
+ jadd(retjson,"messages",array);
+ return(retjson);
+ }
+ lasti = firsti + num - 1;
+ if ( lasti < Num_messages-1 )
+ lasti = Num_messages - 1;
+ DL_FOREACH_SAFE(LP_MSGS,msg,tmp)
+ {
+ if ( msg->ind >= firsti && msg->ind <= lasti )
+ {
+ item = cJSON_CreateObject();
+ jaddnum(item,"ind",msg->ind);
+ jadd(item,"msg",jduplicate(msg->msgjson));
+ jaddi(array,item);
+ if ( mini == -1 || msg->ind < mini )
+ mini = msg->ind;
+ if ( maxi == -1 || msg->ind > maxi )
+ maxi = msg->ind;
+ n++;
+ }
+ }
+ jadd(retjson,"messages",array);
+ jaddnum(retjson,"firsti",firsti);
+ jaddnum(retjson,"lasti",lasti);
+ jaddnum(retjson,"minind",mini);
+ jaddnum(retjson,"maxind",maxi);
+ jaddnum(retjson,"num",n);
+ return(retjson);
+}
diff --git a/iguana/exchanges/LP_nativeDEX.c b/iguana/exchanges/LP_nativeDEX.c
new file mode 100644
index 000000000..fffcf4d93
--- /dev/null
+++ b/iguana/exchanges/LP_nativeDEX.c
@@ -0,0 +1,696 @@
+
+/******************************************************************************
+ * 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. *
+ * *
+ ******************************************************************************/
+//alice only coins GAME UNO BTM ANC: GAME BTCD PPC RDD XZC POT EAC FTC BASH SPR WDC UNO XPM XCN BELA CHC DIME MEC NAUT MED AUR MAX DGC RIC EB3 DOT BTM GEO ANC CANN ICASH WBB SRC PTC ADZ TIPS EQT START EFL FST FJC NYC GCN
+
+//
+// LP_nativeDEX.c
+// marketmaker
+//
+// new features:
+// bittrex balancing
+// detect port conflicts on enable
+// stats
+// PoW, JS
+// verify actual pricing
+// autoutxo, if < 10*txfee and > 10 utxo: combine smallest utxo into dexfee; autosplit if imbalanced
+
+// unduplicated bugs:
+// swap cancel should cleanly cancel
+
+#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,LP_psockmutex,LP_coinmutex,LP_messagemutex,LP_portfoliomutex;
+int32_t LP_canbind;
+
+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;
+#include "LP_network.c"
+
+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" }; //
+
+//uint32_t LP_deadman_switch;
+uint16_t LP_fixed_pairport,LP_publicport;
+int32_t LP_mybussock = -1;
+int32_t LP_mypubsock = -1;
+int32_t LP_mypullsock = -1;
+int32_t LP_pendingswaps,LP_showwif,USERPASS_COUNTER,IAMLP = 0;
+uint32_t LP_sessionid;
+double LP_profitratio = 1.;
+bits256 LP_mypub25519,LP_mypriv25519;
+
+// stubs
+
+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 *LP_getdatadir()
+{
+ return(USERHOME);
+}
+
+char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_t skip)
+{
+ return(0);
+}
+
+#include "LP_secp.c"
+#include "LP_bitcoin.c"
+#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"
+#include "LP_peers.c"
+#include "LP_utxos.c"
+#include "LP_forwarding.c"
+#include "LP_ordermatch.c"
+#include "LP_portfolio.c"
+#include "LP_messages.c"
+#include "LP_commands.c"
+
+char *LP_command_process(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen)
+{
+ char *retstr=0;
+ if ( jobj(argjson,"result") != 0 || jobj(argjson,"error") != 0 )
+ return(0);
+ if ( LP_tradecommand(ctx,myipaddr,pubsock,argjson,data,datalen) <= 0 )
+ {
+ if ( (retstr= stats_JSON(ctx,myipaddr,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 ) //strncmp("{\"error\":",retstr,strlen("{\"error\":")) != 0 &&
+ //LP_send(pubsock,retstr,(int32_t)strlen(retstr)+1,0);
+ }
+ }
+ return(retstr);
+}
+
+char *LP_decrypt(uint8_t *ptr,int32_t *recvlenp)
+{
+ uint8_t decoded[LP_ENCRYPTED_MAXSIZE + crypto_box_ZEROBYTES],*nonce,*cipher; int32_t recvlen,cipherlen; char *jsonstr = 0;
+ recvlen = *recvlenp;
+ nonce = &ptr[2];
+ cipher = &ptr[2 + crypto_box_NONCEBYTES];
+ cipherlen = recvlen - (2 + crypto_box_NONCEBYTES);
+ if ( cipherlen > 0 && cipherlen <= sizeof(decoded) )
+ {
+ if ( (jsonstr= (char *)_SuperNET_decipher(nonce,cipher,decoded,cipherlen,GENESIS_PUBKEY,LP_mypriv25519)) != 0 )
+ {
+ recvlen = (cipherlen - crypto_box_ZEROBYTES);
+ if ( strlen(jsonstr)+1 != recvlen )
+ {
+ printf("unexpected len %d vs recvlen.%d\n",(int32_t)strlen(jsonstr)+1,recvlen);
+ jsonstr = 0;
+ } else printf("decrypted (%s)\n",jsonstr);
+ }
+ } else printf("cipher.%d too big for %d\n",cipherlen,(int32_t)sizeof(decoded));
+ *recvlenp = recvlen;
+ return(jsonstr);
+}
+
+char *LP_process_message(void *ctx,char *typestr,char *myipaddr,int32_t pubsock,uint8_t *ptr,int32_t recvlen,int32_t recvsock)
+{
+ static uint32_t dup,uniq;
+ int32_t i,len,cipherlen,datalen=0,duplicate=0,encrypted=0; char *method,*method2,*tmp,*cipherstr,*retstr=0,*jsonstr=0; cJSON *argjson; uint32_t crc32;
+ crc32 = calc_crc32(0,&ptr[2],recvlen-2);
+ if ( (crc32 & 0xff) == ptr[0] && ((crc32>>8) & 0xff) == ptr[1] )
+ encrypted = 1;
+ portable_mutex_lock(&LP_commandmutex);
+ i = LP_crc32find(&duplicate,-1,crc32);
+ if ( duplicate != 0 )
+ dup++;
+ else uniq++;
+ if ( (rand() % 1000) == 0 )
+ printf("%s dup.%d (%u / %u) %.1f%% encrypted.%d recv.%u [%02x %02x] vs %02x %02x U.%d\n",typestr,duplicate,dup,dup+uniq,(double)100*dup/(dup+uniq),encrypted,crc32,ptr[0],ptr[1],crc32&0xff,(crc32>>8)&0xff,LP_mypeer != 0 ? LP_mypeer->numutxos : -1);
+ if ( duplicate == 0 )
+ {
+ if ( i >= 0 )
+ LP_crc32find(&duplicate,i,crc32);
+ if ( encrypted != 0 )
+ jsonstr = LP_decrypt(ptr,&recvlen);
+ else 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 ( jsonstr != 0 && (argjson= cJSON_Parse(jsonstr)) != 0 )
+ {
+ uint8_t decoded[LP_ENCRYPTED_MAXSIZE + crypto_box_ZEROBYTES];
+ //printf("[%s]\n",jsonstr);
+ cipherlen = 0;
+ if ( (cipherstr= jstr(argjson,"cipher")) != 0 && (cipherlen= is_hexstr(cipherstr,0)) > 32 && cipherlen <= sizeof(decoded)*2 )
+ {
+ method2 = jstr(argjson,"method2");
+ if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"encrypted") == 0 ||(method2 != 0 && strcmp(method2,"encrypted") == 0)) )
+ {
+ cipherlen >>= 1;
+ decode_hex(decoded,cipherlen,cipherstr);
+ crc32 = calc_crc32(0,&decoded[2],cipherlen-2);
+ if ( (tmp= LP_decrypt(decoded,&cipherlen)) != 0 )
+ {
+ jsonstr = tmp;
+ free_json(argjson);
+ argjson = cJSON_Parse(jsonstr);
+ recvlen = cipherlen;
+ encrypted = 1;
+ if ( (crc32 & 0xff) == decoded[0] && ((crc32>>8) & 0xff) == decoded[1] )
+ {
+ i = LP_crc32find(&duplicate,-1,crc32);
+ if ( duplicate == 0 && i >= 0 )
+ LP_crc32find(&duplicate,i,crc32);
+ }
+ printf("%02x %02x %08x duplicate.%d decrypted.(%s)\n",decoded[0],decoded[1],crc32,duplicate,jsonstr);
+ }
+ else
+ {
+ printf("packet not for this node %u\n",crc32);
+ }
+ } else printf("error (%s) method is %s\n",jsonstr,method);
+ }
+ if ( jsonstr != 0 && argjson != 0 )
+ {
+ len = (int32_t)strlen(jsonstr) + 1;
+ if ( (retstr= LP_command_process(ctx,myipaddr,pubsock,argjson,&((uint8_t *)ptr)[len],recvlen - len)) != 0 )
+ {
+ }
+ free_json(argjson);
+ }
+ }
+ } //else printf("DUPLICATE.(%s)\n",(char *)ptr);
+ portable_mutex_unlock(&LP_commandmutex);
+ if ( jsonstr != 0 && (void *)jsonstr != (void *)ptr && encrypted == 0 )
+ free(jsonstr);
+ if ( ptr != 0 )
+ nn_freemsg(ptr), ptr = 0;
+ return(retstr);
+}
+
+void LP_utxo_spentcheck(int32_t pubsock,struct LP_utxoinfo *utxo)
+{
+ struct _LP_utxoinfo u; struct iguana_info *coin; char str[65]; uint32_t now = (uint32_t)time(NULL);
+ if ( IAMLP != 0 && (coin= LP_coinfind(utxo->coin)) != 0 && coin->inactive != 0 )
+ return;
+ //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(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(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);
+ }
+ }
+}
+
+void LP_myutxo_updates(void *ctx,int32_t pubsock,char *passphrase)
+{
+ //LP_utxopurge(0); not good to disrupt existing pointers
+ 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,int32_t interval,int32_t maxentries)
+{
+ int32_t lastn,n = -1;
+ if ( peer->lastutxos < now-interval )
+ {
+ //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;
+ //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,maxentries);
+ }
+ } //else printf("LP_peer_utxosquery skip.(%s) %u\n",peer->ipaddr,peer->lastutxos);
+ return(n);
+}
+
+int32_t LP_sock_check(char *typestr,void *ctx,char *myipaddr,int32_t pubsock,int32_t sock)
+{
+ int32_t recvlen=1,nonz = 0; void *ptr; char *retstr; struct nn_pollfd pfd;
+ if ( sock >= 0 )
+ {
+ while ( nonz < 1000 && recvlen > 0 )
+ {
+ memset(&pfd,0,sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = NN_POLLIN;
+ if ( nn_poll(&pfd,1,1) != 1 )
+ break;
+ if ( (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) > 0 )
+ {
+ nonz++;
+ if ( (retstr= LP_process_message(ctx,typestr,myipaddr,pubsock,ptr,recvlen,sock)) != 0 )
+ free(retstr);
+ }
+ }
+ }
+ return(nonz);
+}
+
+void command_rpcloop(void *myipaddr)
+{
+ int32_t nonz = 0; char *origipaddr; struct LP_peerinfo *peer,*tmp; void *ctx; //struct iguana_info *coin,*ctmp;
+ ctx = bitcoin_ctx();
+ if ( (origipaddr= myipaddr) == 0 )
+ origipaddr = "127.0.0.1";
+ while ( 1 )
+ {
+ nonz = 0;
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ if ( peer->errors >= LP_MAXPEER_ERRORS )
+ {
+ if ( (rand() % 10000) == 0 )
+ peer->errors--;
+ else continue;
+ }
+ //printf("check %s pubsock.%d\n",peer->ipaddr,peer->subsock);
+ nonz += LP_sock_check("PULL",ctx,origipaddr,LP_mypubsock,peer->subsock);
+ }
+ /*HASH_ITER(hh,LP_coins,coin,ctmp) // firstrefht,firstscanht,lastscanht
+ {
+ if ( coin->inactive != 0 )
+ continue;
+ if ( coin->bussock >= 0 )
+ nonz += LP_sock_check(coin->symbol,ctx,origipaddr,-1,coin->bussock,LP_profitratio - 1.);
+ }*/
+ if ( LP_mypullsock >= 0 )
+ nonz += LP_sock_check("SUB",ctx,origipaddr,-1,LP_mypullsock);
+ //if ( LP_mybussock >= 0 )
+ // nonz += LP_sock_check("BUS",ctx,origipaddr,-1,LP_mybussock);
+ if ( nonz == 0 )
+ usleep(10000);
+ }
+}
+
+int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,uint16_t myport,char *passphrase)
+{
+ static uint32_t counter,numpeers,lastresync; //lastforward
+ struct LP_utxoinfo *utxo,*utmp; cJSON *retjson; struct iguana_info *coin,*ctmp; char *retstr,*origipaddr; struct LP_peerinfo *peer,*tmp,*mostpeer; uint32_t id,now; int32_t mostutxos,nonz = 0,n=0,num,lastn=-1;
+ now = (uint32_t)time(NULL);
+ if ( (origipaddr= myipaddr) == 0 )
+ 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 = LP_numpeers();
+ mostutxos = 0;
+ mostpeer = 0;
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ if ( peer->errors >= LP_MAXPEER_ERRORS )
+ {
+ if ( (rand() % 10000) == 0 )
+ {
+ peer->errors--;
+ peer->diduquery = 0;
+ }
+ if ( IAMLP == 0 )
+ continue;
+ }
+ if ( now > peer->lastpeers+60 && peer->numpeers > 0 && (peer->numpeers != numpeers || (rand() % 10000) == 0) )
+ {
+ //if ( IAMLP != 0 )
+ // printf("numpeers.%d updatepeer.%s lag.%d\n",numpeers,peer->ipaddr,now-peer->lastpeers);
+ peer->lastpeers = now;
+ //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);
+ if ( IAMLP != 0 && LP_mypeer != 0 && strcmp(peer->ipaddr,myipaddr) != 0 )
+ {
+ if ( (retstr= issue_LP_numutxos(peer->ipaddr,peer->port,LP_mypeer->ipaddr,LP_mypeer->port,LP_mypeer->numpeers,LP_mypeer->numutxos)) != 0 )
+ {
+ //printf("%d <- (%s)\n",peer->numutxos,retstr);
+ if ( (retjson= cJSON_Parse(retstr)) != 0 )
+ {
+ if ( (num= jint(retjson,"numutxos")) > peer->numutxos )
+ peer->numutxos = num;
+ if ( (num= jint(retjson,"numpeers")) > peer->numpeers )
+ peer->numpeers = num;
+ if ( (id= juint(retjson,"session")) != 0 )
+ peer->sessionid = id;
+ free_json(retjson);
+ }
+ free(retstr);
+ retstr = 0;
+ }
+ }
+ }
+ if ( peer->diduquery == 0 )
+ {
+ if ( lastn != n || n < 20 )
+ {
+ lastn = n;
+ n = LP_peer_utxosquery(mypeer,myport,pubsock,peer,now,60,100);
+ }
+ LP_peer_pricesquery(peer->ipaddr,peer->port);
+ peer->diduquery = now;
+ }
+ if ( peer->numutxos > mostutxos )
+ {
+ mostutxos = peer->numutxos;
+ mostpeer = peer;
+ }
+ }
+ //printf("numutxos vs mine.%d\n",LP_mypeer != 0 ? LP_mypeer->numutxos : -1);
+ if ( LP_mypeer != 0 && mostpeer != 0 && ((LP_mypeer->numutxos < mostutxos && time(NULL) > lastresync+10) || time(NULL) > lastresync+60) )
+ {
+ //printf("myutxos.%d most.%d %s\n",LP_mypeer->numutxos,mostutxos,mostpeer->ipaddr);
+ LP_peer_utxosquery(LP_mypeer,myport,pubsock,mostpeer,now,60,(mostutxos-LP_mypeer->numutxos) * 2);
+ lastresync = (uint32_t)time(NULL);
+ //LP_peer_pricesquery(mostpeer->ipaddr,mostpeer->port);
+ }
+ if ( (counter % 6000) == 10 )
+ {
+ LP_myutxo_updates(ctx,pubsock,passphrase);
+ HASH_ITER(hh,LP_utxoinfos[0],utxo,utmp)
+ {
+ LP_utxo_spentcheck(pubsock,utxo);
+ }
+ HASH_ITER(hh,LP_utxoinfos[1],utxo,utmp)
+ {
+ LP_utxo_spentcheck(pubsock,utxo);
+ if ( LP_isunspent(utxo) > 0 && utxo->T.lasttime == 0 && LP_ismine(utxo) > 0 )
+ {
+ char str[65]; printf("publish mybob %s\n",bits256_str(str,utxo->payment.txid));
+ LP_utxo_clientpublish(utxo);
+ }
+ }
+ }
+ 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);
+ 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 )
+ {
+ coin->longestchain = height;
+ 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);
+ 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+1 )
+ continue;
+ else if ( coin->lastscanht > coin->longestchain+1 )
+ {
+ 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 )
+ {
+ printf("blockinit.%s %d error\n",coin->symbol,coin->lastscanht);
+ continue;
+ }
+ coin->lastscanht++;
+ break;
+ }
+ if ( (counter % 6000) == 60 )
+ {
+ if ( (retstr= basilisk_swapentry(0,0)) != 0 )
+ {
+ //printf("SWAPS.(%s)\n",retstr);
+ free(retstr);
+ }
+ }
+ counter++;
+ return(nonz);
+}
+
+void LP_initcoins(void *ctx,int32_t pubsock,cJSON *coins,char *passphrase)
+{
+ int32_t i,n; cJSON *item;
+ for (i=0; i 0 )
+ {
+ for (i=0; i 25 )
+ // continue;
+ LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport);
+ }
+ } else LP_peersquery(mypeer,pubsock,seednode,myport,mypeer->ipaddr,myport);
+ }
+ 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>>>>>>>>>> set LP_canbind.%d\n",LP_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 )
+ {
+ 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_UTXOmutex);
+ 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_psockmutex);
+ portable_mutex_init(&LP_coinmutex);
+ portable_mutex_init(&LP_pubkeymutex);
+ portable_mutex_init(&LP_messagemutex);
+ portable_mutex_init(&LP_portfoliomutex);
+ LP_sessionid = (uint32_t)time(NULL);
+ printf("getting myipaddr sessionid.%u\n",LP_sessionid);
+
+ #ifdef _WIN32
+ if ( system("curl.exe -s4 checkip.amazonaws.com > ~\Temp") == 0 )
+ {
+ if ( (myipaddr= OS_filestr(&filesize,"~\Temp")) != 0 && myipaddr[0] != 0 )
+ {
+ 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");
+ #else
+ 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;
+ strcpy(LP_myipaddr,myipaddr);
+ } else printf("error getting myipaddr\n");
+ } else printf("error issuing curl\n");
+ #endif
+ if ( IAMLP != 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 )
+ {
+ 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;
+ }
+ printf("got %s, initpeers\n",myipaddr);
+ LP_initpeers(pubsock,mypeer,myipaddr,myport,jstr(argjson,"seednode"));
+ printf("get public socket\n");
+ LP_mypullsock = LP_initpublicaddr(ctx,&mypullport,pushaddr,myipaddr,mypullport,0);
+ strcpy(LP_publicaddr,pushaddr);
+ LP_publicport = mypullport;
+ LP_mybussock = LP_coinbus(mybusport);
+ //LP_deadman_switch = (uint32_t)time(NULL);
+ printf("canbind.%d my command address is (%s) pullsock.%d pullport.%u\n",LP_canbind,pushaddr,LP_mypullsock,mypullport);
+ printf("initcoins\n");
+ LP_initcoins(ctx,pubsock,jobj(argjson,"coins"),passphrase);
+ if ( IAMLP != 0 && OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_psockloop,(void *)&myipaddr) != 0 )
+ {
+ printf("error launching LP_psockloop for (%s)\n",myipaddr);
+ 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);
+ }
+ if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)command_rpcloop,(void *)&myipaddr) != 0 )
+ {
+ printf("error launching stats rpcloop for port.%u\n",myport);
+ exit(-1);
+ }
+ if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)queue_loop,(void *)&myipaddr) != 0 )
+ {
+ printf("error launching stats rpcloop for port.%u\n",myport);
+ exit(-1);
+ }
+ if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)prices_loop,(void *)&myipaddr) != 0 )
+ {
+ 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,".");
+ if ( LP_mainloop_iter(ctx,myipaddr,mypeer,pubsock,pushaddr,myport,passphrase) == 0 )
+ usleep(1000000 / MAINLOOP_PERSEC);
+ }
+}
diff --git a/iguana/exchanges/LP_network.c b/iguana/exchanges/LP_network.c
new file mode 100644
index 000000000..aadc2f485
--- /dev/null
+++ b/iguana/exchanges/LP_network.c
@@ -0,0 +1,720 @@
+
+/******************************************************************************
+ * 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
+//
+
+struct psock
+{
+ uint32_t lasttime,lastping,errors;
+ int32_t publicsock,sendsock,ispaired;
+ uint16_t publicport,sendport;
+ char sendaddr[128],publicaddr[128];
+} *PSOCKS;
+
+uint16_t Numpsocks,Psockport = MIN_PSOCK_PORT;
+
+char *nanomsg_transportname(int32_t bindflag,char *str,char *ipaddr,uint16_t port)
+{
+ sprintf(str,"tcp://%s:%u",bindflag == 0 ? ipaddr : "*",port); // ws is worse
+ return(str);
+}
+
+int32_t _LP_send(int32_t sock,void *msg,int32_t sendlen,int32_t freeflag)
+{
+ int32_t sentbytes;
+ if ( sock < 0 )
+ {
+ printf("LP_send.(%s) to illegal socket\n",(char *)msg);
+ if ( freeflag != 0 )
+ free(msg);
+ return(-1);
+ }
+ 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);
+ return(sentbytes);
+}
+
+int32_t LP_sockcheck(int32_t sock)
+{
+ struct nn_pollfd pfd;
+ pfd.fd = sock;
+ pfd.events = NN_POLLOUT;
+ if ( nn_poll(&pfd,1,1) > 0 )
+ return(1);
+ else return(-1);
+}
+
+struct LP_queue
+{
+ struct LP_queue *next,*prev;
+ int32_t sock,peerind,msglen;
+ uint32_t starttime,crc32;
+ uint8_t msg[];
+} *LP_Q;
+int32_t LP_Qenqueued,LP_Qerrors,LP_Qfound;
+
+void _LP_sendqueueadd(uint32_t crc32,int32_t sock,uint8_t *msg,int32_t msglen,int32_t peerind)
+{
+ struct LP_queue *ptr;
+ ptr = calloc(1,sizeof(*ptr) + msglen);
+ ptr->crc32 = crc32;
+ ptr->sock = sock;
+ ptr->peerind = peerind;
+ ptr->msglen = msglen;
+ memcpy(ptr->msg,msg,msglen);
+ DL_APPEND(LP_Q,ptr);
+ LP_Qenqueued++;
+ //printf("Q.%p: peerind.%d msglen.%d\n",ptr,peerind,msglen);
+}
+
+int32_t LP_crc32find(int32_t *duplicatep,int32_t ind,uint32_t crc32)
+{
+ static uint32_t crcs[8192]; static unsigned long dup,total;
+ int32_t i;
+ *duplicatep = 0;
+ if ( ind < 0 )
+ {
+ total++;
+ for (i=0; i 0 )
+ {
+ crcs[i] = crcs[i >> 1];
+ crcs[i >> 1] = crc32;
+ dup++;
+ //printf("duplicate %u in slot %d -> slot %d (%lu / %lu)\n",crc32,i,i>>1,dup,total);
+ }
+ *duplicatep = 1;
+ break;
+ }
+ else if ( crcs[i] == 0 )
+ break;
+ }
+ if ( i >= sizeof(crcs)/sizeof(*crcs) )
+ i = (rand() % (sizeof(crcs)/sizeof(*crcs)));
+ return(i);
+ }
+ else
+ {
+ crcs[ind] = crc32;
+ return(ind);
+ }
+}
+
+int32_t LP_peerindsock(int32_t *peerindp)
+{
+ struct LP_peerinfo *peer,*tmp; int32_t peerind = 0;
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ peerind++;
+ if ( peer->errors < LP_MAXPEER_ERRORS && peer->pushsock >= 0 )
+ {
+ if ( peerind < *peerindp )
+ continue;
+ *peerindp = peerind;
+ //printf("peerind.%d -> sock %d\n",peerind,peer->pushsock);
+ return(peer->pushsock);
+ }
+ }
+ return(-1);
+}
+
+void queue_loop(void *ignore)
+{
+ struct LP_queue *ptr,*tmp; int32_t sentbytes,nonz,flag,duplicate,n=0;
+ while ( 1 )
+ {
+ nonz = 0;
+ //printf("LP_Q.%p next.%p prev.%p\n",LP_Q,LP_Q!=0?LP_Q->next:0,LP_Q!=0?LP_Q->prev:0);
+ n = 0;
+ DL_FOREACH_SAFE(LP_Q,ptr,tmp)
+ {
+ n++;
+ flag = 0;
+ if ( ptr->sock >= 0 )
+ {
+ if ( LP_sockcheck(ptr->sock) > 0 )
+ {
+ if ( (sentbytes= nn_send(ptr->sock,ptr->msg,ptr->msglen,0)) != ptr->msglen )
+ printf("%d LP_send sent %d instead of %d\n",n,sentbytes,ptr->msglen);
+ // else printf("%d %p qsent %u msglen.%d peerind.%d\n",n,ptr,ptr->crc32,ptr->msglen,ptr->peerind);
+ ptr->sock = -1;
+ if ( ptr->peerind > 0 )
+ ptr->starttime = (uint32_t)time(NULL);
+ else flag = 1;
+ }
+ }
+ else if ( time(NULL) > ptr->starttime+13 )
+ {
+ LP_crc32find(&duplicate,-1,ptr->crc32);
+ if ( duplicate > 0 )
+ {
+ LP_Qfound++;
+ if ( (LP_Qfound % 10) == 0 )
+ printf("found.%u Q.%d err.%d match.%d\n",ptr->crc32,LP_Qenqueued,LP_Qerrors,LP_Qfound);
+ flag = 1;
+ }
+ else
+ {
+ printf("couldnt find.%u peerind.%d Q.%d err.%d match.%d\n",ptr->crc32,ptr->peerind,LP_Qenqueued,LP_Qerrors,LP_Qfound);
+ ptr->peerind++;
+ if ( (ptr->sock= LP_peerindsock(&ptr->peerind)) < 0 )
+ {
+ printf("%d no more peers to try at peerind.%d %p Q_LP.%p\n",n,ptr->peerind,ptr,LP_Q);
+ flag = 1;
+ LP_Qerrors++;
+ }
+ }
+ }
+ if ( flag != 0 )
+ {
+ nonz++;
+ portable_mutex_lock(&LP_networkmutex);
+ DL_DELETE(LP_Q,ptr);
+ portable_mutex_unlock(&LP_networkmutex);
+ free(ptr);
+ ptr = 0;
+ }
+ }
+ //if ( n != 0 )
+ // printf("LP_Q.[%d]\n",n);
+ if ( nonz == 0 )
+ usleep(500000);
+ }
+}
+
+void _LP_queuesend(uint32_t crc32,int32_t sock0,int32_t sock1,uint8_t *msg,int32_t msglen,int32_t needack)
+{
+ int32_t sentbytes,peerind = 0;
+ if ( sock0 >= 0 || sock1 >= 0 )
+ {
+ if ( sock0 >= 0 && LP_sockcheck(sock0) > 0 )
+ {
+ if ( (sentbytes= nn_send(sock0,msg,msglen,0)) != msglen )
+ printf("_LP_queuesend0 sent %d instead of %d\n",sentbytes,msglen);
+ else
+ {
+ //printf("Q sent %u\n",crc32);
+ sock0 = -1;
+ }
+ }
+ if ( sock1 >= 0 && LP_sockcheck(sock1) > 0 )
+ {
+ if ( (sentbytes= nn_send(sock1,msg,msglen,0)) != msglen )
+ printf("_LP_queuesend1 sent %d instead of %d\n",sentbytes,msglen);
+ else sock1 = -1;
+ }
+ if ( sock0 < 0 && sock1 < 0 )
+ return;
+ }
+ else
+ {
+ peerind = 1;
+ sock0 = LP_peerindsock(&peerind);
+ }
+ portable_mutex_lock(&LP_networkmutex);
+ if ( sock0 >= 0 )
+ _LP_sendqueueadd(crc32,sock0,msg,msglen,needack * peerind);
+ if ( sock1 >= 0 )
+ _LP_sendqueueadd(crc32,sock1,msg,msglen,needack);
+ portable_mutex_unlock(&LP_networkmutex);
+}
+
+void LP_queuesend(uint32_t crc32,int32_t pubsock,char *base,char *rel,uint8_t *msg,int32_t msglen)
+{
+ //struct iguana_info *coin; int32_t flag=0,socks[2];
+ if ( pubsock >= 0 )
+ {
+ //socks[0] = socks[1] = -1;
+ //if ( rel != 0 && rel[0] != 0 && (coin= LP_coinfind(rel)) != 0 && coin->bussock >= 0 )
+ // socks[flag++] = coin->bussock;
+ //if ( base != 0 && base[0] != 0 && (coin= LP_coinfind(base)) != 0 && coin->bussock >= 0 )
+ // socks[flag++] = coin->bussock;
+ //if ( flag == 0 && pubsock >= 0 )
+ _LP_queuesend(crc32,pubsock,-1,msg,msglen,0);
+ //else _LP_queuesend(socks[0],socks[1],msg,msglen,0);
+ } else _LP_queuesend(crc32,-1,-1,msg,msglen,1);
+}
+
+// first 2 bytes == (crc32 & 0xffff) if encrypted, then nonce is next crypto_box_NONCEBYTES
+// GENESIS_PRIVKEY is always the sender
+
+void LP_broadcast_finish(int32_t pubsock,char *base,char *rel,uint8_t *msg,cJSON *argjson,uint32_t crc32)
+{
+ int32_t msglen;
+ msg = (void *)jprint(argjson,0);
+ msglen = (int32_t)strlen((char *)msg) + 1;
+ if ( crc32 == 0 )
+ crc32 = calc_crc32(0,&msg[2],msglen - 2);
+ if ( IAMLP == 0 )
+ {
+ free(msg);
+ jdelete(argjson,"method");
+ jaddstr(argjson,"method","broadcast");
+ msg = (void *)jprint(argjson,0);
+ msglen = (int32_t)strlen((char *)msg) + 1;
+ LP_queuesend(crc32,-1,base,rel,msg,msglen);
+ } else LP_queuesend(crc32,pubsock,base,rel,msg,msglen);
+ free(msg);
+}
+
+void LP_broadcast_message(int32_t pubsock,char *base,char *rel,bits256 destpub25519,char *msgstr)
+{
+ uint8_t encoded[LP_ENCRYPTED_MAXSIZE],space[sizeof(encoded)],*msg,*nonce,*cipher; int32_t encrypted=0,msglen; uint32_t crc32=0; cJSON *argjson; char *methodstr,method[64],cipherstr[LP_ENCRYPTED_MAXSIZE*2+1];
+ msglen = (int32_t)strlen(msgstr) + 1;
+ msg = (void *)msgstr;
+ if ( bits256_nonz(destpub25519) != 0 )
+ {
+ nonce = &encoded[2];
+ OS_randombytes(nonce,crypto_box_NONCEBYTES);
+ cipher = &encoded[2 + crypto_box_NONCEBYTES];
+ msglen = _SuperNET_cipher(nonce,&encoded[2 + crypto_box_NONCEBYTES],msg,msglen,destpub25519,GENESIS_PRIVKEY,space);
+ msglen += crypto_box_NONCEBYTES;
+ crc32 = calc_crc32(0,&encoded[2],msglen);
+ encoded[0] = crc32 & 0xff;
+ encoded[1] = (crc32 >> 8) & 0xff;
+ msg = encoded;
+ msglen += 2;
+ encrypted = 1;
+ //printf("msgstr.(%s)\n",msgstr);
+ free(msgstr), msgstr = 0;
+ }
+ if ( encrypted == 0 )
+ {
+ if ( (argjson= cJSON_Parse(msgstr)) != 0 )
+ {
+ if ( (methodstr= jstr(argjson,"method")) != 0 && strlen(methodstr) <= sizeof(method) )
+ {
+ strcpy(method,methodstr);
+ jdelete(argjson,"method");
+ if ( jobj(argjson,"method2") != 0 )
+ jdelete(argjson,"method2");
+ jaddstr(argjson,"method2",method);
+ jaddstr(argjson,"method",method);
+ //printf("CRC32.%u (%s)\n",crc32,(char *)msg);
+ LP_broadcast_finish(pubsock,base,rel,msg,argjson,0);
+ } // else printf("no valid method in (%s)\n",msgstr);
+ free_json(argjson);
+ } else printf("couldnt parse (%s)\n",msgstr);
+ }
+ else
+ {
+ argjson = cJSON_CreateObject();
+ init_hexbytes_noT(cipherstr,msg,msglen);
+ jaddstr(argjson,"cipher",cipherstr);
+ jaddstr(argjson,"method2","encrypted");
+ jaddstr(argjson,"method","encrypted");
+ LP_broadcast_finish(pubsock,base,rel,msg,argjson,crc32);
+ free_json(argjson);
+ }
+ if ( msgstr != 0 )
+ free(msgstr);
+}
+
+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);
+ 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(pairsock,buf,offset,0)) != offset )
+ {
+ printf("sentbytes.%d vs offset.%d\n",sentbytes,offset);
+ if ( sentbytes < 0 )
+ {
+ }
+ }
+ //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);
+}
+
+void LP_psockloop(void *_ptr) // printouts seem to be needed for forwarding to work
+{
+ static struct nn_pollfd *pfds;
+ int32_t i,n,nonz,iter,retval,sentbytes,size=0,sendsock = -1; uint32_t now; struct psock *ptr=0; void *buf=0; char keepalive[512];
+ while ( 1 )
+ {
+ now = (uint32_t)time(NULL);
+ if ( buf != 0 && ptr != 0 && sendsock >= 0 )
+ {
+ if ( size > 0 )
+ {
+ if ( (sentbytes= nn_send(sendsock,buf,size,0)) != size ) // need tight loop
+ printf("LP_psockloop sent %d instead of %d\n",sentbytes,size);
+ if ( buf != 0 )
+ {
+ if ( buf != keepalive )
+ nn_freemsg(buf);
+ buf = 0;
+ size = 0;
+ ptr = 0;
+ sendsock = -1;
+ }
+ }
+ }
+ else if ( Numpsocks > 0 )
+ {
+ if ( pfds == 0 )
+ pfds = calloc(MAX_PSOCK_PORT,sizeof(*pfds));
+ portable_mutex_lock(&LP_psockmutex);
+ 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; ipublicsock;
+ pfds[n].events = POLLIN;
+ }
+ else
+ {
+ if ( pfds[n].fd != ptr->publicsock )
+ {
+ printf("unexpected fd.%d mismatched publicsock.%d\n",pfds[n].fd,ptr->publicsock);
+ break;
+ }
+ else if ( (pfds[n].revents & POLLIN) != 0 )
+ {
+ 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;
+ break;
+ }
+ }
+ }
+ n++;
+ 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 )
+ {
+ 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 )
+ {
+ sendsock = ptr->publicsock;
+ break;
+ }
+ else
+ {
+ nn_freemsg(buf);
+ buf = 0;
+ size = 0;
+ }
+ }
+ }
+ }
+ n++;
+ }
+ if ( iter == 0 )
+ {
+ if ( (retval= nn_poll(pfds,n,1)) <= 0 )
+ {
+ if ( retval != 0 )
+ printf("nn_poll retval.%d\n",retval);
+ break;
+ } else printf("num pfds.%d retval.%d\n",n,retval);
+ }
+ }
+ //free(pfds);
+ //printf("sendsock.%d Numpsocks.%d\n",sendsock,Numpsocks);
+ if ( sendsock < 0 )
+ {
+ for (i=nonz=0; i 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 )
+ nn_close(ptr->publicsock);
+ 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+PSOCK_KEEPALIVE/2 && ptr->errors < 3 )
+ {
+ ptr->lastping = now;
+ if ( 0 )
+ {
+ sendsock = ptr->sendsock;
+ sprintf(keepalive,"{\"method\":\"keepalive\",\"endpoint\":\"%s\"}",ptr->sendaddr);
+ size = (int32_t)strlen(keepalive) + 1;
+ buf = keepalive;
+ printf("send keepalive.(%s)\n",keepalive);
+ }
+ break;
+ }
+ }
+ }
+ if ( nonz == 0 && i == Numpsocks )
+ usleep(100000);
+ }
+ portable_mutex_unlock(&LP_psockmutex);
+ } else usleep(100000);
+ }
+}
+
+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->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);
+ 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,publicport,subport,maxiters=100; int32_t timeout,pullsock=-1,pubsock=-1; cJSON *retjson=0;
+ retjson = cJSON_CreateObject();
+ publicport = Psockport++;
+ subport = Psockport++;
+ for (i=0; i= 0 && (pubsock= nn_socket(AF_SP,ispaired!=0?NN_PAIR:NN_PAIR)) >= 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));
+ if ( ispaired != 0 )
+ {
+ //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_RCVTIMEO,&timeout,sizeof(timeout));
+ }
+ nanomsg_transportname(0,pushaddr,myipaddr,publicport);
+ nanomsg_transportname(0,subaddr,myipaddr,subport);
+ 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",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);
+ if ( pullsock >= 0 )
+ nn_close(pullsock);
+ if ( pubsock >= 0 )
+ nn_close(pubsock);
+ }
+ }
+ if ( Psockport > MAX_PSOCK_PORT )
+ Psockport = MIN_PSOCK_PORT;
+ if ( i == maxiters )
+ 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
+
+*/
+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);
+ //return(LP_issue_curl("psock",destip,destport,url));
+ retstr = issue_curlt(url,LP_HTTP_TIMEOUT*3);
+ printf("issue_LP_psock got (%s) from %s\n",retstr,destip);
+ 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;
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ 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 )
+ {
+ printf("from %s:%u (%s)\n",peer->ipaddr,peer->port,retstr);
+ 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);
+ }
+ printf("got.(%s) connect.%s public.%s\n",retstr,connectaddr,publicaddr);
+ free(retstr);
+ } else printf("error psock from %s:%u\n",peer->ipaddr,peer->port);
+ if ( publicport != 0 )
+ break;
+ }
+ return(publicport);
+}
+
+int32_t LP_initpublicaddr(void *ctx,uint16_t *mypullportp,char *publicaddr,char *myipaddr,uint16_t mypullport,int32_t ispaired)
+{
+ int32_t nntype,pullsock,timeout; char bindaddr[128],connectaddr[128];
+ *mypullportp = mypullport;
+ if ( ispaired == 0 )
+ {
+ if ( LP_canbind != 0 )
+ nntype = LP_COMMAND_RECVSOCK;
+ else nntype = NN_PAIR;//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;
+ if ( ispaired == 0 )
+ {
+ strcpy(publicaddr,"127.0.0.1");
+ return(-1);
+ }
+ while ( *mypullportp == 0 )
+ {
+ if ( (*mypullportp= LP_psock_get(connectaddr,publicaddr,ispaired)) != 0 )
+ break;
+ sleep(10);
+ printf("try to get publicaddr again\n");
+ }
+ }
+ while ( 1 )
+ {
+ if ( (pullsock= nn_socket(AF_SP,nntype)) >= 0 )
+ {
+ 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);
+ } 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 )
+ {
+ 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));
+ 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 ( LP_canbind != 0 || ispaired != 0 || nn_tests(ctx,pullsock,publicaddr,NN_PUSH) >= 0 )
+ // break;
+ //printf("nn_tests failed, try again\n");
+ //sleep(3);
+ break;
+ if ( pullsock >= 0 )
+ nn_close(pullsock);
+ }
+ return(pullsock);
+}
diff --git a/iguana/exchanges/LP_ordermatch.c b/iguana/exchanges/LP_ordermatch.c
new file mode 100644
index 000000000..3e3edf622
--- /dev/null
+++ b/iguana/exchanges/LP_ordermatch.c
@@ -0,0 +1,814 @@
+
+/******************************************************************************
+ * 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_ordermatch.c
+// marketmaker
+//
+
+uint64_t LP_txfeecalc(char *symbol,uint64_t txfee)
+{
+ struct iguana_info *coin;
+ if ( strcmp(symbol,"BTC") == 0 )
+ {
+ if ( txfee == 0 && (txfee= LP_getestimatedrate(symbol) * LP_AVETXSIZE) < LP_MIN_TXFEE )
+ txfee = LP_MIN_TXFEE;
+ }
+ else if ( (coin= LP_coinfind(symbol)) != 0 )
+ txfee = coin->txfee;
+ if ( txfee < LP_MIN_TXFEE )
+ txfee = LP_MIN_TXFEE;
+ return(txfee);
+}
+
+void LP_txfees(uint64_t *txfeep,uint64_t *desttxfeep,char *base,char *rel)
+{
+ *txfeep = LP_txfeecalc(base,0);
+ *desttxfeep = LP_txfeecalc(rel,0);
+}
+
+double LP_qprice_calc(int64_t *destsatoshisp,int64_t *satoshisp,double price,uint64_t b_satoshis,uint64_t txfee,uint64_t a_value,uint64_t maxdestsatoshis,uint64_t desttxfee)
+{
+ uint64_t destsatoshis,satoshis;
+ a_value -= (desttxfee + 1);
+ destsatoshis = ((b_satoshis - txfee) * price);
+ if ( destsatoshis > a_value )
+ destsatoshis = a_value;
+ if ( maxdestsatoshis != 0 && destsatoshis > maxdestsatoshis-desttxfee-1 )
+ destsatoshis = maxdestsatoshis-desttxfee-1;
+ satoshis = (destsatoshis / price + 0.49) - txfee;
+ *destsatoshisp = destsatoshis;
+ *satoshisp = satoshis;
+ if ( satoshis > 0 )
+ return((double)destsatoshis / satoshis);
+ else return(0.);
+}
+
+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->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);
+ 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);
+}
+
+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);
+ 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 ( 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->desttxfee != 0 )
+ jadd64bits(retjson,"desttxfee",qp->desttxfee);
+ if ( qp->destsatoshis != 0 )
+ {
+ jadd64bits(retjson,"destsatoshis",qp->destsatoshis);
+ if ( qp->satoshis != 0 )
+ {
+ price = (double)qp->destsatoshis / 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->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");
+ qp->satoshis = j64bits(argjson,"satoshis");
+ qp->destsatoshis = j64bits(argjson,"destsatoshis");
+ 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,uint64_t satoshis,uint64_t destsatoshis)
+{
+ memset(qp,0,sizeof(*qp));
+ if ( qp->timestamp == 0 )
+ qp->timestamp = (uint32_t)time(NULL);
+ safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin));
+ LP_txfees(&qp->txfee,&qp->desttxfee,utxo->coin,qp->destcoin);
+ qp->satoshis = satoshis;//(destsatoshis / price) + 0.49;
+ qp->destsatoshis = destsatoshis;
+ 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->txid = utxo->payment.txid;
+ qp->vout = utxo->payment.vout;
+ qp->txid2 = utxo->deposit.txid;
+ qp->vout2 = utxo->deposit.vout;
+ if ( qp->desttxfee >= qp->destsatoshis )
+ {
+ printf("quoteinit desttxfee %.8f < %.8f destsatoshis\n",dstr(qp->desttxfee),dstr(qp->destsatoshis));
+ return(-2);
+ }
+ safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin));
+ safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr));
+ qp->srchash = utxo->pubkey;
+ return(0);
+}
+
+int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr)
+{
+ qp->desttxid = desttxid;
+ qp->destvout = destvout;
+ qp->desthash = desthash;
+ qp->feetxid = feetxid;
+ qp->feevout = feevout;
+ 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.satoshis;
+ if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 )
+ {
+ ptr->Q = Q;
+ printf(">>>>>>>>>> received quote %s/%s %.8f\n",Q.srccoin,Q.destcoin,price);
+ return(clonestr("{\"result\":\"updated\"}"));
+ } else return(clonestr("{\"error\":\"nullptr\"}"));
+}
+
+char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,char *base,char *rel,double price)
+{
+ bits256 zero; char *msg; cJSON *reqjson = cJSON_CreateObject();
+ memset(zero.bytes,0,sizeof(zero));
+ jaddbits256(reqjson,"pubkey",LP_mypub25519);
+ jaddstr(reqjson,"base",base);
+ jaddstr(reqjson,"rel",rel);
+ jaddnum(reqjson,"price",price);
+ jaddstr(reqjson,"method","postprice");
+ msg = jprint(reqjson,1);
+ LP_broadcast_message(pubsock,base,rel,zero,msg);
+ return(clonestr("{\"result\":\"success\"}"));
+}
+
+char *LP_postedprice(cJSON *argjson)
+{
+ 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);
+ return(clonestr("{\"result\":\"success\"}"));
+ }
+ }
+ return(clonestr("{\"error\":\"missing fields in posted price\"}"));
+}
+
+int32_t LP_quote_checkmempool(struct LP_quoteinfo *qp)
+{
+ 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);
+}
+
+double LP_quote_validate(struct LP_utxoinfo **autxop,struct LP_utxoinfo **butxop,struct LP_quoteinfo *qp,int32_t iambob)
+{
+ double qprice; uint64_t txfee,desttxfee,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 )
+ {
+ 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 )
+ 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+qp->destsatoshis || srcvalue < qp->txfee+qp->satoshis )
+ {
+ 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);
+ if ( qp->satoshis < (srcvalue / LP_MINVOL) || srcvalue < qp->txfee*LP_MINSIZE_TXFEEMULT )
+ {
+ printf("utxo payment %.8f is less than %f covered by Q %.8f or <10x txfee %.8f\n",dstr(srcvalue),1./LP_MINVOL,dstr(qp->satoshis),dstr(qp->txfee));
+ return(-12);
+ }
+ if ( qp->destsatoshis < (destvalue / LP_MINCLIENTVOL) || destvalue < qp->desttxfee*LP_MINSIZE_TXFEEMULT )
+ {
+ printf("destsatoshis %.8f is less than %f of value %.8f or < 10x txfee %.8f\n",dstr(qp->destsatoshis),1./LP_MINCLIENTVOL,dstr(destvalue),dstr(qp->desttxfee));
+ return(-13);
+ }
+ LP_txfees(&txfee,&desttxfee,qp->srccoin,qp->destcoin);
+ printf("qprice %.8f <- %.8f/%.8f txfees.(%.8f %.8f) vs (%.8f %.8f)\n",qprice,dstr(qp->destsatoshis),dstr(qp->satoshis),dstr(qp->txfee),dstr(qp->desttxfee),dstr(txfee),dstr(desttxfee));
+ if ( qp->txfee < LP_REQUIRED_TXFEE*txfee || qp->desttxfee < LP_REQUIRED_TXFEE*desttxfee )
+ return(-14);
+ return(qprice);
+}
+
+int32_t LP_arrayfind(cJSON *array,bits256 txid,int32_t vout)
+{
+ int32_t i,n = cJSON_GetArraySize(array); cJSON *item;
+ for (i=0; idesttxid,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;
+ jaddbits256(reqjson,"pubkey",qp->srchash);
+ jaddstr(reqjson,"method",method);
+ msg = jprint(reqjson,1);
+ printf("QUERY.(%s)\n",msg);
+ LP_broadcast_message(LP_mypubsock,qp->srccoin,qp->destcoin,qp->srchash,msg);
+ for (i=0; i<30; i++)
+ {
+ if ( (price= LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout)) > SMALLVAL )
+ {
+ if ( flag == 0 || bits256_nonz(qp->desthash) != 0 )
+ {
+ printf("break out of loop.%d price %.8f %s/%s\n",i,price,qp->srccoin,qp->destcoin);
+ break;
+ }
+ }
+ usleep(100000);
+ }
+ return(price);
+}
+
+int32_t LP_nanobind(void *ctx,char *pairstr)
+{
+ int32_t i,r,pairsock = -1; uint16_t mypullport; char bindaddr[128];
+ if ( LP_canbind != 0 )
+ {
+ if ( (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 )
+ printf("error creating utxo->pair\n");
+ else
+ {
+ 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 )
+ {
+ //timeout = 1;
+ //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);
+ if ( LP_fixed_pairport != 0 )
+ break;
+ }
+ }
+ } else pairsock = LP_initpublicaddr(ctx,&mypullport,pairstr,"127.0.0.1",0,1);
+ return(pairsock);
+}
+
+int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJSON *argjson,char *base,char *rel,double price,struct LP_quoteinfo *qp)
+{
+ 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",LP_myipaddr,jprint(argjson,0),LP_myipaddr);
+ qp->quotetime = (uint32_t)time(NULL);
+ 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_mypub25519,qp->srchash) == 0 )
+ {
+ if ( (pair= LP_nanobind(ctx,pairstr)) >= 0 )
+ {
+ LP_requestinit(&qp->R,qp->srchash,qp->desthash,base,qp->satoshis-qp->txfee,rel,qp->destsatoshis-qp->desttxfee,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 )
+ {
+ 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 binds to %d (%s)\n",pubsock,pair,bits256_str(str,utxo->S.otherpubkey));
+ msg = jprint(retjson,1);
+ LP_broadcast_message(pubsock,base,rel,utxo->S.otherpubkey,msg);
+ 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_mypub25519,qp->srchash) == 0);
+ }
+ if ( retval < 0 )
+ {
+ if ( pair >= 0 )
+ nn_close(pair);
+ LP_availableset(utxo);
+ } else LP_unavailableset(utxo,utxo->S.otherpubkey);
+ return(retval);
+}
+
+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; struct iguana_info *coin;
+ if ( LP_quoteparse(&Q,argjson) < 0 )
+ clonestr("{\"error\":\"cant parse quote\"}");
+ if ( bits256_cmp(Q.desthash,LP_mypub25519) != 0 )
+ return(clonestr("{\"result\",\"update stats\"}"));
+ printf("CONNECTED.(%s)\n",jprint(argjson,0));
+ if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,0)) <= SMALLVAL )
+ {
+ LP_availableset(autxo);
+ LP_pendingswaps--;
+ printf("quote validate error %.0f\n",qprice);
+ return(clonestr("{\"error\":\"quote validation error\"}"));
+ }
+ if ( LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin) <= SMALLVAL || bid <= SMALLVAL )
+ {
+ printf("this node has no price for %s/%s (%.8f %.8f)\n",Q.destcoin,Q.srccoin,bid,ask);
+ LP_availableset(autxo);
+ LP_pendingswaps--;
+ return(clonestr("{\"error\":\"no price set\"}"));
+ }
+ printf("%s/%s bid %.8f ask %.8f\n",Q.srccoin,Q.destcoin,bid,ask);
+ //if ( (price= ask) == 0. )
+ price = bid;
+ /*if ( SATOSHIDEN*qprice > (SATOSHIDEN * price) * 1.001 + 10 )
+ {
+ printf("qprice %.8f too big vs %.8f\n",qprice,price);
+ LP_availableset(autxo);
+ LP_pendingswaps--;
+ return(clonestr("{\"error\":\"quote price too expensive\"}"));
+ }*/
+ if ( (coin= LP_coinfind(Q.destcoin)) == 0 )
+ {
+ LP_pendingswaps--;
+ 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();
+ 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 )
+ {
+ //timeout = 1;
+ //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.txfee,Q.destcoin,Q.destsatoshis-Q.desttxfee,Q.timestamp,Q.quotetime,DEXselector);
+ swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q);
+ swap->N.pair = pairsock;
+ autxo->S.swap = swap;
+ swap->utxo = autxo;
+ 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");
+ 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 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);
+ else LP_pendingswaps++;
+ return(jprint(retjson,1));
+ }
+ else
+ {
+ LP_availableset(autxo);
+ printf("no privkey found\n");
+ return(clonestr("{\"error\",\"no privkey\"}"));
+ }
+}
+
+int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen)
+{
+ 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));
+ retval = 1;
+ if ( LP_quoteparse(&Q,argjson) == 0 && bits256_cmp(LP_mypub25519,Q.srchash) == 0 )
+ {
+ if ( (price= LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin)) <= SMALLVAL || ask <= SMALLVAL )
+ {
+ printf("this node has no price for %s/%s\n",Q.srccoin,Q.destcoin);
+ return(-3);
+ }
+ price = ask;
+ if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,1)) <= SMALLVAL )
+ {
+ printf("quote validate error %.0f\n",qprice);
+ return(-4);
+ }
+ if ( qprice < (price - 0.00000001) * 0.9999 )
+ {
+ 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 )
+ butxo->T.swappending = 0;
+ if ( strcmp(method,"request") == 0 ) // bob needs apayment + fee tx's
+ {
+ if ( LP_isavailable(butxo) > 0 )
+ {
+ 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");
+ msg = jprint(retjson,1);
+ printf("set swappending.%u accept qprice %.8f, min %.8f\n(%s)",butxo->T.swappending,qprice,price,msg);
+ LP_broadcast_message(pubsock,Q.srccoin,Q.destcoin,butxo->S.otherpubkey,msg);
+ butxo->T.lasttime = (uint32_t)time(NULL);
+ } else printf("warning swappending.%u swap.%p\n",butxo->T.swappending,butxo->S.swap);
+ }
+ else if ( strcmp(method,"connect") == 0 ) // bob
+ {
+ retval = 4;
+ if ( butxo->T.swappending != 0 && butxo->S.swap == 0 )
+ LP_connectstartbob(ctx,pubsock,butxo,argjson,Q.srccoin,Q.destcoin,qprice,&Q);
+ else printf("pend.%u swap %p when connect came in (%s)\n",butxo->T.swappending,butxo->S.swap,jprint(argjson,0));
+ }
+ }
+ }
+ return(retval);
+}
+
+struct LP_utxoinfo *LP_bestutxo(double *ordermatchpricep,int64_t *bestsatoshisp,int64_t *bestdestsatoshisp,struct LP_utxoinfo *autxo,char *base,double maxprice,int32_t duration,uint64_t txfee,uint64_t desttxfee,uint64_t maxdestsatoshis)
+{
+ int64_t satoshis,destsatoshis; uint64_t val,val2; bits256 txid,pubkey; char *obookstr; cJSON *orderbook,*asks,*item; struct LP_utxoinfo *butxo,*bestutxo = 0; int32_t i,n,j,vout,numasks; double bestmetric=0.,metric,vol,price,qprice,bestprice = 0.; struct LP_pubkeyinfo *pubp;
+ *ordermatchpricep = 0.;
+ *bestsatoshisp = *bestdestsatoshisp = 0;
+ if ( duration <= 0 )
+ duration = LP_ORDERBOOK_DURATION;
+ if ( maxprice <= 0. || LP_priceinfofind(base) == 0 )
+ return(0);
+ LP_txfees(&txfee,&desttxfee,base,autxo->coin);
+ if ( (obookstr= LP_orderbook(base,autxo->coin,duration)) != 0 )
+ {
+ if ( (orderbook= cJSON_Parse(obookstr)) != 0 )
+ {
+ if ( (asks= jarray(&numasks,orderbook,"asks")) != 0 )
+ {
+ for (i=0; i 0 && price <= maxprice )
+ {
+ //price *= 1.0001;
+ //if ( price > maxprice )
+ // price = maxprice;
+ pubkey = jbits256(item,"pubkey");
+ if ( bits256_cmp(pubkey,LP_mypub25519) != 0 && (pubp= LP_pubkeyadd(pubkey)) != 0 && pubp->numerrors < LP_MAXPUBKEY_ERRORS )
+ {
+ 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");
+ 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 && butxo->T.bestflag == 0 )
+ {
+ if ( LP_iseligible(&val,&val2,butxo->iambob,butxo->coin,butxo->payment.txid,butxo->payment.vout,butxo->S.satoshis,butxo->deposit.txid,butxo->deposit.vout) > 0 )
+ {
+ destsatoshis = ((butxo->S.satoshis - txfee) * price);
+ satoshis = (destsatoshis / price + 0.49) - txfee;
+ if ( satoshis <= 0 )
+ continue;
+ qprice = (double)destsatoshis / satoshis;
+ n = (int32_t)((double)destsatoshis / desttxfee);
+ if ( n < 10 )
+ n = 10;
+ else n = 3;
+ for (j=0; jS.satoshis,txfee,autxo->payment.value,maxdestsatoshis,desttxfee)) > price+SMALLVAL )
+ break;
+ }
+ //printf("j.%d/%d qprice %.8f vs price %.8f best.(%.8f %.8f)\n",j,n,qprice,price,dstr(satoshis),dstr(destsatoshis));
+ 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;
+ if ( bestmetric == 0. || metric < bestmetric )
+ {
+ bestutxo = butxo;
+ *ordermatchpricep = price;
+ *bestdestsatoshisp = destsatoshis;
+ *bestsatoshisp = satoshis;
+ 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 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
+ {
+ printf("ineligible.(%.8f %.8f)\n",price,dstr(butxo->S.satoshis));
+ if ( butxo->T.spentflag == 0 )
+ butxo->T.spentflag = (uint32_t)time(NULL);
+ }
+ }
+ 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("cant find butxo.%p or value mismatch %.8f != %.8f or bestflag.%d\n",butxo,vol,butxo!=0?dstr(butxo->S.satoshis):0,butxo->T.bestflag);
+ }
+ } else printf("self trading or blacklisted peer\n");
+ }
+ else
+ {
+ if ( i == 0 )
+ printf("maxprice %.8f vs %.8f\n",maxprice,price);
+ break;
+ }
+ }
+ if ( bestutxo == 0 )
+ {
+ int32_t numrestraints;
+ for (i=numrestraints=0; iT.bestflag = 0;
+ pubp->numerrors = 0;
+ }
+ }
+ }
+ printf("no bob utxo found -> cleared %d restraints\n",numrestraints);
+ }
+ }
+ free_json(orderbook);
+ }
+ free(obookstr);
+ }
+ if ( bestutxo == 0 || *ordermatchpricep == 0. || *bestdestsatoshisp == 0 )
+ return(0);
+ bestutxo->T.bestflag = 1;
+ int32_t changed;
+ LP_mypriceset(&changed,autxo->coin,base,1. / *ordermatchpricep);
+ return(bestutxo);
+}
+
+char *LP_bestfit(char *rel,double relvolume)
+{
+ struct LP_utxoinfo *autxo;
+ if ( relvolume <= 0. || LP_priceinfofind(rel) == 0 )
+ return(clonestr("{\"error\":\"invalid parameter\"}"));
+ if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * relvolume)) == 0 )
+ return(clonestr("{\"error\":\"cant find utxo that is big enough\"}"));
+ return(jprint(LP_utxojson(autxo),1));
+}
+
+char *LP_ordermatch(char *base,int64_t txfee,double maxprice,double maxvolume,char *rel,bits256 txid,int32_t vout,bits256 feetxid,int32_t feevout,int64_t desttxfee,int32_t duration)
+{
+ struct LP_quoteinfo Q; int64_t bestsatoshis=0,bestdestsatoshis = 0; double ordermatchprice = 0.; struct LP_utxoinfo *autxo,*bestutxo;
+ txfee = LP_txfeecalc(base,txfee);
+ desttxfee = LP_txfeecalc(rel,desttxfee);
+ if ( (autxo= LP_utxopairfind(0,txid,vout,feetxid,feevout)) == 0 )
+ return(clonestr("{\"error\":\"cant find alice utxopair\"}"));
+ if ( (bestutxo= LP_bestutxo(&ordermatchprice,&bestsatoshis,&bestdestsatoshis,autxo,base,maxprice,duration,txfee,desttxfee,SATOSHIDEN*maxvolume)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 )
+ return(clonestr("{\"error\":\"cant find ordermatch utxo\"}"));
+ if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 )
+ return(clonestr("{\"error\":\"cant set ordermatch quote\"}"));
+ if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypub25519,autxo->coinaddr) < 0 )
+ return(clonestr("{\"error\":\"cant set ordermatch quote info\"}"));
+ return(jprint(LP_quotejson(&Q),1));
+}
+
+char *LP_trade(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo *qp,double maxprice,int32_t timeout,int32_t duration)
+{
+ struct LP_utxoinfo *bobutxo,*aliceutxo; cJSON *bestitem=0; int32_t DEXselector=0; uint32_t expiration; double price; struct LP_pubkeyinfo *pubp;
+ if ( (aliceutxo= LP_utxopairfind(0,qp->desttxid,qp->destvout,qp->feetxid,qp->feevout)) == 0 )
+ {
+ char str[65],str2[65]; printf("dest.(%s)/v%d fee.(%s)/v%d\n",bits256_str(str,qp->desttxid),qp->destvout,bits256_str(str2,qp->feetxid),qp->feevout);
+ return(clonestr("{\"error\":\"cant find alice utxopair\"}"));
+ }
+ if ( (bobutxo= LP_utxopairfind(1,qp->txid,qp->vout,qp->txid2,qp->vout2)) == 0 )
+ return(clonestr("{\"error\":\"cant find bob utxopair\"}"));
+ bobutxo->T.bestflag = (uint32_t)time(NULL);
+ //if ( (retstr= LP_registerall(0)) != 0 )
+ // free(retstr);
+ price = LP_query(ctx,myipaddr,mypubsock,"request",qp);
+ bestitem = LP_quotejson(qp);
+ if ( LP_pricevalid(price) > 0 )
+ {
+ if ( price <= maxprice )
+ {
+ price = LP_query(ctx,myipaddr,mypubsock,"connect",qp);
+ LP_requestinit(&qp->R,qp->srchash,qp->desthash,bobutxo->coin,qp->satoshis-qp->txfee,qp->destcoin,qp->destsatoshis-qp->desttxfee,qp->timestamp,qp->quotetime,DEXselector);
+ expiration = (uint32_t)time(NULL) + timeout;
+ while ( time(NULL) < expiration )
+ {
+ if ( aliceutxo->S.swap != 0 )
+ break;
+ sleep(1);
+ }
+ if ( aliceutxo->S.swap == 0 )
+ {
+ if ( (pubp= LP_pubkeyadd(bobutxo->pubkey)) != 0 )
+ pubp->numerrors++;
+ jaddstr(bestitem,"status","couldnt establish connection");
+ } else jaddstr(bestitem,"status","connected");
+ jaddnum(bestitem,"quotedprice",price);
+ jaddnum(bestitem,"maxprice",maxprice);
+ jaddnum(bestitem,"requestid",qp->R.requestid);
+ jaddnum(bestitem,"quoteid",qp->R.quoteid);
+ printf("Alice r.%u qp->%u\n",qp->R.requestid,qp->R.quoteid);
+ }
+ else
+ {
+ jaddnum(bestitem,"quotedprice",price);
+ jaddnum(bestitem,"maxprice",maxprice);
+ jaddstr(bestitem,"status","too expensive");
+ }
+ }
+ else
+ {
+ jaddnum(bestitem,"maxprice",maxprice);
+ jaddstr(bestitem,"status","no response to request");
+ }
+ if ( aliceutxo->S.swap == 0 )
+ LP_availableset(aliceutxo);
+ return(jprint(bestitem,0));
+}
+
+char *LP_autotrade(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel,double maxprice,double relvolume,int32_t timeout,int32_t duration)
+{
+ uint64_t desttxfee,txfee; int64_t bestsatoshis=0,bestdestsatoshis=0; struct LP_utxoinfo *autxo,*butxo,*bestutxo = 0; double qprice,ordermatchprice=0.; struct LP_quoteinfo Q;
+ if ( duration <= 0 )
+ duration = LP_ORDERBOOK_DURATION;
+ if ( timeout <= 0 )
+ timeout = LP_AUTOTRADE_TIMEOUT;
+ if ( maxprice <= 0. || relvolume <= 0. || LP_priceinfofind(base) == 0 || LP_priceinfofind(rel) == 0 )
+ return(clonestr("{\"error\":\"invalid parameter\"}"));
+ if ( (autxo= LP_utxo_bestfit(rel,SATOSHIDEN * relvolume)) == 0 )
+ return(clonestr("{\"error\":\"cant find utxo that is big enough\"}"));
+ LP_txfees(&txfee,&desttxfee,base,rel);
+ if ( (bestutxo= LP_bestutxo(&ordermatchprice,&bestsatoshis,&bestdestsatoshis,autxo,base,maxprice,duration,txfee,desttxfee,SATOSHIDEN*relvolume)) == 0 || ordermatchprice == 0. || bestdestsatoshis == 0 )
+ {
+ printf("bestutxo.%p ordermatchprice %.8f bestdestsatoshis %.8f\n",bestutxo,ordermatchprice,dstr(bestdestsatoshis));
+ return(clonestr("{\"error\":\"cant find ordermatch utxo\"}"));
+ }
+ if ( LP_quoteinfoinit(&Q,bestutxo,rel,ordermatchprice,bestsatoshis,bestdestsatoshis) < 0 )
+ return(clonestr("{\"error\":\"cant set ordermatch quote\"}"));
+ if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,LP_mypub25519,autxo->coinaddr) < 0 )
+ return(clonestr("{\"error\":\"cant set ordermatch quote info\"}"));
+ if ( (qprice= LP_quote_validate(&autxo,&butxo,&Q,0)) <= SMALLVAL )
+ {
+ printf("quote validate error %.0f\n",qprice);
+ return(clonestr("{\"error\":\"quote validation error\"}"));
+ }
+ printf("do quote.(%s)\n",jprint(LP_quotejson(&Q),1));
+ return(LP_trade(ctx,myipaddr,mypubsock,&Q,maxprice,timeout,duration));
+}
+
+
+
+
diff --git a/iguana/exchanges/LP_peers.c b/iguana/exchanges/LP_peers.c
new file mode 100644
index 000000000..5e7a26cc3
--- /dev/null
+++ b/iguana/exchanges/LP_peers.c
@@ -0,0 +1,253 @@
+
+/******************************************************************************
+ * 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);
+ if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 )
+ {
+ jaddnum(item,"session",LP_sessionid);
+ if ( LP_mypeer != 0 )
+ jaddnum(item,"numutxos",LP_mypeer->numutxos);
+ } else jaddnum(item,"session",peer->sessionid);
+ //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)
+ {
+ //if ( peer->errors < LP_MAXPEER_ERRORS )
+ jaddi(peersjson,LP_peerjson(peer));
+ }
+ return(jprint(peersjson,1));
+}
+
+struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char *ipaddr,uint16_t port,uint16_t pushport,uint16_t subport,int32_t numpeers,int32_t numutxos,uint32_t sessionid)
+{
+ uint32_t ipbits; int32_t pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0;
+#ifdef LP_STRICTPEERS
+ if ( strncmp("5.9.253",ipaddr,strlen("5.9.253")) != 0 )
+ return(0);
+#endif
+ ipbits = (uint32_t)calc_ipbits(ipaddr);
+ expand_ipbits(checkip,ipbits);
+ if ( strcmp(checkip,ipaddr) == 0 )
+ {
+ if ( (peer= LP_peerfind(ipbits,port)) != 0 )
+ {
+ /*if ( numpeers > peer->numpeers )
+ peer->numpeers = numpeers;
+ if ( numutxos > peer->numutxos )
+ peer->numutxos = numutxos;
+ if ( peer->sessionid == 0 )
+ peer->sessionid = sessionid;*/
+ }
+ else
+ {
+ peer = calloc(1,sizeof(*peer));
+ if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 )
+ peer->sessionid = LP_sessionid;
+ else peer->sessionid = sessionid;
+ peer->pushsock = peer->subsock = pushsock = subsock = -1;
+ strcpy(peer->ipaddr,ipaddr);
+ if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 )
+ {
+ nanomsg_transportname(0,pushaddr,peer->ipaddr,pushport);
+ if ( nn_connect(pushsock,pushaddr) >= 0 )
+ {
+ timeout = 1;
+ 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;
+ if ( (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_transportname(0,subaddr,peer->ipaddr,subport);
+ if ( nn_connect(subsock,subaddr) >= 0 )
+ {
+ peer->subsock = subsock;
+ printf("connected to sub.(%s) %d\n",subaddr,peer->subsock);
+ } 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 ( IAMLP != 0 && mypubsock >= 0 )
+ {
+ struct iguana_info *coin,*ctmp; bits256 zero; char *msg,busaddr[64];
+ msg = jprint(LP_peerjson(peer),1);
+ memset(zero.bytes,0,sizeof(zero));
+ //LP_send(mypubsock,msg,(int32_t)strlen(msg)+1,1);
+ LP_broadcast_message(mypubsock,"","",zero,msg);
+ if ( 0 )
+ {
+ HASH_ITER(hh,LP_coins,coin,ctmp)
+ {
+ if ( coin->bussock >= 0 )
+ {
+ nanomsg_transportname(0,busaddr,peer->ipaddr,coin->busport);
+ nn_connect(coin->bussock,busaddr);
+ }
+ }
+ }
+ }
+ }
+ } else printf("LP_addpeer: checkip.(%s) vs (%s)\n",checkip,ipaddr);
+ return(peer);
+}
+
+int32_t LP_coinbus(uint16_t coin_busport)
+{
+ struct LP_peerinfo *peer,*tmp; char busaddr[64]; int32_t timeout,bussock = -1;
+ return(-1);
+ if ( IAMLP != 0 && LP_mypeer != 0 && (bussock= nn_socket(AF_SP,NN_BUS)) >= 0 )
+ {
+ timeout = 1;
+ nn_setsockopt(bussock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout));
+ nn_setsockopt(bussock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout));
+ nanomsg_transportname(0,busaddr,LP_mypeer->ipaddr,coin_busport);
+ if ( nn_bind(bussock,busaddr) < 0 )
+ {
+ printf("error binding to coin_busport.%s\n",busaddr);
+ nn_close(bussock);
+ }
+ else
+ {
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ if ( LP_mypeer->port != peer->port || strcmp(LP_mypeer->ipaddr,peer->ipaddr) != 0 )
+ {
+ nanomsg_transportname(0,busaddr,peer->ipaddr,coin_busport);
+ nn_connect(bussock,busaddr);
+ }
+ }
+ }
+ }
+ return(bussock);
+}
+
+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 )
+ {
+ 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(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *myipaddr,uint16_t myport)
+{
+ char *retstr; struct LP_peerinfo *peer,*tmp; uint32_t now,flag = 0;
+ peer = LP_peerfind((uint32_t)calc_ipbits(destipaddr),destport);
+ if ( (retstr= issue_LP_getpeers(destipaddr,destport,myipaddr,myport,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);
+ if ( IAMLP != 0 )
+ {
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ if ( peer->lasttime != now )
+ {
+ printf("{%s:%u}.%d ",peer->ipaddr,peer->port,peer->lasttime - now);
+ flag++;
+ if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->numpeers,0,peer->sessionid)) != 0 )
+ free(retstr);
+ }
+ }
+ if ( flag != 0 )
+ printf(" <- missing peers\n");
+ }
+ }
+}
+
+int32_t LP_numpeers()
+{
+ struct LP_peerinfo *peer,*tmp; int32_t numpeers = 0;
+ HASH_ITER(hh,LP_peerinfos,peer,tmp)
+ {
+ numpeers++;
+ }
+ return(numpeers);
+}
diff --git a/iguana/exchanges/LP_portfolio.c b/iguana/exchanges/LP_portfolio.c
new file mode 100644
index 000000000..a5982444d
--- /dev/null
+++ b/iguana/exchanges/LP_portfolio.c
@@ -0,0 +1,577 @@
+
+/******************************************************************************
+ * 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_portfolio.c
+// marketmaker
+//
+
+char LP_portfolio_base[16],LP_portfolio_rel[16];
+double LP_portfolio_relvolume;
+
+cJSON *LP_portfolio_entry(struct iguana_info *coin)
+{
+ cJSON *item = cJSON_CreateObject();
+ jaddstr(item,"coin",coin->symbol);
+ jaddstr(item,"address",coin->smartaddr);
+ jaddnum(item,"amount",dstr(coin->maxamount));
+ jaddnum(item,"price",coin->price_kmd);
+ jaddnum(item,"kmd_equiv",dstr(coin->kmd_equiv));
+ jaddnum(item,"perc",coin->perc);
+ jaddnum(item,"goal",coin->goal);
+ jaddnum(item,"goalperc",coin->goalperc);
+ jaddnum(item,"relvolume",coin->relvolume);
+ jaddnum(item,"force",coin->force);
+ jaddnum(item,"balanceA",dstr(coin->balanceA));
+ jaddnum(item,"valuesumA",dstr(coin->valuesumA));
+ if ( coin->valuesumA != 0 )
+ jaddnum(item,"aliceutil",100. * (double)coin->balanceA/coin->valuesumA);
+ jaddnum(item,"balanceB",dstr(coin->balanceB));
+ jaddnum(item,"valuesumB",dstr(coin->valuesumB));
+ jaddnum(item,"balance",dstr(coin->maxamount));
+ if ( coin->valuesumB != 0 )
+ jaddnum(item,"bobutil",100. * (double)coin->balanceB/coin->valuesumB);
+ return(item);
+}
+
+uint64_t LP_balance(uint64_t *valuep,int32_t iambob,char *symbol,char *coinaddr)
+{
+ cJSON *array,*item; int32_t i,n; uint64_t valuesum,satoshisum,value;
+ valuesum = satoshisum = 0;
+ if ( (array= LP_listunspent(symbol,coinaddr)) != 0 )
+ {
+ if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 )
+ {
+ for (i=0; i 0 && is_cJSON_Array(array) != 0 )
+ {
+ for (i=0; iinactive != 0 )
+ continue;
+ if ( iter == 0 )
+ {
+ LP_privkey_init(-1,coin,LP_mypriv25519,LP_mypub25519);
+ coin->balanceA = LP_balance(&coin->valuesumA,0,coin->symbol,coin->smartaddr);
+ coin->balanceB = LP_balance(&coin->valuesumB,1,coin->symbol,coin->smartaddr);
+ if ( strcmp(coin->symbol,"KMD") != 0 )
+ coin->price_kmd = LP_price(coin->symbol,"KMD");
+ else coin->price_kmd = 1.;
+ coin->maxamount = coin->valuesumA;
+ if ( coin->valuesumB > coin->maxamount )
+ coin->maxamount = coin->valuesumB;
+ coin->kmd_equiv = coin->maxamount * coin->price_kmd;
+ kmdsum += coin->kmd_equiv;
+ goalsum += coin->goal;
+ }
+ else
+ {
+ coin->relvolume = 0.;
+ if ( kmdsum > SMALLVAL )
+ coin->perc = 100. * coin->kmd_equiv / kmdsum;
+ if ( goalsum > SMALLVAL && coin->goal > SMALLVAL )
+ {
+ coin->goalperc = 100. * coin->goal / goalsum;
+ if ( (coin->force= (coin->goalperc - coin->perc)) < 0. )
+ {
+ coin->force *= -coin->force;
+ if ( coin->price_kmd > SMALLVAL )
+ coin->relvolume = (dstr(coin->maxamount) * (coin->perc - coin->goalperc)) / 100.;
+ } else coin->force *= coin->force;
+ if ( coin->force > maxval )
+ {
+ maxval = coin->force;
+ buycoin = coin;
+ }
+ if ( coin->force < minval )
+ {
+ minval = coin->force;
+ sellcoin = coin;
+ }
+ } else coin->goalperc = coin->force = 0.;
+ jaddi(array,LP_portfolio_entry(coin));
+ }
+ }
+ }
+ jaddstr(retjson,"result","success");
+ jaddnum(retjson,"kmd_equiv",dstr(kmdsum));
+ if ( buycoin != 0 )
+ {
+ jaddstr(retjson,"buycoin",buycoin->symbol);
+ jaddnum(retjson,"buyforce",maxval);
+ }
+ if ( sellcoin != 0 )
+ {
+ jaddstr(retjson,"sellcoin",sellcoin->symbol);
+ jaddnum(retjson,"sellforce",minval);
+ }
+ if ( LP_portfolio_relvolume > SMALLVAL )
+ {
+ jaddstr(retjson,"base",LP_portfolio_base);
+ jaddstr(retjson,"rel",LP_portfolio_rel);
+ jaddnum(retjson,"relvolume",LP_portfolio_relvolume);
+ }
+ jadd(retjson,"portfolio",array);
+ return(jprint(retjson,1));
+}
+
+char *LP_portfolio_goal(char *symbol,double goal)
+{
+ struct iguana_info *coin,*tmp; int32_t iter,n = 0; double kmdbtc = 50.;
+ if ( strcmp(symbol,"*") == 0 )
+ {
+ for (iter=0; iter<2; iter++)
+ {
+ HASH_ITER(hh,LP_coins,coin,tmp)
+ {
+ if ( coin->inactive != 0 )
+ continue;
+ if ( iter == 0 )
+ coin->goal = 0;
+ if ( coin->inactive == 0 && strcmp(coin->symbol,"KMD") != 0 && strcmp(coin->symbol,"BTC") != 0 )
+ {
+ if ( iter == 0 )
+ n++;
+ else coin->goal = (100. - kmdbtc) / n;
+ }
+ }
+ if ( n == 0 )
+ break;
+ }
+ if ( (coin= LP_coinfind("KMD")) != 0 && coin->inactive == 0 )
+ coin->goal = kmdbtc * 0.5;
+ if ( (coin= LP_coinfind("BTC")) != 0 && coin->inactive == 0 )
+ coin->goal = kmdbtc * 0.5;
+ return(LP_portfolio());
+ }
+ else if ( (coin= LP_coinfind(symbol)) != 0 && coin->inactive == 0 )
+ {
+ coin->goal = goal;
+ printf("set %s goal %f\n",coin->symbol,goal);
+ return(LP_portfolio());
+ } else return(clonestr("{\"error\":\"cant set goal for inactive coin\"}"));
+}
+
+int32_t LP_autoprices;
+
+/*int32_t LP_autofill(char *base,char *rel,double maxprice,double totalrelvolume)
+{
+ struct LP_priceinfo *basepp,*relpp;
+ if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 )
+ {
+ basepp->maxprices[relpp->ind] = maxprice;
+ basepp->relvols[relpp->ind] = totalrelvolume;
+ LP_autofills++;
+ return(0);
+ }
+ return(-1);
+}*/
+
+int32_t LP_autoprice(char *base,char *rel,double minprice,double margin,char *type)
+{
+ struct LP_priceinfo *basepp,*relpp;
+ if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 )
+ {
+ basepp->minprices[relpp->ind] = minprice;
+ basepp->margins[relpp->ind] = margin;
+ LP_autoprices++;
+ return(0);
+ }
+ return(-1);
+}
+
+void LP_autopriceset(void *ctx,int32_t dir,struct LP_priceinfo *relpp,struct LP_priceinfo *basepp,double price)
+{
+ double margin,minprice,oppomargin; int32_t changed;
+ margin = basepp->margins[relpp->ind];
+ oppomargin = relpp->margins[basepp->ind];
+ if ( margin != 0. || oppomargin != 0. )
+ {
+ if ( margin == 0. )
+ margin = oppomargin;
+ //printf("min %.8f %s/%s %.8f dir.%d margin %.8f (%.8f %.8f)\n",basepp->minprices[relpp->ind],relpp->symbol,basepp->symbol,price,dir,margin,1. / (price * (1. - margin)),(price * (1. + margin)));
+ if ( dir > 0 )
+ price = 1. / (price * (1. - margin));
+ else price = (price * (1. + margin));
+ if ( (minprice= basepp->minprices[relpp->ind]) == 0. || price >= minprice )
+ {
+ LP_mypriceset(&changed,relpp->symbol,basepp->symbol,price);
+ //printf("changed.%d\n",changed);
+ if ( changed != 0 )
+ LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,relpp->symbol,basepp->symbol,price);
+ }
+ }
+}
+
+double LP_pricesparse(void *ctx,int32_t trexflag,char *retstr,struct LP_priceinfo *btcpp)
+{
+ //{"success":true,"message":"","result":[{"MarketName":"BTC-KMD","High":0.00040840,"Low":0.00034900,"Volume":328042.46061669,"Last":0.00037236,"BaseVolume":123.36439511,"TimeStamp":"2017-07-15T13:50:21.87","Bid":0.00035721,"Ask":0.00037069,"OpenBuyOrders":343,"OpenSellOrders":1690,"PrevDay":0.00040875,"Created":"2017-02-11T23:04:01.853"},
+ //{"TradePairId":4762,"Label":"WAVES/BTC","AskPrice":0.00099989,"BidPrice":0.00097350,"Low":0.00095000,"High":0.00108838,"Volume":6501.24403100,"LastPrice":0.00098028,"BuyVolume":1058994.86554882,"SellVolume":2067.87377158,"Change":-7.46,"Open":0.00105926,"Close":0.00098028,"BaseVolume":6.52057452,"BuyBaseVolume":2.33098660,"SellBaseVolume":1167.77655709},
+ int32_t i,j,n,iter; double price,kmdbtc,bid,ask,nxtkmd=0.; struct LP_priceinfo *coinpp,*refpp; char symbol[16],*name,*refcoin; cJSON *retjson,*array,*item;
+ if ( (retjson= cJSON_Parse(retstr)) != 0 )
+ {
+ //printf("got.(%s)\n",retstr);
+ kmdbtc = 0.;
+ refcoin = "BTC";
+ refpp = btcpp;
+ if ( (array= jarray(&n,retjson,trexflag != 0 ? "result" : "Data")) != 0 )
+ {
+ for (iter=0; iter<2; iter++)
+ {
+ for (i=0; i SMALLVAL && strcmp(symbol,"NXT") == 0 )
+ nxtkmd = 0.5 * (bid + ask) / kmdbtc;
+ if ( (coinpp= LP_priceinfofind(symbol)) != 0 )
+ {
+ coinpp->high[trexflag] = jdouble(item,"High");
+ coinpp->low[trexflag] = jdouble(item,"Low");
+ //coinpp->volume = jdouble(item,"Volume");
+ //coinpp->btcvolume = jdouble(item,"BaseVolume");
+ coinpp->last[trexflag] = jdouble(item,trexflag != 0 ? "Last" : "LastPrice");
+ coinpp->bid[trexflag] = bid;
+ coinpp->ask[trexflag] = ask;
+ //coinpp->prevday = jdouble(item,"PrevDay");
+ //printf("iter.%d trexflag.%d %s high %.8f, low %.8f, last %.8f hbla.(%.8f %.8f)\n",iter,trexflag,symbol,coinpp->high[trexflag],coinpp->low[trexflag],coinpp->last[trexflag],coinpp->bid[trexflag],coinpp->ask[trexflag]);
+ if ( coinpp->bid[trexflag] > SMALLVAL && coinpp->ask[trexflag] > SMALLVAL )
+ {
+ price = 0.5 * (coinpp->bid[trexflag] + coinpp->ask[trexflag]);
+ if ( iter == 0 )
+ {
+ if ( strcmp(symbol,"KMD") == 0 )
+ kmdbtc = price;
+ }
+ else
+ {
+ if ( strcmp(symbol,"KMD") == 0 )
+ continue;
+ //printf("(%s/%s) iter.%d trexflag.%d %s %.8f %.8f\n",refpp->symbol,coinpp->symbol,iter,trexflag,symbol,price,price/kmdbtc);
+ price /= kmdbtc;
+ }
+ if ( trexflag == 0 && coinpp->bid[1] > SMALLVAL && coinpp->ask[1] > SMALLVAL )
+ {
+ //printf("have trex: iter.%d trexflag.%d %s %.8f %.8f\n",iter,trexflag,symbol,coinpp->bid[1],coinpp->ask[1]);
+ continue;
+ }
+ LP_autopriceset(ctx,1,refpp,coinpp,price);
+ LP_autopriceset(ctx,-1,coinpp,refpp,price);
+ }
+ }
+ }
+ }
+ }
+ refcoin = "KMD";
+ if ( kmdbtc == 0. || (refpp= LP_priceinfofind("KMD")) == 0 )
+ break;
+ }
+ }
+ free_json(retjson);
+ }
+ return(nxtkmd);
+}
+
+static char *assetids[][3] =
+{
+ { "12071612744977229797", "UNITY", "10000" },
+ { "15344649963748848799", "DEX", "1" },
+ { "6883271355794806507", "PANGEA", "10000" },
+ { "17911762572811467637", "JUMBLR", "10000" },
+ { "17083334802666450484", "BET", "10000" },
+ { "13476425053110940554", "CRYPTO", "1000" },
+ { "6932037131189568014", "HODL", "1" },
+ { "3006420581923704757", "SHARK", "10000" },
+ { "17571711292785902558", "BOTS", "1" },
+ { "10524562908394749924", "MGW", "1" },
+};
+
+void LP_autoprice_iter(void *ctx,struct LP_priceinfo *btcpp)
+{
+ char *retstr; cJSON *retjson,*bid,*ask; uint64_t bidsatoshis,asksatoshis; int32_t i; double nxtkmd,price; struct LP_priceinfo *kmdpp,*fiatpp,*nxtpp;
+ if ( (retstr= issue_curlt("https://bittrex.com/api/v1.1/public/getmarketsummaries",LP_HTTP_TIMEOUT*10)) == 0 )
+ {
+ printf("trex error getting marketsummaries\n");
+ sleep(60);
+ return;
+ }
+ nxtkmd = LP_pricesparse(ctx,1,retstr,btcpp);
+ free(retstr);
+ if ( (retstr= issue_curlt("https://www.cryptopia.co.nz/api/GetMarkets",LP_HTTP_TIMEOUT*10)) == 0 )
+ {
+ printf("cryptopia error getting marketsummaries\n");
+ sleep(60);
+ return;
+ }
+ LP_pricesparse(ctx,0,retstr,btcpp);
+ free(retstr);
+ if ( (kmdpp= LP_priceinfofind("KMD")) != 0 )
+ {
+ for (i=0; i<32; i++)
+ {
+ if ( (fiatpp= LP_priceinfofind(CURRENCIES[i])) != 0 )
+ {
+ if ( (retjson= LP_paxprice(CURRENCIES[i])) != 0 )
+ {
+ //printf("(%s %.8f %.8f) ",CURRENCIES[i],jdouble(retjson,"price"),jdouble(retjson,"invprice"));
+ price = jdouble(retjson,"price");
+ LP_autopriceset(ctx,1,kmdpp,fiatpp,price);
+ LP_autopriceset(ctx,-1,fiatpp,kmdpp,price);
+ free_json(retjson);
+ }
+ }
+ }
+ }
+ if ( nxtkmd > SMALLVAL )
+ {
+ for (i=0; i (%s) nxtkmd %.8f %.8f %.8f\n",assetids[i][1],assetids[i][0],jprint(retjson,0),nxtkmd,0.5*dstr(bidsatoshis + asksatoshis),price);
+ free_json(retjson);
+ }
+ }
+ }
+ }
+}
+
+int32_t LP_portfolio_trade(void *ctx,uint32_t *requestidp,uint32_t *quoteidp,struct iguana_info *buy,struct iguana_info *sell,double relvolume,int32_t setbaserel)
+{
+ char *retstr2; double bid,ask,maxprice; uint32_t requestid,quoteid,iter,i; cJSON *retjson2;
+ requestid = quoteid = 0;
+ LP_myprice(&bid,&ask,buy->symbol,sell->symbol);
+ maxprice = ask;
+ if ( setbaserel != 0 )
+ {
+ strcpy(LP_portfolio_base,"");
+ strcpy(LP_portfolio_rel,"");
+ LP_portfolio_relvolume = 0.;
+ }
+ printf("pending.%d base buy.%s, rel sell.%s relvolume %f maxprice %.8f (%.8f %.8f)\n",LP_pendingswaps,buy->symbol,sell->symbol,sell->relvolume,maxprice,bid,ask);
+ if ( LP_pricevalid(maxprice) > 0 )
+ {
+ relvolume = sell->relvolume;
+ for (iter=0; iter<2; iter++)
+ {
+ if ( relvolume < dstr(LP_MIN_TXFEE) )
+ break;
+ if ( LP_utxo_bestfit(sell->symbol,SATOSHIDEN * relvolume) != 0 )
+ {
+ if ( (retstr2= LP_autotrade(ctx,"127.0.0.1",-1,buy->symbol,sell->symbol,maxprice,relvolume,60,24*3600)) != 0 )
+ {
+ if ( (retjson2= cJSON_Parse(retstr2)) != 0 )
+ {
+ if ( (requestid= juint(retjson2,"requestid")) != 0 && (quoteid= juint(retjson2,"quoteid")) != 0 )
+ {
+
+ }
+ free_json(retjson2);
+ }
+ printf("%s relvolume %.8f LP_autotrade.(%s)\n",sell->symbol,relvolume,retstr2);
+ free(retstr2);
+ }
+ if ( requestid != 0 && quoteid != 0 )
+ break;
+ } else printf("cant find alice %.8f %s\n",relvolume,sell->symbol);
+ if ( iter == 0 )
+ {
+ for (i=0; i<100; i++)
+ {
+ relvolume *= .99;
+ if ( LP_utxo_bestfit(sell->symbol,SATOSHIDEN * relvolume) != 0 )
+ {
+ printf("i.%d relvolume %.8f from %.8f\n",i,relvolume,sell->relvolume);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if ( setbaserel != 0 )
+ {
+ strcpy(LP_portfolio_base,buy->symbol);
+ strcpy(LP_portfolio_rel,sell->symbol);
+ LP_portfolio_relvolume = sell->relvolume;
+ }
+ *requestidp = requestid;
+ *quoteidp = quoteid;
+ if ( requestid != 0 && quoteid != 0 )
+ return(0);
+ else return(-1);
+}
+
+struct LP_portfoliotrade { double metric; char buycoin[16],sellcoin[16]; };
+
+int32_t LP_portfolio_order(struct LP_portfoliotrade *trades,int32_t max,cJSON *array)
+{
+ int32_t i,j,m,n = 0; cJSON *item; struct LP_portfoliotrade coins[256];
+ memset(coins,0,sizeof(coins));
+ if ( (m= cJSON_GetArraySize(array)) > 0 )
+ {
+ for (i=j=0; i SMALLVAL && coins[j].buycoin[0] != 0 )
+ j++;
+ }
+ if ( (m= j) > 1 )
+ {
+ for (i=n=0; i 0. )
+ {
+ trades[n].metric = (coins[i].metric - coins[j].metric);
+ strcpy(trades[n].buycoin,coins[i].buycoin);
+ strcpy(trades[n].sellcoin,coins[j].buycoin);
+ printf("buy %s %f, sell %s %f -> %f\n",trades[n].buycoin,coins[i].metric,trades[n].sellcoin,coins[j].metric,trades[n].metric);
+ }
+ else
+ {
+ trades[n].metric = (coins[j].metric - coins[i].metric);
+ strcpy(trades[n].buycoin,coins[j].buycoin);
+ strcpy(trades[n].sellcoin,coins[i].buycoin);
+ printf("buy %s %f, sell %s %f -> %f\n",trades[n].buycoin,coins[j].metric,trades[n].sellcoin,coins[i].metric,trades[n].metric);
+ }
+ n++;
+ if ( n >= max )
+ break;
+ }
+ revsortds((void *)trades,n,sizeof(*trades));
+ for (i=0; i %f\n",i,trades[i].buycoin,trades[i].sellcoin,trades[i].metric);
+ }
+ }
+ return(n);
+}
+
+void prices_loop(void *ignore)
+{
+ char *retstr; cJSON *retjson,*array; char *buycoin,*sellcoin; struct iguana_info *buy,*sell; uint32_t requestid,quoteid; int32_t i,n,m; struct LP_portfoliotrade trades[256]; struct LP_priceinfo *btcpp; void *ctx = bitcoin_ctx();
+ while ( 1 )
+ {
+ if ( (btcpp= LP_priceinfofind("BTC")) == 0 )
+ {
+ sleep(60);
+ continue;
+ }
+ if ( LP_autoprices != 0 )
+ LP_autoprice_iter(ctx,btcpp);
+ if ( (retstr= LP_portfolio()) != 0 )
+ {
+ if ( (retjson= cJSON_Parse(retstr)) != 0 )
+ {
+ if ( (buycoin= jstr(retjson,"buycoin")) != 0 && (buy= LP_coinfind(buycoin)) != 0 && (sellcoin= jstr(retjson,"sellcoin")) != 0 && (sell= LP_coinfind(sellcoin)) != 0 && buy->inactive == 0 && sell->inactive == 0 )
+ {
+ if ( LP_portfolio_trade(ctx,&requestid,"eid,buy,sell,sell->relvolume,1) < 0 )
+ {
+ array = jarray(&m,retjson,"portfolio");
+ if ( array != 0 && (n= LP_portfolio_order(trades,(int32_t)(sizeof(trades)/sizeof(*trades)),array)) > 0 )
+ {
+ for (i=0; irelvolume,0) == 0 )
+ break;
+ }
+ }
+ }
+ }
+ }
+ free_json(retjson);
+ }
+ free(retstr);
+ }
+ sleep(60);
+ }
+}
+
+
diff --git a/iguana/exchanges/LP_prices.c b/iguana/exchanges/LP_prices.c
new file mode 100644
index 000000000..d68ae2257
--- /dev/null
+++ b/iguana/exchanges/LP_prices.c
@@ -0,0 +1,849 @@
+
+/******************************************************************************
+ * 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
+//
+
+struct LP_orderbookentry { bits256 txid,txid2,pubkey; double price; uint64_t basesatoshis; int32_t vout,vout2,age; };
+
+#define LP_MAXPRICEINFOS 256
+struct LP_priceinfo
+{
+ char symbol[16];
+ uint64_t coinbits;
+ int32_t ind,pad;
+ double diagval,high[2],low[2],last[2],bid[2],ask[2]; //volume,btcvolume,prevday; // mostly bittrex info
+ double relvals[LP_MAXPRICEINFOS];
+ double myprices[LP_MAXPRICEINFOS];
+ double minprices[LP_MAXPRICEINFOS]; // autoprice
+ double margins[LP_MAXPRICEINFOS];
+ //double maxprices[LP_MAXPRICEINFOS]; // autofill of base/rel
+ //double relvols[LP_MAXPRICEINFOS];
+ FILE *fps[LP_MAXPRICEINFOS];
+} LP_priceinfos[LP_MAXPRICEINFOS];
+int32_t LP_numpriceinfos;
+
+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;
+
+struct LP_pubkeyinfo
+{
+ UT_hash_handle hh;
+ bits256 pubkey;
+ double matrix[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS];
+ uint32_t timestamp,istrusted,numerrors;
+} *LP_pubkeyinfos;
+
+int32_t LP_pricevalid(double price)
+{
+ if ( price > SMALLVAL && isnan(price) == 0 && price < SATOSHIDEN )
+ return(1);
+ else return(0);
+}
+
+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);
+ 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;
+ 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 ( base == 0 || rel == 0 )
+ return(0);
+ 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);
+}
+
+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);
+ pubp = calloc(1,sizeof(*pubp));
+ pubp->pubkey = pubkey;
+ 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");
+ }
+ 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_trustset(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;
+ obj = cJSON_CreateObject();
+ array = cJSON_CreateArray();
+ for (baseid=0; baseidmatrix[baseid][relid];
+ if ( LP_pricevalid(price) > 0 )
+ {
+ item = cJSON_CreateArray();
+ jaddistr(item,base);
+ jaddistr(item,LP_priceinfos[relid].symbol);
+ jaddinum(item,price);
+ jaddi(array,item);
+ }
+ }
+ }
+ 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);
+}
+
+char *LP_prices()
+{
+ struct LP_pubkeyinfo *pubp,*tmp; cJSON *array = cJSON_CreateArray();
+ HASH_ITER(hh,LP_pubkeyinfos,pubp,tmp)
+ {
+ jaddi(array,LP_pubkeyjson(pubp));
+ }
+ return(jprint(array,1));
+}
+
+void LP_prices_parse(cJSON *obj)
+{
+ struct LP_pubkeyinfo *pubp; struct LP_priceinfo *basepp,*relpp; 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 )
+ {
+ if ( (timestamp= juint(obj,"timestamp")) > pubp->timestamp && (asks= jarray(&n,obj,"asks")) != 0 )
+ {
+ pubp->timestamp = timestamp;
+ for (i=0; i 0 )
+ {
+ if ( (basepp= LP_priceinfoptr(&relid,base,rel)) != 0 )
+ {
+ char str[65]; printf("%s %s/%s (%d/%d) %.8f\n",bits256_str(str,pubkey),base,rel,basepp->ind,relid,askprice);
+ pubp->matrix[basepp->ind][relid] = askprice;
+ if ( (relpp= LP_priceinfofind(rel)) != 0 )
+ {
+ dxblend(&basepp->relvals[relpp->ind],askprice,0.9);
+ dxblend(&relpp->relvals[basepp->ind],1. / askprice,0.9);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+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 )
+ {
+ 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 )
+ {
+ ptr->price = (double)ptr->Q.destsatoshis / ptr->Q.satoshis;
+ if ( LP_pricevalid(ptr->price) <= 0 )
+ ptr->price = 0.;
+ //printf("LP_pricecache: set %s/%s ptr->price %.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);
+ return(0.);
+}
+
+void LP_priceinfoupdate(char *base,char *rel,double price)
+{
+ struct LP_priceinfo *basepp,*relpp;
+ if ( LP_pricevalid(price) > 0 )
+ {
+ 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);
+ basepp->relvals[relpp->ind] = price;
+ relpp->relvals[basepp->ind] = 1. / 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 )
+ {
+ *askp = basepp->myprices[relpp->ind];
+ if ( LP_pricevalid(*askp) > 0 )
+ {
+ val = relpp->myprices[basepp->ind];
+ if ( LP_pricevalid(val) > 0 )
+ {
+ *bidp = 1. / val;
+ return((*askp + *bidp) * 0.5);
+ }
+ else
+ {
+ *bidp = 0.;
+ return(*askp);
+ }
+ }
+ else
+ {
+ val = relpp->myprices[basepp->ind];
+ if ( LP_pricevalid(val) > 0 )
+ {
+ *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(int32_t *changedp,char *base,char *rel,double price)
+{
+ struct LP_priceinfo *basepp,*relpp; struct LP_pubkeyinfo *pubp;
+ *changedp = 0;
+ if ( base != 0 && rel != 0 && LP_pricevalid(price) > 0 && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 )
+ {
+ if ( fabs(basepp->myprices[relpp->ind] - price) > SMALLVAL )
+ *changedp = 1;
+ basepp->myprices[relpp->ind] = price; // ask
+ //printf("LP_mypriceset base.%s rel.%s <- price %.8f\n",base,rel,price);
+ //relpp->myprices[basepp->ind] = (1. / price); // bid
+ if ( (pubp= LP_pubkeyadd(LP_mypub25519)) != 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);
+}
+
+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-3600*2 || 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 > SMALLVAL )
+ {
+ sum += val;
+ n++;
+ }
+ }
+ if ( n > 0 )
+ {
+ pp->diagval = sum / n;
+ total += pp->diagval, m++;
+ }
+ }
+ if ( m > 0 )
+ {
+ pp = LP_priceinfos;
+ for (i=0; idiagval > SMALLVAL )
+ {
+ pp->diagval /= total;
+ jaddnum(vectorjson,pp->symbol,pp->diagval);
+ }
+ }
+ }
+ return(vectorjson);
+}
+
+struct LP_priceinfo *LP_priceinfoadd(char *symbol)
+{
+ struct LP_priceinfo *pp; cJSON *retjson;
+ if ( symbol == 0 )
+ return(0);
+ 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));
+ pp->coinbits = stringbits(symbol);
+ pp->ind = LP_numpriceinfos++;
+ LP_numpriceinfos++;
+ if ( (retjson= LP_priceinfomatrix(0)) != 0 )
+ free_json(retjson);
+ return(pp);
+}
+
+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 ( LP_pricevalid(price) > 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->Q = *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);
+ } else ptr->price = price;
+ }
+ return(ptr);
+}
+
+static int _cmp_orderbook(const void *a,const void *b)
+{
+ int32_t retval = 0;
+#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
+ {
+#undef ptr_a
+#undef ptr_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);
+ }
+ // printf("%.8f vs %.8f -> %d\n",ptr_a,ptr_b,retval);
+ return(retval);
+#undef ptr_a
+#undef ptr_b
+}
+
+cJSON *LP_orderbookjson(struct LP_orderbookentry *op)
+{
+ cJSON *item = cJSON_CreateObject();
+ if ( LP_pricevalid(op->price) > 0 )
+ {
+ jaddnum(item,"price",op->price);
+ jaddnum(item,"volume",dstr(op->basesatoshis));
+ jaddbits256(item,"txid",op->txid);
+ jaddnum(item,"vout",op->vout);
+ jaddbits256(item,"pubkey",op->pubkey);
+ jaddnum(item,"age",op->age);
+ }
+ 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,bits256 pubkey,int32_t age)
+{
+ 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;
+ op->pubkey = pubkey;
+ op->age = age;
+ }
+ 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) || (array[i]->vout2 == vout && bits256_cmp(array[i]->txid2,txid) == 0) )
+ return(i);
+ 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,int32_t duration)
+{
+ struct LP_utxoinfo *utxo,*tmp; struct LP_pubkeyinfo *pubp=0; struct LP_priceinfo *basepp; struct LP_orderbookentry *op; uint32_t oldest; double price; int32_t baseid,relid; uint64_t basesatoshis,val,val2;
+ if ( (basepp= LP_priceinfoptr(&relid,base,rel)) != 0 )
+ baseid = basepp->ind;
+ else return(num);
+ now = (uint32_t)time(NULL);
+ oldest = now - duration;
+ HASH_ITER(hh,LP_utxoinfos[1],utxo,tmp)
+ {
+ if ( pubp == 0 || bits256_cmp(pubp->pubkey,utxo->pubkey) != 0 )
+ pubp = LP_pubkeyfind(utxo->pubkey);
+ 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 && pubp->timestamp > oldest && pubp->timestamp <= now )
+ {
+ if ( LP_orderbookfind(*arrayp,cachednum,utxo->payment.txid,utxo->payment.vout) < 0 )
+ {
+ if ( LP_iseligible(&val,&val2,utxo->iambob,utxo->coin,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,utxo->deposit.txid,utxo->deposit.vout) == 0 )
+ continue;
+ 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,now - pubp->timestamp)) != 0 )
+ {
+ *arrayp = realloc(*arrayp,sizeof(*(*arrayp)) * (num+1));
+ (*arrayp)[num++] = op;
+ if ( LP_ismine(utxo) > 0 && utxo->T.lasttime == 0 )
+ LP_utxo_clientpublish(utxo);
+ }
+ }
+ }
+ }
+ return(num);
+}
+
+char *LP_orderbook(char *base,char *rel,int32_t duration)
+{
+ 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\"}"));
+ if ( duration <= 0 )
+ duration = LP_ORDERBOOK_DURATION;
+ baseid = basepp->ind;
+ relid = relpp->ind;
+ now = (uint32_t)time(NULL);
+ 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,duration);
+ numbids = LP_orderbook_utxoentries(now,-1,rel,base,&bids,numbids,cachenumbids,duration);
+ retjson = cJSON_CreateObject();
+ array = cJSON_CreateArray();
+ if ( numbids > 1 )
+ qsort(bids,numbids,sizeof(*bids),_cmp_orderbook);
+ 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 SMALLVAL && origprice < price )
+ price = origprice;
+ }
+ if ( LP_pricevalid(price) > 0 )
+ {
+ retjson = cJSON_CreateObject();
+ jaddstr(retjson,"result","success");
+ jaddstr(retjson,"method","postprice");
+ jaddbits256(retjson,"pubkey",LP_mypub25519);
+ 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\"}"));
+}
+
+void LP_priceupdate(char *base,char *rel,double price,double avebid,double aveask,double highbid,double lowask,double PAXPRICES[32])
+{
+ LP_priceinfoupdate(base,rel,price);
+}
+
+void LP_pricefname(char *fname,char *base,char *rel)
+{
+ sprintf(fname,"%s/PRICES/%s_%s",GLOBAL_DBDIR,base,rel);
+ OS_compatible_path(fname);
+}
+
+void LP_priceitemadd(cJSON *retarray,uint32_t timestamp,double avebid,double aveask,double highbid,double lowask)
+{
+ cJSON *item = cJSON_CreateArray();
+ jaddinum(item,timestamp);
+ jaddinum(item,avebid);
+ jaddinum(item,aveask);
+ jaddinum(item,highbid);
+ jaddinum(item,lowask);
+ jaddi(retarray,item);
+}
+
+cJSON *LP_pricearray(char *base,char *rel,uint32_t firsttime,uint32_t lasttime,int32_t timescale)
+{
+ cJSON *retarray; char askfname[1024],bidfname[1024]; uint64_t bidprice64,askprice64; uint32_t bidnow,asknow,bidi,aski,lastbidi,lastaski; int32_t numbids,numasks; double bidemit,askemit,bidsum,asksum,bid,ask,highbid,lowbid,highask,lowask,bidemit2,askemit2; FILE *askfp=0,*bidfp=0;
+ if ( timescale <= 0 )
+ timescale = 60;
+ if ( lasttime == 0 )
+ lasttime = (uint32_t)-1;
+ LP_pricefname(askfname,base,rel);
+ LP_pricefname(bidfname,rel,base);
+ retarray = cJSON_CreateArray();
+ lastbidi = lastaski = 0;
+ numbids = numasks = 0;
+ bidsum = asksum = askemit = bidemit = highbid = lowbid = highask = lowask = 0.;
+ if ( (bidfp= fopen(bidfname,"rb")) != 0 && (askfp= fopen(askfname,"rb")) != 0 )
+ {
+ while ( bidfp != 0 || askfp != 0 )
+ {
+ bidi = aski = 0;
+ bidemit = askemit = bidemit2 = askemit2 = 0.;
+ if ( bidfp != 0 && fread(&bidnow,1,sizeof(bidnow),bidfp) == sizeof(bidnow) && fread(&bidprice64,1,sizeof(bidprice64),bidfp) == sizeof(bidprice64) )
+ {
+ //printf("bidnow.%u %.8f\n",bidnow,dstr(bidprice64));
+ if ( bidnow != 0 && bidprice64 != 0 && bidnow >= firsttime && bidnow <= lasttime )
+ {
+ bidi = bidnow / timescale;
+ if ( bidi != lastbidi )
+ {
+ if ( bidsum != 0. && numbids != 0 )
+ {
+ bidemit = bidsum / numbids;
+ bidemit2 = highbid;
+ }
+ bidsum = highbid = lowbid = 0.;
+ numbids = 0;
+ }
+ if ( (bid= 1. / dstr(bidprice64)) != 0. )
+ {
+ if ( bid > highbid )
+ highbid = bid;
+ if ( lowbid == 0. || bid < lowbid )
+ lowbid = bid;
+ bidsum += bid;
+ numbids++;
+ //printf("bidi.%u num.%d %.8f [%.8f %.8f]\n",bidi,numbids,bid,lowbid,highbid);
+ }
+ }
+ } else fclose(bidfp), bidfp = 0;
+ if ( askfp != 0 && fread(&asknow,1,sizeof(asknow),askfp) == sizeof(asknow) && fread(&askprice64,1,sizeof(askprice64),askfp) == sizeof(askprice64) )
+ {
+ //printf("asknow.%u %.8f\n",asknow,dstr(askprice64));
+ if ( asknow != 0 && askprice64 != 0 && asknow >= firsttime && asknow <= lasttime )
+ {
+ aski = asknow / timescale;
+ if ( aski != lastaski )
+ {
+ if ( asksum != 0. && numasks != 0 )
+ {
+ askemit = asksum / numasks;
+ askemit2 = lowask;
+ }
+ asksum = highask = lowask = 0.;
+ numasks = 0;
+ }
+ if ( (ask= dstr(askprice64)) != 0. )
+ {
+ if ( ask > highask )
+ highask = ask;
+ if ( lowask == 0. || ask < lowask )
+ lowask = ask;
+ asksum += ask;
+ numasks++;
+ //printf("aski.%u num.%d %.8f [%.8f %.8f]\n",aski,numasks,ask,lowask,highask);
+ }
+ }
+ } else fclose(askfp), askfp = 0;
+ if ( bidemit != 0. || askemit != 0. )
+ {
+ if ( bidemit != 0. && askemit != 0. && lastbidi == lastaski )
+ {
+ LP_priceitemadd(retarray,lastbidi * timescale,bidemit,askemit,bidemit2,askemit2);
+ highbid = lowbid = highask = lowask = 0.;
+ }
+ else
+ {
+ if ( bidemit != 0. )
+ {
+ printf("bidonly %.8f %.8f\n",bidemit,highbid);
+ LP_priceitemadd(retarray,lastbidi * timescale,bidemit,0.,bidemit2,0.);
+ highbid = lowbid = 0.;
+ }
+ if ( askemit != 0. )
+ {
+ printf("askonly %.8f %.8f\n",askemit,lowask);
+ LP_priceitemadd(retarray,lastaski * timescale,0.,askemit,0.,askemit2);
+ highask = lowask = 0.;
+ }
+ }
+ }
+ if ( bidi != 0 )
+ lastbidi = bidi;
+ if ( aski != 0 )
+ lastaski = aski;
+ }
+ } else printf("couldnt open either %s %p or %s %p\n",bidfname,bidfp,askfname,askfp);
+ if ( bidfp != 0 )
+ fclose(bidfp);
+ if ( askfp != 0 )
+ fclose(askfp);
+ return(retarray);
+}
+
+void LP_pricefeedupdate(bits256 pubkey,char *base,char *rel,double price)
+{
+ struct LP_priceinfo *basepp,*relpp; uint32_t now; uint64_t price64; struct LP_pubkeyinfo *pubp; char str[65],fname[512]; FILE *fp;
+ //printf("check PRICEFEED UPDATE.(%s/%s) %.8f %s\n",base,rel,price,bits256_str(str,pubkey));
+ if ( LP_pricevalid(price) > 0 && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 )
+ {
+ if ( (fp= basepp->fps[relpp->ind]) == 0 )
+ {
+ LP_pricefname(fname,base,rel);
+ fp = basepp->fps[relpp->ind] = OS_appendfile(fname);
+ }
+ if ( fp != 0 )
+ {
+ now = (uint32_t)time(NULL);
+ price64 = price * SATOSHIDEN;
+ fwrite(&now,1,sizeof(now),fp);
+ fwrite(&price64,1,sizeof(price64),fp);
+ fflush(fp);
+ }
+ if ( (fp= relpp->fps[basepp->ind]) == 0 )
+ {
+ sprintf(fname,"%s/PRICES/%s_%s",GLOBAL_DBDIR,rel,base);
+ fp = relpp->fps[basepp->ind] = OS_appendfile(fname);
+ }
+ if ( fp != 0 )
+ {
+ now = (uint32_t)time(NULL);
+ price64 = (1. / price) * SATOSHIDEN;
+ fwrite(&now,1,sizeof(now),fp);
+ fwrite(&price64,1,sizeof(price64),fp);
+ fflush(fp);
+ }
+ if ( (pubp= LP_pubkeyadd(pubkey)) != 0 )
+ {
+ if ( (rand() % 100) == 0 && fabs(pubp->matrix[basepp->ind][relpp->ind] - price) > SMALLVAL )
+ printf("PRICEFEED UPDATE.(%-6s/%6s) %12.8f %s %12.8f\n",base,rel,price,bits256_str(str,pubkey),1./price);
+ {
+ pubp->matrix[basepp->ind][relpp->ind] = price;
+ dxblend(&basepp->relvals[relpp->ind],price,0.9);
+ dxblend(&relpp->relvals[basepp->ind],1. / price,0.9);
+ }
+ pubp->timestamp = (uint32_t)time(NULL);
+ } else printf("error creating pubkey entry\n");
+ }
+ else if ( (rand() % 100) == 0 )
+ printf("error finding %s/%s %.8f\n",base,rel,price);
+}
+
diff --git a/iguana/exchanges/LP_remember.c b/iguana/exchanges/LP_remember.c
new file mode 100644
index 000000000..9e25a6241
--- /dev/null
+++ b/iguana/exchanges/LP_remember.c
@@ -0,0 +1,1075 @@
+
+/******************************************************************************
+ * 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
+//
+
+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 )
+ {
+ LP_swap_coinaddr(swap,&swap->bobcoin,coinaddr,rawtx->txbytes,rawtx->I.datalen);
+ if ( coinaddr[0] != 0 )
+ {
+ 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));
+ }
+ }
+ }
+ 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.taddr,swap->alicecoin.p2shtype,swap->I.pubAm,swap->I.pubBn);
+ 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);
+ 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,\"Atxfee\":%llu,\"Btxfee\":%llu",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,(long long)swap->I.Atxfee,(long long)swap->I.Btxfee);
+ 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 basilisk_swap *swap,struct basilisk_rawtx *rawtx)
+{
+ bits256 triggertxid;
+ memset(triggertxid.bytes,0,sizeof(triggertxid));
+ if ( rawtx == 0 )
+ {
+ basilisk_dontforget(swap,0,0,triggertxid);
+ return;
+ }
+ 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 )
+ {
+ 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 )
+ {
+ basilisk_dontforget(swap,&swap->bobrefund,0,triggertxid);
+ basilisk_dontforget(swap,&swap->aliceclaim,0,swap->bobrefund.I.actualtxid);
+ }
+ else if ( rawtx == &swap->alicepayment )
+ {
+ basilisk_dontforget(swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid);
+ }
+ else if ( rawtx == &swap->bobspend )
+ {
+ basilisk_dontforget(swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid);
+ basilisk_dontforget(swap,&swap->bobspend,0,swap->alicepayment.I.actualtxid);
+ }
+ else if ( rawtx == &swap->alicereclaim )
+ {
+ basilisk_dontforget(swap,&swap->alicepayment,0,swap->bobdeposit.I.actualtxid);
+ basilisk_dontforget(swap,&swap->alicereclaim,0,swap->bobrefund.I.actualtxid);
+ }
+ else if ( rawtx == &swap->bobpayment )
+ {
+ basilisk_dontforget(swap,&swap->bobpayment,0,triggertxid);
+ basilisk_dontforget(swap,&swap->bobreclaim,swap->bobpayment.I.locktime,triggertxid);
+ }
+ else if ( rawtx == &swap->alicespend )
+ {
+ basilisk_dontforget(swap,&swap->bobpayment,0,triggertxid);
+ basilisk_dontforget(swap,&swap->alicespend,0,triggertxid);
+ }
+ else if ( rawtx == &swap->bobreclaim )
+ 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
+ memset(&privkey,0,sizeof(privkey));
+ if ( (scriptlen= basilisk_swap_getsigscript(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(bits256 *bobrefundp,char *bobcoin,bits256 bobdeposit,bits256 privBn)
+{
+ char destaddr[64];
+ if ( bits256_nonz(privBn) == 0 )
+ {
+ if ( bits256_nonz(bobdeposit) != 0 )
+ *bobrefundp = LP_swap_spendtxid(bobcoin,destaddr,bobdeposit,0);
+ if ( bits256_nonz(*bobrefundp) != 0 )
+ privBn = basilisk_swap_privbob_extract(bobcoin,*bobrefundp,0,0);
+ }
+ return(privBn);
+}
+
+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];
+ 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 = LP_swap_spendtxid(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;
+ sentflags[bobspent] = 0;
+ 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;
+ sentflags[alicespent] = 0;
+ txids[bobspent] = spendtxid;
+ }
+ else
+ {
+ //printf("OTHER dest spent.(%s) -> %s\n",bits256_str(str,txid),destaddr);
+ if ( aliceaddr != 0 )
+ {
+ sentflags[bobspent] = 1;
+ sentflags[alicespent] = 0;
+ txids[bobspent] = spendtxid;
+ }
+ else if ( bobaddr != 0 )
+ {
+ sentflags[alicespent] = 1;
+ sentflags[bobspent] = 0;
+ 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>= 1;
+ decode_hex(redeem,len,redeemstr);
+ t = redeem[5];
+ t = (t << 8) | redeem[4];
+ t = (t << 8) | redeem[3];
+ t = (t << 8) | redeem[2];
+ //printf("extracted timestamp.%u\n",t);
+ }
+ }
+ free(filestr);
+ }
+ return(t);
+}
+
+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,Predeemlen,Dredeemlen,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],Predeemscript[1024],Dredeemscript[1024],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,*rstr,*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 Atxfee=0,Btxfee=0;
+ if ( ctx == 0 )
+ ctx = bitcoin_ctx();
+ bobpaymentaddr[0] = bobdepositaddr[0] = alicepaymentaddr[0] = 0;
+ memset(Predeemscript,0,sizeof(Predeemscript));
+ memset(Dredeemscript,0,sizeof(Dredeemscript));
+ Predeemlen = Dredeemlen = 0;
+ memset(values,0,sizeof(values));
+ 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));
+ 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);
+ if ( (fstr= OS_filestr(&fsize,fname)) != 0 )
+ {
+ 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) == 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) == 64 )
+ decode_hex(secretBn256,32,secretstr);
+ if ( (srcstr= jstr(item,"src")) != 0 )
+ safecopy(src,srcstr,sizeof(src));
+ 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);
+ }
+ if ( (plocktime= juint(item,"plocktime")) == 0 )
+ plocktime = LP_extract(requestid,quoteid,fname,"plocktime");
+ if ( (dlocktime= juint(item,"dlocktime")) == 0 )
+ dlocktime = LP_extract(requestid,quoteid,fname,"dlocktime");
+ r = juint(item,"requestid");
+ q = juint(item,"quoteid");
+ Atxfee = j64bits(item,"Atxfee");
+ Btxfee = j64bits(item,"Btxfee");
+ 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;
+ //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));
+ }
+ 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);
+ }
+ 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,"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 ( 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"));
+ //printf("[%s] TX.(%s)\n",txnames[i],txbytes[i]);
+ }
+ if ( strcmp(txnames[i],"bobpayment") == 0 && (rstr= jstr(txobj,"redeem")) != 0 && (Predeemlen= is_hexstr(rstr,0)) > 0 )
+ {
+ Predeemlen >>= 1;
+ decode_hex(Predeemscript,Predeemlen,rstr);
+ }
+ else if ( strcmp(txnames[i],"bobdeposit") == 0 && (rstr= jstr(txobj,"redeem")) != 0 && (Dredeemlen= is_hexstr(rstr,0)) > 0 )
+ {
+ Dredeemlen >>= 1;
+ decode_hex(Dredeemscript,Dredeemlen,rstr);
+ }
+ 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= LP_gettx(symbol,txid)) == 0 )
+ {
+ char str2[65]; printf("%s %s ready to broadcast\n",symbol,bits256_str(str2,txid));
+ }
+ else
+ {
+ 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,txid)) > 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 )
+ {
+ //printf(">>>>>> %s txid %s\n",jprint(sentobj,0),bits256_str(str,txid));
+ sentflags[i] = 1;
+ }
+ 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);
+ } else if ( 0 && 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;
+ if ( bobcoin[0] == 0 || alicecoin[0] == 0 )
+ return(0);
+ Atxfee = LP_txfeecalc(alicecoin,Atxfee);
+ Btxfee = LP_txfeecalc(bobcoin,Btxfee);
+ //printf("%s %.8f txfee, %s %.8f txfee\n",alicecoin,dstr(Atxfee),bobcoin,dstr(Btxfee));
+ //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 ( (alice= LP_coinfind(alicecoin)) != 0 )
+ {
+ bitcoin_address(Adestaddr,alice->taddr,alice->pubtype,pubkey33,33);
+ AAdest = Adestaddr;
+ }
+ if ( (bob= LP_coinfind(bobcoin)) != 0 )
+ {
+ bitcoin_address(destaddr,bob->taddr,bob->pubtype,pubkey33,33);
+ Adest = destaddr;
+ }
+ }
+ else
+ {
+ if ( (bob= LP_coinfind(bobcoin)) != 0 )
+ {
+ bitcoin_address(destaddr,bob->taddr,bob->pubtype,pubkey33,33);
+ Bdest = destaddr;
+ }
+ if ( (alice= LP_coinfind(alicecoin)) != 0 )
+ {
+ bitcoin_address(Adestaddr,alice->taddr,alice->pubtype,pubkey33,33);
+ ABdest = Adestaddr;
+ }
+ }
+ if ( bob == 0 || alice == 0 )
+ {
+ printf("Bob.%p is null or Alice.%p is null\n",bob,alice);
+ return(0);
+ }
+ if ( alice->inactive != 0 || bob->inactive != 0 )
+ {
+ printf("Alice.%s inactive.%u or Bob.%s inactive.%u\n",alicecoin,alice->inactive,bobcoin,bob->inactive);
+ return(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= LP_gettx(alicecoin,txids[BASILISK_ALICEPAYMENT])) != 0 )
+ {
+ sentflags[BASILISK_ALICEPAYMENT] = 1;
+ free_json(sentobj);
+ }
+ }
+ 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 )
+ {
+ 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));
+ if ( Predeemlen != 0 )
+ redeemlen = Predeemlen, memcpy(redeemscript,Predeemscript,Predeemlen);
+ else 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]);
+ 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,Btxfee,"alicespend",bobcoin,bob->wiftaddr,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]);
+ }
+ }
+ if ( txbytes[BASILISK_ALICESPEND] != 0 )
+ {
+ txids[BASILISK_ALICESPEND] = LP_broadcast("alicespend",bobcoin,txbytes[BASILISK_ALICESPEND],zero);
+ 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 )
+ {
+ if ( Dredeemlen != 0 )
+ redeemlen = Dredeemlen, memcpy(redeemscript,Dredeemscript,Dredeemlen);
+ else 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(&signedtxid,Btxfee,"aliceclaim",bobcoin,bob->wiftaddr,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]);
+ }
+ }
+ if ( txbytes[BASILISK_ALICECLAIM] != 0 )
+ {
+ txids[BASILISK_ALICECLAIM] = LP_broadcast("aliceclaim",bobcoin,txbytes[BASILISK_ALICECLAIM],zero);
+ 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(&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,Atxfee,alice->wiftaddr,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]);
+ }
+ }
+ if ( txbytes[BASILISK_ALICERECLAIM] != 0 )
+ {
+ txids[BASILISK_ALICERECLAIM] = LP_broadcast("alicereclaim",alicecoin,txbytes[BASILISK_ALICERECLAIM],zero);
+ 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(bobcoin,txids[BASILISK_ALICESPEND],0,1);
+ }
+ if ( bits256_nonz(privAm) != 0 && bits256_nonz(privBn) != 0 )
+ {
+ if ( (txbytes[BASILISK_BOBSPEND]= basilisk_swap_Aspend("bobspend",alicecoin,Atxfee,alice->wiftaddr,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]);
+ }
+ }
+ if ( txbytes[BASILISK_BOBSPEND] != 0 )
+ {
+ txids[BASILISK_BOBSPEND] = LP_broadcast("bobspend",alicecoin,txbytes[BASILISK_BOBSPEND],zero);
+ 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(&signedtxid,Btxfee,"bobrefund",bobcoin,bob->wiftaddr,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++)
+ 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] = LP_broadcast("bobreclaim",bobcoin,txbytes[BASILISK_BOBRECLAIM],zero);
+ 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(&signedtxid,Btxfee,"bobrefund",bobcoin,bob->wiftaddr,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 )
+ {
+ txids[BASILISK_BOBREFUND] = LP_broadcast("bobrefund",bobcoin,txbytes[BASILISK_BOBREFUND],zero);
+ if ( bits256_nonz(txids[BASILISK_BOBREFUND]) != 0 ) // tested
+ {
+ sentflags[BASILISK_BOBREFUND] = 1;
+ depositspent = txids[BASILISK_BOBREFUND];
+ }
+ }
+ } else printf("bobrefund's 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(swap));
+ flag = 1;
+ break;
+ }*/
+ if ( flag == 0 )
+ {
+ if ( (item= basilisk_remember(KMDtotals,BTCtotals,requestid,quoteid)) != 0 )
+ {
+ jaddi(array,item);
+ //if ( (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);*/
+ portable_mutex_unlock(&LP_swaplistmutex);
+ return(jprint(retjson,1));
+}
+
+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 )
+ {
+ if ( (retjson= cJSON_Parse(liststr)) != 0 )
+ {
+ if ( (array= jarray(&n,retjson,"swaps")) != 0 )
+ {
+ for (i=0; ierrors < maxerrs || peer->good >= LP_MINPEER_GOOD) )
+ {
+ if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 )
+ {
+ if ( peer != 0 )
+ {
+ peer->errors++;
+ peer->good *= LP_PEERGOOD_ERRORDECAY;
+ } else printf("%s error on (%s:%u) without peer\n",debugstr,destip,port);
+ }
+ else if ( peer != 0 )
+ peer->good++;
+ }
+ 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,int32_t numpeers,int32_t numutxos)
+{
+ char url[512],*retstr;
+ sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,numpeers,numutxos);
+ retstr = LP_issue_curl("getpeers",destip,port,url);
+ //printf("%s -> getpeers.(%s)\n",destip,retstr);
+ return(retstr);
+}
+
+char *issue_LP_numutxos(char *destip,uint16_t destport,char *ipaddr,uint16_t port,int32_t numpeers,int32_t numutxos)
+{
+ char url[512],*retstr;
+ sprintf(url,"http://%s:%u/api/stats/numutxos?ipaddr=%s&port=%u&numpeers=%d&numutxos=%d",destip,destport,ipaddr,port,numpeers,numutxos);
+ retstr = LP_issue_curl("numutxos",destip,port,url);
+ //printf("%s -> getpeers.(%s)\n",destip,retstr);
+ return(retstr);
+}
+
+char *issue_LP_getutxos(char *destip,uint16_t destport,char *coin,int32_t lastn,char *ipaddr,uint16_t port,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&numpeers=%d&numutxos=%d",destip,destport,coin,lastn,ipaddr,port,numpeers,numutxos);
+ 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;
+ sprintf(url,"http://%s:%u/api/stats/getutxos?coin=%s&lastn=%d&ipaddr=127.0.0.1&port=0",destip,destport,coin,lastn);
+ return(LP_issue_curl("clientgetutxos",destip,destport,url));
+ //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,int32_t numpeers,int32_t numutxos,uint32_t sessionid)
+{
+ 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&numpeers=%d&numutxos=%d&session=%u",destip,destport,ipaddr,port,numpeers,numutxos,sessionid);
+ return(LP_issue_curl("notify",destip,destport,url));
+ //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(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)
+{
+ char *retstr; cJSON *retjson = 0;
+ 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 || strcmp(method,"validateaddress") == 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);
+ retjson = cJSON_Parse(retstr);
+ free(retstr);
+ }
+ //usleep(100);
+ //printf("dpow_gettxout.(%s)\n",retstr);
+ } else retjson = cJSON_Parse("{\"result\":\"disabled\"}");
+ } else printf("bitcoin_json cant talk to NULL coin\n");
+ return(retjson);
+}
+
+void LP_unspents_mark(char *symbol,cJSON *vins)
+{
+ printf("LOCK (%s)\n",jprint(vins,0));
+}
+
+char *NXTnodes[] = { "62.75.159.113", "91.44.203.238", "82.114.88.225", "78.63.207.76", "188.174.110.224", "91.235.72.49", "213.144.130.91", "209.222.98.250", "216.155.128.10", "178.33.203.157", "162.243.122.251", "69.163.47.173", "193.151.106.129", "78.94.2.74", "192.3.196.10", "173.33.112.87", "104.198.173.28", "35.184.154.126", "174.140.167.239", "23.88.113.131", "198.71.84.173", "178.150.207.53", "23.88.61.53", "192.157.233.106", "192.157.241.212", "23.89.192.88", "23.89.200.27", "192.157.241.139", "23.89.200.63", "23.89.192.98", "163.172.214.102", "176.9.85.5", "80.150.243.88", "80.150.243.92", "80.150.243.98", "109.70.186.198", "146.148.84.237", "104.155.56.82", "104.197.157.140", "37.48.73.249", "146.148.77.226", "84.57.170.200", "107.161.145.131", "80.150.243.97", "80.150.243.93", "80.150.243.100", "80.150.243.95", "80.150.243.91", "80.150.243.99", "80.150.243.96", "93.231.187.177", "212.237.23.85", "35.158.179.254", "46.36.66.41", "185.170.113.79", "163.172.68.112", "78.47.35.210", "77.90.90.75", "94.177.196.134", "212.237.22.215", "94.177.234.11", "167.160.180.199", "54.68.189.9", "94.159.62.14", "195.181.221.89", "185.33.145.94", "195.181.209.245", "195.181.221.38", "195.181.221.162", "185.33.145.12", "185.33.145.176", "178.79.128.235", "94.177.214.120", "94.177.199.41", "94.177.214.200", "94.177.213.201", "212.237.13.162", "195.181.221.236", "195.181.221.185", "185.28.103.187", "185.33.146.244", "217.61.123.71", "195.181.214.45", "195.181.212.99", "195.181.214.46", "195.181.214.215", "195.181.214.68", "217.61.123.118", "195.181.214.79", "217.61.123.14", "217.61.124.100", "195.181.214.111", "85.255.0.176", "81.2.254.116", "217.61.123.184", "195.181.212.231", "94.177.214.110", "195.181.209.164", "104.129.56.238", "85.255.13.64", "167.160.180.206", "217.61.123.226", "167.160.180.208", "93.186.253.127", "212.237.6.208", "94.177.207.190", "217.61.123.119", "85.255.1.245", "217.61.124.157", "37.59.57.141", "167.160.180.58", "104.223.53.14", "217.61.124.69", "195.181.212.103", "85.255.13.141", "104.207.133.204", "71.90.7.107", "107.150.18.108", "23.94.134.161", "80.150.243.13", "80.150.243.11", "185.81.165.52", "80.150.243.8" };
+
+
+cJSON *LP_assethbla(char *assetid)
+{
+ char url[1024],*retstr; int32_t n; cJSON *array,*bid=0,*ask=0,*retjson;
+ sprintf(url,"http://%s:7876/nxt?=%%2Fnxt&requestType=getBidOrders&asset=%s&firstIndex=0&lastIndex=0",NXTnodes[rand() % (sizeof(NXTnodes)/sizeof(*NXTnodes))],assetid);
+ if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) != 0 )
+ {
+ bid = cJSON_Parse(retstr);
+ free(retstr);
+ }
+ sprintf(url,"http://%s:7876/nxt?=%%2Fnxt&requestType=getAskOrders&asset=%s&firstIndex=0&lastIndex=0",NXTnodes[rand() % (sizeof(NXTnodes)/sizeof(*NXTnodes))],assetid);
+ if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) != 0 )
+ {
+ ask = cJSON_Parse(retstr);
+ free(retstr);
+ }
+ retjson = cJSON_CreateObject();
+ if ( bid != 0 && ask != 0 )
+ {
+ if ( (array= jarray(&n,bid,"bidOrders")) != 0 )
+ jadd(retjson,"bid",jduplicate(jitem(array,0)));
+ if ( (array= jarray(&n,ask,"askOrders")) != 0 )
+ jadd(retjson,"ask",jduplicate(jitem(array,0)));
+ }
+ if ( bid != 0 )
+ free_json(bid);
+ if ( ask != 0 )
+ free_json(ask);
+ return(retjson);
+}
+
+cJSON *LP_getinfo(char *symbol)
+{
+ struct iguana_info *coin = LP_coinfind(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_paxprice(char *fiat)
+{
+ char buf[128],lfiat[65]; struct iguana_info *coin = LP_coinfind("KMD");
+ strcpy(lfiat,fiat);
+ tolowercase(lfiat);
+ sprintf(buf,"[\"%s\", \"kmd\"]",lfiat);
+ return(bitcoin_json(coin,"paxprice",buf));
+}
+
+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, true]",bits256_str(str,txid),vout);
+ return(bitcoin_json(coin,"gettxout",buf));
+}
+
+cJSON *LP_gettx(char *symbol,bits256 txid)
+{
+ char buf[128],str[65]; struct iguana_info *coin = LP_coinfind(symbol);
+ sprintf(buf,"[\"%s\", 1]",bits256_str(str,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);
+ sprintf(buf,"[0, 99999999, [\"%s\"]]",coinaddr);
+ return(bitcoin_json(coin,"listunspent",buf));
+}
+
+cJSON *LP_listtransactions(char *symbol,char *coinaddr,int32_t count,int32_t skip)
+{
+ char buf[128]; struct iguana_info *coin = LP_coinfind(symbol);
+ if ( count == 0 )
+ count = 100;
+ sprintf(buf,"[\"%s\", %d, %d, true]",coinaddr,count,skip);
+ return(bitcoin_json(coin,"listtransactions",buf));
+}
+
+cJSON *LP_validateaddress(char *symbol,char *address)
+{
+ char buf[512]; struct iguana_info *coin = LP_coinfind(symbol);
+ sprintf(buf,"[\"%s\"]",address);
+ return(bitcoin_json(coin,"validateaddress",buf));
+}
+
+cJSON *LP_importprivkey(char *symbol,char *wifstr,char *label,int32_t flag)
+{
+ static void *ctx;
+ char buf[512],address[64]; cJSON *retjson; struct iguana_info *coin; int32_t doneflag = 0;
+ coin = LP_coinfind(symbol);
+ if ( ctx == 0 )
+ ctx = bitcoin_ctx();
+ bitcoin_wif2addr(ctx,coin->wiftaddr,coin->taddr,coin->pubtype,address,wifstr);
+ if ( (retjson= LP_validateaddress(symbol,address)) != 0 )
+ {
+ if ( jobj(retjson,"ismine") != 0 && is_cJSON_True(jobj(retjson,"ismine")) != 0 )
+ {
+ doneflag = 1;
+ //printf("%s already ismine\n",address);
+ }
+ //printf("%s\n",jprint(retjson,0));
+ free_json(retjson);
+ }
+ if ( doneflag == 0 )
+ {
+ if ( coin->noimportprivkey_flag != 0 )
+ sprintf(buf,"[\"%s\"]",wifstr);
+ else sprintf(buf,"\"%s\", \"%s\", %s",wifstr,label,flag < 0 ? "false" : "true");
+ return(bitcoin_json(coin,"importprivkey",buf));
+ } else return(cJSON_Parse("{\"result\":\"success\"}"));
+}
+
+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 ( coin == 0 )
+ return(-2);
+ if ( (validatejson= LP_validateaddress(symbol,address)) != 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 ( isvalid == 0 )
+ return(-1);
+ if ( doneflag != 0 )
+ 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);
+}
+
+double LP_getestimatedrate(char *symbol)
+{
+ char buf[512],*retstr; double rate = 20; struct iguana_info *coin = LP_coinfind(symbol);
+ if ( coin != 0 && (strcmp(coin->symbol,"BTC") == 0 || coin->txfee == 0) )
+ {
+ sprintf(buf,"[%d]",3);
+ if ( (retstr= bitcoind_passthru(symbol,coin->serverport,coin->userpass,"estimatefee",buf)) != 0 )
+ {
+ if ( retstr[0] != '-' )
+ {
+ rate = atof(retstr) / 1024.;
+ //printf("estimated rate.(%s) %s -> %.8f\n",symbol,retstr,rate);
+ }
+ free(retstr);
+ }
+ } else return((double)coin->txfee / LP_AVETXSIZE);
+ return(SATOSHIDEN * rate);
+}
+
+uint64_t LP_txfee(char *symbol)
+{
+ uint64_t txfee = 0;
+ if ( strcmp(symbol,"BTC") != 0 )
+ txfee = LP_MIN_TXFEE;
+ 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);
+ 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);
+}
+
+char *LP_signrawtx(char *symbol,bits256 *signedtxidp,int32_t *completedp,cJSON *vins,char *rawtx,cJSON *privkeys,struct vin_info *V)
+{
+ 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 )
+ {
+ printf("LP_signrawtx cant find coin.(%s)\n",symbol);
+ 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 )
+ {
+ if ( (json= cJSON_Parse(retstr)) != 0 )
+ {
+ if ( (hexstr= jstr(json,"hex")) != 0 )
+ {
+ len = (int32_t)strlen(hexstr);
+ signedtx = calloc(1,len+1);
+ strcpy(signedtx,hexstr);
+ *completedp = is_cJSON_True(jobj(json,"complete"));
+ data = malloc(len >> 1);
+ 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);
+ free_json(json);
+ }
+ free(retstr);
+ }
+ 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 for %s (%s)\n",*heightp,height,blockhashstr,jprint(json,0));
+ *heightp = -1;
+ free_json(json);
+ json = 0;
+ }
+ }
+ }
+ if ( flag != 0 && blockhashstr != 0 )
+ free(blockhashstr);
+ }
+ return(json);
+}
+
diff --git a/iguana/exchanges/LP_scan.c b/iguana/exchanges/LP_scan.c
new file mode 100644
index 000000000..60a66c006
--- /dev/null
+++ b/iguana/exchanges/LP_scan.c
@@ -0,0 +1,747 @@
+
+/******************************************************************************
+ * 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
+//
+
+
+struct LP_address *_LP_addressfind(struct iguana_info *coin,char *coinaddr)
+{
+ struct LP_address *ap;
+ HASH_FIND(hh,coin->addresses,coinaddr,strlen(coinaddr),ap);
+ return(ap);
+}
+
+struct LP_address *_LP_addressadd(struct iguana_info *coin,char *coinaddr)
+{
+ struct LP_address *ap;
+ ap = calloc(1,sizeof(*ap));
+ safecopy(ap->coinaddr,coinaddr,sizeof(ap->coinaddr));
+ HASH_ADD_KEYPTR(hh,coin->addresses,ap->coinaddr,strlen(ap->coinaddr),ap);
+ return(ap);
+}
+
+struct LP_address *_LP_address(struct iguana_info *coin,char *coinaddr)
+{
+ struct LP_address *ap;
+ if ( (ap= _LP_addressfind(coin,coinaddr)) == 0 )
+ ap = _LP_addressadd(coin,coinaddr);
+ return(ap);
+}
+
+struct LP_transaction *LP_transactionfind(struct iguana_info *coin,bits256 txid)
+{
+ 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 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;
+ tx->height = height;
+ 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);
+ } // 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,bits256 txid)
+{
+ bits256 blockhash; cJSON *blockobj,*txobj; int32_t height = 0;
+ if ( (txobj= LP_gettx(coin->symbol,txid)) != 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("%s LP_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;
+ HASH_ITER(hh,coin->transactions,tx,tmp)
+ {
+ for (i=0; inumvouts; i++)
+ {
+ if ( bits256_nonz(tx->outpoints[i].spendtxid) == 0 )
+ continue;
+ if ( (ht= tx->outpoints[i].spendheight) == 0 )
+ {
+ tx->outpoints[i].spendheight = LP_txheight(×tamp,&blocktime,coin,tx->outpoints[i].spendtxid);
+ }
+ 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));
+ }
+ }
+ }
+ return(num);
+}
+
+uint64_t LP_txinterestvalue(uint64_t *interestp,char *destaddr,struct iguana_info *coin,bits256 txid,int32_t vout)
+{
+ 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",coin->symbol,bits256_str(str,txid),jprint(txobj,0),vout);
+ }
+ else if ( strcmp(coin->symbol,"KMD") == 0 )
+ {
+ if ( (interest= jdouble(txobj,"interest")) != 0. )
+ {
+ //printf("add interest of %.8f to %.8f\n",interest,dstr(value));
+ *interestp = SATOSHIDEN * interest;
+ }
+ }
+ if ( (sobj= jobj(txobj,"scriptPubKey")) != 0 && (array= jarray(&n,sobj,"addresses")) != 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("%s %.8f <- %s.(%s) txobj.(%s)\n",destaddr,dstr(value),coin->symbol,bits256_str(str,txid),jprint(txobj,0));
+ free_json(txobj);
+ } //else { char str[65]; printf("null gettxout return %s/v%d\n",bits256_str(str,txid),vout); }
+ return(value);
+}
+
+int32_t LP_transactioninit(struct iguana_info *coin,bits256 txid,int32_t iter)
+{
+ struct LP_transaction *tx; char *address; int32_t i,n,height,numvouts,numvins,spentvout; uint32_t timestamp,blocktime; cJSON *txobj,*vins,*vouts,*vout,*vin,*sobj,*addresses; bits256 spenttxid; char str[65];
+ if ( (txobj= LP_gettx(coin->symbol,txid)) != 0 )
+ {
+ //printf("TX.(%s)\n",jprint(txobj,0));
+ height = LP_txheight(×tamp,&blocktime,coin,txid);
+ if ( timestamp == 0 && height > 0 )
+ timestamp = blocktime;
+ vins = jarray(&numvins,txobj,"vin");
+ vouts = jarray(&numvouts,txobj,"vout");
+ if ( iter == 0 && vouts != 0 && (tx= LP_transactionadd(coin,txid,height,numvouts,numvins,timestamp)) != 0 )
+ {
+ for (i=0; ioutpoints[i].value= SATOSHIDEN * jdouble(vout,"value")) == 0 )
+ tx->outpoints[i].value = SATOSHIDEN * jdouble(vout,"amount");
+ tx->outpoints[i].interest = SATOSHIDEN * jdouble(vout,"interest");
+ if ( (sobj= jobj(vout,"scriptPubKey")) != 0 )
+ {
+ if ( (addresses= jarray(&n,sobj,"addresses")) != 0 && n > 0 )
+ {
+ if ( n > 1 )
+ printf("LP_transactioninit: txid.(%s) multiple addresses.[%s]\n",bits256_str(str,txid),jprint(addresses,0));
+ if ( (address= jstri(addresses,0)) != 0 && strlen(address) < sizeof(tx->outpoints[i].coinaddr) )
+ {
+ strcpy(tx->outpoints[i].coinaddr,address);
+ } else if ( tx->outpoints[i].value != 0 )
+ printf("LP_transactioninit: unexpected address.(%s)\n",jprint(addresses,0));
+ }
+ //else if ( tx->outpoints[i].value != 0 )
+ // printf("LP_transactioninit: pax tx ht.%d i.%d (%s) n.%d\n",height,i,jprint(vout,0),n);
+ }
+ }
+ }
+ if ( iter == 1 && vins != 0 )
+ {
+ for (i=0; inumvouts )
+ {
+ tx->outpoints[spentvout].spendtxid = txid;
+ tx->outpoints[spentvout].spendvini = i;
+ tx->outpoints[spentvout].spendheight = height;
+ //printf("spend %s %s/v%d at ht.%d\n",coin->symbol,bits256_str(str,tx->txid),spentvout,height);
+ } else printf("LP_transactioninit: %s spentvout.%d < numvouts.%d\n",bits256_str(str,spenttxid),spentvout,tx->numvouts);
+ } //else printf("LP_transactioninit: couldnt find (%s) ht.%d %s\n",bits256_str(str,spenttxid),height,jprint(vin,0));
+ if ( bits256_cmp(spenttxid,txid) == 0 )
+ printf("spending same tx's %p vout ht.%d %s.[%d] s%d\n",tx,height,bits256_str(str,txid),tx!=0?tx->numvouts:0,spentvout);
+ }
+ }
+ free_json(txobj);
+ return(0);
+ } //else printf("LP_transactioninit error for %s %s\n",coin->symbol,bits256_str(str,txid));
+ return(-1);
+}
+
+int32_t LP_blockinit(struct iguana_info *coin,int32_t height)
+{
+ int32_t i,j,iter,numtx,checkht=-1; cJSON *blockobj,*txs; bits256 txid; struct LP_transaction *tx;
+ if ( (blockobj= LP_blockjson(&checkht,coin->symbol,0,height)) != 0 && checkht == height )
+ {
+ if ( (txs= jarray(&numtx,blockobj,"tx")) != 0 )
+ {
+ for (iter=0; iter<2; iter++)
+ 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;
+ }
+ if ( iter == 1 )
+ for (j=0; j<10; j++)
+ {
+ if (LP_transactioninit(coin,txid,iter) == 0 )
+ break;
+ printf("transaction ht.%d init error.%d, pause\n",height,j);
+ sleep(1);
+ }
+ }
+ else
+ {
+ for (j=0; j<10; j++)
+ {
+ if (LP_transactioninit(coin,txid,iter) == 0 )
+ break;
+ printf("transaction ht.%d init error.%d, pause\n",height,j);
+ sleep(1);
+ }
+ }
+ }
+ }
+ free_json(blockobj);
+ }
+ if ( checkht == height )
+ return(0);
+ else return(-1);
+}
+
+int32_t LP_scanblockchain(struct iguana_info *coin,int32_t startheight,int32_t endheight)
+{
+ int32_t ht,n = 0;
+ for (ht=startheight; ht<=endheight; ht++)
+ {
+ if ( LP_blockinit(coin,ht) < 0 )
+ {
+ printf("error loading block.%d of (%d, %d)\n",ht,startheight,endheight);
+ return(ht-1);
+ }
+ n++;
+ if ( (n % 1000) == 0 )
+ fprintf(stderr,"%.1f%% ",100. * (double)n/(endheight-startheight+1));
+ }
+ return(endheight);
+}
+
+char *banned_txids[] =
+{
+ "78cb4e21245c26b015b888b14c4f5096e18137d2741a6de9734d62b07014dfca", //233559
+ "00697be658e05561febdee1aafe368b821ca33fbb89b7027365e3d77b5dfede5", //234172
+ "e909465788b32047c472d73e882d79a92b0d550f90be008f76e1edaee6d742ea", //234187
+ "f56c6873748a327d0b92b8108f8ec8505a2843a541b1926022883678fb24f9dc", //234188
+ "abf08be07d8f5b3a433ddcca7ef539e79a3571632efd6d0294ec0492442a0204", //234213
+ "3b854b996cc982fba8c06e76cf507ae7eed52ab92663f4c0d7d10b3ed879c3b0", //234367
+ "fa9e474c2cda3cb4127881a40eb3f682feaba3f3328307d518589024a6032cc4", //234635
+ "ca746fa13e0113c4c0969937ea2c66de036d20274efad4ce114f6b699f1bc0f3", //234662
+ "43ce88438de4973f21b1388ffe66e68fda592da38c6ef939be10bb1b86387041", //234697
+ "0aeb748de82f209cd5ff7d3a06f65543904c4c17387c9d87c65fd44b14ad8f8c", //234899
+ "bbd3a3d9b14730991e1066bd7c626ca270acac4127131afe25f877a5a886eb25", //235252
+ "fa9943525f2e6c32cbc243294b08187e314d83a2870830180380c3c12a9fd33c", //235253
+ "a01671c8775328a41304e31a6693bbd35e9acbab28ab117f729eaba9cb769461", //235265
+ "2ef49d2d27946ad7c5d5e4ab5c089696762ff04e855f8ab48e83bdf0cc68726d", //235295
+ "c85dcffb16d5a45bd239021ad33443414d60224760f11d535ae2063e5709efee", //235296
+ // all vouts banned
+ "c4ea1462c207547cd6fb6a4155ca6d042b22170d29801a465db5c09fec55b19d", //246748
+ "305dc96d8bc23a69d3db955e03a6a87c1832673470c32fe25473a46cc473c7d1", //247204
+};
+
+int32_t komodo_bannedset(int32_t *indallvoutsp,bits256 *array,int32_t max)
+{
+ int32_t i;
+ if ( sizeof(banned_txids)/sizeof(*banned_txids) > max )
+ {
+ fprintf(stderr,"komodo_bannedset: buffer too small %ld vs %d\n",sizeof(banned_txids)/sizeof(*banned_txids),max);
+ exit(-1);
+ }
+ for (i=0; i b)
+ */
+ aval = ((struct LP_address *)a)->balance;
+ bval = ((struct LP_address *)b)->balance;
+ //printf("%.8f vs %.8f -> %d\n",dstr(aval),dstr(bval),(int32_t)(bval - aval));
+ return((aval == bval) ? 0 : ((aval < bval) ? 1 : -1));
+}
+
+// a primitive restore can be done by loading the previous snapshot and creating a virtual tx for all the balance at height-1. this wont allow anything but new snapshots, but for many use cases that is all that is needed
+
+cJSON *LP_snapshot(struct iguana_info *coin,int32_t height)
+{
+ static bits256 bannedarray[64]; static int32_t numbanned,indallvouts,maxsnapht; static char lastcoin[16];
+ struct LP_transaction *tx,*tmp; struct LP_address *ap,*atmp; int32_t isKMD,i,j,n,skipflag=0,startht,endht,ht; uint64_t banned_balance=0,balance=0,noaddr_balance=0; cJSON *retjson,*array,*item;
+ if ( bannedarray[0].txid == 0 )
+ numbanned = komodo_bannedset(&indallvouts,bannedarray,(int32_t)(sizeof(bannedarray)/sizeof(*bannedarray)));
+ startht = 1;
+ endht = height-1;
+ if ( strcmp(coin->symbol,lastcoin) == 0 )
+ {
+ if ( maxsnapht > height )
+ skipflag = 1;
+ else startht = maxsnapht+1;
+ }
+ else
+ {
+ maxsnapht = 0;
+ strcpy(lastcoin,coin->symbol);
+ }
+ retjson = cJSON_CreateObject();
+ if ( skipflag == 0 && startht < endht )
+ {
+ if ( (ht= LP_scanblockchain(coin,startht,endht)) < endht )
+ {
+ if ( ht > maxsnapht )
+ {
+ maxsnapht = ht;
+ printf("maxsnapht.%d for %s\n",maxsnapht,coin->symbol);
+ }
+ sleep(10);
+ if ( (ht= LP_scanblockchain(coin,maxsnapht+1,endht)) < endht )
+ {
+ if ( ht > maxsnapht )
+ {
+ maxsnapht = ht;
+ printf("maxsnapht.%d for %s\n",maxsnapht,coin->symbol);
+ }
+ jaddstr(retjson,"error","blockchain scan error");
+ return(retjson);
+ }
+ }
+ if ( ht > maxsnapht )
+ {
+ maxsnapht = ht;
+ printf("maxsnapht.%d for %s\n",maxsnapht,coin->symbol);
+ }
+ }
+ portable_mutex_lock(&coin->txmutex);
+ HASH_ITER(hh,coin->addresses,ap,atmp)
+ {
+ ap->balance = 0;
+ }
+ isKMD = (strcmp(coin->symbol,"KMD") == 0) ? 1 : 0;
+ HASH_ITER(hh,coin->transactions,tx,tmp)
+ {
+ if ( tx->height < height )
+ {
+ if ( isKMD != 0 )
+ {
+ for (j=0; jtxid) == 0 )
+ break;
+ if ( j < numbanned )
+ {
+ for (i=0; inumvouts; i++)
+ banned_balance += tx->outpoints[i].value;
+ //char str[256]; printf("skip banned %s bannedtotal: %.8f\n",bits256_str(str,tx->txid),dstr(banned_balance));
+ continue;
+ }
+ }
+ for (i=0; inumvouts; i++)
+ {
+ if ( (ht=tx->outpoints[i].spendheight) > 0 && ht < height )
+ continue;
+ if ( tx->outpoints[i].coinaddr[0] != 0 && (ap= _LP_address(coin,tx->outpoints[i].coinaddr)) != 0 )
+ {
+ balance += tx->outpoints[i].value;
+ ap->balance += tx->outpoints[i].value;
+ //printf("(%s/%s) %.8f %.8f\n",tx->outpoints[i].coinaddr,ap->coinaddr,dstr(tx->outpoints[i].value),dstr(ap->balance));
+ } else noaddr_balance += tx->outpoints[i].value;
+ }
+ }
+ }
+ HASH_SORT(coin->addresses,sort_balance);
+ portable_mutex_unlock(&coin->txmutex);
+ printf("%s balance %.8f at height.%d\n",coin->symbol,dstr(balance),height);
+ array = cJSON_CreateArray();
+ n = 0;
+ HASH_ITER(hh,coin->addresses,ap,atmp)
+ {
+ if ( ap->balance != 0 )
+ {
+ item = cJSON_CreateObject();
+ jaddnum(item,ap->coinaddr,dstr(ap->balance));
+ jaddi(array,item);
+ n++;
+ }
+ }
+ jadd(retjson,"balances",array);
+ jaddstr(retjson,"coin",coin->symbol);
+ jaddnum(retjson,"height",height);
+ jaddnum(retjson,"numaddresses",n);
+ jaddnum(retjson,"total",dstr(balance));
+ jaddnum(retjson,"noaddr_total",dstr(noaddr_balance));
+ return(retjson);
+}
+
+char *LP_snapshot_balance(struct iguana_info *coin,int32_t height,cJSON *argjson)
+{
+ cJSON *snapjson,*retjson,*balances,*array,*addrs,*child,*item,*item2; char *coinaddr,*refaddr; int32_t i,n,j,m; uint64_t total=0,value,balance = 0;
+ retjson = cJSON_CreateObject();
+ array = cJSON_CreateArray();
+ if ( (snapjson= LP_snapshot(coin,height)) != 0 )
+ {
+ total = jdouble(snapjson,"total") * SATOSHIDEN;
+ if ( (addrs= jarray(&m,argjson,"addresses")) != 0 )
+ {
+ if ( (balances= jarray(&n,snapjson,"balances")) != 0 )
+ {
+ for (i=0; ichild) != 0 )
+ {
+ value = (uint64_t)(child->valuedouble * SATOSHIDEN);
+ if ( (refaddr= get_cJSON_fieldname(child)) != 0 )
+ {
+ //printf("check %s %.8f against %d\n",refaddr,dstr(value),m);
+ for (j=0; jsymbol);
+ jaddnum(retjson,"height",height);
+ jaddnum(retjson,"balance",dstr(balance));
+ jaddnum(retjson,"total",dstr(total));
+ return(jprint(retjson,1));
+}
+
+char *LP_dividends(struct iguana_info *coin,int32_t height,cJSON *argjson)
+{
+ cJSON *array,*retjson,*item,*child,*exclude=0; int32_t i,j,emitted=0,dusted=0,n,execflag=0,flag,iter,numexcluded=0; char buf[1024],*field,*prefix="",*suffix=""; uint64_t dustsum=0,excluded=0,total=0,dividend=0,value,val,emit=0,dust=0; double ratio = 1.;
+ if ( (retjson= LP_snapshot(coin,height)) != 0 )
+ {
+ //printf("SNAPSHOT.(%s)\n",retstr);
+ if ( (array= jarray(&n,retjson,"balances")) != 0 )
+ {
+ if ( (n= cJSON_GetArraySize(array)) != 0 )
+ {
+ if ( argjson != 0 )
+ {
+ exclude = jarray(&numexcluded,argjson,"exclude");
+ dust = (uint64_t)(jdouble(argjson,"dust") * SATOSHIDEN);
+ dividend = (uint64_t)(jdouble(argjson,"dividend") * SATOSHIDEN);
+ if ( jstr(argjson,"prefix") != 0 )
+ prefix = jstr(argjson,"prefix");
+ if ( jstr(argjson,"suffix") != 0 )
+ suffix = jstr(argjson,"suffix");
+ execflag = jint(argjson,"system");
+ }
+ for (iter=0; iter<2; iter++)
+ {
+ for (i=0; ichild) != 0 )
+ {
+ value = (uint64_t)(child->valuedouble * SATOSHIDEN);
+ if ( (field= get_cJSON_fieldname(child)) != 0 )
+ {
+ for (j=0; j= dust )
+ {
+ sprintf(buf,"%s %s %.8f %s",prefix,field,dstr(val),suffix);
+ if ( execflag != 0 )
+ {
+ if ( system(buf) != 0 )
+ printf("error system.(%s)\n",buf);
+ }
+ else printf("%s\n",buf);
+ emit += val;
+ emitted++;
+ } else dustsum += val, dusted++;
+ }
+ }
+ }
+ }
+ if ( iter == 0 )
+ {
+ if ( total > 0 )
+ {
+ if ( dividend == 0 )
+ dividend = total;
+ ratio = (double)dividend / total;
+ } else break;
+ }
+ }
+ }
+ }
+ free_json(retjson);
+ retjson = cJSON_CreateObject();
+ jaddstr(retjson,"coin",coin->symbol);
+ jaddnum(retjson,"height",height);
+ jaddnum(retjson,"total",dstr(total));
+ jaddnum(retjson,"emitted",emitted);
+ jaddnum(retjson,"excluded",dstr(excluded));
+ if ( dust != 0 )
+ {
+ jaddnum(retjson,"dust",dstr(dust));
+ jaddnum(retjson,"dusted",dusted);
+ }
+ if ( dustsum != 0 )
+ jaddnum(retjson,"dustsum",dstr(dustsum));
+ jaddnum(retjson,"dividend",dstr(dividend));
+ jaddnum(retjson,"dividends",dstr(emit));
+ jaddnum(retjson,"ratio",ratio);
+ if ( execflag != 0 )
+ jaddnum(retjson,"system",execflag);
+ /*if ( prefix[0] != 0 )
+ jaddstr(retjson,"prefix",prefix);
+ if ( suffix[0] != 0 )
+ jaddstr(retjson,"suffix",suffix);*/
+ return(jprint(retjson,1));
+ }
+ return(clonestr("{\"error\":\"symbol not found\"}"));
+}
+
+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);
+ //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; 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 )
+ coinaddr[0] = 0;
+ if ( (tx= LP_transactionfind(coin,txid)) != 0 )
+ {
+ 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 )
+ 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 ( tx == 0 )
+ {
+ LP_transactioninit(coin,txid,0);
+ LP_transactioninit(coin,txid,1);
+ }
+ 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);
+}
+
+int32_t LP_spendsearch(bits256 *spendtxidp,int32_t *indp,char *symbol,bits256 searchtxid,int32_t searchvout)
+{
+ 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 )
+ {
+ if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 )
+ {
+ for (i=0; icoin->symbol)) == 0 || coin->inactive != 0 )
+ return(-1);
+ numconfirms = -1;
+ if ( (txobj= LP_gettx(rawtx->coin->symbol,rawtx->I.signedtxid)) != 0 )
+ {
+ numconfirms = jint(txobj,"confirmations");
+ free_json(txobj);
+ }
+ else if ( mempool != 0 && 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(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)
+{
+ 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 ( time(NULL) > coin->lastmempool+LP_MEMPOOL_TIMEINCR )
+ {
+ if ( (array= LP_getmempool(symbol)) != 0 )
+ {
+ 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_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..dcb67c8a9
--- /dev/null
+++ b/iguana/exchanges/LP_statemachine.c
@@ -0,0 +1,1603 @@
+
+/******************************************************************************
+ * 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
+//
+/*struct LP_cacheinfo *ptr,*tmp;
+ HASH_ITER(hh,LP_cacheinfos,ptr,tmp)
+ {
+ if ( ptr->timestamp < now-3600*2 || ptr->price == 0. )
+ continue;
+ 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,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,ptr->Q.srchash)) != 0 )
+ bids[numbids++] = op;
+ }
+ }*/
+
+/*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);
+}
+/*char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo)
+ {
+ 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 ( 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) > 0 )
+ {
+ sprintf(url,"http://%s:%u/api/stats/notified?iambob=%d&pubkey=%s&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->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));
+ //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));
+ if ( utxo->T.spentflag == 0 )
+ utxo->T.spentflag = (uint32_t)time(NULL);
+ return(0);
+ }
+ }*/
+
+/*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(LP_issue_curl("lookup",destip,destport,url));
+ //return(issue_curlt(url,LP_HTTP_TIMEOUT));
+ }*/
+
+
+/*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 %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(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);
+ }
+ }*/
+/*if ( lastforward < now-3600 )
+ {
+ if ( (retstr= LP_registerall(0)) != 0 )
+ free(retstr);
+ //LP_forwarding_register(LP_mypubkey,pushaddr,pushport,10);
+ lastforward = now;
+ }*/
+//if ( IAMLP != 0 && (counter % 600) == 42 )
+// LP_hellos();
+/*if ( 0 && LP_canbind == 0 && (counter % (PSOCK_KEEPALIVE*MAINLOOP_PERSEC/2)) == 13 )
+ {
+ char keepalive[128];
+ sprintf(keepalive,"{\"method\":\"keepalive\"}");
+ //printf("send keepalive to %s pullsock.%d\n",pushaddr,pullsock);
+ if ( /LP_send(pullsock,keepalive,(int32_t)strlen(keepalive)+1,0) < 0 )
+ {
+ //LP_deadman_switch = 0;
+ }
+ }*/
+
+/*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);
+ if ( (sock= nn_socket(AF_SP,nnother)) >= 0 )
+ {
+ if ( nn_connect(sock,pushaddr) < 0 )
+ 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);
+ 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,(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 )
+ {
+ free(retstr);
+ retval = 0;
+ }
+ }
+ nn_close(sock);
+ }
+ return(retval);
+ }*/
+
+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,NN_DONTWAIT)) >= 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;
+ 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;
+ 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->smartaddr);
+ 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)
+{
+ 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,1) >= 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,1) >= 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) >= 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,1) >= 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,1) >= 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,1)) >= 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();
+ 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
+
+
+#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;
+ // 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);
+ }*/
+
+/*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);
+ }*/
+/*
+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; i 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);
+ }*/
+/*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_swap.c b/iguana/exchanges/LP_swap.c
new file mode 100644
index 000000000..89edc2ce6
--- /dev/null
+++ b/iguana/exchanges/LP_swap.c
@@ -0,0 +1,1080 @@
+
+/******************************************************************************
+ * 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
+//
+
+/*
+ make sure to broadcast deposit before claiming refund, or to just skip it if neither is done
+ */
+
+
+// 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
+
+ */
+
+
+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 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);
+ 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;
+ if ( swap->N.pair >= 0 )
+ nn_close(swap->N.pair), swap->N.pair = -1;
+}
+
+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;
+ 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 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)));
+}
+
+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++)
+ datalen += iguana_rwnum(1,&data[datalen],sizeof(swap->deck[i>>1][i&1]),&swap->deck[i>>1][i&1]);
+ return(datalen);
+}
+
+int32_t LP_pubkeys_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datalen)
+{
+ int32_t i,len = 0;
+ if ( datalen == sizeof(swap->otherdeck) )
+ {
+ 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);
+ }
+ 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)
+{
+ 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));
+ }
+ return(datalen);
+}
+
+int32_t LP_choosei_verify(struct basilisk_swap *swap,uint8_t *data,int32_t datalen)
+{
+ int32_t otherchoosei=-1,i,len = 0; uint8_t pubkey33[33]; char str[65],str2[65];
+ if ( datalen == sizeof(otherchoosei)+sizeof(bits256)*2 )
+ {
+ len += iguana_rwnum(0,data,sizeof(otherchoosei),&otherchoosei);
+ if ( otherchoosei >= 0 && otherchoosei < INSTANTDEX_DECKSIZE )
+ {
+ 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(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);
+ }
+ 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(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->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);
+ }
+ return(0);
+ }
+ }
+ printf("illegal otherchoosei.%d datalen.%d vs %d\n",otherchoosei,datalen,(int32_t)(sizeof(otherchoosei)+sizeof(bits256)*2));
+ return(-1);
+}
+
+int32_t LP_mostprivs_data(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];
+ }
+ return(datalen);
+}
+
+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_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 )
+ {
+ 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(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(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);
+}
+
+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 )
+ {
+ 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 ( 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(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(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);
+}
+
+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))
+{
+ struct nn_pollfd pfd; void *data; int32_t datalen,retval = -1; uint32_t expiration = (uint32_t)time(NULL) + timeout;
+ while ( time(NULL) < expiration )
+ {
+ memset(&pfd,0,sizeof(pfd));
+ pfd.fd = pairsock;
+ pfd.events = NN_POLLIN;
+ if ( nn_poll(&pfd,1,1) > 0 )
+ {
+ //printf("start wait\n");
+ if ( (datalen= nn_recv(pairsock,&data,NN_MSG,0)) >= 0 )
+ {
+ //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");
+ }
+ }
+ printf("waitfor timedout\n");
+ return(retval);
+}
+
+int32_t swap_nn_send(int32_t sock,uint8_t *data,int32_t datalen,uint32_t flags,int32_t timeout)
+{
+ struct nn_pollfd pfd; int32_t i;
+ for (i=0; i 0 )
+ return(nn_send(sock,data,datalen,flags));
+ usleep(1000);
+ }
+ return(-1);
+}
+
+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 timeout.%d\n",statename,timeout);
+ if ( LP_waitfor(pairsock,swap,timeout,verify) == 0 )
+ {
+ //printf("waited for %s\n",statename);
+ if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 )
+ {
+ if ( (sendlen= swap_nn_send(pairsock,data,datalen,0,timeout)) == 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 after %d\n",timeout);
+ 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;
+ //printf("sendwait.%s\n",statename);
+ if ( (datalen= (*datagen)(swap,data,maxlen)) > 0 )
+ {
+ //printf("generated %d for %s, timeout.%d\n",datalen,statename,timeout);
+ if ( (sendlen= swap_nn_send(pairsock,data,datalen,0,timeout)) == 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("send %s error\n",statename);
+ } else printf("no datagen for %s\n",statename);
+ return(retval);
+}
+
+void LP_swapsfp_update(struct basilisk_request *rp)
+{
+ 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);
+ }
+}
+
+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);
+ }
+ printf("swapdata rawtx has null txbytes\n");
+ 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; int64_t txfee; 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++)
+ 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]);
+ bitcoin_address(redeemaddr,rawtx->coin->taddr,rawtx->coin->p2shtype,rawtx->redeemscript,rawtx->I.redeemlen);
+ 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 )
+ {
+ 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 )
+ {
+ //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+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));
+ if ( bits256_cmp(txid,rawtx->I.actualtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 )
+ rawtx->I.actualtxid = txid;
+ 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;
+ rawtx->I.locktime = rawtx->msgtx.lock_time;
+ if ( (vouts= jarray(&n,txobj,"vout")) != 0 && v < n )
+ {
+ vout = jitem(vouts,v);
+ if ( strcmp("BTC",rawtx->coin->symbol) == 0 && rawtx == &swap->otherfee )
+ txfee = LP_MIN_TXFEE;
+ else
+ {
+ if ( strcmp(rawtx->coin->symbol,swap->bobcoin.symbol) == 0 )
+ txfee = swap->I.Btxfee;
+ else if ( strcmp(rawtx->coin->symbol,swap->alicecoin.symbol) == 0 )
+ txfee = swap->I.Atxfee;
+ else txfee = LP_MIN_TXFEE;
+ }
+ 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;
+ //if ( swap != 0 )
+ // basilisk_txlog(swap->myinfoptr,swap,rawtx,-1); // bobdeposit, bobpayment or alicepayment
+ retval = 0;
+ if ( rawtx == &swap->otherfee )
+ {
+ char str[65];
+ LP_swap_coinaddr(swap,rawtx->coin,rawtx->p2shaddr,data,datalen);
+ printf("got %s txid.%s (%s) -> %s\n",rawtx->name,bits256_str(str,rawtx->I.signedtxid),jprint(txobj,0),rawtx->p2shaddr);
+ } else bitcoin_address(rawtx->p2shaddr,rawtx->coin->taddr,rawtx->coin->p2shtype,rawtx->spendscript,hexlen);
+ }
+ } else printf("%s ERROR.(%s) txfees.[%.8f %.8f: %.8f] amount.%.8f -> %.8f\n",rawtx->name,jprint(txobj,0),dstr(swap->I.Atxfee),dstr(swap->I.Btxfee),dstr(txfee),dstr(rawtx->I.amount),dstr(rawtx->I.amount)-dstr(txfee));
+ }
+ 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,retval = -1;
+ if ( LP_swapdata_rawtx(swap,data,maxlen,rawtx) != 0 )
+ {
+ if ( bits256_nonz(rawtx->I.signedtxid) != 0 && bits256_nonz(rawtx->I.actualtxid) == 0 )
+ {
+ 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));
+ 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;
+ //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 )
+ {
+ 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 )
+ {
+ retval = LP_swapsend(pairsock,swap,msgbits,sendbuf,sendlen,nextbits,rawtx->I.crcs);
+ 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;
+ }
+ return(retval);
+ }
+ 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);
+}
+
+int32_t LP_swapwait(uint32_t requestid,uint32_t quoteid,int32_t duration,int32_t sleeptime)
+{
+ 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 )
+ {
+ 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/divisor);
+ if ( divisor > 1 )
+ divisor--;
+ }
+ if ( 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 )
+ {
+ printf("second call.(%s)\n",retstr);
+ free(retstr);
+ }
+ return(0);
+ } else return(-1);
+}
+
+void LP_bobloop(void *_swap)
+{
+ uint8_t *data; int32_t maxlen,m,n; 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) + LP_SWAPSTEP_TIMEOUT;
+ if ( swap != 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");
+ 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");
+ 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(swap->N.pair,swap,LP_SWAPSTEP_TIMEOUT*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,LP_SWAPSTEP_TIMEOUT*3,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 ( strcmp(swap->alicecoin.symbol,"BTC") == 0 )
+ m = 0;
+ else m = 1;
+ while ( (n= LP_numconfirms(swap,&swap->alicepayment,1)) < m ) // sync with alice
+ {
+ 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 )
+ 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);
+ 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);
+ }
+ }
+ }
+ basilisk_swap_finished(swap);
+ free(swap);
+ } else printf("swap timed out\n");
+}
+
+void LP_aliceloop(void *_swap)
+{
+ uint8_t *data; int32_t maxlen,n,m; uint32_t expiration; struct basilisk_swap *swap = _swap;
+ maxlen = 1024*1024 + sizeof(*swap);
+ data = malloc(maxlen);
+ 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",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");
+ 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");
+ else
+ {
+ 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,LP_SWAPSTEP_TIMEOUT*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");
+ else
+ {
+ if ( strcmp(swap->alicecoin.symbol,"BTC") == 0 )
+ m = 0;
+ else m = 1;
+ while ( (n= LP_numconfirms(swap,&swap->alicepayment,1)) < m )
+ {
+ 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*3,LP_verify_bobpayment) < 0 )
+ printf("error waiting for bobpayment\n");
+ else
+ {
+ while ( (n= LP_numconfirms(swap,&swap->bobpayment,1)) < swap->I.bobconfirms )
+ {
+ 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 ( (n= LP_numconfirms(swap,&swap->alicespend,1)) < swap->I.aliceconfirms )
+ {
+ 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);
+ }
+ 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);
+ }
+ }
+ }
+ basilisk_swap_finished(swap);
+ free(swap);
+ }
+ free(data);
+ if ( swap->N.pair >= 0 )
+ {
+ nn_close(swap->N.pair);
+ swap->N.pair = -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));
+}
+
+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)
+{
+#ifdef BASILISK_DISABLEWAITTX
+ numconfirms = 0;
+#endif
+ strcpy(rawtx->name,name);
+ rawtx->coin = coin;
+ strcpy(rawtx->I.coinstr,coin->symbol);
+ rawtx->I.numconfirms = numconfirms;
+ if ( (rawtx->I.amount= satoshis) < LP_MIN_TXFEE )
+ rawtx->I.amount = LP_MIN_TXFEE;
+ 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->taddr,rawtx->coin->pubtype,rawtx->I.rmd160,20);
+ }
+ if ( pubkey33 != 0 )
+ {
+ memcpy(rawtx->I.pubkey33,pubkey33,33);
+ 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 )
+ {
+ 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,struct LP_quoteinfo *qp)
+{
+ //FILE *fp; char fname[512];
+ uint8_t *alicepub33=0,*bobpub33=0; int32_t bobistrusted,aliceistrusted,jumblrflag=-2,x = -1; struct iguana_info *coin;
+ swap->I.Atxfee = qp->desttxfee;
+ swap->I.Btxfee = qp->txfee;
+ 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.srcamount;
+ swap->I.alicesatoshis = swap->I.req.destamount;
+ if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < LP_MIN_TXFEE )
+ swap->I.bobinsurance = LP_MIN_TXFEE;
+ if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < LP_MIN_TXFEE )
+ swap->I.aliceinsurance = LP_MIN_TXFEE;
+ 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));
+ 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;
+ 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 )
+ {
+ char str[65]; printf("couldnt generate privkeys %d %s\n",x,bits256_str(str,privkey));
+ return(0);
+ }
+ if ( (coin= LP_coinfind(swap->I.alicestr)) != 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 ( (coin= LP_coinfind(swap->I.bobstr)) != 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 ( 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);
+ }
+ 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);
+ }
+ else
+ {
+ swap->I.bobconfirms = BASILISK_DEFAULT_NUMCONFIRMS;
+ swap->I.aliceconfirms = BASILISK_DEFAULT_NUMCONFIRMS;
+ }
+ swap->I.bobconfirms *= !bobistrusted;
+ swap->I.aliceconfirms *= !aliceistrusted;
+ 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);
+ 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,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,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,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;
+
+ 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;
+ 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],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);
+}
+
+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));
+ swap->I.req.quoteid = rp->quoteid;
+ 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) quoteid.%u\n",rp->requestid,iambob,rp->src,rp->dest,rp->quoteid);
+ 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);
+ calc_rmd160_sha256(swap->changermd160,pubkey33,33);
+ if ( bitcoin_swapinit(privkey,pubkey33,pubkey25519,swap,optionduration,!iambob,qp) == 0 )
+ {
+ printf("error doing swapinit\n");
+ free(swap);
+ swap = 0;
+ }
+ return(swap);
+}
+
diff --git a/iguana/exchanges/LP_transaction.c b/iguana/exchanges/LP_transaction.c
new file mode 100644
index 000000000..2fcb6d89a
--- /dev/null
+++ b/iguana/exchanges/LP_transaction.c
@@ -0,0 +1,1490 @@
+
+/******************************************************************************
+ * 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
+//
+
+bits256 LP_broadcast(char *txname,char *symbol,char *txbytes,bits256 expectedtxid)
+{
+ char *retstr; bits256 txid; cJSON *retjson,*errorobj; int32_t i,sentflag = 0;
+ memset(&txid,0,sizeof(txid));
+ for (i=0; i<1; i++)
+ {
+ if ( (retstr= LP_sendrawtransaction(symbol,txbytes)) != 0 )
+ {
+ if ( is_hexstr(retstr,0) == 64 )
+ {
+ decode_hex(txid.bytes,32,retstr);
+ if ( bits256_cmp(txid,expectedtxid) == 0 || (bits256_nonz(expectedtxid) == 0 && bits256_nonz(txid) != 0) )
+ 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;
+ sentflag = 1;
+ }
+ }
+ free_json(retjson);
+ }
+ char str[65]; printf("sentflag.%d [%s] %s RETSTR.(%s) %s.%s\n",sentflag,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 )
+ {
+ signedtx = malloc(datalen*2 + 1);
+ init_hexbytes_noT(signedtx,data,datalen);
+ 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);
+#endif
+ free(signedtx);
+ }
+ return(txid);
+}
+
+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; i 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(activescript,activescriptlen);
+ 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);
+ 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(uint8_t wiftaddr,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(wiftaddr,&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_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;
+ 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(taddr,pubtype,p2shtype,vp);
+ if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) > 0 )
+ bitcoin_address(vp->coinaddr,taddr,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 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;
+ 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;
+ //for (j=0; jp2shlen.%d\n",V->p2shlen);
+ }
+ else
+ {
+ script = msgtx->vins[vini].spendscript;
+ scriptlen = msgtx->vins[vini].spendlen;
+ }
+ 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];
+ 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; char tmpaddr[64];
+ for (z=0; z