Browse Source

Merge pull request #468 from jl777/dev

dICO release candidate, no changes for notaries
beta
jl777 7 years ago
committed by GitHub
parent
commit
63e2ddd7e2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      OSlibs/win/mingw.h
  2. 9
      crypto777/OS_portable.h
  3. 26
      iguana/dexscripts.win32/how_to_use.md
  4. 2
      iguana/exchanges/DEXstats.h
  5. 12
      iguana/exchanges/LP_bitcoin.c
  6. 339
      iguana/exchanges/LP_cache.c
  7. 66
      iguana/exchanges/LP_coins.c
  8. 235
      iguana/exchanges/LP_commands.c
  9. 77
      iguana/exchanges/LP_include.h
  10. 307
      iguana/exchanges/LP_nativeDEX.c
  11. 88
      iguana/exchanges/LP_network.c
  12. 511
      iguana/exchanges/LP_ordermatch.c
  13. 134
      iguana/exchanges/LP_peers.c
  14. 33
      iguana/exchanges/LP_portfolio.c
  15. 40
      iguana/exchanges/LP_prices.c
  16. 22
      iguana/exchanges/LP_remember.c
  17. 172
      iguana/exchanges/LP_rpc.c
  18. 50
      iguana/exchanges/LP_signatures.c
  19. 239
      iguana/exchanges/LP_socket.c
  20. 318
      iguana/exchanges/LP_statemachine.c
  21. 31
      iguana/exchanges/LP_swap.c
  22. 192
      iguana/exchanges/LP_tradebots.c
  23. 256
      iguana/exchanges/LP_transaction.c
  24. 350
      iguana/exchanges/LP_utxo.c
  25. 93
      iguana/exchanges/LP_utxos.c
  26. 2
      iguana/exchanges/bot_settings
  27. 3
      iguana/exchanges/bot_statuslist
  28. 2
      iguana/exchanges/coins
  29. 4
      iguana/exchanges/coins.json
  30. 2
      iguana/exchanges/install
  31. 4
      iguana/exchanges/mm.c
  32. 3
      iguana/exchanges/processfiles
  33. 2
      iguana/exchanges/sell
  34. 126
      iguana/exchanges/stats.c
  35. 1
      marketmaker.vcxproj

19
OSlibs/win/mingw.h

@ -61,13 +61,18 @@
* @remarks - #if (defined(_M_X64) || defined(__amd64__)) && defined(WIN32) * @remarks - #if (defined(_M_X64) || defined(__amd64__)) && defined(WIN32)
* is equivalent to #if defined(_M_X64) as _M_X64 is defined for MSVC only * is equivalent to #if defined(_M_X64) as _M_X64 is defined for MSVC only
*/ */
#if !defined(_M_X64)
struct pollfd {
SOCKET fd; /* file descriptor */ // [Decker] pollfs is already defined in winsock2.h
short events; /* requested events */
short revents; /* returned events */ //#if !defined(_M_X64)
}; //struct pollfd {
#endif //SOCKET fd; /* file descriptor */
//short events; /* requested events */
//short revents; /* returned events */
//};
//#endif
#if defined(_M_X64) #if defined(_M_X64)
/* /*

9
crypto777/OS_portable.h

@ -143,6 +143,15 @@ typedef struct queue
char name[64],initflag; char name[64],initflag;
} queue_t; } queue_t;
struct rpcrequest_info
{
struct rpcrequest_info *next,*prev;
pthread_t T;
int32_t sock;
uint32_t ipbits;
uint16_t port,pad;
};
struct OS_mappedptr struct OS_mappedptr
{ {
char fname[512]; char fname[512];

26
iguana/dexscripts.win32/how_to_use.md

@ -1,15 +1,15 @@
## DexScripts for Windows. How to use? ## ## DexScripts for Windows. How to use? ##
**1.** Before start you should put scripts and following binaries into one folder: **1. ** Before start you should put scripts and following binaries into one folder:
- curl.exe (required for all scripts) - curl.exe (required for all scripts)
- marketmaker.exe - marketmaker.exe
- libcurl.dll (required to run marketmaker) - libcurl.dll (required to run marketmaker)
- nanomsg.dll (required to run marketmaker) - nanomsg.dll (required to run marketmaker)
**2.** Don't forget to put `coins.json` file into a same folder. This file is available it this repo. **2. ** Don't forget to put `coins.json` file into a same folder. This file is available it this repo.
**3.** Type your passphrase into passphrase file in this folder (you should create file with name `passphrase` and without extension) and run `1-client.cmd`. This will run marketmaker. Next step is to obtain userpass needed for other scripts, you can simply copy and paste it from marketmaker output on startup into userpass file. **3. ** Type your passphrase into passphrase file in this folder (you should create file with name `passphrase` and without extension) and run `1-client.cmd`. This will run marketmaker. Next step is to obtain userpass needed for other scripts, you can simply copy and paste it from marketmaker output on startup into userpass file.
![](./images/userpass.png) ![](./images/userpass.png)
@ -22,3 +22,23 @@ Sample output of correct `2-getuserpass.cmd` usage is:
You should see your userpass on screen, and after it will automatically copied in userpass file. It's important to all other scripts to have this password in userpass file. If output of `2-getuserpass.cmd` is not same as showed on screen above - wait some seconds and run `2-getuserpass.cmd` again. Also make sure that you have allowed marketmaker to accept incoming connections in your Windows Firewall (first time launched system should automatically asked for it). You should see your userpass on screen, and after it will automatically copied in userpass file. It's important to all other scripts to have this password in userpass file. If output of `2-getuserpass.cmd` is not same as showed on screen above - wait some seconds and run `2-getuserpass.cmd` again. Also make sure that you have allowed marketmaker to accept incoming connections in your Windows Firewall (first time launched system should automatically asked for it).
**4.** For using other scripts please refer to barterDEX API. Or **barterDEX API Summary by Category** document by *shossain*. **4.** For using other scripts please refer to barterDEX API. Or **barterDEX API Summary by Category** document by *shossain*.
## F.A.Q. ##
**Q.** Is any simple way how i can display JSON results returned by all scripts, like orderbook and others, in human readable form?
**A.** Yes, you can use this service [JSON Editor Online](http://jsoneditoronline.org/), just copy and paste output of script in left column and see structured output in right.
**Q.** I see an output like this when i'm start `1-client.cmd` :
bind(0.0.0.0) port.7783 failed: No error sock.1468. errno.0
bind(0.0.0.0) port.7783 failed: No error sock.1516. errno.0
bind(0.0.0.0) port.7783 failed: No error sock.1444. errno.0
bind(0.0.0.0) port.7783 failed: No error sock.1484. errno.0
bind(0.0.0.0) port.7783 failed: No error sock.1412. errno.0
bind(0.0.0.0) port.7783 failed: No error sock.1524. errno.0
bind(0.0.0.0) port.7783 failed: No error sock.1008. errno.0
And nothing works.
**A.** Before run `1-client.cmd` make sure in Task Manager that you haven't already running `marketmaker.exe`. If have - kill this process via Task Manager or via command line command `taskkill /f /im taskkill.exe` .

2
iguana/exchanges/DEXstats.h

@ -927,6 +927,7 @@ char *stats_prices(char *symbol,char *dest,struct DEXstats_disp *prices,int32_t
} }
#ifndef FROM_MARKETMAKER #ifndef FROM_MARKETMAKER
#ifndef FROM_PRIVATEBET
char *stats_JSON(void *ctx,char *myipaddr,int32_t mypubsock,cJSON *argjson,char *remoteaddr,uint16_t port) 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; char *method,*agent,*retstr,*source,*dest; struct tai T; uint32_t endtimestamp; struct DEXstats_disp prices[365]; int32_t leftdatenum,seconds,numdates;
@ -953,5 +954,6 @@ char *stats_JSON(void *ctx,char *myipaddr,int32_t mypubsock,cJSON *argjson,char
return(clonestr(jprint(argjson,0))); return(clonestr(jprint(argjson,0)));
} }
#endif #endif
#endif
#endif /* DEXstats_h */ #endif /* DEXstats_h */

12
iguana/exchanges/LP_bitcoin.c

@ -1959,6 +1959,18 @@ int32_t bitcoin_timelockspend(uint8_t *script,int32_t n,uint8_t rmd160[20],uint3
return(n); return(n);
} }
int32_t bitcoin_performancebond(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,uint32_t unlocktimestamp,uint8_t cltv_rmd160[20],uint8_t anytime_rmd160[20])
{
script[n++] = SCRIPT_OP_IF;
n = bitcoin_checklocktimeverify(script,n,unlocktimestamp);
n = bitcoin_standardspend(script,n,cltv_rmd160);
script[n++] = SCRIPT_OP_ELSE;
n = bitcoin_standardspend(script,n,anytime_rmd160);
script[n++] = SCRIPT_OP_ENDIF;
calc_rmd160_sha256(p2sh_rmd160,script,n);
return(n);
}
int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,const struct vin_info *vp) int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,const struct vin_info *vp)
{ {
int32_t i,plen; int32_t i,plen;

339
iguana/exchanges/LP_cache.c

@ -0,0 +1,339 @@
/******************************************************************************
* 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_cache.c
// marketmaker
//
cJSON *LP_transaction_fromdata(struct iguana_info *coin,bits256 txid,uint8_t *serialized,int32_t len)
{
uint8_t *extraspace; cJSON *txobj; char str[65],str2[65]; struct iguana_msgtx msgtx; bits256 checktxid;
extraspace = calloc(1,4000000);
memset(&msgtx,0,sizeof(msgtx));
txobj = bitcoin_data2json(coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->height,&checktxid,&msgtx,extraspace,4000000,serialized,len,0,0,coin->zcash);
//printf("TX.(%s) match.%d\n",jprint(txobj,0),bits256_cmp(txid,checktxid));
free(extraspace);
if ( bits256_cmp(txid,checktxid) != 0 )
{
printf("%s LP_transaction_fromdata mismatched txid %s vs %s\n",coin->symbol,bits256_str(str,txid),bits256_str(str2,checktxid));
free_json(txobj);
txobj = 0;
}
return(txobj);
}
struct LP_transaction *LP_create_transaction(struct iguana_info *coin,bits256 txid,uint8_t *serialized,int32_t len,int32_t height,long fpos)
{
cJSON *txobj; bits256 spenttxid; int32_t i,spentvout,numvins,numvouts; cJSON *vout,*vin,*vins,*vouts; struct LP_transaction *tx; char str[65];
if ( (tx= LP_transactionfind(coin,txid)) != 0 )
return(tx);
if ( (txobj= LP_transaction_fromdata(coin,txid,serialized,len)) != 0 )
{
vins = jarray(&numvins,txobj,"vin");
vouts = jarray(&numvouts,txobj,"vout");
tx = LP_transactionadd(coin,txid,height,numvouts,numvins);
tx->serialized = serialized;
//free(serialized);
tx->fpos = fpos;
tx->len = tx->len;
tx->SPV = tx->height = height;
//printf("tx.%s numvins.%d numvouts.%d\n",bits256_str(str,txid),numvins,numvouts);
for (i=0; i<numvouts; i++)
{
vout = jitem(vouts,i);
tx->outpoints[i].value = LP_value_extract(vout,0);
tx->outpoints[i].interest = SATOSHIDEN * jdouble(vout,"interest");
LP_destaddr(tx->outpoints[i].coinaddr,vout);
//printf("from transaction init %s %s %s/v%d <- %.8f\n",coin->symbol,tx->outpoints[i].coinaddr,bits256_str(str,txid),i,dstr(tx->outpoints[i].value));
LP_address_utxoadd("LP_create_transaction",coin,tx->outpoints[i].coinaddr,txid,i,tx->outpoints[i].value,height,-1);
}
for (i=0; i<numvins; i++)
{
vin = jitem(vins,i);
spenttxid = jbits256(vin,"txid");
spentvout = jint(vin,"vout");
if ( i == 0 && bits256_nonz(spenttxid) == 0 )
continue;
if ( (tx= LP_transactionfind(coin,spenttxid)) != 0 )
{
if ( spentvout < tx->numvouts )
{
if ( tx->outpoints[spentvout].spendheight <= 0 )
{
tx->outpoints[spentvout].spendtxid = txid;
tx->outpoints[spentvout].spendvini = i;
tx->outpoints[spentvout].spendheight = height > 0 ? height : 1;
LP_address_utxoadd("LP_transactioninit iter1",coin,tx->outpoints[spentvout].coinaddr,spenttxid,spentvout,tx->outpoints[spentvout].value,-1,height>0?height:1);
if ( 0 && strcmp(coin->symbol,"REVS") == 0 )
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 spendheight.%d\n",bits256_str(str,spenttxid),spentvout,tx->numvouts,tx->outpoints[spentvout].spendheight);
} //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(tx);
}
void LP_SPV_store(struct iguana_info *coin,bits256 txid,int32_t height)
{
FILE *fp; char fname[512]; struct LP_transaction *tx = 0;
if ( (tx= LP_transactionfind(coin,txid)) != 0 && tx->serialized != 0 && tx->len > 0 && tx->fpos == 0 )
{
sprintf(fname,"%s/UNSPENTS/%s.SPV",GLOBAL_DBDIR,coin->symbol), OS_portable_path(fname);
if ( (fp= OS_appendfile(fname)) != 0 )
{
fwrite(&tx->txid,1,sizeof(tx->txid),fp);
fwrite(&tx->len,1,sizeof(tx->len),fp);
fwrite(&tx->height,1,sizeof(tx->height),fp);
tx->fpos = ftell(fp);
fwrite(tx->serialized,1,tx->len,fp);
fclose(fp);
}
} //else printf("cant store %s %s tx.%p [%d] fpos.%ld SPV.%d\n",coin->symbol,bits256_str(str,txid),tx,tx!=0?tx->len:-1,tx!=0?tx->fpos:-1,tx!=0?tx->SPV:-1);
}
int32_t LP_cacheitem(struct iguana_info *coin,FILE *fp)
{
bits256 txid,hash; long fpos; int32_t offset,retval,height,len; uint8_t *serialized; char str[65],str2[65];
fpos = ftell(fp);
if ( fread(&txid,1,sizeof(txid),fp) == sizeof(txid) && fread(&len,1,sizeof(len),fp) == sizeof(len) && fread(&height,1,sizeof(height),fp) == sizeof(height) && len < 100000 )
{
offset = (int32_t)(sizeof(txid) + sizeof(len) + sizeof(height));
serialized = malloc(len);
if ( (retval= (int32_t)fread(serialized,1,len,fp)) == len )
{
hash = bits256_doublesha256(0,serialized,len);
if ( bits256_cmp(hash,txid) == 0 )
{
//printf("%s validated in cache\n",bits256_str(str,hash));
LP_create_transaction(coin,txid,serialized,len,height,fpos+offset);
return((int32_t)(ftell(fp) - fpos));
}
printf("%s vs %s did not validated in cache\n",bits256_str(str,hash),bits256_str(str2,txid));
} else printf("retval.%d vs len.%d\n",retval,len);
} else printf("fread error\n");
return(-1);
}
void LP_cacheptrs_init(struct iguana_info *coin)
{
char fname[1024]; FILE *fp; int32_t count,tflag=0; long n,fsize=0,len = 0;
sprintf(fname,"%s/UNSPENTS/%s.SPV",GLOBAL_DBDIR,coin->symbol), OS_portable_path(fname);
fp = fopen(fname,"rb");
count = 0;
if ( fp != 0 )
{
fseek(fp,0,SEEK_END);
fsize = ftell(fp);
rewind(fp);
while ( len < fsize )
{
if ( (n= LP_cacheitem(coin,fp)) < 0 )
{
printf("cacheitem error at %s offset.%ld when fsize.%ld\n",coin->symbol,len,fsize);
tflag = 1;
break;
}
count++;
len += n;
}
printf("loaded %s %d entries total len.%ld\n",fname,count,len);
fclose(fp);
} //else printf("couldnt find.(%s)\n",fname);
if ( tflag != 0 )
OS_truncate(fname,len);
}
bits256 iguana_merkle(bits256 *tree,int32_t txn_count)
{
int32_t i,n=0,prev; uint8_t serialized[sizeof(bits256) * 2];
if ( txn_count == 1 )
return(tree[0]);
prev = 0;
while ( txn_count > 1 )
{
if ( (txn_count & 1) != 0 )
tree[prev + txn_count] = tree[prev + txn_count-1], txn_count++;
n += txn_count;
for (i=0; i<txn_count; i+=2)
{
iguana_rwbignum(1,serialized,sizeof(*tree),tree[prev + i].bytes);
iguana_rwbignum(1,&serialized[sizeof(*tree)],sizeof(*tree),tree[prev + i + 1].bytes);
tree[n + (i >> 1)] = bits256_doublesha256(0,serialized,sizeof(serialized));
}
prev = n;
txn_count >>= 1;
}
return(tree[n]);
}
bits256 validate_merkle(int32_t pos,bits256 txid,cJSON *proofarray,int32_t proofsize)
{
int32_t i; uint8_t serialized[sizeof(bits256) * 2]; bits256 hash,proof;
hash = txid;
for (i=0; i<proofsize; i++)
{
proof = jbits256i(proofarray,i);
if ( (pos & 1) == 0 )
{
iguana_rwbignum(1,&serialized[0],sizeof(hash),hash.bytes);
iguana_rwbignum(1,&serialized[sizeof(hash)],sizeof(proof),proof.bytes);
}
else
{
iguana_rwbignum(1,&serialized[0],sizeof(proof),proof.bytes);
iguana_rwbignum(1,&serialized[sizeof(hash)],sizeof(hash),hash.bytes);
}
hash = bits256_doublesha256(0,serialized,sizeof(serialized));
pos >>= 1;
}
return(hash);
}
bits256 LP_merkleroot(struct iguana_info *coin,struct electrum_info *ep,int32_t height)
{
cJSON *hdrobj; bits256 merkleroot;
memset(merkleroot.bytes,0,sizeof(merkleroot));
if ( coin->cachedmerkleheight == height )
return(coin->cachedmerkle);
if ( (hdrobj= electrum_getheader(coin->symbol,ep,&hdrobj,height)) != 0 )
{
if ( jobj(hdrobj,"merkle_root") != 0 )
{
merkleroot = jbits256(hdrobj,"merkle_root");
if ( bits256_nonz(merkleroot) != 0 )
{
coin->cachedmerkle = merkleroot;
coin->cachedmerkleheight = height;
}
}
free_json(hdrobj);
} else printf("couldnt get header for ht.%d\n",height);
return(merkleroot);
}
int32_t LP_merkleproof(struct iguana_info *coin,char *coinaddr,struct electrum_info *ep,bits256 txid,int32_t height)
{
struct LP_transaction *tx=0; cJSON *merkobj,*merkles,*retjson; bits256 roothash,merkleroot; int32_t m,SPV = 0;
if ( height <= 0 )
return(0);
if ( (tx= LP_transactionfind(coin,txid)) == 0 && strcmp(coinaddr,coin->smartaddr) == 0 )
{
if ( (retjson= electrum_transaction(coin->symbol,ep,&retjson,txid)) != 0 )
free_json(retjson);
}
if ( tx != 0 )
{
tx->height = height;
if ( tx->SPV > 0 )
return(tx->SPV);
}
if ( (merkobj= electrum_getmerkle(coin->symbol,ep,&merkobj,txid,height)) != 0 )
{
char str[65],str2[65],str3[65];
SPV = -1;
memset(roothash.bytes,0,sizeof(roothash));
if ( (merkles= jarray(&m,merkobj,"merkle")) != 0 )
{
roothash = validate_merkle(jint(merkobj,"pos"),txid,merkles,m);
merkleroot = LP_merkleroot(coin,ep,height);
if ( bits256_nonz(merkleroot) != 0 )
{
if ( bits256_cmp(merkleroot,roothash) == 0 )
{
SPV = height;
LP_SPV_store(coin,txid,height);
if ( tx != 0 )
{
tx->SPV = height;
if ( tx->serialized != 0 )
{
free(tx->serialized);
tx->serialized = 0;
tx->len = 0;
}
}
//printf("validated MERK %s ht.%d -> %s root.(%s)\n",bits256_str(str,txid),height,jprint(merkobj,0),bits256_str(str2,roothash));
}
else printf("ERROR MERK %s ht.%d -> %s root.(%s) vs %s\n",bits256_str(str,txid),height,jprint(merkobj,0),bits256_str(str2,roothash),bits256_str(str3,merkleroot));
} else SPV = 0;
}
if ( SPV < 0 )
{
printf("MERKLE DIDNT VERIFY.%s %s ht.%d (%s)\n",coin->symbol,bits256_str(str,txid),height,jprint(merkobj,0));
if ( jobj(merkobj,"error") != 0 )
SPV = 0; // try again later
}
free_json(merkobj);
}
return(SPV);
}
char *LP_unspents_filestr(char *symbol,char *addr)
{
char fname[1024]; long fsize;
sprintf(fname,"%s/UNSPENTS/%s_%s",GLOBAL_DBDIR,symbol,addr), OS_portable_path(fname);
return(OS_filestr(&fsize,fname));
}
void LP_unspents_cache(char *symbol,char *addr,char *arraystr,int32_t updatedflag)
{
char fname[1024]; FILE *fp=0;
sprintf(fname,"%s/UNSPENTS/%s_%s",GLOBAL_DBDIR,symbol,addr), OS_portable_path(fname);
//printf("unspents cache.(%s) for %s %s, updated.%d\n",fname,symbol,addr,updatedflag);
if ( updatedflag == 0 && (fp= fopen(fname,"rb")) == 0 )
updatedflag = 1;
else if ( fp != 0 )
fclose(fp);
if ( updatedflag != 0 && (fp= fopen(fname,"wb")) != 0 )
{
fwrite(arraystr,1,strlen(arraystr),fp);
fclose(fp);
}
}
uint64_t LP_unspents_load(char *symbol,char *addr)
{
char *arraystr; uint64_t balance = 0; int32_t i,n; cJSON *retjson,*item; struct iguana_info *coin;
if ( (coin= LP_coinfind(symbol)) != 0 )
{
if ( (arraystr= LP_unspents_filestr(symbol,addr)) != 0 )
{
if ( (retjson= cJSON_Parse(arraystr)) != 0 )
{
//printf("PROCESS UNSPENTS %s\n",arraystr);
if ( (n= cJSON_GetArraySize(retjson)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(retjson,i);
balance += j64bits(item,"value");
}
}
electrum_process_array(coin,coin->electrum,coin->smartaddr,retjson,1);
free_json(retjson);
}
free(arraystr);
}
}
return(balance);
}

66
iguana/exchanges/LP_coins.c

@ -23,9 +23,12 @@ char *portstrs[][3] = { { "BTC", "8332" }, { "KMD", "7771" } };
uint16_t LP_rpcport(char *symbol) uint16_t LP_rpcport(char *symbol)
{ {
int32_t i; int32_t i;
for (i=0; i<sizeof(portstrs)/sizeof(*portstrs); i++) if ( symbol != 0 && symbol[0] != 0 )
if ( strcmp(portstrs[i][0],symbol) == 0 ) {
return(atoi(portstrs[i][1])); for (i=0; i<sizeof(portstrs)/sizeof(*portstrs); i++)
if ( strcmp(portstrs[i][0],symbol) == 0 )
return(atoi(portstrs[i][1]));
}
return(0); return(0);
} }
@ -198,7 +201,9 @@ cJSON *LP_coinjson(struct iguana_info *coin,int32_t showwif)
if ( coin->userpass[0] != 0 ) if ( coin->userpass[0] != 0 )
{ {
jaddnum(item,"height",LP_getheight(coin)); jaddnum(item,"height",LP_getheight(coin));
balance = LP_RTsmartbalance(coin); if ( coin->electrum != 0 )
balance = LP_unspents_load(coin->symbol,coin->smartaddr);
else balance = LP_RTsmartbalance(coin);
jaddnum(item,"balance",dstr(balance)); jaddnum(item,"balance",dstr(balance));
jaddnum(item,"KMDvalue",dstr(LP_KMDvalue(coin,balance))); jaddnum(item,"KMDvalue",dstr(LP_KMDvalue(coin,balance)));
} }
@ -231,12 +236,15 @@ cJSON *LP_coinjson(struct iguana_info *coin,int32_t showwif)
struct iguana_info *LP_conflicts_find(struct iguana_info *refcoin) struct iguana_info *LP_conflicts_find(struct iguana_info *refcoin)
{ {
struct iguana_info *coin=0,*tmp; struct iguana_info *coin=0,*tmp;
HASH_ITER(hh,LP_coins,coin,tmp) if ( refcoin != 0 )
{ {
if ( coin->inactive != 0 || coin->electrum != 0 || coin == refcoin ) HASH_ITER(hh,LP_coins,coin,tmp)
continue; {
if ( strcmp(coin->serverport,refcoin->serverport) == 0 ) if ( coin->inactive != 0 || coin->electrum != 0 || coin == refcoin )
break; continue;
if ( strcmp(coin->serverport,refcoin->serverport) == 0 )
break;
}
} }
return(coin); return(coin);
} }
@ -254,31 +262,37 @@ cJSON *LP_coinsjson(int32_t showwif)
char *LP_getcoin(char *symbol) char *LP_getcoin(char *symbol)
{ {
int32_t numenabled,numdisabled; struct iguana_info *coin,*tmp; cJSON *item=0,*retjson; int32_t numenabled,numdisabled; struct iguana_info *coin,*tmp; cJSON *item=0,*retjson;
numenabled = numdisabled = 0;
retjson = cJSON_CreateObject(); retjson = cJSON_CreateObject();
HASH_ITER(hh,LP_coins,coin,tmp) if ( symbol != 0 && symbol[0] != 0 )
{ {
if ( strcmp(symbol,coin->symbol) == 0 ) numenabled = numdisabled = 0;
item = LP_coinjson(coin,0); HASH_ITER(hh,LP_coins,coin,tmp)
if ( coin->inactive == 0 ) {
numenabled++; if ( strcmp(symbol,coin->symbol) == 0 )
else numdisabled++; 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);
} }
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)); return(jprint(retjson,1));
} }
struct iguana_info *LP_coinsearch(char *symbol) struct iguana_info *LP_coinsearch(char *symbol)
{ {
struct iguana_info *coin; struct iguana_info *coin = 0;
portable_mutex_lock(&LP_coinmutex); if ( symbol != 0 && symbol[0] != 0 )
HASH_FIND(hh,LP_coins,symbol,strlen(symbol),coin); {
portable_mutex_unlock(&LP_coinmutex); portable_mutex_lock(&LP_coinmutex);
HASH_FIND(hh,LP_coins,symbol,strlen(symbol),coin);
portable_mutex_unlock(&LP_coinmutex);
}
return(coin); return(coin);
} }

235
iguana/exchanges/LP_commands.c

@ -34,10 +34,10 @@ char *LP_numutxos()
char *stats_JSON(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,char *remoteaddr,uint16_t port) // from rpc port 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,flag = 0; struct LP_peerinfo *peer; cJSON *retjson,*reqjson = 0; struct iguana_info *ptr; char *method,*userpass,*base,*rel,*coin,*retstr = 0; int32_t changed,flag = 0; cJSON *retjson,*reqjson = 0; struct iguana_info *ptr;
//printf("stats_JSON(%s)\n",jprint(argjson,0)); //printf("stats_JSON(%s)\n",jprint(argjson,0));
method = jstr(argjson,"method"); method = jstr(argjson,"method");
if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (method == 0 || strcmp(method,"electrum") != 0) ) /*if ( (ipaddr= jstr(argjson,"ipaddr")) != 0 && (argport= juint(argjson,"port")) != 0 && (method == 0 || strcmp(method,"electrum") != 0) )
{ {
if ( strcmp(ipaddr,"127.0.0.1") != 0 && argport >= 1000 ) if ( strcmp(ipaddr,"127.0.0.1") != 0 && argport >= 1000 )
{ {
@ -50,31 +50,26 @@ char *stats_JSON(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,char *r
{ {
if ( 0 && (otherpeers= jint(argjson,"numpeers")) > peer->numpeers ) if ( 0 && (otherpeers= jint(argjson,"numpeers")) > peer->numpeers )
peer->numpeers = otherpeers; 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 ) if ( peer->sessionid == 0 )
peer->sessionid = juint(argjson,"session"); 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)); //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")); } else LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,argport,pushport,subport,jint(argjson,"numpeers"),jint(argjson,"numutxos"),juint(argjson,"session"));
} }
} }*/
if ( method == 0 ) if ( method == 0 )
{ {
if ( is_cJSON_Array(argjson) != 0 ) if ( is_cJSON_Array(argjson) != 0 )
printf("RAWARRAY command? %s\n",jprint(argjson,0)); printf("RAWARRAY command? %s\n",jprint(argjson,0));
if ( flag == 0 || jobj(argjson,"result") != 0 ) if ( flag == 0 || jobj(argjson,"result") != 0 )
printf("stats_JSON no method: (%s) (%s:%u)\n",jprint(argjson,0),ipaddr,argport); printf("stats_JSON no method: (%s)\n",jprint(argjson,0));
return(0); return(0);
} }
/*if ( strcmp(method,"hello") == 0 ) if ( strcmp(method,"hello") == 0 )
{ {
//printf("got hello from %s:%u\n",ipaddr!=0?ipaddr:"",argport); //printf("got hello from %s:%u\n",ipaddr!=0?ipaddr:"",argport);
return(0); return(clonestr("{\"result\":\"success\",\"status\":\"got hello\"}"));
} }
else*/ if ( strcmp(method,"sendmessage") == 0 && jobj(argjson,"userpass") == 0 ) /*else if ( strcmp(method,"sendmessage") == 0 && jobj(argjson,"userpass") == 0 )
{ {
static char *laststr; static char *laststr;
char *newstr; bits256 pubkey = jbits256(argjson,"pubkey"); char *newstr; bits256 pubkey = jbits256(argjson,"pubkey");
@ -91,7 +86,7 @@ char *stats_JSON(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,char *r
retstr = clonestr(laststr); retstr = clonestr(laststr);
} }
} else retstr = clonestr("{\"error\":\"duplicate message\"}"); } else retstr = clonestr("{\"error\":\"duplicate message\"}");
} }*/
//else if ( strcmp(method,"nn_tests") == 0 ) //else if ( strcmp(method,"nn_tests") == 0 )
// return(clonestr("{\"result\":\"success\"}")); // return(clonestr("{\"result\":\"success\"}"));
else if ( strcmp(method,"help") == 0 ) else if ( strcmp(method,"help") == 0 )
@ -99,7 +94,7 @@ char *stats_JSON(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,char *r
available localhost RPC commands: \n \ available localhost RPC commands: \n \
pricearray(base, rel, starttime=0, endtime=-1, timescale=60) -> [timestamp, avebid, aveask, highbid, lowask]\n\ pricearray(base, rel, starttime=0, endtime=-1, timescale=60) -> [timestamp, avebid, aveask, highbid, lowask]\n\
setprice(base, rel, price)\n\ setprice(base, rel, price)\n\
autoprice(base, rel, minprice, margin, refbase, refrel, factor, offset)*\n\ autoprice(base, rel, fixed, minprice, margin, refbase, refrel, factor, offset)*\n\
goal(coin=*, val=<autocalc>)\n\ goal(coin=*, val=<autocalc>)\n\
myprice(base, rel)\n\ myprice(base, rel)\n\
enable(coin)\n\ enable(coin)\n\
@ -111,8 +106,8 @@ getrawtransaction(coin, txid)\n\
inventory(coin)\n\ inventory(coin)\n\
bestfit(rel, relvolume)\n\ bestfit(rel, relvolume)\n\
lastnonce()\n\ lastnonce()\n\
buy(base, rel, price, relvolume, timeout=10, duration=3600, nonce, pubkey="")\n\ buy(base, rel, price, relvolume, timeout=10, duration=3600, nonce, destpubkey="")\n\
sell(base, rel, price, basevolume, timeout=10, duration=3600, nonce, pubkey="")\n\ sell(base, rel, price, basevolume, timeout=10, duration=3600, nonce, destpubkey="")\n\
withdraw(coin, outputs[])\n\ withdraw(coin, outputs[])\n\
sendrawtransaction(coin, signedtx)\n\ sendrawtransaction(coin, signedtx)\n\
swapstatus()\n\ swapstatus()\n\
@ -132,9 +127,9 @@ trust(pubkey, trust) # positive to trust, 0 for normal, negative to blacklist\n\
balance(coin, address)\n\ balance(coin, address)\n\
orderbook(base, rel, duration=3600)\n\ orderbook(base, rel, duration=3600)\n\
getprices(base, rel)\n\ getprices(base, rel)\n\
sendmessage(base=coin, rel="", pubkey=zero, <argjson method2>)\n\ //sendmessage(base=coin, rel="", pubkey=zero, <argjson method2>)\n\
getmessages(firsti=0, num=100)\n\ //getmessages(firsti=0, num=100)\n\
deletemessages(firsti=0, num=100)\n\ //deletemessages(firsti=0, num=100)\n\
secretaddresses(prefix='secretaddress', passphrase, num=10, pubtype=60, taddr=0)\n\ secretaddresses(prefix='secretaddress', passphrase, num=10, pubtype=60, taddr=0)\n\
electrum(coin, ipaddr, port)\n\ electrum(coin, ipaddr, port)\n\
snapshot(coin, height)\n\ snapshot(coin, height)\n\
@ -142,6 +137,7 @@ snapshot_balance(coin, height, addresses[])\n\
dividends(coin, height, <args>)\n\ dividends(coin, height, <args>)\n\
stop()\n\ stop()\n\
bot_list()\n\ bot_list()\n\
bot_statuslist()\n\
bot_buy(base, rel, maxprice, relvolume) -> botid\n\ bot_buy(base, rel, maxprice, relvolume) -> botid\n\
bot_sell(base, rel, minprice, basevolume) -> botid\n\ bot_sell(base, rel, minprice, basevolume) -> botid\n\
bot_settings(botid, newprice, newvolume)\n\ bot_settings(botid, newprice, newvolume)\n\
@ -152,9 +148,12 @@ bot_resume(botid)\n\
\"}")); \"}"));
//sell(base, rel, price, basevolume, timeout=10, duration=3600)\n\ //sell(base, rel, price, basevolume, timeout=10, duration=3600)\n\
base = jstr(argjson,"base"); if ( (base= jstr(argjson,"base")) == 0 )
rel = jstr(argjson,"rel"); base = "";
coin = jstr(argjson,"coin"); if ((rel= jstr(argjson,"rel")) == 0 )
rel = "";
if ( (coin= jstr(argjson,"coin")) == 0 )
coin = "";
if ( G.USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) // protected localhost if ( G.USERPASS[0] != 0 && strcmp(remoteaddr,"127.0.0.1") == 0 && port != 0 ) // protected localhost
{ {
if ( G.USERPASS_COUNTER == 0 ) if ( G.USERPASS_COUNTER == 0 )
@ -182,14 +181,25 @@ bot_resume(botid)\n\
return(jprint(retjson,1)); return(jprint(retjson,1));
} }
} }
else if ( strcmp(method,"sendmessage") == 0 ) /*else if ( strcmp(method,"sendmessage") == 0 )
{ {
if ( jobj(argjson,"method2") == 0 ) if ( jobj(argjson,"method2") == 0 )
{ {
LP_broadcast_message(LP_mypubsock,base!=0?base:jstr(argjson,"coin"),rel,jbits256(argjson,"pubkey"),jprint(argjson,0)); LP_broadcast_message(LP_mypubsock,base!=0?base:coin,rel,jbits256(argjson,"pubkey"),jprint(argjson,0));
} }
return(clonestr("{\"result\":\"success\"}")); 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,"recentswaps") == 0 ) else if ( strcmp(method,"recentswaps") == 0 )
{ {
return(LP_recent_swaps(jint(argjson,"limit"))); return(LP_recent_swaps(jint(argjson,"limit")));
@ -204,17 +214,12 @@ bot_resume(botid)\n\
LP_millistats_update(0); LP_millistats_update(0);
return(clonestr("{\"result\":\"success\"}")); return(clonestr("{\"result\":\"success\"}"));
} }
else if ( strcmp(method,"getmessages") == 0 ) else if ( strcmp(method,"getprices") == 0 )
{ return(LP_prices());
if ( (retjson= LP_getmessages(jint(argjson,"firsti"),jint(argjson,"num"))) != 0 ) else if ( strcmp(method,"getpeers") == 0 )
return(jprint(retjson,1)); return(LP_peers());
else return(clonestr("{\"error\":\"null messages\"}")); else if ( strcmp(method,"getcoins") == 0 )
} return(jprint(LP_coinsjson(0),1));
else if ( strcmp(method,"deletemessages") == 0 )
{
LP_deletemessages(jint(argjson,"firsti"),jint(argjson,"num"));
return(clonestr("{\"result\":\"success\"}"));
}
else if ( strcmp(method,"notarizations") == 0 ) else if ( strcmp(method,"notarizations") == 0 )
{ {
int32_t height,bestheight; int32_t height,bestheight;
@ -256,17 +261,23 @@ bot_resume(botid)\n\
uint32_t requestid,quoteid; uint32_t requestid,quoteid;
if ( (requestid= juint(argjson,"requestid")) != 0 && (quoteid= juint(argjson,"quoteid")) != 0 ) if ( (requestid= juint(argjson,"requestid")) != 0 && (quoteid= juint(argjson,"quoteid")) != 0 )
return(basilisk_swapentry(requestid,quoteid)); return(basilisk_swapentry(requestid,quoteid));
else if ( coin != 0 && coin[0] != 0 ) else if ( coin[0] != 0 )
return(basilisk_swapentries(coin,0,jint(argjson,"limit"))); return(basilisk_swapentries(coin,0,jint(argjson,"limit")));
else if ( base != 0 && base[0] != 0 && rel != 0 && rel[0] != 0 ) else if ( base[0] != 0 && rel[0] != 0 )
return(basilisk_swapentries(base,rel,jint(argjson,"limit"))); return(basilisk_swapentries(base,rel,jint(argjson,"limit")));
else return(basilisk_swaplist(0,0)); else return(basilisk_swaplist(0,0));
} }
else if ( (retstr= LP_istradebots_command(ctx,pubsock,method,argjson)) != 0 ) else if ( (retstr= LP_istradebots_command(ctx,pubsock,method,argjson)) != 0 )
return(retstr); return(retstr);
if ( base != 0 && rel != 0 ) if ( base[0] != 0 && rel[0] != 0 )
{ {
double price,bid,ask; double price,bid,ask;
if ( strcmp(method,"autoprice") == 0 )
{
if ( LP_autoprice(base,rel,argjson) < 0 )
return(clonestr("{\"error\":\"couldnt set autoprice\"}"));
else return(clonestr("{\"result\":\"success\"}"));
}
if ( IAMLP == 0 && LP_isdisabled(base,rel) != 0 ) if ( IAMLP == 0 && LP_isdisabled(base,rel) != 0 )
return(clonestr("{\"error\":\"at least one of coins disabled\"}")); return(clonestr("{\"error\":\"at least one of coins disabled\"}"));
price = jdouble(argjson,"price"); price = jdouble(argjson,"price");
@ -278,16 +289,22 @@ bot_resume(botid)\n\
// return(clonestr("{\"error\":\"couldnt set price\"}")); // return(clonestr("{\"error\":\"couldnt set price\"}"));
else return(LP_pricepings(ctx,myipaddr,LP_mypubsock,base,rel,price * LP_profitratio)); else return(LP_pricepings(ctx,myipaddr,LP_mypubsock,base,rel,price * LP_profitratio));
} }
else if ( strcmp(method,"autoprice") == 0 ) else if ( strcmp(method,"pricearray") == 0 )
{ {
if ( LP_autoprice(base,rel,argjson) < 0 ) uint32_t firsttime;
return(clonestr("{\"error\":\"couldnt set autoprice\"}")); if ( base[0] != 0 && rel[0] != 0 )
else return(clonestr("{\"result\":\"success\"}")); {
if ( (firsttime= juint(argjson,"firsttime")) < time(NULL)-30*24*3600 )
firsttime = (uint32_t)(time(NULL)-30*24*3600);
return(jprint(LP_pricearray(base,rel,firsttime,juint(argjson,"lasttime"),jint(argjson,"timescale")),1));
} else return(clonestr("{\"error\":\"pricearray needs base and rel\"}"));
} }
else if ( strcmp(method,"pricearray") == 0 ) /*else if ( strcmp(method,"pricearray") == 0 )
{ {
return(jprint(LP_pricearray(base,rel,juint(argjson,"starttime"),juint(argjson,"endtime"),jint(argjson,"timescale")),1)); return(jprint(LP_pricearray(base,rel,juint(argjson,"starttime"),juint(argjson,"endtime"),jint(argjson,"timescale")),1));
} }*/
else if ( strcmp(method,"orderbook") == 0 )
return(LP_orderbook(base,rel,jint(argjson,"duration")));
else if ( strcmp(method,"myprice") == 0 ) else if ( strcmp(method,"myprice") == 0 )
{ {
if ( LP_myprice(&bid,&ask,base,rel) > SMALLVAL ) if ( LP_myprice(&bid,&ask,base,rel) > SMALLVAL )
@ -305,7 +322,7 @@ bot_resume(botid)\n\
//* //*
if ( price > SMALLVAL ) if ( price > SMALLVAL )
{ {
return(LP_autobuy(ctx,myipaddr,pubsock,base,rel,price,jdouble(argjson,"relvolume"),jint(argjson,"timeout"),jint(argjson,"duration"),jstr(argjson,"gui"),juint(argjson,"nonce"),jbits256(argjson,"pubkey"),0)); return(LP_autobuy(ctx,myipaddr,pubsock,base,rel,price,jdouble(argjson,"relvolume"),jint(argjson,"timeout"),jint(argjson,"duration"),jstr(argjson,"gui"),juint(argjson,"nonce"),jbits256(argjson,"destpubkey"),0));
} else return(clonestr("{\"error\":\"no price set\"}")); } else return(clonestr("{\"error\":\"no price set\"}"));
} }
else if ( strcmp(method,"sell") == 0 ) else if ( strcmp(method,"sell") == 0 )
@ -313,18 +330,18 @@ bot_resume(botid)\n\
//* //*
if ( price > SMALLVAL ) if ( price > SMALLVAL )
{ {
return(LP_autobuy(ctx,myipaddr,pubsock,rel,base,1./price,jdouble(argjson,"basevolume"),jint(argjson,"timeout"),jint(argjson,"duration"),jstr(argjson,"gui"),juint(argjson,"nonce"),jbits256(argjson,"pubkey"),0)); return(LP_autobuy(ctx,myipaddr,pubsock,rel,base,1./price,jdouble(argjson,"basevolume"),jint(argjson,"timeout"),jint(argjson,"duration"),jstr(argjson,"gui"),juint(argjson,"nonce"),jbits256(argjson,"destpubkey"),0));
} else return(clonestr("{\"error\":\"no price set\"}")); } else return(clonestr("{\"error\":\"no price set\"}"));
} }
} }
else if ( rel != 0 && strcmp(method,"bestfit") == 0 ) else if ( rel[0] != 0 && strcmp(method,"bestfit") == 0 )
{ {
double relvolume; double relvolume;
if ( (relvolume= jdouble(argjson,"relvolume")) > SMALLVAL ) if ( (relvolume= jdouble(argjson,"relvolume")) > SMALLVAL )
return(LP_bestfit(rel,relvolume)); return(LP_bestfit(rel,relvolume));
else return(clonestr("{\"error\":\"no relvolume set\"}")); else return(clonestr("{\"error\":\"no relvolume set\"}"));
} }
else if ( (coin= jstr(argjson,"coin")) != 0 ) else if ( coin[0] != 0 )
{ {
if ( strcmp(method,"enable") == 0 ) if ( strcmp(method,"enable") == 0 )
{ {
@ -341,9 +358,15 @@ bot_resume(botid)\n\
if ( LP_conflicts_find(ptr) == 0 ) if ( LP_conflicts_find(ptr) == 0 )
{ {
ptr->inactive = 0; ptr->inactive = 0;
cJSON *array = cJSON_CreateArray(); cJSON *array;
if ( ptr->smartaddr[0] != 0 ) if ( ptr->smartaddr[0] != 0 )
LP_unspents_load(coin,ptr->smartaddr); LP_unspents_load(coin,ptr->smartaddr);
if ( LP_getheight(ptr) <= 0 )
{
ptr->inactive = (uint32_t)time(NULL);
return(clonestr("{\"error\":\"coin cant be activated till synced\"}"));
} else LP_unspents_load(coin,ptr->smartaddr);
array = cJSON_CreateArray();
jaddi(array,LP_coinjson(ptr,0)); jaddi(array,LP_coinjson(ptr,0));
return(jprint(array,1)); return(jprint(array,1));
} else return(clonestr("{\"error\":\"coin port conflicts with existing coin\"}")); } else return(clonestr("{\"error\":\"coin port conflicts with existing coin\"}"));
@ -360,6 +383,40 @@ bot_resume(botid)\n\
return(jprint(array,1)); return(jprint(array,1));
} else return(clonestr("{\"error\":\"couldnt find coin\"}")); } else return(clonestr("{\"error\":\"couldnt find coin\"}"));
} }
else if ( strcmp(method,"listunspent") == 0 )
{
if ( (ptr= LP_coinsearch(coin)) != 0 )
{
char *coinaddr;
if ( (coinaddr= jstr(argjson,"address")) != 0 )
{
if ( coinaddr[0] != 0 )
{
LP_address(ptr,coinaddr);
if ( strcmp(coinaddr,ptr->smartaddr) == 0 && bits256_nonz(G.LP_privkey) != 0 )
{
LP_listunspent_issue(coin,coinaddr,2);
LP_privkey_init(-1,ptr,G.LP_privkey,G.LP_mypub25519);
//LP_smartutxos_push(ptr);
if ( ptr->electrum != 0 )
return(LP_unspents_filestr(coin,ptr->smartaddr));
else return(jprint(LP_address_utxos(ptr,coinaddr,1),1));
}
else
{
return(clonestr("{\"error\":\"not my address\"}"));
}
}
return(jprint(LP_address_utxos(ptr,coinaddr,1),1));
} else return(clonestr("{\"error\":\"no address specified\"}"));
} else return(clonestr("{\"error\":\"cant find coind\"}"));
}
else if ( strcmp(method,"balance") == 0 )
{
if ( (ptr= LP_coinsearch(coin)) != 0 )
return(jprint(LP_address_balance(ptr,jstr(argjson,"address"),1),1));
else return(clonestr("{\"error\":\"cant find coind\"}"));
}
else if ( strcmp(method,"electrum") == 0 ) else if ( strcmp(method,"electrum") == 0 )
{ {
if ( (ptr= LP_coinsearch(coin)) != 0 ) if ( (ptr= LP_coinsearch(coin)) != 0 )
@ -429,6 +486,8 @@ bot_resume(botid)\n\
{ {
//privkey = LP_privkeycalc(ctx,pubkey33,&pubkey,ptr,"",USERPASS_WIFSTR); //privkey = LP_privkeycalc(ctx,pubkey33,&pubkey,ptr,"",USERPASS_WIFSTR);
//LP_utxopurge(0); //LP_utxopurge(0);
LP_address(ptr,ptr->smartaddr);
LP_listunspent_issue(coin,ptr->smartaddr,2);
if ( bits256_nonz(G.LP_privkey) != 0 ) if ( bits256_nonz(G.LP_privkey) != 0 )
LP_privkey_init(-1,ptr,G.LP_privkey,G.LP_mypub25519); LP_privkey_init(-1,ptr,G.LP_privkey,G.LP_mypub25519);
else printf("no LP_privkey\n"); else printf("no LP_privkey\n");
@ -485,45 +544,35 @@ bot_resume(botid)\n\
return(LP_uitem_recv(argjson)); return(LP_uitem_recv(argjson));
else if ( strcmp(method,"notify") == 0 ) else if ( strcmp(method,"notify") == 0 )
return(LP_notify_recv(argjson)); return(LP_notify_recv(argjson));
else if ( strcmp(method,"getpeers") == 0 )
retstr = clonestr("{\"error\":\"deprecated\"}");
/*else if ( strcmp(method,"getpeers") == 0 )
{
char *tmpstr;
if ( (tmpstr= jstr(argjson,"LPnode")) != 0 )
LP_addpeer(LP_mypeer,LP_mypubsock,tmpstr,RPC_port,RPC_port+10,RPC_port+20,1,G.LP_sessionid);
if ( IAMLP != 0 )
{
printf("send peers list %s\n",LP_peers());
bits256 zero; memset(zero.bytes,0,sizeof(zero));
LP_reserved_msg(0,"","",zero,LP_peers());
}
retstr = clonestr("{\"result\":\"success\"}");
}*/
// end received response // end received response
// public access, even from http
else if ( strcmp(method,"tradestatus") == 0 ) else if ( strcmp(method,"tradestatus") == 0 )
{ {
LP_tradecommand_log(argjson); LP_tradecommand_log(argjson);
printf("GOT TRADESTATUS! %s\n",jprint(argjson,0)); printf("GOT TRADESTATUS! %s\n",jprint(argjson,0));
retstr = clonestr("{\"result\":\"success\"}"); retstr = clonestr("{\"result\":\"success\"}");
} }
else if ( strcmp(method,"balance") == 0 )
{
if ( (ptr= LP_coinsearch(jstr(argjson,"coin"))) != 0 )
return(jprint(LP_address_balance(ptr,jstr(argjson,"address"),1),1));
else return(clonestr("{\"error\":\"cant find coind\"}"));
}
else if ( strcmp(method,"pricearray") == 0 )
{
uint32_t firsttime;
if ( base != 0 && rel != 0 )
{
if ( (firsttime= juint(argjson,"firsttime")) < time(NULL)-30*24*3600 )
firsttime = (uint32_t)(time(NULL)-30*24*3600);
return(jprint(LP_pricearray(base,rel,firsttime,juint(argjson,"lasttime"),jint(argjson,"timescale")),1));
} else return(clonestr("{\"error\":\"pricearray needs base and rel\"}"));
}
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,"getpeers") == 0 )
return(LP_peers());
else if ( strcmp(method,"getcoins") == 0 )
return(jprint(LP_coinsjson(0),1));
else if ( strcmp(method,"wantnotify") == 0 ) else if ( strcmp(method,"wantnotify") == 0 )
{ {
bits256 pub; static uint32_t lastnotify; bits256 pub; static uint32_t lastnotify;
pub = jbits256(argjson,"pub"); pub = jbits256(argjson,"pub");
//char str[65]; printf("got wantnotify.(%s) vs %s\n",jprint(argjson,0),bits256_str(str,G.LP_mypub25519)); //char str[65]; printf("got wantnotify.(%s) vs %s\n",jprint(argjson,0),bits256_str(str,G.LP_mypub25519));
if ( bits256_cmp(pub,G.LP_mypub25519) == 0 && time(NULL) > lastnotify+30 ) if ( bits256_cmp(pub,G.LP_mypub25519) == 0 && time(NULL) > lastnotify+60 )
{ {
lastnotify = (uint32_t)time(NULL); lastnotify = (uint32_t)time(NULL);
//printf("wantnotify for me!\n"); //printf("wantnotify for me!\n");
@ -531,36 +580,10 @@ bot_resume(botid)\n\
} }
retstr = clonestr("{\"result\":\"success\"}"); retstr = clonestr("{\"result\":\"success\"}");
} }
else if ( strcmp(method,"listunspent") == 0 )
{
if ( (ptr= LP_coinsearch(jstr(argjson,"coin"))) != 0 )
{
char *coinaddr;
if ( (coinaddr= jstr(argjson,"address")) != 0 )
{
if ( coinaddr[0] != 0 )
{
LP_address(ptr,coinaddr);
LP_listunspent_issue(coin,coinaddr,1);
if ( strcmp(coinaddr,ptr->smartaddr) == 0 && bits256_nonz(G.LP_privkey) != 0 )
{
//printf("network invoked\n");
LP_privkey_init(-1,ptr,G.LP_privkey,G.LP_mypub25519);
//LP_smartutxos_push(ptr);
}
else
{
}
}
return(jprint(LP_address_utxos(ptr,coinaddr,1),1));
} else return(clonestr("{\"error\":\"no address specified\"}"));
} else return(clonestr("{\"error\":\"cant find coind\"}"));
}
else if ( strcmp(method,"addr_unspents") == 0 ) else if ( strcmp(method,"addr_unspents") == 0 )
{ {
//printf("GOT ADDR_UNSPENTS %s %s\n",jstr(argjson,"coin"),jstr(argjson,"address")); //printf("GOT ADDR_UNSPENTS %s %s\n",jstr(argjson,"coin"),jstr(argjson,"address"));
if ( (ptr= LP_coinsearch(jstr(argjson,"coin"))) != 0 ) if ( (ptr= LP_coinsearch(coin)) != 0 )
{ {
char *coinaddr; char *coinaddr;
if ( (coinaddr= jstr(argjson,"address")) != 0 ) if ( (coinaddr= jstr(argjson,"address")) != 0 )
@ -571,6 +594,8 @@ bot_resume(botid)\n\
if ( strcmp(coinaddr,ptr->smartaddr) == 0 && bits256_nonz(G.LP_privkey) != 0 ) if ( strcmp(coinaddr,ptr->smartaddr) == 0 && bits256_nonz(G.LP_privkey) != 0 )
{ {
//printf("ADDR_UNSPENTS %s %s is my address being asked for!\n",ptr->symbol,coinaddr); //printf("ADDR_UNSPENTS %s %s is my address being asked for!\n",ptr->symbol,coinaddr);
if ( ptr->lastpushtime > 0 && ptr->addr_listunspent_requested > (uint32_t)time(NULL)-10 )
ptr->lastpushtime -= LP_ORDERBOOK_DURATION*0.1;
ptr->addr_listunspent_requested = (uint32_t)time(NULL); ptr->addr_listunspent_requested = (uint32_t)time(NULL);
} }
} }

77
iguana/exchanges/LP_include.h

@ -21,6 +21,10 @@
#ifndef LP_INCLUDE_H #ifndef LP_INCLUDE_H
#define LP_INCLUDE_H #define LP_INCLUDE_H
#define LP_MAJOR_VERSION "0"
#define LP_MINOR_VERSION "1"
#define LP_BUILD_NUMBER "14336"
#ifdef FROM_JS #ifdef FROM_JS
#include <emscripten.h> #include <emscripten.h>
#define sleep(x) emscripten_usleep((x) * 1000000) #define sleep(x) emscripten_usleep((x) * 1000000)
@ -34,16 +38,24 @@ void emscripten_usleep(int32_t x); // returns immediate, no sense for sleeping
#endif #endif
//#define LP_STRICTPEERS //#define LP_STRICTPEERS
#define LP_BARTERDEX_VERSION 0 #define LP_BARTERDEX_VERSION 1
#define LP_MAGICBITS 8 #define LP_MAGICBITS 8
#define LP_MAXVINS 64
#define LP_HTTP_TIMEOUT 3 // 1 is too small due to edge cases of time(NULL) #define LP_HTTP_TIMEOUT 3 // 1 is too small due to edge cases of time(NULL)
#define LP_AUTOTRADE_TIMEOUT 20 #define LP_AUTOTRADE_TIMEOUT 40
#define ELECTRUM_TIMEOUT 10 #define ELECTRUM_TIMEOUT 7
#define LP_ELECTRUM_KEEPALIVE 60 #define LP_ELECTRUM_KEEPALIVE 60
#define LP_ELECTRUM_MAXERRORS 777 #define LP_ELECTRUM_MAXERRORS 777
#define LP_MEMPOOL_TIMEINCR 10 #define LP_MEMPOOL_TIMEINCR 10
#define LP_MIN_PEERS 8
#define LP_MAX_PEERS 32
#define LP_MAXDESIRED_UTXOS 128
#define LP_MINDESIRED_UTXOS 32
#define LP_DUSTCOMBINE_THRESHOLD 1000000
// RTmetrics // RTmetrics
#define LP_RTMETRICS_TOPGROUP 1.01 #define LP_RTMETRICS_TOPGROUP 1.01
#define LP_MAXPENDING_SWAPS 13 #define LP_MAXPENDING_SWAPS 13
@ -52,7 +64,7 @@ void emscripten_usleep(int32_t x); // returns immediate, no sense for sleeping
#define LP_COMMAND_RECVSOCK NN_PULL #define LP_COMMAND_RECVSOCK NN_PULL
#define DPOW_MIN_ASSETCHAIN_SIGS 11 #define DPOW_MIN_ASSETCHAIN_SIGS 11
#define LP_ENCRYPTED_MAXSIZE (4096 + 2 + crypto_box_NONCEBYTES + crypto_box_ZEROBYTES) #define LP_ENCRYPTED_MAXSIZE (16384 + 2 + crypto_box_NONCEBYTES + crypto_box_ZEROBYTES)
#define LP_MAXPUBKEY_ERRORS 10 #define LP_MAXPUBKEY_ERRORS 10
#define PSOCK_KEEPALIVE 3600 #define PSOCK_KEEPALIVE 3600
@ -156,7 +168,7 @@ struct basilisk_rawtxinfo
{ {
char destaddr[64],coinstr[16]; char destaddr[64],coinstr[16];
bits256 txid,signedtxid,actualtxid; bits256 txid,signedtxid,actualtxid;
uint64_t amount,change,inputsum; int64_t amount,change,inputsum;
int32_t redeemlen,datalen,completed,vintype,vouttype,numconfirms,spendlen,secretstart,suppress_pubkeys; int32_t redeemlen,datalen,completed,vintype,vouttype,numconfirms,spendlen,secretstart,suppress_pubkeys;
uint32_t locktime,crcs[2]; uint32_t locktime,crcs[2];
uint8_t addrtype,pubkey33[33],rmd160[20]; uint8_t addrtype,pubkey33[33],rmd160[20];
@ -165,7 +177,7 @@ struct basilisk_rawtxinfo
struct basilisk_request struct basilisk_request
{ {
uint32_t requestid,timestamp,quoteid,quotetime; // 0 to 15 uint32_t requestid,timestamp,quoteid,quotetime; // 0 to 15
uint64_t srcamount,unused; // 16 to 31 int64_t srcamount,unused; // 16 to 31
bits256 srchash; // 32 to 63 bits256 srchash; // 32 to 63
bits256 desthash; bits256 desthash;
char src[8],dest[8]; char src[8],dest[8];
@ -192,7 +204,7 @@ struct basilisk_swapinfo
bits256 myhash,otherhash,orderhash; bits256 myhash,otherhash,orderhash;
uint32_t statebits,otherstatebits,started,expiration,finished,dead,reftime,putduration,callduration; uint32_t statebits,otherstatebits,started,expiration,finished,dead,reftime,putduration,callduration;
int32_t bobconfirms,aliceconfirms,iambob,reclaimed,bobspent,alicespent,pad,aliceistrusted,bobistrusted,otheristrusted,otherstrust,alicemaxconfirms,bobmaxconfirms; int32_t bobconfirms,aliceconfirms,iambob,reclaimed,bobspent,alicespent,pad,aliceistrusted,bobistrusted,otheristrusted,otherstrust,alicemaxconfirms,bobmaxconfirms;
uint64_t alicesatoshis,bobsatoshis,bobinsurance,aliceinsurance,Atxfee,Btxfee; int64_t alicesatoshis,bobsatoshis,bobinsurance,aliceinsurance,Atxfee,Btxfee;
bits256 myprivs[2],mypubs[2],otherpubs[2],pubA0,pubA1,pubB0,pubB1,privAm,pubAm,privBn,pubBn; 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]; uint32_t crcs_mypub[2],crcs_mychoosei[2],crcs_myprivs[2],crcs_mypriv[2];
@ -226,18 +238,26 @@ struct LP_swap_remember
bits256 pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)]; bits256 pubA0,pubB0,pubB1,privAm,privBn,paymentspent,Apaymentspent,depositspent,myprivs[2],txids[sizeof(txnames)/sizeof(*txnames)];
uint64_t Atxfee,Btxfee,srcamount,destamount,aliceid; uint64_t Atxfee,Btxfee,srcamount,destamount,aliceid;
int64_t values[sizeof(txnames)/sizeof(*txnames)]; int64_t values[sizeof(txnames)/sizeof(*txnames)];
uint32_t tradeid,requestid,quoteid,plocktime,dlocktime,expiration,state,otherstate; uint32_t finishtime,tradeid,requestid,quoteid,plocktime,dlocktime,expiration,state,otherstate;
int32_t iambob,finishedflag,origfinishedflag,Predeemlen,Dredeemlen,sentflags[sizeof(txnames)/sizeof(*txnames)]; int32_t iambob,finishedflag,origfinishedflag,Predeemlen,Dredeemlen,sentflags[sizeof(txnames)/sizeof(*txnames)];
uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],Predeemscript[1024],Dredeemscript[1024],pubkey33[33],other33[33]; uint8_t secretAm[20],secretAm256[32],secretBn[20],secretBn256[32],Predeemscript[1024],Dredeemscript[1024],pubkey33[33],other33[33];
char src[64],dest[64],destaddr[64],Adestaddr[64],Sdestaddr[64],alicepaymentaddr[64],bobpaymentaddr[64],bobdepositaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)]; char src[64],dest[64],destaddr[64],Adestaddr[64],Sdestaddr[64],alicepaymentaddr[64],bobpaymentaddr[64],bobdepositaddr[64],alicecoin[64],bobcoin[64],*txbytes[sizeof(txnames)/sizeof(*txnames)];
}; };
struct LP_outpoint { bits256 spendtxid; uint64_t value,interest; int32_t spendvini,spendheight; char coinaddr[64]; }; struct LP_outpoint
{
bits256 spendtxid;
uint64_t value,interest;
int32_t spendvini,spendheight;
char coinaddr[64];
};
struct LP_transaction struct LP_transaction
{ {
UT_hash_handle hh; UT_hash_handle hh;
bits256 txid; int32_t height,numvouts,numvins,len; //uint32_t timestamp; bits256 txid;
long fpos;
int32_t height,numvouts,numvins,len,SPV;
uint8_t *serialized; uint8_t *serialized;
struct LP_outpoint outpoints[]; struct LP_outpoint outpoints[];
}; };
@ -247,8 +267,8 @@ struct iguana_info
UT_hash_handle hh; UT_hash_handle hh;
portable_mutex_t txmutex,addrmutex; struct LP_transaction *transactions; struct LP_address *addresses; portable_mutex_t txmutex,addrmutex; struct LP_transaction *transactions; struct LP_address *addresses;
uint64_t txfee; uint64_t txfee;
int32_t longestchain,firstrefht,firstscanht,lastscanht,bussock,height; uint16_t busport; int32_t numutxos,longestchain,firstrefht,firstscanht,lastscanht,bussock,height; uint16_t busport;
uint32_t importedprivkey,lastpushtime,lastutxosync,addr_listunspent_requested,lastutxos,updaterate,counter,inactive,lastmempool,lastgetinfo,ratetime,heighttime,lastmonitor,obooktime; uint32_t loadedcache,electrumlist,lastunspent,importedprivkey,lastpushtime,lastutxosync,addr_listunspent_requested,lastutxos,updaterate,counter,inactive,lastmempool,lastgetinfo,ratetime,heighttime,lastmonitor,obooktime;
uint8_t pubtype,p2shtype,isPoS,wiftype,wiftaddr,taddr,noimportprivkey_flag,userconfirms,isassetchain,maxconfirms; uint8_t pubtype,p2shtype,isPoS,wiftype,wiftaddr,taddr,noimportprivkey_flag,userconfirms,isassetchain,maxconfirms;
char symbol[16],smartaddr[64],userpass[1024],serverport[128]; char symbol[16],smartaddr[64],userpass[1024],serverport[128];
// portfolio // portfolio
@ -256,6 +276,7 @@ struct iguana_info
void *electrum; void *ctx; void *electrum; void *ctx;
uint64_t maxamount,kmd_equiv,balanceA,balanceB,valuesumA,valuesumB; uint64_t maxamount,kmd_equiv,balanceA,balanceB,valuesumA,valuesumB;
uint8_t pubkey33[33],zcash; uint8_t pubkey33[33],zcash;
bits256 lastprivkey; uint32_t lastprivkeytime; int32_t privkeydepth;
bits256 cachedtxid; uint8_t *cachedtxiddata; int32_t cachedtxidlen; bits256 cachedtxid; uint8_t *cachedtxiddata; int32_t cachedtxidlen;
bits256 cachedmerkle; int32_t cachedmerkleheight; bits256 cachedmerkle; int32_t cachedmerkleheight;
}; };
@ -306,8 +327,8 @@ struct LP_peerinfo
{ {
UT_hash_handle hh; UT_hash_handle hh;
uint64_t ip_port; uint64_t ip_port;
uint32_t ipbits,errortime,errors,numpeers,needping,lasttime,connected,lastutxos,lastpeers,diduquery,good,sessionid; uint32_t recvtime,numrecv,ipbits,errortime,errors,numpeers,needping,lasttime,connected,lastutxos,lastpeers,diduquery,good,sessionid;
int32_t pushsock,subsock; int32_t pushsock,subsock,isLP;
uint16_t port; uint16_t port;
char ipaddr[64]; char ipaddr[64];
}; };
@ -350,11 +371,24 @@ struct LP_pubkeyinfo
bits256 pubkey; bits256 pubkey;
float matrix[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS]; float matrix[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS];
//uint32_t timestamps[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS]; //uint32_t timestamps[LP_MAXPRICEINFOS][LP_MAXPRICEINFOS];
uint32_t timestamp,numerrors; uint32_t timestamp,numerrors,lasttime;
int32_t istrusted; int32_t istrusted;
uint8_t rmd160[20],sig[65],pubsecp[33],siglen; uint8_t rmd160[20],sig[65],pubsecp[33],siglen;
}; };
struct electrum_info
{
queue_t sendQ,pendingQ;
portable_mutex_t mutex,txmutex;
struct electrum_info *prev;
int32_t bufsize,sock,*heightp,numerrors;
struct iguana_info *coin;
uint32_t stratumid,lasttime,keepalive,pending,*heighttimep;
char ipaddr[64],symbol[16];
uint16_t port;
uint8_t buf[];
};
int32_t LP_pubkey_sigcheck(struct LP_pubkeyinfo *pubp,cJSON *item); int32_t LP_pubkey_sigcheck(struct LP_pubkeyinfo *pubp,cJSON *item);
int32_t LP_pubkey_sigadd(cJSON *item,uint32_t timestamp,bits256 priv,bits256 pub,uint8_t *rmd160,uint8_t *pubsecp); int32_t LP_pubkey_sigadd(cJSON *item,uint32_t timestamp,bits256 priv,bits256 pub,uint8_t *rmd160,uint8_t *pubsecp);
int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson); int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson);
@ -385,12 +419,19 @@ uint16_t LP_psock_get(char *connectaddr,char *publicaddr,int32_t ispaired);
//void LP_utxo_clientpublish(struct LP_utxoinfo *utxo); //void LP_utxo_clientpublish(struct LP_utxoinfo *utxo);
int32_t LP_coinbus(uint16_t coin_busport); int32_t LP_coinbus(uint16_t coin_busport);
int32_t LP_nanomsg_recvs(void *ctx); int32_t LP_nanomsg_recvs(void *ctx);
void LP_aliceid(uint32_t tradeid,uint64_t aliceid,char *event,uint32_t requestid,uint32_t quoteid);
cJSON *LP_cache_transaction(struct iguana_info *coin,bits256 txid,uint8_t *serialized,int32_t len);
cJSON *LP_transaction_fromdata(struct iguana_info *coin,bits256 txid,uint8_t *serialized,int32_t len);
uint64_t LP_RTsmartbalance(struct iguana_info *coin); uint64_t LP_RTsmartbalance(struct iguana_info *coin);
int32_t LP_getheight(struct iguana_info *coin); int32_t LP_getheight(struct iguana_info *coin);
int32_t LP_reserved_msg(int32_t priority,char *base,char *rel,bits256 pubkey,char *msg); int32_t LP_reserved_msg(int32_t priority,char *base,char *rel,bits256 pubkey,char *msg);
struct iguana_info *LP_coinfind(char *symbol); struct iguana_info *LP_coinfind(char *symbol);
int32_t LP_crc32find(int32_t *duplicatep,int32_t ind,uint32_t crc32); 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); char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,char *base,char *rel,double price);
int32_t LP_merkleproof(struct iguana_info *coin,char *coinaddr,struct electrum_info *ep,bits256 txid,int32_t height);
int32_t _LP_utxos_remove(bits256 txid,int32_t vout);
int32_t LP_utxos_remove(bits256 txid,int32_t vout);
struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,int32_t height,int32_t numvouts,int32_t numvins);
void LP_tradebot_finished(uint32_t tradeid,uint32_t requestid,uint32_t quoteid); void LP_tradebot_finished(uint32_t tradeid,uint32_t requestid,uint32_t quoteid);
uint64_t LP_txfeecalc(struct iguana_info *coin,uint64_t txfee,int32_t txlen); uint64_t LP_txfeecalc(struct iguana_info *coin,uint64_t txfee,int32_t txlen);
struct LP_address *_LP_address(struct iguana_info *coin,char *coinaddr); struct LP_address *_LP_address(struct iguana_info *coin,char *coinaddr);
@ -402,6 +443,9 @@ struct LP_address_utxo *LP_address_utxofind(struct iguana_info *coin,char *coina
int32_t LP_destaddr(char *destaddr,cJSON *item); int32_t LP_destaddr(char *destaddr,cJSON *item);
int32_t LP_waitmempool(char *symbol,char *coinaddr,bits256 txid,int32_t vout,int32_t duration); int32_t LP_waitmempool(char *symbol,char *coinaddr,bits256 txid,int32_t vout,int32_t duration);
char *LP_statslog_disp(int32_t n,uint32_t starttime,uint32_t endtime,char *refgui,bits256 refpubkey); char *LP_statslog_disp(int32_t n,uint32_t starttime,uint32_t endtime,char *refgui,bits256 refpubkey);
uint32_t LP_heighttime(char *symbol,int32_t height);
uint64_t LP_unspents_load(char *symbol,char *addr);
int32_t LP_validSPV(char *symbol,char *coinaddr,bits256 txid,int32_t vout);
struct LP_transaction *LP_transactionfind(struct iguana_info *coin,bits256 txid); struct LP_transaction *LP_transactionfind(struct iguana_info *coin,bits256 txid);
cJSON *LP_transactioninit(struct iguana_info *coin,bits256 txid,int32_t iter,cJSON *txobj); cJSON *LP_transactioninit(struct iguana_info *coin,bits256 txid,int32_t iter,cJSON *txobj);
int32_t LP_mempoolscan(char *symbol,bits256 searchtxid); int32_t LP_mempoolscan(char *symbol,bits256 searchtxid);
@ -411,11 +455,14 @@ char *basilisk_swapentry(uint32_t requestid,uint32_t quoteid);
uint64_t LP_KMDvalue(struct iguana_info *coin,uint64_t balance); uint64_t LP_KMDvalue(struct iguana_info *coin,uint64_t balance);
int32_t LP_address_utxoadd(char *debug,struct iguana_info *coin,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t height,int32_t spendheight); int32_t LP_address_utxoadd(char *debug,struct iguana_info *coin,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t height,int32_t spendheight);
void LP_smartutxos_push(struct iguana_info *coin); void LP_smartutxos_push(struct iguana_info *coin);
void LP_cacheptrs_init(struct iguana_info *coin);
cJSON *LP_address_utxos(struct iguana_info *coin,char *coinaddr,int32_t electrumret); cJSON *LP_address_utxos(struct iguana_info *coin,char *coinaddr,int32_t electrumret);
cJSON *LP_gettxout(char *symbol,char *coinaddr,bits256 txid,int32_t vout); cJSON *LP_gettxout(char *symbol,char *coinaddr,bits256 txid,int32_t vout);
void LP_postutxos(char *symbol,char *coinaddr); void LP_postutxos(char *symbol,char *coinaddr);
int32_t LP_listunspent_both(char *symbol,char *coinaddr,int32_t fullflag); int32_t LP_listunspent_both(char *symbol,char *coinaddr,int32_t fullflag);
uint16_t LP_randpeer(char *destip); uint16_t LP_randpeer(char *destip);
char *issue_LP_psock(char *destip,uint16_t destport,int32_t ispaired);
char *LP_unspents_filestr(char *symbol,char *addr);
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 zcash); 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 zcash);
//int32_t LP_butxo_findeither(bits256 txid,int32_t vout); //int32_t LP_butxo_findeither(bits256 txid,int32_t vout);
cJSON *LP_listunspent(char *symbol,char *coinaddr); cJSON *LP_listunspent(char *symbol,char *coinaddr);

307
iguana/exchanges/LP_nativeDEX.c

@ -18,10 +18,15 @@
// LP_nativeDEX.c // LP_nativeDEX.c
// marketmaker // marketmaker
// //
// verify portfolio, interest to KMD withdraw // alice waiting for bestprice
// regen inventory
// previously, it used to show amount, kmd equiv, perc
// there is still a pending one with `-1 wait for bobpayment bYoNxkfvwQ42Yufry8J5y8BYi6mQxokvW9 numconfs.1 MNZ c0ea4aa808a653222a15122d96692fecf734dbbacfb9a54cb4711306ea0c3cef`, but that tx is already spent including 6 confirmation
// bot safe to exit?
//
// BCH signing
// dPoW security -> 4: KMD notarized, 5: BTC notarized, after next notary elections // dPoW security -> 4: KMD notarized, 5: BTC notarized, after next notary elections
// bigendian architectures need to use little endian for sighash calcs // bigendian architectures need to use little endian for sighash calcs
// BCH signing
#include <stdio.h> #include <stdio.h>
struct LP_millistats struct LP_millistats
@ -29,7 +34,7 @@ struct LP_millistats
double lastmilli,millisum,threshold; double lastmilli,millisum,threshold;
uint32_t count; uint32_t count;
char name[64]; char name[64];
} LP_psockloop_stats,LP_reserved_msgs_stats,utxosQ_loop_stats,command_rpcloop_stats,queue_loop_stats,prices_loop_stats,LP_coinsloop_stats,LP_coinsloopBTC_stats,LP_coinsloopKMD_stats,LP_pubkeysloop_stats,LP_privkeysloop_stats,LP_swapsloop_stats; } LP_psockloop_stats,LP_reserved_msgs_stats,utxosQ_loop_stats,command_rpcloop_stats,queue_loop_stats,prices_loop_stats,LP_coinsloop_stats,LP_coinsloopBTC_stats,LP_coinsloopKMD_stats,LP_pubkeysloop_stats,LP_privkeysloop_stats,LP_swapsloop_stats,LP_gcloop_stats;
extern int32_t IAMLP; extern int32_t IAMLP;
void LP_millistats_update(struct LP_millistats *mp) void LP_millistats_update(struct LP_millistats *mp)
@ -52,6 +57,7 @@ void LP_millistats_update(struct LP_millistats *mp)
mp = &LP_pubkeysloop_stats, printf("%32s lag %10.2f millis, threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,OS_milliseconds() - mp->lastmilli,mp->threshold,mp->millisum/(mp->count > 0 ? mp->count: 1),mp->count); mp = &LP_pubkeysloop_stats, printf("%32s lag %10.2f millis, threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,OS_milliseconds() - mp->lastmilli,mp->threshold,mp->millisum/(mp->count > 0 ? mp->count: 1),mp->count);
mp = &LP_privkeysloop_stats, printf("%32s lag %10.2f millis, threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,OS_milliseconds() - mp->lastmilli,mp->threshold,mp->millisum/(mp->count > 0 ? mp->count: 1),mp->count); mp = &LP_privkeysloop_stats, printf("%32s lag %10.2f millis, threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,OS_milliseconds() - mp->lastmilli,mp->threshold,mp->millisum/(mp->count > 0 ? mp->count: 1),mp->count);
mp = &LP_swapsloop_stats, printf("%32s lag %10.2f millis, threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,OS_milliseconds() - mp->lastmilli,mp->threshold,mp->millisum/(mp->count > 0 ? mp->count: 1),mp->count); mp = &LP_swapsloop_stats, printf("%32s lag %10.2f millis, threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,OS_milliseconds() - mp->lastmilli,mp->threshold,mp->millisum/(mp->count > 0 ? mp->count: 1),mp->count);
mp = &LP_gcloop_stats, printf("%32s lag %10.2f millis, threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,OS_milliseconds() - mp->lastmilli,mp->threshold,mp->millisum/(mp->count > 0 ? mp->count: 1),mp->count);
} }
else else
{ {
@ -65,7 +71,8 @@ void LP_millistats_update(struct LP_millistats *mp)
mp->millisum += elapsed; mp->millisum += elapsed;
if ( mp->threshold != 0. && elapsed > mp->threshold ) if ( mp->threshold != 0. && elapsed > mp->threshold )
{ {
printf("%32s elapsed %10.2f millis > threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,elapsed,mp->threshold,mp->millisum/mp->count,mp->count); //if ( IAMLP == 0 )
printf("%32s elapsed %10.2f millis > threshold %10.2f, ave %10.2f millis, count.%u\n",mp->name,elapsed,mp->threshold,mp->millisum/mp->count,mp->count);
} }
mp->lastmilli = millis; mp->lastmilli = millis;
} }
@ -73,7 +80,7 @@ void LP_millistats_update(struct LP_millistats *mp)
} }
#include "LP_include.h" #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,LP_electrummutex,LP_butxomutex,LP_reservedmutex,LP_nanorecvsmutex,LP_tradebotsmutex; 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,LP_electrummutex,LP_butxomutex,LP_reservedmutex,LP_nanorecvsmutex,LP_tradebotsmutex,LP_gcmutex;
int32_t LP_canbind; int32_t LP_canbind;
char *Broadcaststr,*Reserved_msgs[2][1000]; char *Broadcaststr,*Reserved_msgs[2][1000];
int32_t num_Reserved_msgs[2],max_Reserved_msgs[2]; int32_t num_Reserved_msgs[2],max_Reserved_msgs[2];
@ -81,17 +88,7 @@ struct LP_peerinfo *LP_peerinfos,*LP_mypeer;
struct LP_forwardinfo *LP_forwardinfos; struct LP_forwardinfo *LP_forwardinfos;
struct iguana_info *LP_coins; struct iguana_info *LP_coins;
struct LP_pubkeyinfo *LP_pubkeyinfos; struct LP_pubkeyinfo *LP_pubkeyinfos;
struct rpcrequest_info *LP_garbage_collector;
#include "LP_network.c"
char *activecoins[] = { "BTC", "KMD" };
char GLOBAL_DBDIR[] = { "DB" };
char 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",
//"51.15.203.171", "51.15.86.136", "51.15.94.249", "51.15.80.18", "51.15.91.40", "51.15.54.2", "51.15.86.31", "51.15.82.29", "51.15.89.155",
};//"5.9.253.204" }; //
//uint32_t LP_deadman_switch; //uint32_t LP_deadman_switch;
@ -112,11 +109,24 @@ struct LP_globals
uint64_t LP_skipstatus[10000]; uint64_t LP_skipstatus[10000];
uint8_t LP_myrmd160[20],LP_pubsecp[33]; uint8_t LP_myrmd160[20],LP_pubsecp[33];
uint32_t LP_sessionid,counter; uint32_t LP_sessionid,counter;
int32_t LP_pendingswaps,USERPASS_COUNTER,LP_numprivkeys,initializing,waiting,LP_numskips; int32_t LP_IAMLP,LP_pendingswaps,USERPASS_COUNTER,LP_numprivkeys,initializing,waiting,LP_numskips;
char USERPASS[65],USERPASS_WIFSTR[64],LP_myrmd160str[41],gui[16]; char USERPASS[65],USERPASS_WIFSTR[64],LP_myrmd160str[41],gui[16];
struct LP_privkey LP_privkeys[100]; struct LP_privkey LP_privkeys[100];
} G; } G;
#include "LP_network.c"
char *activecoins[] = { "BTC", "KMD" };
char GLOBAL_DBDIR[] = { "DB" };
char 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",
//"24.54.206.138", "173.212.225.176", "136.243.45.140", "107.72.162.127", "72.50.16.86", "51.15.202.191", "173.228.198.88",
"51.15.203.171", "51.15.86.136", "51.15.94.249", "51.15.80.18", "51.15.91.40", "51.15.54.2", "51.15.86.31", "51.15.82.29", "51.15.89.155",
};//"5.9.253.204" }; //
// stubs // stubs
void tradebot_swap_balancingtrade(struct basilisk_swap *swap,int32_t iambob) void tradebot_swap_balancingtrade(struct basilisk_swap *swap,int32_t iambob)
@ -144,6 +154,7 @@ char *blocktrail_listtransactions(char *symbol,char *coinaddr,int32_t num,int32_
#include "LP_bitcoin.c" #include "LP_bitcoin.c"
#include "LP_coins.c" #include "LP_coins.c"
#include "LP_rpc.c" #include "LP_rpc.c"
#include "LP_cache.c"
#include "LP_RTmetrics.c" #include "LP_RTmetrics.c"
#include "LP_utxo.c" #include "LP_utxo.c"
#include "LP_prices.c" #include "LP_prices.c"
@ -329,6 +340,7 @@ int32_t LP_sock_check(char *typestr,void *ctx,char *myipaddr,int32_t pubsock,int
if ( (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) > 0 ) if ( (recvlen= nn_recv(sock,&ptr,NN_MSG,0)) > 0 )
{ {
methodstr[0] = 0; methodstr[0] = 0;
//printf("%s.(%s)\n",typestr,(char *)ptr);
if ( 0 ) if ( 0 )
{ {
cJSON *recvjson; char *mstr;//,*cstr; cJSON *recvjson; char *mstr;//,*cstr;
@ -433,126 +445,43 @@ void command_rpcloop(void *myipaddr)
if ( nonz == 0 ) if ( nonz == 0 )
{ {
if ( IAMLP != 0 ) if ( IAMLP != 0 )
usleep(1000); usleep(10000);
else usleep(10000); else usleep(50000);
} }
else if ( IAMLP == 0 ) else if ( IAMLP == 0 )
usleep(100); usleep(1000);
} }
} }
void utxosQ_loop(void *myipaddr) void utxosQ_loop(void *myipaddr)
{ {
strcpy(utxosQ_loop_stats.name,"utxosQ_loop"); strcpy(utxosQ_loop_stats.name,"utxosQ_loop");
utxosQ_loop_stats.threshold = 50.; utxosQ_loop_stats.threshold = 5000.;
while ( 1 ) while ( 1 )
{ {
LP_millistats_update(&utxosQ_loop_stats); LP_millistats_update(&utxosQ_loop_stats);
if ( LP_utxosQ_process() == 0 ) if ( LP_utxosQ_process() == 0 )
usleep(10000); usleep(50000);
}
}
int32_t LP_utxos_sync(struct LP_peerinfo *peer)
{
int32_t i,j,n=0,m,v,posted=0; bits256 txid; cJSON *array,*item,*item2,*array2; uint64_t total,total2; struct iguana_info *coin,*ctmp; char *retstr,*retstr2;
if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 )
return(0);
HASH_ITER(hh,LP_coins,coin,ctmp)
{
if ( IAMLP == 0 && coin->inactive != 0 )
continue;
if ( coin->smartaddr[0] == 0 )
continue;
total = 0;
if ( (j= LP_listunspent_both(coin->symbol,coin->smartaddr,0)) == 0 )
continue;
if ( (array= LP_address_utxos(coin,coin->smartaddr,1)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
total += j64bits(item,"value");
}
}
if ( n > 0 && total > 0 && (retstr= issue_LP_listunspent(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr)) != 0 )
{
//printf("UTXO sync.%d %s n.%d total %.8f -> %s (%s)\n",j,coin->symbol,n,dstr(total),peer->ipaddr,retstr);
total2 = 0;
if ( (array2= cJSON_Parse(retstr)) != 0 )
{
if ( (m= cJSON_GetArraySize(array2)) > 0 )
{
for (i=0; i<m; i++)
{
item2 = jitem(array2,i);
total2 += j64bits(item2,"value");
}
}
if ( total != total2 || n != m )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
txid = jbits256(item,"tx_hash");
v = jint(item,"tx_pos");
for (j=0; j<m; j++)
{
if ( v == jint(jitem(array2,i),"tx_pos") && bits256_cmp(txid,jbits256(jitem(array2,i),"tx_hash")) == 0 )
break;
}
if ( j == m )
{
//printf("%s missing %s %s\n",peer->ipaddr,coin->symbol,jprint(item,0));
if ( (retstr2= issue_LP_uitem(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr,txid,v,jint(item,"height"),j64bits(item,"value"))) != 0 )
free(retstr2);
posted++;
}
}
if ( 0 && posted != 0 )
printf(">>>>>>>> %s compare %s %s (%.8f n%d) (%.8f m%d)\n",peer->ipaddr,coin->symbol,coin->smartaddr,dstr(total),n,dstr(total2),m);
} //else printf("%s matches %s\n",peer->ipaddr,coin->symbol);
free_json(array2);
} else printf("parse error (%s)\n",retstr);
free(retstr);
}
else if ( n != 0 && total != 0 )
{
//printf("no response from %s for %s %s\n",peer->ipaddr,coin->symbol,coin->smartaddr);
for (i=0; i<n; i++)
{
item = jitem(array,i);
txid = jbits256(item,"tx_hash");
v = jint(item,"tx_pos");
if ( (retstr2= issue_LP_uitem(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr,txid,v,jint(item,"height"),j64bits(item,"value"))) != 0 )
free(retstr2);
}
}
free_json(array);
}
} }
return(posted);
} }
void LP_coinsloop(void *_coins) void LP_coinsloop(void *_coins)
{ {
struct LP_address *ap=0,*atmp; cJSON *retjson; struct LP_address_utxo *up,*tmp; struct iguana_info *coin,*ctmp; char str[65]; struct electrum_info *ep,*backupep=0; bits256 zero; int32_t oldht,j,nonz; char *coins = _coins; struct LP_address *ap=0,*atmp; struct LP_transaction *tx; cJSON *retjson; struct LP_address_utxo *up,*tmp; struct iguana_info *coin,*ctmp; char str[65]; struct electrum_info *ep,*backupep=0; bits256 zero; int32_t oldht,j,nonz; char *coins = _coins;
if ( strcmp("BTC",coins) == 0 ) if ( strcmp("BTC",coins) == 0 )
{ {
strcpy(LP_coinsloopBTC_stats.name,"BTC coin loop"); strcpy(LP_coinsloopBTC_stats.name,"BTC coin loop");
LP_coinsloopBTC_stats.threshold = 2000.; LP_coinsloopBTC_stats.threshold = 20000.;
} }
else if ( strcmp("KMD",coins) == 0 ) else if ( strcmp("KMD",coins) == 0 )
{ {
strcpy(LP_coinsloopKMD_stats.name,"KMD coin loop"); strcpy(LP_coinsloopKMD_stats.name,"KMD coin loop");
LP_coinsloopKMD_stats.threshold = 1000.; LP_coinsloopKMD_stats.threshold = 10000.;
} }
else else
{ {
strcpy(LP_coinsloop_stats.name,"other coins loop"); strcpy(LP_coinsloop_stats.name,"other coins loop");
LP_coinsloop_stats.threshold = 500.; LP_coinsloop_stats.threshold = 5000.;
} }
while ( 1 ) while ( 1 )
{ {
@ -586,6 +515,19 @@ void LP_coinsloop(void *_coins)
{ {
if ( (backupep= ep->prev) == 0 ) if ( (backupep= ep->prev) == 0 )
backupep = ep; backupep = ep;
// skip cLP_address MNZ bXcSsYBiVKtTzYErqxvma4UsojZTEf5L6H
//printf("electrum %s\n",coin->symbol);
if ( (ap= LP_addressfind(coin,coin->smartaddr)) != 0 )
{
if ( (retjson= electrum_address_listunspent(coin->symbol,ep,&retjson,ap->coinaddr,1)) != 0 )
free_json(retjson);
}
HASH_ITER(hh,coin->addresses,ap,atmp)
{
//printf("call unspent %s\n",ap->coinaddr);
if ( (retjson= electrum_address_listunspent(coin->symbol,ep,&retjson,ap->coinaddr,1)) != 0 )
free_json(retjson);
}
HASH_ITER(hh,coin->addresses,ap,atmp) HASH_ITER(hh,coin->addresses,ap,atmp)
{ {
DL_FOREACH_SAFE(ap->utxos,up,tmp) DL_FOREACH_SAFE(ap->utxos,up,tmp)
@ -595,9 +537,15 @@ void LP_coinsloop(void *_coins)
if ( up->SPV == 0 ) if ( up->SPV == 0 )
{ {
nonz++; nonz++;
up->SPV = LP_merkleproof(coin,backupep,up->U.txid,up->U.height); up->SPV = LP_merkleproof(coin,coin->smartaddr,backupep,up->U.txid,up->U.height);
if ( 0 && up->SPV > 0 ) if ( up->SPV > 0 )
printf("%s %s: SPV.%d\n",coin->symbol,bits256_str(str,up->U.txid),up->SPV); {
if ( (tx= LP_transactionfind(coin,up->U.txid)) != 0 && tx->SPV == 0 )
{
tx->SPV = up->SPV;
//printf("%s %s: SPV.%d\n",coin->symbol,bits256_str(str,up->U.txid),up->SPV);
}
}
} }
else if ( up->SPV == -1 ) else if ( up->SPV == -1 )
{ {
@ -606,7 +554,7 @@ void LP_coinsloop(void *_coins)
oldht = up->U.height; oldht = up->U.height;
LP_txheight_check(coin,ap->coinaddr,up); LP_txheight_check(coin,ap->coinaddr,up);
if ( oldht != up->U.height ) if ( oldht != up->U.height )
up->SPV = LP_merkleproof(coin,backupep,up->U.txid,up->U.height); up->SPV = LP_merkleproof(coin,coin->smartaddr,backupep,up->U.txid,up->U.height);
if ( up->SPV <= 0 ) if ( up->SPV <= 0 )
up->SPV = -2; up->SPV = -2;
else printf("%s %s: corrected SPV.%d\n",coin->symbol,bits256_str(str,up->U.txid),up->SPV); else printf("%s %s: corrected SPV.%d\n",coin->symbol,bits256_str(str,up->U.txid),up->SPV);
@ -619,7 +567,7 @@ void LP_coinsloop(void *_coins)
if ( time(NULL) > ep->keepalive+LP_ELECTRUM_KEEPALIVE ) if ( time(NULL) > ep->keepalive+LP_ELECTRUM_KEEPALIVE )
{ {
//printf("%s electrum.%p needs a keepalive: lag.%d\n",ep->symbol,ep,(int32_t)(time(NULL) - ep->keepalive)); //printf("%s electrum.%p needs a keepalive: lag.%d\n",ep->symbol,ep,(int32_t)(time(NULL) - ep->keepalive));
if ( (retjson= electrum_donation(ep->symbol,ep,&retjson)) != 0 ) if ( (retjson= electrum_address_listunspent(coin->symbol,ep,&retjson,coin->smartaddr,1)) != 0 )
free_json(retjson); free_json(retjson);
} }
ep = ep->prev; ep = ep->prev;
@ -651,7 +599,7 @@ void LP_coinsloop(void *_coins)
continue; continue;
} }
nonz++; nonz++;
if ( coin->lastscanht < coin->longestchain-3 ) if ( 0 && coin->lastscanht < coin->longestchain-3 )
printf("[%s]: %s ref.%d scan.%d to %d, longest.%d\n",coins,coin->symbol,coin->firstrefht,coin->firstscanht,coin->lastscanht,coin->longestchain); printf("[%s]: %s ref.%d scan.%d to %d, longest.%d\n",coins,coin->symbol,coin->firstrefht,coin->firstscanht,coin->lastscanht,coin->longestchain);
for (j=0; j<100; j++) for (j=0; j<100; j++)
{ {
@ -668,76 +616,38 @@ void LP_coinsloop(void *_coins)
if ( coins == 0 ) if ( coins == 0 )
return; return;
if ( nonz == 0 ) if ( nonz == 0 )
usleep(1000); usleep(100000);
} }
} }
int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,uint16_t myport) int32_t LP_mainloop_iter(void *ctx,char *myipaddr,struct LP_peerinfo *mypeer,int32_t pubsock,char *pushaddr,uint16_t myport)
{ {
static uint32_t counter,numpeers; static uint32_t counter;
struct iguana_info *coin,*ctmp; char *retstr,*origipaddr; struct LP_peerinfo *peer,*tmp; uint32_t now; int32_t needpings,height,nonz = 0; struct iguana_info *coin,*ctmp; char *origipaddr; uint32_t now; int32_t height,nonz = 0;
now = (uint32_t)time(NULL);
if ( (origipaddr= myipaddr) == 0 ) if ( (origipaddr= myipaddr) == 0 )
origipaddr = "127.0.0.1"; origipaddr = "127.0.0.1";
if ( mypeer == 0 ) if ( mypeer == 0 )
myipaddr = "127.0.0.1"; myipaddr = "127.0.0.1";
numpeers = LP_numpeers();
needpings = 0;
HASH_ITER(hh,LP_peerinfos,peer,tmp)
{
if ( peer->errors >= LP_MAXPEER_ERRORS )
{
if ( (rand() % 10000) == 0 )
{
peer->errors--;
if ( peer->errors < LP_MAXPEER_ERRORS )
peer->diduquery = 0;
}
if ( IAMLP == 0 )
continue;
}
if ( now > peer->lastpeers+60 || (rand() % 10000) == 0 )
{
if ( strcmp(peer->ipaddr,myipaddr) != 0 )
{
nonz++;
LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport);
peer->diduquery = 0;
LP_peer_pricesquery(peer);
LP_utxos_sync(peer);
needpings++;
}
peer->lastpeers = now;
}
if ( peer->needping != 0 )
{
peer->diduquery = now;
nonz++;
if ( (retstr= issue_LP_notify(peer->ipaddr,peer->port,"127.0.0.1",0,numpeers,G.LP_sessionid,G.LP_myrmd160str,G.LP_mypub25519)) != 0 )
free(retstr);
peer->needping = 0;
needpings++;
}
}
HASH_ITER(hh,LP_coins,coin,ctmp) // firstrefht,firstscanht,lastscanht HASH_ITER(hh,LP_coins,coin,ctmp) // firstrefht,firstscanht,lastscanht
{ {
if ( coin->addr_listunspent_requested != 0 && time(NULL) > coin->lastpushtime+60 ) now = (uint32_t)time(NULL);
if ( (coin->addr_listunspent_requested != 0 && now > coin->lastpushtime+LP_ORDERBOOK_DURATION*.5) || now > coin->lastpushtime+LP_ORDERBOOK_DURATION*5 )
{ {
//printf("PUSH addr_listunspent_requested %u\n",coin->addr_listunspent_requested); //printf("PUSH addr_listunspent_requested %u\n",coin->addr_listunspent_requested);
coin->lastpushtime = (uint32_t)time(NULL); coin->lastpushtime = (uint32_t)now;
LP_smartutxos_push(coin); LP_smartutxos_push(coin);
coin->addr_listunspent_requested = 0; coin->addr_listunspent_requested = 0;
} }
if ( coin->electrum == 0 && coin->inactive == 0 && time(NULL) > coin->lastgetinfo+LP_GETINFO_INCR ) if ( coin->electrum == 0 && coin->inactive == 0 && now > coin->lastgetinfo+LP_GETINFO_INCR )
{ {
nonz++; nonz++;
if ( (height= LP_getheight(coin)) > coin->longestchain ) if ( (height= LP_getheight(coin)) > coin->longestchain )
{ {
coin->longestchain = height; coin->longestchain = height;
if ( coin->firstrefht != 0 ) if ( 0 && coin->firstrefht != 0 )
printf(">>>>>>>>>> set %s longestchain %d (ref.%d [%d, %d])\n",coin->symbol,height,coin->firstrefht,coin->firstscanht,coin->lastscanht); 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); } //else LP_mempoolscan(coin->symbol,zero);
coin->lastgetinfo = (uint32_t)time(NULL); coin->lastgetinfo = (uint32_t)now;
} }
} }
counter++; counter++;
@ -756,7 +666,7 @@ void LP_initcoins(void *ctx,int32_t pubsock,cJSON *coins)
{ {
if ( LP_getheight(coin) <= 0 ) if ( LP_getheight(coin) <= 0 )
coin->inactive = (uint32_t)time(NULL); coin->inactive = (uint32_t)time(NULL);
LP_unspents_load(coin->symbol,coin->smartaddr); else LP_unspents_load(coin->symbol,coin->smartaddr);
} }
} }
if ( (n= cJSON_GetArraySize(coins)) > 0 ) if ( (n= cJSON_GetArraySize(coins)) > 0 )
@ -773,7 +683,7 @@ void LP_initcoins(void *ctx,int32_t pubsock,cJSON *coins)
{ {
if ( LP_getheight(coin) <= 0 ) if ( LP_getheight(coin) <= 0 )
coin->inactive = (uint32_t)time(NULL); coin->inactive = (uint32_t)time(NULL);
LP_unspents_load(coin->symbol,coin->smartaddr); else LP_unspents_load(coin->symbol,coin->smartaddr);
} }
} }
} }
@ -781,12 +691,12 @@ void LP_initcoins(void *ctx,int32_t pubsock,cJSON *coins)
printf("privkey updates\n"); printf("privkey updates\n");
} }
void LP_initpeers(int32_t pubsock,struct LP_peerinfo *mypeer,char *myipaddr,uint16_t myport,char *seednode) void LP_initpeers(int32_t pubsock,struct LP_peerinfo *mypeer,char *myipaddr,uint16_t myport,char *seednode,uint16_t pushport,uint16_t subport)
{ {
int32_t i,j; uint32_t r; int32_t i,j; uint32_t r;
if ( IAMLP != 0 ) if ( IAMLP != 0 )
{ {
LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,0,0,0,0,G.LP_sessionid); LP_mypeer = mypeer = LP_addpeer(mypeer,pubsock,myipaddr,myport,pushport,subport,1,G.LP_sessionid);
if ( myipaddr == 0 || mypeer == 0 ) if ( myipaddr == 0 || mypeer == 0 )
{ {
printf("couldnt get myipaddr or null mypeer.%p\n",mypeer); printf("couldnt get myipaddr or null mypeer.%p\n",mypeer);
@ -796,11 +706,9 @@ void LP_initpeers(int32_t pubsock,struct LP_peerinfo *mypeer,char *myipaddr,uint
{ {
for (i=0; i<sizeof(default_LPnodes)/sizeof(*default_LPnodes); i++) for (i=0; i<sizeof(default_LPnodes)/sizeof(*default_LPnodes); i++)
{ {
//if ( (rand() % 100) > 25 ) LP_addpeer(mypeer,pubsock,default_LPnodes[i],myport,pushport,subport,0,G.LP_sessionid);
// continue;
LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,mypeer->ipaddr,myport);
} }
} else LP_peersquery(mypeer,pubsock,seednode,myport,mypeer->ipaddr,myport); } else LP_addpeer(mypeer,pubsock,seednode,myport,pushport,subport,0,G.LP_sessionid);
} }
else else
{ {
@ -811,26 +719,40 @@ void LP_initpeers(int32_t pubsock,struct LP_peerinfo *mypeer,char *myipaddr,uint
} }
if ( seednode == 0 || seednode[0] == 0 ) if ( seednode == 0 || seednode[0] == 0 )
{ {
//LP_addpeer(mypeer,pubsock,"51.15.86.136",myport,pushport,subport,0,G.LP_sessionid);
OS_randombytes((void *)&r,sizeof(r)); OS_randombytes((void *)&r,sizeof(r));
//r = 0;
for (j=0; j<sizeof(default_LPnodes)/sizeof(*default_LPnodes); j++) for (j=0; j<sizeof(default_LPnodes)/sizeof(*default_LPnodes); j++)
{ {
i = (r + j) % (sizeof(default_LPnodes)/sizeof(*default_LPnodes)); i = (r + j) % (sizeof(default_LPnodes)/sizeof(*default_LPnodes));
LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,"127.0.0.1",myport); LP_addpeer(mypeer,pubsock,default_LPnodes[i],myport,pushport,subport,0,G.LP_sessionid);
//issue_LP_getpeers(default_LPnodes[i],myport);
//LP_peersquery(mypeer,pubsock,default_LPnodes[i],myport,"127.0.0.1",myport);
} }
} else LP_peersquery(mypeer,pubsock,seednode,myport,"127.0.0.1",myport); } else LP_addpeer(mypeer,pubsock,seednode,myport,pushport,subport,0,G.LP_sessionid);
} }
} }
void LP_pubkeysloop(void *ctx) void LP_pubkeysloop(void *ctx)
{ {
static uint32_t lasttime; static uint32_t lasttime; cJSON *retjson; struct iguana_info *coin,*tmp;
strcpy(LP_pubkeysloop_stats.name,"LP_pubkeysloop"); strcpy(LP_pubkeysloop_stats.name,"LP_pubkeysloop");
LP_pubkeysloop_stats.threshold = 5000.; LP_pubkeysloop_stats.threshold = 15000.;
sleep(10); sleep(10);
while ( 1 ) while ( 1 )
{ {
LP_millistats_update(&LP_pubkeysloop_stats); LP_millistats_update(&LP_pubkeysloop_stats);
if ( time(NULL) > lasttime+60 ) HASH_ITER(hh,LP_coins,coin,tmp) // firstrefht,firstscanht,lastscanht
{
if ( coin->electrum != 0 && time(NULL) > coin->lastunspent+30 )
{
//printf("call electrum listunspent.%s\n",coin->symbol);
if ( (retjson= electrum_address_listunspent(coin->symbol,coin->electrum,&retjson,coin->smartaddr,2)) != 0 )
free_json(retjson);
coin->lastunspent = (uint32_t)time(NULL);
}
}
if ( time(NULL) > lasttime+LP_ORDERBOOK_DURATION*0.5 )
{ {
//printf("LP_pubkeysloop %u\n",(uint32_t)time(NULL)); //printf("LP_pubkeysloop %u\n",(uint32_t)time(NULL));
LP_notify_pubkeys(ctx,LP_mypubsock); LP_notify_pubkeys(ctx,LP_mypubsock);
@ -868,22 +790,24 @@ void LP_swapsloop(void *ignore)
//printf("LP_swapsloop %u\n",LP_counter); //printf("LP_swapsloop %u\n",LP_counter);
if ( (retstr= basilisk_swapentry(0,0)) != 0 ) if ( (retstr= basilisk_swapentry(0,0)) != 0 )
free(retstr); free(retstr);
LP_millistats_update(0); //LP_millistats_update(0);
sleep(600); sleep(600);
} }
} }
void LP_reserved_msgs(void *ignore) void LP_reserved_msgs(void *ignore)
{ {
bits256 zero; int32_t flag; struct nn_pollfd pfd; bits256 zero; int32_t flag,nonz; struct nn_pollfd pfd;
memset(zero.bytes,0,sizeof(zero)); memset(zero.bytes,0,sizeof(zero));
strcpy(LP_reserved_msgs_stats.name,"LP_reserved_msgs"); strcpy(LP_reserved_msgs_stats.name,"LP_reserved_msgs");
LP_reserved_msgs_stats.threshold = 50.; LP_reserved_msgs_stats.threshold = 150.;
while ( 1 ) while ( 1 )
{ {
nonz = 0;
LP_millistats_update(&LP_reserved_msgs_stats); LP_millistats_update(&LP_reserved_msgs_stats);
if ( num_Reserved_msgs[0] > 0 || num_Reserved_msgs[1] > 0 ) if ( num_Reserved_msgs[0] > 0 || num_Reserved_msgs[1] > 0 )
{ {
nonz++;
flag = 0; flag = 0;
if ( LP_mypubsock >= 0 ) if ( LP_mypubsock >= 0 )
{ {
@ -899,12 +823,14 @@ void LP_reserved_msgs(void *ignore)
if ( num_Reserved_msgs[1] > 0 ) if ( num_Reserved_msgs[1] > 0 )
{ {
num_Reserved_msgs[1]--; num_Reserved_msgs[1]--;
//printf("PRIORITY BROADCAST.(%s)\n",Reserved_msgs[1][num_Reserved_msgs[1]]);
LP_broadcast_message(LP_mypubsock,"","",zero,Reserved_msgs[1][num_Reserved_msgs[1]]); LP_broadcast_message(LP_mypubsock,"","",zero,Reserved_msgs[1][num_Reserved_msgs[1]]);
Reserved_msgs[1][num_Reserved_msgs[1]] = 0; Reserved_msgs[1][num_Reserved_msgs[1]] = 0;
} }
else if ( num_Reserved_msgs[0] > 0 ) else if ( num_Reserved_msgs[0] > 0 )
{ {
num_Reserved_msgs[0]--; num_Reserved_msgs[0]--;
//printf("BROADCAST.(%s)\n",Reserved_msgs[0][num_Reserved_msgs[0]]);
LP_broadcast_message(LP_mypubsock,"","",zero,Reserved_msgs[0][num_Reserved_msgs[0]]); LP_broadcast_message(LP_mypubsock,"","",zero,Reserved_msgs[0][num_Reserved_msgs[0]]);
Reserved_msgs[0][num_Reserved_msgs[0]] = 0; Reserved_msgs[0][num_Reserved_msgs[0]] = 0;
} }
@ -913,7 +839,9 @@ void LP_reserved_msgs(void *ignore)
} }
if ( ignore == 0 ) if ( ignore == 0 )
break; break;
usleep(3000); if ( nonz != 0 )
usleep(3000);
else usleep(25000);
} }
} }
@ -926,18 +854,20 @@ int32_t LP_reserved_msg(int32_t priority,char *base,char *rel,bits256 pubkey,cha
Reserved_msgs[priority][num_Reserved_msgs[priority]++] = msg; Reserved_msgs[priority][num_Reserved_msgs[priority]++] = msg;
n = num_Reserved_msgs[priority]; n = num_Reserved_msgs[priority];
} else LP_broadcast_message(LP_mypubsock,base,rel,pubkey,msg); } else LP_broadcast_message(LP_mypubsock,base,rel,pubkey,msg);
portable_mutex_unlock(&LP_reservedmutex);
if ( num_Reserved_msgs[priority] > max_Reserved_msgs[priority] ) if ( num_Reserved_msgs[priority] > max_Reserved_msgs[priority] )
{ {
max_Reserved_msgs[priority] = num_Reserved_msgs[priority]; max_Reserved_msgs[priority] = num_Reserved_msgs[priority];
printf("New priority.%d max_Reserved_msgs.%d\n",priority,max_Reserved_msgs[priority]); if ( (max_Reserved_msgs[priority] % 100) == 0 )
printf("New priority.%d max_Reserved_msgs.%d\n",priority,max_Reserved_msgs[priority]);
} }
portable_mutex_unlock(&LP_reservedmutex);
return(n); return(n);
} }
void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybusport,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson) void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybusport,char *passphrase,int32_t amclient,char *userhome,cJSON *argjson)
{ {
char *myipaddr=0; long filesize,n; int32_t valid,timeout,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128],*coins_str=0; cJSON *coinsjson=0; void *ctx = bitcoin_ctx(); char *myipaddr=0; long filesize,n; int32_t valid,timeout,pubsock=-1; struct LP_peerinfo *mypeer=0; char pushaddr[128],subaddr[128],bindaddr[128],*coins_str=0; cJSON *coinsjson=0; void *ctx = bitcoin_ctx();
printf("Marketmaker %s.%s %s\n",LP_MAJOR_VERSION,LP_MINOR_VERSION,LP_BUILD_NUMBER);
LP_showwif = juint(argjson,"wif"); LP_showwif = juint(argjson,"wif");
if ( passphrase == 0 || passphrase[0] == 0 ) if ( passphrase == 0 || passphrase[0] == 0 )
{ {
@ -987,6 +917,7 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybu
portable_mutex_init(&LP_swaplistmutex); portable_mutex_init(&LP_swaplistmutex);
portable_mutex_init(&LP_cachemutex); portable_mutex_init(&LP_cachemutex);
portable_mutex_init(&LP_networkmutex); portable_mutex_init(&LP_networkmutex);
portable_mutex_init(&LP_gcmutex);
portable_mutex_init(&LP_forwardmutex); portable_mutex_init(&LP_forwardmutex);
portable_mutex_init(&LP_psockmutex); portable_mutex_init(&LP_psockmutex);
portable_mutex_init(&LP_coinmutex); portable_mutex_init(&LP_coinmutex);
@ -1047,7 +978,8 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybu
LP_mypubsock = pubsock; LP_mypubsock = pubsock;
} }
printf("got %s, initpeers\n",myipaddr); printf("got %s, initpeers\n",myipaddr);
LP_initpeers(pubsock,mypeer,myipaddr,myport,jstr(argjson,"seednode")); LP_initpeers(pubsock,mypeer,myipaddr,myport,jstr(argjson,"seednode"),mypullport,mypubport);
RPC_port = myport;
printf("get public socket\n"); printf("get public socket\n");
LP_mypullsock = LP_initpublicaddr(ctx,&mypullport,pushaddr,myipaddr,mypullport,0); LP_mypullsock = LP_initpublicaddr(ctx,&mypullport,pushaddr,myipaddr,mypullport,0);
strcpy(LP_publicaddr,pushaddr); strcpy(LP_publicaddr,pushaddr);
@ -1095,6 +1027,12 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybu
printf("error launching stats rpcloop for port.%u\n",myport); printf("error launching stats rpcloop for port.%u\n",myport);
exit(-1); exit(-1);
} }
uint16_t myport2 = myport-1;
if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)stats_rpcloop,(void *)&myport2) != 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 ) if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)command_rpcloop,(void *)myipaddr) != 0 )
{ {
printf("error launching command_rpcloop for port.%u\n",myport); printf("error launching command_rpcloop for port.%u\n",myport);
@ -1105,6 +1043,11 @@ void LPinit(uint16_t myport,uint16_t mypullport,uint16_t mypubport,uint16_t mybu
printf("error launching queue_loop for port.%u\n",myport); printf("error launching queue_loop for port.%u\n",myport);
exit(-1); exit(-1);
} }
if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)gc_loop,(void *)myipaddr) != 0 )
{
printf("error launching gc_loop for port.%u\n",myport);
exit(-1);
}
if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)prices_loop,ctx) != 0 ) if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)prices_loop,ctx) != 0 )
{ {
printf("error launching prices_loop for port.%u\n",myport); printf("error launching prices_loop for port.%u\n",myport);

88
iguana/exchanges/LP_network.c

@ -140,7 +140,7 @@ struct LP_queue
{ {
struct LP_queue *next,*prev; struct LP_queue *next,*prev;
int32_t sock,peerind,msglen; int32_t sock,peerind,msglen;
uint32_t starttime,crc32; uint32_t starttime,crc32,notready;
uint8_t msg[]; uint8_t msg[];
} *LP_Q; } *LP_Q;
int32_t LP_Qenqueued,LP_Qerrors,LP_Qfound; int32_t LP_Qenqueued,LP_Qerrors,LP_Qfound;
@ -183,11 +183,11 @@ bits256 LP_calc_magic(uint8_t *msg,int32_t len)
sum += (OS_milliseconds() - millis); sum += (OS_milliseconds() - millis);
nsum += n; nsum += n;
counter++; counter++;
if ( n > maxn || (rand() % 100) == 0 ) if ( n > maxn || (rand() % 10000) == 0 )
{ {
if ( n > maxn ) if ( n > maxn )
{ {
printf("LP_calc_magic maxn.%d <- %d\n",maxn,n); printf("LP_calc_magic maxn.%d <- %d | ",maxn,n);
maxn = n; maxn = n;
} }
printf("millis %.3f ave %.3f, aveiters %.1f\n",OS_milliseconds() - millis,sum/counter,(double)nsum/counter); printf("millis %.3f ave %.3f, aveiters %.1f\n",OS_milliseconds() - millis,sum/counter,(double)nsum/counter);
@ -265,35 +265,66 @@ int32_t LP_peerindsock(int32_t *peerindp)
return(-1); return(-1);
} }
void gc_loop(void *arg)
{
struct rpcrequest_info *req,*rtmp; int32_t flag = 0;
strcpy(LP_gcloop_stats.name,"gc_loop");
LP_gcloop_stats.threshold = 1100.;
while ( 1 )
{
flag = 0;
LP_millistats_update(&LP_gcloop_stats);
portable_mutex_lock(&LP_gcmutex);
DL_FOREACH_SAFE(LP_garbage_collector,req,rtmp)
{
DL_DELETE(LP_garbage_collector,req);
//printf("garbage collect ipbits.%x\n",req->ipbits);
free(req);
flag++;
}
portable_mutex_unlock(&LP_gcmutex);
if ( 0 && flag != 0 )
printf("gc_loop.%d\n",flag);
sleep(1);
}
}
void queue_loop(void *arg) void queue_loop(void *arg)
{ {
struct LP_queue *ptr,*tmp; int32_t sentbytes,nonz,flag,duplicate,n=0; struct LP_queue *ptr,*tmp; int32_t sentbytes,nonz,flag,duplicate,n=0;
strcpy(queue_loop_stats.name,"queue_loop"); strcpy(queue_loop_stats.name,"queue_loop");
queue_loop_stats.threshold = 500.; queue_loop_stats.threshold = 1000.;
while ( 1 ) while ( 1 )
{ {
LP_millistats_update(&queue_loop_stats); LP_millistats_update(&queue_loop_stats);
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); //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; n = nonz = flag = 0;
DL_FOREACH_SAFE(LP_Q,ptr,tmp) DL_FOREACH_SAFE(LP_Q,ptr,tmp)
{ {
n++; n++;
flag = 0; flag = 0;
if ( ptr->sock >= 0 ) if ( ptr->sock >= 0 )
{ {
if ( LP_sockcheck(ptr->sock) > 0 ) if ( ptr->notready == 0 || (rand() % ptr->notready) == 0 )
{ {
bits256 magic; if ( LP_sockcheck(ptr->sock) > 0 )
magic = LP_calc_magic(ptr->msg,(int32_t)(ptr->msglen - sizeof(bits256))); {
memcpy(&ptr->msg[ptr->msglen - sizeof(bits256)],&magic,sizeof(magic)); bits256 magic;
if ( (sentbytes= nn_send(ptr->sock,ptr->msg,ptr->msglen,0)) != ptr->msglen ) magic = LP_calc_magic(ptr->msg,(int32_t)(ptr->msglen - sizeof(bits256)));
printf("%d LP_send sent %d instead of %d\n",n,sentbytes,ptr->msglen); memcpy(&ptr->msg[ptr->msglen - sizeof(bits256)],&magic,sizeof(magic));
ptr->sock = -1; if ( (sentbytes= nn_send(ptr->sock,ptr->msg,ptr->msglen,0)) != ptr->msglen )
if ( ptr->peerind > 0 ) printf("%d LP_send sent %d instead of %d\n",n,sentbytes,ptr->msglen);
ptr->starttime = (uint32_t)time(NULL); else flag++;
else flag = 1; ptr->sock = -1;
} //else printf("sock not ready to send.%d\n",ptr->msglen); if ( ptr->peerind > 0 )
ptr->starttime = (uint32_t)time(NULL);
}
else
{
if ( ptr->notready++ > 1000 )
flag = 1;
}
}
} }
else if ( 0 && time(NULL) > ptr->starttime+13 ) else if ( 0 && time(NULL) > ptr->starttime+13 )
{ {
@ -303,7 +334,7 @@ void queue_loop(void *arg)
LP_Qfound++; LP_Qfound++;
if ( (LP_Qfound % 100) == 0 ) if ( (LP_Qfound % 100) == 0 )
printf("found.%u Q.%d err.%d match.%d\n",ptr->crc32,LP_Qenqueued,LP_Qerrors,LP_Qfound); printf("found.%u Q.%d err.%d match.%d\n",ptr->crc32,LP_Qenqueued,LP_Qerrors,LP_Qfound);
flag = 1; flag++;
} }
else if ( 0 ) // too much beyond duplicate filter when network is busy else if ( 0 ) // too much beyond duplicate filter when network is busy
{ {
@ -312,7 +343,7 @@ void queue_loop(void *arg)
if ( (ptr->sock= LP_peerindsock(&ptr->peerind)) < 0 ) 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); printf("%d no more peers to try at peerind.%d %p Q_LP.%p\n",n,ptr->peerind,ptr,LP_Q);
flag = 1; flag++;
LP_Qerrors++; LP_Qerrors++;
} }
} }
@ -325,16 +356,17 @@ void queue_loop(void *arg)
portable_mutex_unlock(&LP_networkmutex); portable_mutex_unlock(&LP_networkmutex);
free(ptr); free(ptr);
ptr = 0; ptr = 0;
break;
} }
} }
if ( arg == 0 ) if ( arg == 0 )
break; break;
//if ( n != 0 )
// printf("LP_Q.[%d]\n",n);
if ( nonz == 0 ) if ( nonz == 0 )
usleep(5000); {
else if ( IAMLP == 0 ) if ( IAMLP == 0 )
usleep(1000); usleep(50000);
else usleep(10000);
}
} }
} }
@ -377,9 +409,14 @@ void LP_broadcast_finish(int32_t pubsock,char *base,char *rel,uint8_t *msg,cJSON
msglen = (int32_t)strlen((char *)msg) + 1; msglen = (int32_t)strlen((char *)msg) + 1;
if ( crc32 == 0 ) if ( crc32 == 0 )
crc32 = calc_crc32(0,&msg[2],msglen - 2); crc32 = calc_crc32(0,&msg[2],msglen - 2);
#ifdef FROM_MARKETMAKER
if ( G.LP_IAMLP == 0 )
#else
if ( IAMLP == 0 ) if ( IAMLP == 0 )
#endif
{ {
free(msg); free(msg);
//printf("broadcast %s\n",jstr(argjson,"method"));
jdelete(argjson,"method"); jdelete(argjson,"method");
jaddstr(argjson,"method","broadcast"); jaddstr(argjson,"method","broadcast");
if ( jobj(argjson,"timestamp") == 0 ) if ( jobj(argjson,"timestamp") == 0 )
@ -731,10 +768,11 @@ char *LP_psock(char *myipaddr,int32_t ispaired)
both are combined in LP_psock_get both are combined in LP_psock_get
*/ */
char *issue_LP_psock(char *destip,uint16_t destport,int32_t ispaired) char *issue_LP_psock(char *destip,uint16_t destport,int32_t ispaired)
{ {
char url[512],*retstr; char url[512],*retstr;
sprintf(url,"http://%s:%u/api/stats/psock?ispaired=%d",destip,destport,ispaired); sprintf(url,"http://%s:%u/api/stats/psock?ispaired=%d",destip,destport-1,ispaired);
//return(LP_issue_curl("psock",destip,destport,url)); //return(LP_issue_curl("psock",destip,destport,url));
retstr = issue_curlt(url,LP_HTTP_TIMEOUT*3); retstr = issue_curlt(url,LP_HTTP_TIMEOUT*3);
printf("issue_LP_psock got (%s) from %s\n",retstr,destip); printf("issue_LP_psock got (%s) from %s\n",retstr,destip);

511
iguana/exchanges/LP_ordermatch.c

@ -18,6 +18,35 @@
// LP_ordermatch.c // LP_ordermatch.c
// marketmaker // marketmaker
// //
struct LP_quoteinfo LP_Alicequery;
double LP_Alicemaxprice;
uint32_t Alice_expiration;
struct { uint64_t aliceid; double bestprice; } Bob_competition[512];
double LP_bob_competition(uint64_t aliceid,double price)
{
int32_t i,firsti = -1;
for (i=0; i<sizeof(Bob_competition)/sizeof(*Bob_competition); i++)
{
if ( Bob_competition[i].aliceid == aliceid )
{
if ( price != 0. && (Bob_competition[i].bestprice == 0. || price < Bob_competition[i].bestprice) )
{
Bob_competition[i].bestprice = price;
//printf("Bob competition aliceid.%llx <- bestprice %.8f\n",(long long)aliceid,price);
}
return(Bob_competition[i].bestprice);
}
else if ( Bob_competition[i].aliceid == 0 )
firsti = i;
}
if ( firsti < 0 )
firsti = (rand() % (sizeof(Bob_competition)/sizeof(*Bob_competition)));
Bob_competition[firsti].aliceid = aliceid;
Bob_competition[firsti].bestprice = price;
//printf("Bob competition aliceid.%llx %.8f\n",(long long)aliceid,price);
return(price);
}
uint64_t LP_txfeecalc(struct iguana_info *coin,uint64_t txfee,int32_t txlen) uint64_t LP_txfeecalc(struct iguana_info *coin,uint64_t txfee,int32_t txlen)
{ {
@ -83,7 +112,7 @@ double LP_quote_validate(struct LP_utxoinfo *autxo,struct LP_utxoinfo *butxo,str
{ {
if ( LP_iseligible(&srcvalue,&srcvalue2,1,qp->srccoin,qp->txid,qp->vout,qp->satoshis,qp->txid2,qp->vout2) == 0 ) if ( LP_iseligible(&srcvalue,&srcvalue2,1,qp->srccoin,qp->txid,qp->vout,qp->satoshis,qp->txid2,qp->vout2) == 0 )
{ {
printf("bob not eligible %s\n",jprint(LP_quotejson(qp),1)); printf("bob not eligible %s (%.8f %.8f)\n",jprint(LP_quotejson(qp),1),dstr(srcvalue),dstr(srcvalue2));
return(-2); return(-2);
} }
if ( (txout= LP_gettxout(qp->srccoin,qp->coinaddr,qp->txid,qp->vout)) != 0 ) if ( (txout= LP_gettxout(qp->srccoin,qp->coinaddr,qp->txid,qp->vout)) != 0 )
@ -115,7 +144,7 @@ double LP_quote_validate(struct LP_utxoinfo *autxo,struct LP_utxoinfo *butxo,str
{ {
if ( LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout) == 0 ) if ( LP_iseligible(&destvalue,&destvalue2,0,qp->destcoin,qp->desttxid,qp->destvout,qp->destsatoshis,qp->feetxid,qp->feevout) == 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); char str[65],str2[65]; printf("alice not eligible %.8f -> dest %.8f %.8f (%.8f %.8f) %s/v%d %s/v%d\n",dstr(qp->satoshis),dstr(qp->destsatoshis),(double)qp->destsatoshis/qp->satoshis,dstr(destvalue),dstr(destvalue2),bits256_str(str,qp->desttxid),qp->destvout,bits256_str(str2,qp->feetxid),qp->feevout);
return(-3); return(-3);
} }
if ( (txout= LP_gettxout(qp->destcoin,qp->destaddr,qp->desttxid,qp->destvout)) != 0 ) if ( (txout= LP_gettxout(qp->destcoin,qp->destaddr,qp->desttxid,qp->destvout)) != 0 )
@ -146,12 +175,12 @@ double LP_quote_validate(struct LP_utxoinfo *autxo,struct LP_utxoinfo *butxo,str
if ( strcmp(autxo->coinaddr,qp->destaddr) != 0 ) if ( strcmp(autxo->coinaddr,qp->destaddr) != 0 )
return(-10); return(-10);
} }
if ( autxo != 0 && destvalue < 2*qp->desttxfee+qp->destsatoshis ) if ( autxo != 0 && destvalue < qp->desttxfee+qp->destsatoshis )
{ {
printf("destvalue %.8f destsatoshis %.8f is too small txfee %.8f?\n",dstr(destvalue),dstr(qp->destsatoshis),dstr(qp->desttxfee)); printf("destvalue %.8f destsatoshis %.8f is too small txfee %.8f?\n",dstr(destvalue),dstr(qp->destsatoshis),dstr(qp->desttxfee));
return(-11); return(-11);
} }
if ( butxo != 0 && srcvalue < 2*qp->txfee+qp->satoshis ) if ( butxo != 0 && srcvalue < qp->txfee+qp->satoshis )
{ {
printf("srcvalue %.8f [%.8f] satoshis %.8f is too small txfee %.8f?\n",dstr(srcvalue),dstr(srcvalue) - dstr(qp->txfee+qp->satoshis),dstr(qp->satoshis),dstr(qp->txfee)); printf("srcvalue %.8f [%.8f] satoshis %.8f is too small txfee %.8f?\n",dstr(srcvalue),dstr(srcvalue) - dstr(qp->txfee+qp->satoshis),dstr(qp->satoshis),dstr(qp->txfee));
return(-33); return(-33);
@ -246,7 +275,7 @@ int32_t LP_nearest_utxovalue(struct iguana_info *coin,char *coinaddr,struct LP_a
//printf("nearest i.%d target %.8f val %.8f dist %.8f mindist %.8f mini.%d spent.%d\n",i,dstr(targetval),dstr(up->U.value),dstr(dist),dstr(mindist),mini,up->spendheight); //printf("nearest i.%d target %.8f val %.8f dist %.8f mindist %.8f mini.%d spent.%d\n",i,dstr(targetval),dstr(up->U.value),dstr(dist),dstr(mindist),mini,up->spendheight);
if ( up->spendheight <= 0 ) if ( up->spendheight <= 0 )
{ {
if ( (coin->electrum == 0 || up->SPV > 0) && dist >= 0 && dist < mindist ) if ( dist >= 0 && dist < mindist ) //(coin->electrum == 0 || up->SPV > 0) &&
{ {
//printf("(%.8f %.8f %.8f).%d ",dstr(up->U.value),dstr(dist),dstr(mindist),mini); //printf("(%.8f %.8f %.8f).%d ",dstr(up->U.value),dstr(dist),dstr(mindist),mini);
mini = i; mini = i;
@ -269,12 +298,13 @@ uint64_t LP_basesatoshis(double relvolume,double price,uint64_t txfee,uint64_t d
struct LP_utxoinfo *LP_address_utxopair(int32_t iambob,struct LP_address_utxo **utxos,int32_t max,struct iguana_info *coin,char *coinaddr,uint64_t txfee,double relvolume,double price,uint64_t desttxfee) struct LP_utxoinfo *LP_address_utxopair(int32_t iambob,struct LP_address_utxo **utxos,int32_t max,struct iguana_info *coin,char *coinaddr,uint64_t txfee,double relvolume,double price,uint64_t desttxfee)
{ {
struct LP_address *ap; uint64_t targetval,targetval2; int32_t m,mini; struct LP_address_utxo *up,*up2; struct LP_utxoinfo *utxo = 0; struct LP_address *ap; uint64_t targetval,targetval2; int32_t m,mini; struct LP_address_utxo *up,*up2; struct LP_utxoinfo *utxo = 0;//,*utmp;
targetval = LP_basesatoshis(relvolume,price,txfee,desttxfee);
targetval2 = (targetval / 8) * 9 + 2*txfee;
if ( coin != 0 && (ap= LP_addressfind(coin,coinaddr)) != 0 ) if ( coin != 0 && (ap= LP_addressfind(coin,coinaddr)) != 0 )
{ {
if ( (m= LP_address_utxo_ptrs(coin,iambob,utxos,max,ap,coinaddr)) > 1 ) if ( (m= LP_address_utxo_ptrs(coin,iambob,utxos,max,ap,coinaddr)) > 1 )
{ {
targetval = LP_basesatoshis(relvolume,price,txfee,desttxfee);
if ( 0 ) if ( 0 )
{ {
int32_t i; int32_t i;
@ -287,7 +317,6 @@ struct LP_utxoinfo *LP_address_utxopair(int32_t iambob,struct LP_address_utxo **
{ {
up = utxos[mini]; up = utxos[mini];
utxos[mini] = 0; utxos[mini] = 0;
targetval2 = (targetval / 8) * 9 + 2*txfee;
//printf("found mini.%d %.8f for targetval %.8f -> targetval2 %.8f, ratio %.2f\n",mini,dstr(up->U.value),dstr(targetval),dstr(targetval2),(double)up->U.value/targetval); //printf("found mini.%d %.8f for targetval %.8f -> targetval2 %.8f, ratio %.2f\n",mini,dstr(up->U.value),dstr(targetval),dstr(targetval2),(double)up->U.value/targetval);
if ( (double)up->U.value/targetval < LP_MINVOL-1 ) if ( (double)up->U.value/targetval < LP_MINVOL-1 )
@ -296,7 +325,7 @@ struct LP_utxoinfo *LP_address_utxopair(int32_t iambob,struct LP_address_utxo **
{ {
if ( up != 0 && (up2= utxos[mini]) != 0 ) if ( up != 0 && (up2= utxos[mini]) != 0 )
{ {
if ( (utxo= LP_utxoadd(1,coin->symbol,up->U.txid,up->U.vout,up->U.value,up2->U.txid,up2->U.vout,up2->U.value,coinaddr,ap->pubkey,G.gui,0)) != 0 ) if ( (utxo= LP_utxoadd(1,coin->symbol,up->U.txid,up->U.vout,up->U.value,up2->U.txid,up2->U.vout,up2->U.value,coinaddr,ap->pubkey,G.gui,0,targetval)) != 0 )
{ {
utxo->S.satoshis = targetval; utxo->S.satoshis = targetval;
char str[65],str2[65]; printf("butxo.%p targetval %.8f, found val %.8f %s | targetval2 %.8f val2 %.8f %s\n",utxo,dstr(targetval),dstr(up->U.value),bits256_str(str,utxo->payment.txid),dstr(targetval2),dstr(up2->U.value),bits256_str(str2,utxo->deposit.txid)); char str[65],str2[65]; printf("butxo.%p targetval %.8f, found val %.8f %s | targetval2 %.8f val2 %.8f %s\n",utxo,dstr(targetval),dstr(up->U.value),bits256_str(str,utxo->payment.txid),dstr(targetval2),dstr(up2->U.value),bits256_str(str2,utxo->deposit.txid));
@ -309,6 +338,15 @@ struct LP_utxoinfo *LP_address_utxopair(int32_t iambob,struct LP_address_utxo **
printf("targetval %.8f mini.%d\n",dstr(targetval),mini); printf("targetval %.8f mini.%d\n",dstr(targetval),mini);
} //else printf("no %s utxos pass LP_address_utxo_ptrs filter\n",coinaddr); } //else printf("no %s utxos pass LP_address_utxo_ptrs filter\n",coinaddr);
} else printf("couldnt find %s %s\n",coin->symbol,coinaddr); } else printf("couldnt find %s %s\n",coin->symbol,coinaddr);
/*HASH_ITER(hh,G.LP_utxoinfos[iambob],utxo,utmp)
{
if ( LP_isavailable(utxo) != 0 && utxo->payment.value >= targetval && targetval >= utxo->payment.value/2 && utxo->deposit.value >= targetval2 )
{
utxo->S.satoshis = targetval;
printf("backup method found utxo!\n");
return(utxo);
}
}*/
return(0); return(0);
} }
@ -359,10 +397,14 @@ int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJ
privkey = LP_privkey(utxo->coinaddr,coin->taddr); privkey = LP_privkey(utxo->coinaddr,coin->taddr);
if ( bits256_nonz(privkey) != 0 && bits256_cmp(G.LP_mypub25519,qp->srchash) == 0 ) //qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending && if ( bits256_nonz(privkey) != 0 && bits256_cmp(G.LP_mypub25519,qp->srchash) == 0 ) //qp->quotetime >= qp->timestamp-3 && qp->quotetime <= utxo->T.swappending &&
{ {
LP_requestinit(&qp->R,qp->srchash,qp->desthash,base,qp->satoshis-qp->txfee,rel,qp->destsatoshis-qp->desttxfee,qp->timestamp,qp->quotetime,DEXselector);
if ( (swap= LP_swapinit(1,0,privkey,&qp->R,qp)) == 0 )
{
printf("cant initialize swap\n");
return(-1);
}
if ( (pair= LP_nanobind(ctx,pairstr)) >= 0 ) if ( (pair= LP_nanobind(ctx,pairstr)) >= 0 )
{ {
LP_requestinit(&qp->R,qp->srchash,qp->desthash,base,qp->satoshis-2*qp->txfee,rel,qp->destsatoshis-2*qp->desttxfee,qp->timestamp,qp->quotetime,DEXselector);
swap = LP_swapinit(1,0,privkey,&qp->R,qp);
swap->N.pair = pair; swap->N.pair = pair;
utxo->S.swap = swap; utxo->S.swap = swap;
swap->utxo = utxo; swap->utxo = utxo;
@ -400,9 +442,6 @@ int32_t LP_connectstartbob(void *ctx,int32_t pubsock,struct LP_utxoinfo *utxo,cJ
return(retval); return(retval);
} }
struct LP_quoteinfo LP_Alicequery;
double LP_Alicemaxprice;
uint32_t Alice_expiration;
char *LP_trade(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo *qp,double maxprice,int32_t timeout,int32_t duration,uint32_t tradeid) char *LP_trade(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo *qp,double maxprice,int32_t timeout,int32_t duration,uint32_t tradeid)
{ {
struct LP_utxoinfo *aliceutxo; double price; //cJSON *bestitem=0; int32_t DEXselector=0; uint32_t expiration; double price; struct LP_pubkeyinfo *pubp; struct basilisk_swap *swap; struct LP_utxoinfo *aliceutxo; double price; //cJSON *bestitem=0; int32_t DEXselector=0; uint32_t expiration; double price; struct LP_pubkeyinfo *pubp; struct basilisk_swap *swap;
@ -412,6 +451,8 @@ char *LP_trade(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo *q
return(clonestr("{\"error\":\"cant find alice utxopair\"}")); return(clonestr("{\"error\":\"cant find alice utxopair\"}"));
} }
price = 0.; price = 0.;
memset(qp->txid.bytes,0,sizeof(qp->txid));
qp->txid2 = qp->txid;
qp->aliceid = LP_aliceid_calc(qp->desttxid,qp->destvout,qp->feetxid,qp->feevout); qp->aliceid = LP_aliceid_calc(qp->desttxid,qp->destvout,qp->feetxid,qp->feevout);
qp->tradeid = tradeid; qp->tradeid = tradeid;
LP_query(ctx,myipaddr,mypubsock,"request",qp); LP_query(ctx,myipaddr,mypubsock,"request",qp);
@ -422,7 +463,7 @@ char *LP_trade(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo *q
int32_t LP_quotecmp(struct LP_quoteinfo *qp,struct LP_quoteinfo *qp2) int32_t LP_quotecmp(struct LP_quoteinfo *qp,struct LP_quoteinfo *qp2)
{ {
if ( bits256_cmp(qp->srchash,qp2->srchash) == 0 && bits256_cmp(qp->desthash,qp2->desthash) == 0 && strcmp(qp->srccoin,qp2->srccoin) == 0 && strcmp(qp->destcoin,qp2->destcoin) == 0 && bits256_cmp(qp->desttxid,qp2->desttxid) == 0 && qp->destvout == qp2->destvout && bits256_cmp(qp->feetxid,qp2->feetxid) == 0 && qp->feevout == qp2->feevout && qp->destsatoshis == qp2->destsatoshis && qp->txfee >= qp2->txfee && qp->desttxfee == qp2->desttxfee ) if ( bits256_cmp(qp->desthash,qp2->desthash) == 0 && strcmp(qp->srccoin,qp2->srccoin) == 0 && strcmp(qp->destcoin,qp2->destcoin) == 0 && bits256_cmp(qp->desttxid,qp2->desttxid) == 0 && qp->destvout == qp2->destvout && bits256_cmp(qp->feetxid,qp2->feetxid) == 0 && qp->feevout == qp2->feevout && qp->destsatoshis == qp2->destsatoshis && qp->txfee >= qp2->txfee && qp->desttxfee == qp2->desttxfee ) //bits256_cmp(qp->srchash,qp2->srchash) == 0 &&
return(0); return(0);
else return(-1); else return(-1);
} }
@ -445,46 +486,52 @@ void LP_reserved(void *ctx,char *myipaddr,int32_t mypubsock,struct LP_quoteinfo
if ( LP_alice_eligible() > 0 && LP_quotecmp(qp,&LP_Alicequery) == 0 ) if ( LP_alice_eligible() > 0 && LP_quotecmp(qp,&LP_Alicequery) == 0 )
{ {
price = LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout); price = LP_pricecache(qp,qp->srccoin,qp->destcoin,qp->txid,qp->vout);
if ( LP_pricevalid(price) > 0 && maxprice > SMALLVAL && price <= maxprice ) if ( LP_pricevalid(price) > 0 && maxprice > SMALLVAL && price <= maxprice*1.005 )
{ {
qp->tradeid = LP_Alicequery.tradeid; qp->tradeid = LP_Alicequery.tradeid;
memset(&LP_Alicequery,0,sizeof(LP_Alicequery)); memset(&LP_Alicequery,0,sizeof(LP_Alicequery));
LP_Alicemaxprice = 0.; LP_Alicemaxprice = 0.;
Alice_expiration = 0; Alice_expiration = 0;
printf("send CONNECT\n");
LP_query(ctx,myipaddr,mypubsock,"connect",qp); LP_query(ctx,myipaddr,mypubsock,"connect",qp);
} } else printf("LP_reserved price %.8f vs maxprice %.8f\n",price,maxprice*1.005);
} else printf("reject reserved due to not eligible.%d or mismatched quote price %.8f vs maxprice %.8f\n",LP_alice_eligible(),price,maxprice); } else printf("probably a timeout, reject reserved due to not eligible.%d or mismatched quote price %.8f vs maxprice %.8f\n",LP_alice_eligible(),price,maxprice);
} }
char *LP_connectedalice(cJSON *argjson) // alice 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,B,*butxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; struct iguana_info *coin; //uint64_t value,value2; cJSON *retjson; double bid,ask,price,qprice; int32_t pairsock = -1; char *pairstr; int32_t DEXselector = 0; struct LP_utxoinfo *autxo,B,*butxo; struct LP_quoteinfo Q; struct basilisk_swap *swap; struct iguana_info *coin; //uint64_t value,value2;
if ( LP_quoteparse(&Q,argjson) < 0 ) if ( LP_quoteparse(&Q,argjson) < 0 )
{
LP_aliceid(Q.tradeid,Q.aliceid,"error0",0,0);
clonestr("{\"error\":\"cant parse quote\"}"); clonestr("{\"error\":\"cant parse quote\"}");
}
if ( bits256_cmp(Q.desthash,G.LP_mypub25519) != 0 ) if ( bits256_cmp(Q.desthash,G.LP_mypub25519) != 0 )
return(clonestr("{\"result\",\"update stats\"}"));
printf("CONNECTED.(%s) numpending.%d tradeid.%u\n",jprint(argjson,0),G.LP_pendingswaps,Q.tradeid);
/*if ( LP_alice_eligible() == 0 || LP_quotecmp(&Q,&LP_Alicequery) != 0 )
{ {
printf("reject mismatched alice query\n"); LP_aliceid(Q.tradeid,Q.aliceid,"error1",0,0);
return(clonestr("{\"error\",\"mismatched alice query\"}")); return(clonestr("{\"result\",\"update stats\"}"));
} }
memset(&LP_Alicequery,0,sizeof(LP_Alicequery)); printf("CONNECTED.(%s) numpending.%d tradeid.%u\n",jprint(argjson,0),G.LP_pendingswaps,Q.tradeid);
LP_Alicemaxprice = 0.;
Alice_expiration = 0;*/
if ( (autxo= LP_utxopairfind(0,Q.desttxid,Q.destvout,Q.feetxid,Q.feevout)) == 0 ) if ( (autxo= LP_utxopairfind(0,Q.desttxid,Q.destvout,Q.feetxid,Q.feevout)) == 0 )
{ {
printf("cant find autxo\n"); printf("cant find autxo\n");
LP_aliceid(Q.tradeid,Q.aliceid,"error2",0,0);
return(clonestr("{\"error\":\"cant find autxo\"}")); return(clonestr("{\"error\":\"cant find autxo\"}"));
} }
if ( autxo->S.swap != 0 ) if ( autxo->S.swap != 0 )
{
printf("ignore duplicate swap\n");
LP_aliceid(Q.tradeid,Q.aliceid,"error3",0,0);
return(clonestr("{\"error\":\"ignore duplicate swap\"}")); return(clonestr("{\"error\":\"ignore duplicate swap\"}"));
}
LP_aliceid(Q.tradeid,Q.aliceid,"connected",Q.R.requestid,Q.R.quoteid);
butxo = &B; butxo = &B;
memset(butxo,0,sizeof(*butxo)); memset(butxo,0,sizeof(*butxo));
LP_abutxo_set(0,butxo,&Q); LP_abutxo_set(0,butxo,&Q);
if ( (qprice= LP_quote_validate(autxo,butxo,&Q,0)) <= SMALLVAL ) if ( (qprice= LP_quote_validate(autxo,butxo,&Q,0)) <= SMALLVAL )
{ {
LP_availableset(autxo); LP_availableset(autxo);
LP_aliceid(Q.tradeid,Q.aliceid,"error4",0,0);
printf("quote validate error %.0f\n",qprice); printf("quote validate error %.0f\n",qprice);
return(clonestr("{\"error\":\"quote validation error\"}")); return(clonestr("{\"error\":\"quote validation error\"}"));
} }
@ -492,29 +539,43 @@ char *LP_connectedalice(cJSON *argjson) // alice
{ {
printf("this node has no price for %s/%s (%.8f %.8f)\n",Q.destcoin,Q.srccoin,bid,ask); printf("this node has no price for %s/%s (%.8f %.8f)\n",Q.destcoin,Q.srccoin,bid,ask);
LP_availableset(autxo); LP_availableset(autxo);
LP_aliceid(Q.tradeid,Q.aliceid,"error5",0,0);
return(clonestr("{\"error\":\"no price set\"}")); return(clonestr("{\"error\":\"no price set\"}"));
} }
printf("%s/%s bid %.8f ask %.8f values %.8f %.8f\n",Q.srccoin,Q.destcoin,bid,ask,dstr(butxo->payment.value),dstr(butxo->deposit.value)); printf("%s/%s bid %.8f ask %.8f values %.8f %.8f\n",Q.srccoin,Q.destcoin,bid,ask,dstr(butxo->payment.value),dstr(butxo->deposit.value));
price = bid; price = bid;
if ( (coin= LP_coinfind(Q.destcoin)) == 0 ) if ( (coin= LP_coinfind(Q.destcoin)) == 0 )
{
LP_aliceid(Q.tradeid,Q.aliceid,"error6",0,0);
return(clonestr("{\"error\":\"cant get alicecoin\"}")); return(clonestr("{\"error\":\"cant get alicecoin\"}"));
}
Q.privkey = LP_privkey(Q.destaddr,coin->taddr); Q.privkey = LP_privkey(Q.destaddr,coin->taddr);
if ( bits256_nonz(Q.privkey) != 0 )//&& Q.quotetime >= Q.timestamp-3 ) if ( bits256_nonz(Q.privkey) != 0 )//&& Q.quotetime >= Q.timestamp-3 )
{ {
retjson = cJSON_CreateObject(); retjson = cJSON_CreateObject();
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);
if ( (swap= LP_swapinit(0,0,Q.privkey,&Q.R,&Q)) == 0 )
{
jaddstr(retjson,"error","couldnt swapinit");
LP_availableset(autxo);
LP_aliceid(Q.tradeid,Q.aliceid,"error7",Q.R.requestid,Q.R.quoteid);
return(jprint(retjson,1));
}
if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 ) if ( (pairstr= jstr(argjson,"pair")) == 0 || (pairsock= nn_socket(AF_SP,NN_PAIR)) < 0 )
{
LP_aliceid(Q.tradeid,Q.aliceid,"error8",Q.R.requestid,Q.R.quoteid);
jaddstr(retjson,"error","couldnt create pairsock"); jaddstr(retjson,"error","couldnt create pairsock");
}
else if ( nn_connect(pairsock,pairstr) >= 0 ) else if ( nn_connect(pairsock,pairstr) >= 0 )
{ {
//timeout = 1; //timeout = 1;
//nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout));
//nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout)); //nn_setsockopt(pairsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout));
LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis-2*Q.txfee,Q.destcoin,Q.destsatoshis-2*Q.desttxfee,Q.timestamp,Q.quotetime,DEXselector);
swap = LP_swapinit(0,0,Q.privkey,&Q.R,&Q);
swap->tradeid = Q.tradeid; swap->tradeid = Q.tradeid;
swap->N.pair = pairsock; swap->N.pair = pairsock;
autxo->S.swap = swap; autxo->S.swap = swap;
swap->utxo = autxo; swap->utxo = autxo;
LP_aliceid(Q.tradeid,Q.aliceid,"started",Q.R.requestid,Q.R.quoteid);
printf("alice pairstr.(%s) pairsock.%d\n",pairstr,pairsock); printf("alice pairstr.(%s) pairsock.%d\n",pairstr,pairsock);
if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 ) if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_aliceloop,(void *)swap) == 0 )
{ {
@ -522,8 +583,18 @@ char *LP_connectedalice(cJSON *argjson) // alice
jaddstr(retjson,"result","success"); jaddstr(retjson,"result","success");
//jaddnum(retjson,"requestid",Q.R.requestid); //jaddnum(retjson,"requestid",Q.R.requestid);
//jaddnum(retjson,"quoteid",Q.R.quoteid); //jaddnum(retjson,"quoteid",Q.R.quoteid);
} else jaddstr(retjson,"error","couldnt aliceloop"); }
} else printf("connect error %s\n",nn_strerror(nn_errno())); else
{
LP_aliceid(Q.tradeid,Q.aliceid,"error9",Q.R.requestid,Q.R.quoteid);
jaddstr(retjson,"error","couldnt aliceloop");
}
}
else
{
LP_aliceid(Q.tradeid,Q.aliceid,"error10",Q.R.requestid,Q.R.quoteid);
printf("connect error %s\n",nn_strerror(nn_errno()));
}
printf("connected result.(%s)\n",jprint(retjson,0)); printf("connected result.(%s)\n",jprint(retjson,0));
if ( jobj(retjson,"error") != 0 ) if ( jobj(retjson,"error") != 0 )
LP_availableset(autxo); LP_availableset(autxo);
@ -532,6 +603,7 @@ char *LP_connectedalice(cJSON *argjson) // alice
else else
{ {
LP_availableset(autxo); LP_availableset(autxo);
LP_aliceid(Q.tradeid,Q.aliceid,"error11",0,0);
printf("no privkey found coin.%s %s taddr.%u\n",Q.destcoin,Q.destaddr,coin->taddr); printf("no privkey found coin.%s %s taddr.%u\n",Q.destcoin,Q.destaddr,coin->taddr);
return(clonestr("{\"error\",\"no privkey\"}")); return(clonestr("{\"error\",\"no privkey\"}"));
} }
@ -594,21 +666,68 @@ int32_t LP_aliceonly(char *symbol)
else return(0); else return(0);
} }
int32_t LP_validSPV(char *symbol,char *coinaddr,bits256 txid,int32_t vout)
{
struct electrum_info *ep,*backupep; struct LP_address_utxo *up; struct iguana_info *coin;
coin = LP_coinfind(symbol);
if ( coin != 0 && (ep= coin->electrum) != 0 )
{
if ( (up= LP_address_utxofind(coin,coinaddr,txid,vout)) != 0 )
{
if ( up->SPV < 0 )
return(-1);
if ( (backupep= ep->prev) == 0 )
backupep = ep;
up->SPV = LP_merkleproof(coin,coinaddr,backupep,up->U.txid,up->U.height);
if ( up->SPV <= 0 )
return(-1);
}
}
return(0);
}
int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen) int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,uint8_t *data,int32_t datalen)
{ {
char *method,*msg,*retstr,str[65]; int32_t DEXselector = 0; uint64_t value,value2; cJSON *retjson; double qprice,price,bid,ask; struct LP_utxoinfo A,B,*autxo,*butxo; struct iguana_info *coin; struct LP_address_utxo *utxos[1000]; struct LP_quoteinfo Q; int32_t retval = -1,max=(int32_t)(sizeof(utxos)/sizeof(*utxos)); char *method,*msg,*retstr,str[65]; int32_t DEXselector = 0; uint64_t aliceid,value,value2; cJSON *retjson; double qprice,range,bestprice,price,bid,ask; struct LP_utxoinfo A,B,*autxo,*butxo; struct iguana_info *coin; struct LP_address_utxo *utxos[1000]; struct LP_quoteinfo Q; int32_t r,retval = -1,recalc,max=(int32_t)(sizeof(utxos)/sizeof(*utxos));
if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"reserved") == 0 ||strcmp(method,"connected") == 0 || strcmp(method,"request") == 0 || strcmp(method,"connect") == 0) ) if ( (method= jstr(argjson,"method")) != 0 && (strcmp(method,"reserved") == 0 ||strcmp(method,"connected") == 0 || strcmp(method,"request") == 0 || strcmp(method,"connect") == 0) )
{ {
// LP_checksig // LP_checksig
LP_quoteparse(&Q,argjson); LP_quoteparse(&Q,argjson);
LP_requestinit(&Q.R,Q.srchash,Q.desthash,Q.srccoin,Q.satoshis-2*Q.txfee,Q.destcoin,Q.destsatoshis-2*Q.desttxfee,Q.timestamp,Q.quotetime,DEXselector); 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);
LP_tradecommand_log(argjson); LP_tradecommand_log(argjson);
//printf("LP_tradecommand: check received method %s aliceid.%llx\n",method,(long long)Q.aliceid); //printf("LP_tradecommand: check received method %12s aliceid.%16llx %5s/%-5s %12.8f -> %12.8f price %12.8f\n",method,(long long)Q.aliceid,Q.srccoin,Q.destcoin,dstr(Q.satoshis),dstr(Q.destsatoshis),(double)Q.destsatoshis/Q.satoshis);
retval = 1; retval = 1;
autxo = &A;
butxo = &B;
memset(autxo,0,sizeof(*autxo));
memset(butxo,0,sizeof(*butxo));
LP_abutxo_set(autxo,butxo,&Q);
aliceid = j64bits(argjson,"aliceid");
qprice = jdouble(argjson,"price");
if ( strcmp(method,"reserved") == 0 ) if ( strcmp(method,"reserved") == 0 )
{ {
bestprice = LP_bob_competition(aliceid,qprice);
//printf("aliceid.%llx price %.8f -> bestprice %.8f\n",(long long)aliceid,qprice,bestprice);
if ( LP_Alicemaxprice == 0. )
return(retval);
if ( bits256_cmp(G.LP_mypub25519,Q.desthash) == 0 && bits256_cmp(G.LP_mypub25519,Q.srchash) != 0 && LP_alice_eligible() > 0 ) if ( bits256_cmp(G.LP_mypub25519,Q.desthash) == 0 && bits256_cmp(G.LP_mypub25519,Q.srchash) != 0 && LP_alice_eligible() > 0 )
{ {
if ( (qprice= LP_quote_validate(autxo,butxo,&Q,0)) <= SMALLVAL )
{
printf("reserved quote validate error %.0f\n",qprice);
return(retval);
}
if ( LP_validSPV(Q.srccoin,Q.coinaddr,Q.txid,Q.vout) < 0 )
{
printf("%s src %s failed SPV check\n",Q.srccoin,bits256_str(str,Q.txid));
return(retval);
}
else if ( LP_validSPV(Q.srccoin,Q.coinaddr,Q.txid2,Q.vout2) < 0 )
{
printf("%s src2 %s failed SPV check\n",Q.srccoin,bits256_str(str,Q.txid2));
return(retval);
}
LP_aliceid(Q.tradeid,Q.aliceid,"reserved",0,0);
printf("alice %s received RESERVED.(%s)\n",bits256_str(str,G.LP_mypub25519),jprint(argjson,0)); printf("alice %s received RESERVED.(%s)\n",bits256_str(str,G.LP_mypub25519),jprint(argjson,0));
if ( (retstr= LP_quotereceived(argjson)) != 0 ) if ( (retstr= LP_quotereceived(argjson)) != 0 )
free(retstr); free(retstr);
@ -620,148 +739,199 @@ int32_t LP_tradecommand(void *ctx,char *myipaddr,int32_t pubsock,cJSON *argjson,
{ {
if ( bits256_cmp(G.LP_mypub25519,Q.desthash) == 0 && bits256_cmp(G.LP_mypub25519,Q.srchash) != 0 ) if ( bits256_cmp(G.LP_mypub25519,Q.desthash) == 0 && bits256_cmp(G.LP_mypub25519,Q.srchash) != 0 )
{ {
//printf("alice %s received CONNECTED.(%s)\n",bits256_str(str,G.LP_mypub25519),jprint(argjson,0)); if ( (qprice= LP_quote_validate(autxo,butxo,&Q,0)) <= SMALLVAL )
{
printf("quote validate error %.0f\n",qprice);
return(retval);
}
if ( LP_validSPV(Q.srccoin,Q.coinaddr,Q.txid,Q.vout) < 0 )
{
printf("%s src %s failed SPV check\n",Q.srccoin,bits256_str(str,Q.txid));
return(retval);
}
else if (LP_validSPV(Q.srccoin,Q.coinaddr,Q.txid2,Q.vout2) < 0 )
{
printf("%s src2 %s failed SPV check\n",Q.srccoin,bits256_str(str,Q.txid2));
return(retval);
}
//printf("alice %s received CONNECTED.(%s)\n",bits256_str(str,G.LP_mypub25519),jprint(argjson,0));
if ( (retstr= LP_connectedalice(argjson)) != 0 ) if ( (retstr= LP_connectedalice(argjson)) != 0 )
free(retstr); free(retstr);
} }
return(retval); return(retval);
} }
if ( bits256_cmp(G.LP_mypub25519,Q.srchash) == 0 && bits256_cmp(G.LP_mypub25519,Q.desthash) != 0 ) price = LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin);
if ( (coin= LP_coinfind(Q.srccoin)) == 0 || price <= SMALLVAL || ask <= SMALLVAL )
{
//printf("this node has no price for %s/%s\n",Q.srccoin,Q.destcoin);
return(retval);
}
price = ask;
//printf("MYPRICE %s/%s %.8f\n",Q.srccoin,Q.destcoin,price);
if ( LP_validSPV(Q.destcoin,Q.destaddr,Q.desttxid,Q.destvout) < 0 )
{
printf("%s dest %s failed SPV check\n",Q.destcoin,bits256_str(str,Q.desttxid));
return(retval);
}
else if (LP_validSPV(Q.destcoin,Q.destaddr,Q.feetxid,Q.feevout) < 0 )
{
printf("%s dexfee %s failed SPV check\n",Q.destcoin,bits256_str(str,Q.feetxid));
return(retval);
}
if ( LP_aliceonly(Q.srccoin) > 0 )
{ {
if ( (coin= LP_coinfind(Q.srccoin)) == 0 || (price= LP_myprice(&bid,&ask,Q.srccoin,Q.destcoin)) <= SMALLVAL || ask <= SMALLVAL ) printf("{\"error\":\"GAME can only be alice coin\"}\n");
return(retval);
}
if ( strcmp(method,"request") == 0 )
{
char str[65];//,str2[65];
recalc = 0;
if ( bits256_cmp(Q.srchash,G.LP_mypub25519) != 0 || strcmp(butxo->coinaddr,coin->smartaddr) != 0 || bits256_nonz(butxo->payment.txid) == 0 || bits256_nonz(butxo->deposit.txid) == 0 )
{ {
printf("this node has no price for %s/%s\n",Q.srccoin,Q.destcoin); qprice = (double)Q.destsatoshis / Q.satoshis;
return(retval); strcpy(Q.gui,G.gui);
strcpy(Q.coinaddr,coin->smartaddr);
strcpy(butxo->coinaddr,coin->smartaddr);
Q.srchash = G.LP_mypub25519;
memset(&Q.txid,0,sizeof(Q.txid));
memset(&Q.txid2,0,sizeof(Q.txid2));
Q.vout = Q.vout2 = -1;
recalc = 1;
} }
/*if ( coin->electrum != 0 ) else if ( (qprice= LP_quote_validate(autxo,butxo,&Q,1)) < SMALLVAL )
{ recalc = 1;
printf("electrum can only be for alice\n"); else if ( price < qprice )
return(retval);
}*/
if ( LP_aliceonly(Q.srccoin) > 0 )
{ {
printf("{\"error\":\"GAME can only be alice coin\"}\n"); char tmp[64];
return(retval); if ( bits256_nonz(Q.txid) != 0 )
} LP_utxos_remove(Q.txid,Q.vout);
if ( strcmp(Q.coinaddr,coin->smartaddr) != 0 ) else recalc = 1;
if ( bits256_nonz(Q.txid2) != 0 )
LP_utxos_remove(Q.txid2,Q.vout2);
else recalc = 1;
printf("price %.8f qprice %.8f\n",price,qprice);
if ( recalc == 0 )
{
value = LP_txvalue(tmp,Q.srccoin,Q.txid,Q.vout);
value2 = LP_txvalue(tmp,Q.srccoin,Q.txid2,Q.vout2);
//printf("call LP_utxoadd.(%s) %.8f %.8f\n",Q.coinaddr,dstr(value),dstr(value2));
if ( (butxo= LP_utxoadd(1,coin->symbol,Q.txid,Q.vout,value,Q.txid2,Q.vout2,value2,Q.coinaddr,Q.srchash,G.gui,0,Q.satoshis)) == 0 )
recalc = 1;
else if ( bits256_cmp(Q.txid,butxo->payment.txid) != 0 || Q.vout != butxo->payment.vout || bits256_cmp(Q.txid2,butxo->deposit.txid) != 0 || Q.vout2 != butxo->deposit.vout )
recalc = 1;
}
} else return(retval);
if ( qprice > price )
{ {
printf("bob is patching Q.coinaddr %s mismatch != %s\n",Q.coinaddr,coin->smartaddr); r = (rand() % 100);
strcpy(Q.coinaddr,coin->smartaddr); range = (qprice - price);
} printf(">>>>>>>>>>>>> price %.8f qprice %.8f r.%d range %.8f -> %.8f vs bestprice %.8f\n",price,qprice,r,range,price + (r*range)/100.,LP_bob_competition(aliceid,price));
price = ask; price += (r * range) / 100.;
autxo = &A; bestprice = LP_bob_competition(aliceid,price);
butxo = &B; if ( price < bestprice+SMALLVAL )
memset(autxo,0,sizeof(*autxo)); return(retval);
memset(butxo,0,sizeof(*butxo)); } else return(retval);
LP_abutxo_set(autxo,butxo,&Q); //printf("recalc.%d address.(%s/%s) price %.8f request.(%s)\n",recalc,Q.coinaddr,coin->smartaddr,price,jprint(argjson,0));
printf("utxopairfind\n"); if ( recalc != 0 )
if ( (butxo= LP_utxopairfind(1,Q.txid,Q.vout,Q.txid2,Q.vout2)) == 0 )
butxo = &B;
//LP_butxo_swapfields(butxo);
if ( strcmp(method,"request") == 0 )
{ {
char str[65],str2[65]; LP_RTmetrics_update(Q.srccoin,Q.destcoin);
printf("request.(%s)\n",jprint(argjson,0)); if ( LP_RTmetrics_blacklisted(Q.desthash) >= 0 )
if ( 1 )//LP_allocated(butxo->payment.txid,butxo->payment.vout) != 0 || LP_allocated(butxo->deposit.txid,butxo->deposit.vout) != 0 || (qprice= LP_quote_validate(autxo,butxo,&Q,1)) <= SMALLVAL )
{ {
LP_RTmetrics_update(Q.srccoin,Q.destcoin); printf("request from blacklisted %s, ignore\n",bits256_str(str,Q.desthash));
if ( LP_RTmetrics_blacklisted(Q.desthash) >= 0 ) return(retval);
{ }
printf("request from blacklisted %s, ignore\n",bits256_str(str,Q.desthash)); LP_listunspent_both(Q.srccoin,Q.coinaddr,0);
return(retval); if ( (butxo= LP_address_utxopair(1,utxos,max,LP_coinfind(Q.srccoin),Q.coinaddr,Q.txfee,dstr(Q.destsatoshis),price,Q.desttxfee)) != 0 )
} {
printf("butxo.%p replace path %p %s, %p %s, %.8f\n",butxo,LP_allocated(butxo->payment.txid,butxo->payment.vout),bits256_str(str,butxo->payment.txid),LP_allocated(butxo->deposit.txid,butxo->deposit.vout),bits256_str(str2,butxo->deposit.txid),LP_quote_validate(autxo,butxo,&Q,1)); strcpy(Q.gui,G.gui);
LP_listunspent_both(Q.srccoin,Q.coinaddr,0); strcpy(Q.coinaddr,coin->smartaddr);
if ( (butxo= LP_address_utxopair(1,utxos,max,LP_coinfind(Q.srccoin),Q.coinaddr,Q.txfee,dstr(Q.destsatoshis),price,Q.desttxfee)) != 0 ) Q.srchash = G.LP_mypub25519;
{ Q.txid = butxo->payment.txid;
Q.txid = butxo->payment.txid; Q.vout = butxo->payment.vout;
Q.vout = butxo->payment.vout; Q.txid2 = butxo->deposit.txid;
Q.txid2 = butxo->deposit.txid; Q.vout2 = butxo->deposit.vout;
Q.vout2 = butxo->deposit.vout; Q.satoshis = butxo->S.satoshis;
printf("set butxo.%p %s/v%d %s/v%d %.8f %.8f -> bsat %.8f asat %.8f\n",butxo,bits256_str(str,butxo->payment.txid),butxo->payment.vout,bits256_str(str2,butxo->deposit.txid),butxo->deposit.vout,dstr(butxo->payment.value),dstr(butxo->deposit.value),dstr(butxo->S.satoshis),dstr(autxo->S.satoshis)); //printf("set butxo.%p %s/v%d %s/v%d %.8f %.8f -> bsat %.8f asat %.8f\n",butxo,bits256_str(str,butxo->payment.txid),butxo->payment.vout,bits256_str(str2,butxo->deposit.txid),butxo->deposit.vout,dstr(butxo->payment.value),dstr(butxo->deposit.value),dstr(butxo->S.satoshis),dstr(autxo->S.satoshis));
} else printf("cant find utxopair\n");
//LP_abutxo_set(0,butxo,&Q);
//LP_butxo_swapfields(butxo);
} }
else else
{ {
printf("other path %p %p %.8f\n",LP_allocated(butxo->payment.txid,butxo->payment.vout),LP_allocated(butxo->deposit.txid,butxo->deposit.vout), LP_quote_validate(autxo,butxo,&Q,1)); //printf("cant find utxopair\n");
value = LP_txvalue(Q.coinaddr,Q.srccoin,Q.txid,Q.vout); return(retval);
value2 = LP_txvalue(Q.coinaddr,Q.srccoin,Q.txid2,Q.vout2);
if ( (butxo= LP_utxoadd(1,coin->symbol,Q.txid,Q.vout,value,Q.txid2,Q.vout2,value2,Q.coinaddr,G.LP_mypub25519,G.gui,0)) == 0 )
printf("couldnt create bob's utxopair\n");
else printf("created butxo.(%s %s)\n",bits256_str(str,butxo->payment.txid),bits256_str(str2,butxo->deposit.txid));
} }
} }
if ( butxo == 0 || butxo == &B ) }
butxo = LP_utxopairfind(1,Q.txid,Q.vout,Q.txid2,Q.vout2); else // "connect"
if ( butxo == 0 || bits256_cmp(Q.txid,butxo->payment.txid) != 0 || bits256_cmp(Q.txid2,butxo->deposit.txid) != 0 ) {
if ( bits256_cmp(G.LP_mypub25519,Q.srchash) == 0 && bits256_cmp(G.LP_mypub25519,Q.desthash) != 0 )
{ {
printf("%s %s null butxo.%p case\n",Q.srccoin,Q.coinaddr,butxo); butxo = LP_utxopairfind(1,Q.txid,Q.vout,Q.txid2,Q.vout2); // better work!
value = LP_txvalue(Q.coinaddr,Q.srccoin,Q.txid,Q.vout); } else return(retval);
value2 = LP_txvalue(Q.coinaddr,Q.srccoin,Q.txid2,Q.vout2); }
butxo = LP_utxoadd(1,Q.srccoin,Q.txid,Q.vout,value,Q.txid2,Q.vout2,value2,Q.coinaddr,Q.srchash,LP_gui,0); if ( strcmp(Q.coinaddr,coin->smartaddr) != 0 )
} {
char str[65],str2[65]; printf("butxo.%p (%s %s) TRADECOMMAND.(%s)\n",butxo,butxo!=0?bits256_str(str,butxo->payment.txid):"",butxo!=0?bits256_str(str2,butxo->deposit.txid):"",jprint(argjson,0)); printf("bob is patching Q.coinaddr %s mismatch != %s\n",Q.coinaddr,coin->smartaddr);
if ( butxo == 0 || bits256_nonz(butxo->payment.txid) == 0 || bits256_nonz(butxo->deposit.txid) == 0 || butxo->payment.vout < 0 || butxo->deposit.vout < 0 ) strcpy(Q.coinaddr,coin->smartaddr);
}
if ( butxo == 0 || bits256_nonz(butxo->payment.txid) == 0 || bits256_nonz(butxo->deposit.txid) == 0 || butxo->payment.vout < 0 || butxo->deposit.vout < 0 )
{
char str[65],str2[65]; printf("couldnt find bob utxos for autxo %s/v%d %s/v%d %.8f -> %.8f\n",bits256_str(str,Q.txid),Q.vout,bits256_str(str2,Q.txid2),Q.vout2,dstr(Q.satoshis),dstr(Q.destsatoshis));
return(retval);
}
if ( (qprice= LP_quote_validate(autxo,butxo,&Q,1)) <= SMALLVAL )
{
printf("quote validate error %.0f\n",qprice);
return(-3);
}
if ( qprice < (ask - 0.00000001) * 0.998 )
{
printf("(%.8f %.8f) quote price %.8f too low vs %.8f for %s/%s %.8f < %.8f\n",bid,ask,qprice,price,Q.srccoin,Q.destcoin,qprice,(ask - 0.00000001) * 0.998);
return(retval);
}
char str[65],str2[65]; printf("butxo.%p (%s %s) TRADECOMMAND.(%s)\n",butxo,butxo!=0?bits256_str(str,butxo->payment.txid):"",butxo!=0?bits256_str(str2,butxo->deposit.txid):"",jprint(argjson,0));
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 )
{ {
char str[65],str2[65]; printf("couldnt find bob utxos for autxo %s/v%d %s/v%d %.8f -> %.8f\n",bits256_str(str,Q.txid),Q.vout,bits256_str(str2,Q.txid2),Q.vout2,dstr(Q.satoshis),dstr(Q.destsatoshis)); autxo->T.swappending = 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,0);
butxo->T.lasttime = (uint32_t)time(NULL);
printf("return after queued RESERVED: set swappending.%u accept qprice %.8f, min %.8f\n(%s)\n",butxo->T.swappending,qprice,ask,msg);
// LP_addsig
//msg2 = clonestr(msg);
LP_reserved_msg(1,Q.srccoin,Q.destcoin,butxo->S.otherpubkey,clonestr(msg));
sleep(1);
bits256 zero;
memset(zero.bytes,0,sizeof(zero));
LP_reserved_msg(1,Q.srccoin,Q.destcoin,zero,msg);
//LP_broadcast_message(LP_mypubsock,Q.srccoin,Q.destcoin,Q.desthash,jprint(retjson,0));
free_json(retjson);
return(retval); return(retval);
} } else printf("warning swappending.%u swap.%p\n",butxo->T.swappending,butxo->S.swap);
if ( (qprice= LP_quote_validate(autxo,butxo,&Q,1)) <= SMALLVAL ) }
{ else if ( strcmp(method,"connect") == 0 ) // bob
printf("quote validate error %.0f\n",qprice); {
return(-3); retval = 4;
} if ( butxo->S.swap == 0 && butxo->T.swappending != 0 )
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(-4);
}
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 )
{
autxo->T.swappending = 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,0);
butxo->T.lasttime = (uint32_t)time(NULL);
printf("return after queued RESERVED: set swappending.%u accept qprice %.8f, min %.8f\n(%s)\n",butxo->T.swappending,qprice,price,msg);
// LP_addsig
//msg2 = clonestr(msg);
LP_reserved_msg(1,Q.srccoin,Q.destcoin,butxo->S.otherpubkey,clonestr(msg));
sleep(1);
bits256 zero;
memset(zero.bytes,0,sizeof(zero));
LP_reserved_msg(1,Q.srccoin,Q.destcoin,zero,msg);
//LP_broadcast_message(LP_mypubsock,Q.srccoin,Q.destcoin,Q.desthash,jprint(retjson,0));
free_json(retjson);
return(retval);
} else printf("warning swappending.%u swap.%p\n",butxo->T.swappending,butxo->S.swap);
}
else if ( strcmp(method,"connect") == 0 ) // bob
{ {
retval = 4; // validate SPV alice
if ( butxo->S.swap == 0 && butxo->T.swappending != 0 ) LP_connectstartbob(ctx,pubsock,butxo,argjson,Q.srccoin,Q.destcoin,qprice,&Q);
{ //LP_butxo_swapfields_set(butxo);
// validate SPV alice return(retval);
LP_connectstartbob(ctx,pubsock,butxo,argjson,Q.srccoin,Q.destcoin,qprice,&Q);
//LP_butxo_swapfields_set(butxo);
return(retval);
}
else printf("pend.%u swap %p when connect came in (%s)\n",butxo->T.swappending,butxo->S.swap,jprint(argjson,0));
} }
//LP_butxo_swapfields_set(butxo); else printf("pend.%u swap %p when connect came in (%s)\n",butxo->T.swappending,butxo->S.swap,jprint(argjson,0));
} }
//LP_butxo_swapfields_set(butxo);
} }
return(retval); return(retval);
} }
@ -770,6 +940,7 @@ struct LP_utxoinfo *LP_ordermatch_iter(struct LP_address_utxo **utxos,int32_t ma
{ {
uint64_t basesatoshis; struct LP_utxoinfo *bestutxo; uint64_t basesatoshis; struct LP_utxoinfo *bestutxo;
basesatoshis = LP_basesatoshis(dstr(asatoshis),price,txfee,desttxfee); basesatoshis = LP_basesatoshis(dstr(asatoshis),price,txfee,desttxfee);
//printf("basesatoshis %.8f price %.8f txfee %.8f desttxfee %.8f\n",dstr(basesatoshis),price,dstr(txfee),dstr(desttxfee));
if ( basesatoshis != 0 && (bestutxo= LP_address_utxopair(0,utxos,max,basecoin,coinaddr,txfee,dstr(basesatoshis)*price,price,desttxfee)) != 0 ) if ( basesatoshis != 0 && (bestutxo= LP_address_utxopair(0,utxos,max,basecoin,coinaddr,txfee,dstr(basesatoshis)*price,price,desttxfee)) != 0 )
{ {
bestutxo->pubkey = pubkey; bestutxo->pubkey = pubkey;
@ -795,10 +966,10 @@ struct LP_utxoinfo *LP_buyutxo(double *ordermatchpricep,int64_t *bestsatoshisp,i
return(0); return(0);
if ( basecoin->electrum == 0 ) if ( basecoin->electrum == 0 )
max = 1000; max = 1000;
else max = 40; else max = LP_MAXDESIRED_UTXOS;
utxos = calloc(max,sizeof(*utxos)); utxos = calloc(max,sizeof(*utxos));
LP_txfees(&txfee,&desttxfee,base,autxo->coin); LP_txfees(&txfee,&desttxfee,base,autxo->coin);
//printf("LP_buyutxo maxprice %.8f relvol %.8f %s/%s %.8f %.8f\n",maxprice,dstr(autxo->S.satoshis),base,autxo->coin,dstr(txfee),dstr(desttxfee)); printf("LP_buyutxo maxprice %.8f relvol %.8f %s/%s %.8f %.8f\n",maxprice,dstr(autxo->S.satoshis),base,autxo->coin,dstr(txfee),dstr(desttxfee));
if ( (obookstr= LP_orderbook(base,autxo->coin,duration)) != 0 ) if ( (obookstr= LP_orderbook(base,autxo->coin,duration)) != 0 )
{ {
if ( (orderbook= cJSON_Parse(obookstr)) != 0 ) if ( (orderbook= cJSON_Parse(obookstr)) != 0 )
@ -811,15 +982,15 @@ struct LP_utxoinfo *LP_buyutxo(double *ordermatchpricep,int64_t *bestsatoshisp,i
{ {
item = jitem(asks,i); item = jitem(asks,i);
price = jdouble(item,"price"); price = jdouble(item,"price");
if ( price/maxprice < .9 ) //if ( price < maxprice && price > maxprice*0.8)
price *= 1.025; // price = price * 0.9 + 0.1 * maxprice;
else price *= 1.001; //else price *= 1.005;
pubkey = jbits256(item,"pubkey"); pubkey = jbits256(item,"pubkey");
if ( bits256_nonz(destpubkey) != 0 && bits256_cmp(destpubkey,pubkey) != 0 ) if ( bits256_nonz(destpubkey) != 0 && bits256_cmp(destpubkey,pubkey) != 0 )
continue; continue;
if ( LP_RTmetrics_blacklisted(pubkey) >= 0 ) if ( LP_RTmetrics_blacklisted(pubkey) >= 0 )
continue; continue;
//printf("[%d/%d] %s pubcmp %d price %.8f vs maxprice %.8f\n",i,numasks,jprint(item,0),bits256_cmp(pubkey,G.LP_mypub25519),price,maxprice); //printf("[%d/%d] %s pubcmp %d price %.8f vs maxprice %.8f asatoshis %.8f\n",i,numasks,jprint(item,0),bits256_cmp(pubkey,G.LP_mypub25519),price,maxprice,dstr(autxo->S.satoshis));
if ( LP_pricevalid(price) > 0 && price <= maxprice ) if ( LP_pricevalid(price) > 0 && price <= maxprice )
{ {
if ( bits256_nonz(destpubkey) == 0 ) if ( bits256_nonz(destpubkey) == 0 )
@ -835,10 +1006,9 @@ struct LP_utxoinfo *LP_buyutxo(double *ordermatchpricep,int64_t *bestsatoshisp,i
bitcoin_address(coinaddr,basecoin->taddr,basecoin->pubtype,pubp->rmd160,sizeof(pubp->rmd160)); bitcoin_address(coinaddr,basecoin->taddr,basecoin->pubtype,pubp->rmd160,sizeof(pubp->rmd160));
asatoshis = autxo->S.satoshis; asatoshis = autxo->S.satoshis;
LP_listunspent_query(base,coinaddr); LP_listunspent_query(base,coinaddr);
//LP_listunspent_both(base,coinaddr,1);
for (j=0; j<maxiters; j++) for (j=0; j<maxiters; j++)
{ {
if ( (bestutxo= LP_ordermatch_iter(utxos,max,ordermatchpricep,bestsatoshisp,bestdestsatoshisp,basecoin,coinaddr,asatoshis,price,txfee,desttxfee,pubp->pubkey,gui)) != 0 ) if ( (bestutxo= LP_ordermatch_iter(utxos,max,ordermatchpricep,bestsatoshisp,bestdestsatoshisp,basecoin,coinaddr,asatoshis,maxprice*.999,txfee,desttxfee,pubp->pubkey,gui)) != 0 )
{ {
//printf("j.%d/%d ordermatch %.8f best satoshis %.8f destsatoshis %.8f txfees (%.8f %.8f)\n",j,maxiters,price,dstr(*bestsatoshisp),dstr(*bestdestsatoshisp),dstr(txfee),dstr(desttxfee)); //printf("j.%d/%d ordermatch %.8f best satoshis %.8f destsatoshis %.8f txfees (%.8f %.8f)\n",j,maxiters,price,dstr(*bestsatoshisp),dstr(*bestdestsatoshisp),dstr(txfee),dstr(desttxfee));
break; break;
@ -873,7 +1043,7 @@ struct LP_utxoinfo *LP_buyutxo(double *ordermatchpricep,int64_t *bestsatoshisp,i
char *LP_autobuy(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel,double maxprice,double relvolume,int32_t timeout,int32_t duration,char *gui,uint32_t nonce,bits256 destpubkey,uint32_t tradeid) char *LP_autobuy(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel,double maxprice,double relvolume,int32_t timeout,int32_t duration,char *gui,uint32_t nonce,bits256 destpubkey,uint32_t tradeid)
{ {
uint64_t desttxfee,txfee; uint32_t lastnonce; int32_t i,maxiters,numpubs = 0; int64_t bestsatoshis=0,destsatoshis,bestdestsatoshis=0; struct iguana_info *basecoin,*relcoin; struct LP_utxoinfo *autxo,*bestutxo = 0; double qprice,ordermatchprice=0.; struct LP_quoteinfo Q; bits256 pubkeys[100]; uint64_t desttxfee,txfee; uint32_t lastnonce; int32_t i,maxiters,numpubs = 0; int64_t bestsatoshis=0,destsatoshis,bestdestsatoshis=0; struct iguana_info *basecoin,*relcoin; struct LP_utxoinfo *autxo,B,*bestutxo = 0; double qprice,ordermatchprice=0.; struct LP_quoteinfo Q; bits256 pubkeys[100];
basecoin = LP_coinfind(base); basecoin = LP_coinfind(base);
relcoin = LP_coinfind(rel); relcoin = LP_coinfind(rel);
if ( gui == 0 ) if ( gui == 0 )
@ -921,15 +1091,15 @@ char *LP_autobuy(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel
destsatoshis = SATOSHIDEN * relvolume; destsatoshis = SATOSHIDEN * relvolume;
if ( (autxo= LP_utxo_bestfit(rel,destsatoshis + 2*desttxfee)) == 0 ) if ( (autxo= LP_utxo_bestfit(rel,destsatoshis + 2*desttxfee)) == 0 )
return(clonestr("{\"error\":\"cant find alice utxo that is big enough\"}")); return(clonestr("{\"error\":\"cant find alice utxo that is big enough\"}"));
if ( destsatoshis - 2*desttxfee < autxo->S.satoshis ) if ( destsatoshis - desttxfee < autxo->S.satoshis )
{ {
destsatoshis -= 2*desttxfee; destsatoshis -= desttxfee;
autxo->S.satoshis = destsatoshis; autxo->S.satoshis = destsatoshis;
//printf("first path dest %.8f from %.8f\n",dstr(destsatoshis),dstr(autxo->S.satoshis)); //printf("first path dest %.8f from %.8f\n",dstr(destsatoshis),dstr(autxo->S.satoshis));
} }
else if ( autxo->S.satoshis - 2*desttxfee < destsatoshis ) else if ( autxo->S.satoshis - desttxfee < destsatoshis )
{ {
autxo->S.satoshis -= 2*desttxfee; autxo->S.satoshis -= desttxfee;
destsatoshis = autxo->S.satoshis; destsatoshis = autxo->S.satoshis;
printf("second path dest %.8f from %.8f\n",dstr(destsatoshis),dstr(autxo->S.satoshis)); printf("second path dest %.8f from %.8f\n",dstr(destsatoshis),dstr(autxo->S.satoshis));
} }
@ -938,6 +1108,17 @@ char *LP_autobuy(void *ctx,char *myipaddr,int32_t mypubsock,char *base,char *rel
printf("destsatoshis %.8f vs utxo %.8f this would have triggered an quote error -13\n",dstr(destsatoshis),dstr(autxo->payment.value)); printf("destsatoshis %.8f vs utxo %.8f this would have triggered an quote error -13\n",dstr(destsatoshis),dstr(autxo->payment.value));
return(clonestr("{\"error\":\"cant find alice utxo that is small enough\"}")); return(clonestr("{\"error\":\"cant find alice utxo that is small enough\"}"));
} }
bestsatoshis = LP_basesatoshis(dstr(destsatoshis),maxprice,txfee,desttxfee);
memset(&B,0,sizeof(B));
strcpy(B.coin,base);
if ( LP_quoteinfoinit(&Q,&B,rel,maxprice,bestsatoshis,destsatoshis) < 0 )
return(clonestr("{\"error\":\"cant set ordermatch quote\"}"));
if ( LP_quotedestinfo(&Q,autxo->payment.txid,autxo->payment.vout,autxo->fee.txid,autxo->fee.vout,G.LP_mypub25519,autxo->coinaddr) < 0 )
return(clonestr("{\"error\":\"cant set ordermatch quote info\"}"));
int32_t changed;
LP_mypriceset(&changed,autxo->coin,base,1. / maxprice);
return(LP_trade(ctx,myipaddr,mypubsock,&Q,maxprice,timeout,duration,tradeid));
LP_RTmetrics_update(base,rel); LP_RTmetrics_update(base,rel);
while ( 1 ) while ( 1 )
{ {

134
iguana/exchanges/LP_peers.c

@ -31,7 +31,7 @@ struct LP_peerinfo *LP_peerfind(uint32_t ipbits,uint16_t port)
cJSON *LP_peerjson(struct LP_peerinfo *peer) cJSON *LP_peerjson(struct LP_peerinfo *peer)
{ {
cJSON *item = cJSON_CreateObject(); cJSON *item = cJSON_CreateObject();
jaddstr(item,"ipaddr",peer->ipaddr); jaddstr(item,"isLP",peer->ipaddr);
jaddnum(item,"port",peer->port); jaddnum(item,"port",peer->port);
if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 ) if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 )
{ {
@ -49,15 +49,15 @@ char *LP_peers()
HASH_ITER(hh,LP_peerinfos,peer,tmp) HASH_ITER(hh,LP_peerinfos,peer,tmp)
{ {
//if ( peer->errors < LP_MAXPEER_ERRORS ) //if ( peer->errors < LP_MAXPEER_ERRORS )
if ( peer->isLP != 0 )
jaddi(peersjson,LP_peerjson(peer)); jaddi(peersjson,LP_peerjson(peer));
} }
return(jprint(peersjson,1)); 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) 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 isLP,uint32_t sessionid)
{ {
uint32_t ipbits; int32_t valid,pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0; uint32_t ipbits; int32_t valid,pushsock,subsock,timeout; char checkip[64],pushaddr[64],subaddr[64]; struct LP_peerinfo *peer = 0;
printf("addpeer (%s:%u) pushport.%u subport.%u\n",ipaddr,port,pushport,subport);
#ifdef LP_STRICTPEERS #ifdef LP_STRICTPEERS
if ( strncmp("5.9.253",ipaddr,strlen("5.9.253")) != 0 ) if ( strncmp("5.9.253",ipaddr,strlen("5.9.253")) != 0 )
return(0); return(0);
@ -68,6 +68,8 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char
{ {
if ( (peer= LP_peerfind(ipbits,port)) != 0 ) if ( (peer= LP_peerfind(ipbits,port)) != 0 )
{ {
if ( isLP != 0 )
peer->isLP = isLP;
/*if ( numpeers > peer->numpeers ) /*if ( numpeers > peer->numpeers )
peer->numpeers = numpeers; peer->numpeers = numpeers;
if ( numutxos > peer->numutxos ) if ( numutxos > peer->numutxos )
@ -77,6 +79,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char
} }
else else
{ {
//printf("addpeer (%s:%u) pushport.%u subport.%u\n",ipaddr,port,pushport,subport);
peer = calloc(1,sizeof(*peer)); peer = calloc(1,sizeof(*peer));
if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 ) if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 )
peer->sessionid = G.LP_sessionid; peer->sessionid = G.LP_sessionid;
@ -85,6 +88,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char
strcpy(peer->ipaddr,ipaddr); strcpy(peer->ipaddr,ipaddr);
//peer->profitmargin = profitmargin; //peer->profitmargin = profitmargin;
peer->ipbits = ipbits; peer->ipbits = ipbits;
peer->isLP = isLP;
peer->port = port; peer->port = port;
peer->ip_port = ((uint64_t)port << 32) | ipbits; peer->ip_port = ((uint64_t)port << 32) | ipbits;
if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 ) if ( pushport != 0 && subport != 0 && (pushsock= nn_socket(AF_SP,NN_PUSH)) >= 0 )
@ -102,7 +106,7 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char
nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout)); nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout));
//maxsize = 2 * 1024 * 1024; //maxsize = 2 * 1024 * 1024;
//nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDBUF,&maxsize,sizeof(maxsize)); //nn_setsockopt(pushsock,NN_SOL_SOCKET,NN_SNDBUF,&maxsize,sizeof(maxsize));
printf("connected to push.(%s) pushsock.%d valid.%d\n",pushaddr,pushsock,valid); printf("connected to push.(%s) pushsock.%d valid.%d | ",pushaddr,pushsock,valid);
peer->connected = (uint32_t)time(NULL); peer->connected = (uint32_t)time(NULL);
peer->pushsock = pushsock; peer->pushsock = pushsock;
if ( (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 ) if ( (subsock= nn_socket(AF_SP,NN_SUB)) >= 0 )
@ -139,21 +143,21 @@ struct LP_peerinfo *LP_addpeer(struct LP_peerinfo *mypeer,int32_t mypubsock,char
} else printf("%s pushport.%u subport.%u pushsock.%d\n",ipaddr,pushport,subport,pushsock); } else printf("%s pushport.%u subport.%u pushsock.%d\n",ipaddr,pushport,subport,pushsock);
if ( peer->pushsock >= 0 && peer->subsock >= 0 ) if ( peer->pushsock >= 0 && peer->subsock >= 0 )
{ {
printf("add peer %s\n",peer->ipaddr); //printf("add peer %s\n",peer->ipaddr);
portable_mutex_lock(&LP_peermutex); portable_mutex_lock(&LP_peermutex);
HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer); HASH_ADD(hh,LP_peerinfos,ip_port,sizeof(peer->ip_port),peer);
if ( mypeer != 0 ) if ( mypeer != 0 )
{ {
mypeer->numpeers++; mypeer->numpeers++;
printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d other.(%d %d)\n",ipaddr,mypeer->numpeers,mypubsock,numpeers,numutxos); printf("_LPaddpeer %s -> numpeers.%d mypubsock.%d other.(%d)\n",ipaddr,mypeer->numpeers,mypubsock,isLP);
} else peer->numpeers = 1; // will become mypeer } else peer->numpeers = 1; // will become mypeer
portable_mutex_unlock(&LP_peermutex); portable_mutex_unlock(&LP_peermutex);
if ( IAMLP != 0 && mypubsock >= 0 ) if ( IAMLP != 0 && mypubsock >= 0 )
{ {
struct iguana_info *coin,*ctmp; bits256 zero; char busaddr[64]; struct iguana_info *coin,*ctmp; char busaddr[64]; //
memset(zero.bytes,0,sizeof(zero)); //memset(zero.bytes,0,sizeof(zero));
//LP_send(mypubsock,msg,(int32_t)strlen(msg)+1,1); //LP_send(mypubsock,msg,(int32_t)strlen(msg)+1,1);
LP_reserved_msg(0,"","",zero,jprint(LP_peerjson(peer),1)); //LP_reserved_msg(0,"","",zero,jprint(LP_peerjson(peer),1));
if ( 0 ) if ( 0 )
{ {
HASH_ITER(hh,LP_coins,coin,ctmp) HASH_ITER(hh,LP_coins,coin,ctmp)
@ -202,67 +206,14 @@ int32_t LP_coinbus(uint16_t coin_busport)
return(bussock); return(bussock);
} }
int32_t LP_peersparse(struct LP_peerinfo *mypeer,int32_t mypubsock,char *destipaddr,uint16_t destport,char *retstr,uint32_t now) void LP_peer_recv(char *ipaddr,int32_t ismine)
{ {
struct LP_peerinfo *peer; uint32_t argipbits; char *argipaddr; uint16_t argport,pushport,subport; cJSON *array,*item; int32_t i,n=0; struct LP_peerinfo *peer;
if ( (array= cJSON_Parse(retstr)) != 0 ) if ( (peer= LP_peerfind((uint32_t)calc_ipbits(ipaddr),RPC_port)) != 0 )
{ {
if ( (n= cJSON_GetArraySize(array)) > 0 ) peer->numrecv++;
{ if ( ismine != 0 )
for (i=0; i<n; i++) peer->recvtime = (uint32_t)time(NULL);
{
item = jitem(array,i);
if ( (argipaddr= jstr(item,"ipaddr")) != 0 && (argport= juint(item,"port")) != 0 )
{
if ( (pushport= juint(item,"push")) == 0 )
pushport = argport + 1;
if ( (subport= juint(item,"sub")) == 0 )
subport = argport + 2;
argipbits = (uint32_t)calc_ipbits(argipaddr);
if ( (peer= LP_peerfind(argipbits,argport)) == 0 )
{
peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jint(item,"numpeers"),jint(item,"numutxos"),juint(item,"session"));
}
if ( peer != 0 )
{
peer->lasttime = 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; bits256 zero; 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)) != 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++;
memset(&zero,0,sizeof(zero));
if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->numpeers,peer->sessionid,0,zero)) != 0 )
free(retstr);
}
}
if ( flag != 0 )
printf(" <- missing peers\n");
}
} }
} }
@ -271,7 +222,8 @@ int32_t LP_numpeers()
struct LP_peerinfo *peer,*tmp; int32_t numpeers = 0; struct LP_peerinfo *peer,*tmp; int32_t numpeers = 0;
HASH_ITER(hh,LP_peerinfos,peer,tmp) HASH_ITER(hh,LP_peerinfos,peer,tmp)
{ {
numpeers++; if ( peer->isLP != 0 )
numpeers++;
} }
return(numpeers); return(numpeers);
} }
@ -279,23 +231,51 @@ int32_t LP_numpeers()
uint16_t LP_randpeer(char *destip) uint16_t LP_randpeer(char *destip)
{ {
struct LP_peerinfo *peer,*tmp; uint16_t port = 0; int32_t n,r,numpeers = 0; struct LP_peerinfo *peer,*tmp; uint16_t port = 0; int32_t n,r,numpeers = 0;
HASH_ITER(hh,LP_peerinfos,peer,tmp) destip[0] = 0;
{ numpeers = LP_numpeers();
numpeers++;
}
if ( numpeers > 0 ) if ( numpeers > 0 )
{ {
r = rand() % numpeers; r = rand() % numpeers;
n = 0; n = 0;
HASH_ITER(hh,LP_peerinfos,peer,tmp) HASH_ITER(hh,LP_peerinfos,peer,tmp)
{ {
if ( n++ == r ) if ( peer->isLP != 0 )
{ {
strcpy(destip,peer->ipaddr); if ( n++ == r )
port = peer->port; {
break; strcpy(destip,peer->ipaddr);
port = peer->port;
break;
}
} }
} }
} }
return(port); return(port);
} }
uint16_t LP_rarestpeer(char *destip)
{
struct LP_peerinfo *peer,*tmp,*rarest = 0; int32_t iter; uint32_t now;
now = (uint32_t)time(NULL);
destip[0] = 0;
for (iter=0; iter<2; iter++)
{
HASH_ITER(hh,LP_peerinfos,peer,tmp)
{
if ( iter == 0 && peer->recvtime < now-3600*24 )
continue;
if ( peer->isLP != 0 )
{
if ( rarest == 0 || peer->numrecv < rarest->numrecv )
rarest = peer;
}
}
if ( rarest != 0 )
break;
}
if ( rarest == 0 )
LP_randpeer(destip);
else strcpy(destip,rarest->ipaddr);
return(rarest != 0 ? rarest->port : RPC_port);
}

33
iguana/exchanges/LP_portfolio.c

@ -222,7 +222,7 @@ struct LP_autoprice_ref
int32_t LP_autoprice(char *base,char *rel,cJSON *argjson) int32_t LP_autoprice(char *base,char *rel,cJSON *argjson)
{ {
//curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"autoprice\",\"base\":\"MNZ\",\"rel\":\"KMD\",\"offset\":0.1,\"refbase\":\"KMD\",\refrel\":\"BTC\",\"factor\":15000,\"margin\":0.01}" //curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"autoprice\",\"base\":\"MNZ\",\"rel\":\"KMD\",\"offset\":0.1,\"refbase\":\"KMD\",\refrel\":\"BTC\",\"factor\":15000,\"margin\":0.01}"
struct LP_priceinfo *basepp,*relpp; int32_t i; char *refbase,*refrel; double minprice,margin,offset,factor; struct LP_priceinfo *basepp,*relpp; int32_t i; char *refbase="",*refrel=""; double minprice,margin,offset,factor,fixedprice;
//printf("autoprice.(%s %s) %s\n",base,rel,jprint(argjson,0)); //printf("autoprice.(%s %s) %s\n",base,rel,jprint(argjson,0));
if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 ) if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 )
{ {
@ -232,12 +232,19 @@ int32_t LP_autoprice(char *base,char *rel,cJSON *argjson)
margin = jdouble(argjson,"margin"); margin = jdouble(argjson,"margin");
offset = jdouble(argjson,"offset"); offset = jdouble(argjson,"offset");
factor = jdouble(argjson,"factor"); factor = jdouble(argjson,"factor");
fixedprice = jdouble(argjson,"fixed");
basepp->fixedprices[relpp->ind] = fixedprice;
basepp->minprices[relpp->ind] = minprice; basepp->minprices[relpp->ind] = minprice;
basepp->margins[relpp->ind] = margin; basepp->margins[relpp->ind] = margin;
basepp->offsets[relpp->ind] = offset; basepp->offsets[relpp->ind] = offset;
basepp->factors[relpp->ind] = factor; basepp->factors[relpp->ind] = factor;
if ( (refbase= jstr(argjson,"refbase")) != 0 && (refrel= jstr(argjson,"refrel")) != 0 ) if ( fixedprice > SMALLVAL || ((refbase= jstr(argjson,"refbase")) != 0 && (refrel= jstr(argjson,"refrel")) != 0) )
{ {
if ( fixedprice > SMALLVAL )
{
refbase = base;
refrel = rel;
}
for (i=0; i<num_LP_autorefs; i++) for (i=0; i<num_LP_autorefs; i++)
{ {
if ( strcmp(base,LP_autorefs[i].base) == 0 && strcmp(rel,LP_autorefs[i].rel) == 0 ) if ( strcmp(base,LP_autorefs[i].base) == 0 && strcmp(rel,LP_autorefs[i].rel) == 0 )
@ -254,7 +261,7 @@ int32_t LP_autoprice(char *base,char *rel,cJSON *argjson)
safecopy(LP_autorefs[num_LP_autorefs].refrel,refrel,sizeof(LP_autorefs[num_LP_autorefs].refrel)); safecopy(LP_autorefs[num_LP_autorefs].refrel,refrel,sizeof(LP_autorefs[num_LP_autorefs].refrel));
safecopy(LP_autorefs[num_LP_autorefs].base,base,sizeof(LP_autorefs[num_LP_autorefs].base)); safecopy(LP_autorefs[num_LP_autorefs].base,base,sizeof(LP_autorefs[num_LP_autorefs].base));
safecopy(LP_autorefs[num_LP_autorefs].rel,rel,sizeof(LP_autorefs[num_LP_autorefs].rel)); safecopy(LP_autorefs[num_LP_autorefs].rel,rel,sizeof(LP_autorefs[num_LP_autorefs].rel));
printf("%d Using ref %s/%s for %s/%s factor %.8f, offset %.8f, margin %.8f\n",num_LP_autorefs,refbase,refrel,base,rel,factor,offset,margin); printf("%d Using ref %s/%s for %s/%s factor %.8f, offset %.8f, margin %.8f fixed %.8f\n",num_LP_autorefs,refbase,refrel,base,rel,factor,offset,margin,fixedprice);
num_LP_autorefs++; num_LP_autorefs++;
} }
} }
@ -267,9 +274,16 @@ int32_t LP_autoprice(char *base,char *rel,cJSON *argjson)
void LP_autopriceset(void *ctx,int32_t dir,struct LP_priceinfo *basepp,struct LP_priceinfo *relpp,double price,char *refbase,char *refrel) void LP_autopriceset(void *ctx,int32_t dir,struct LP_priceinfo *basepp,struct LP_priceinfo *relpp,double price,char *refbase,char *refrel)
{ {
static uint32_t lasttime; static uint32_t lasttime;
double margin,minprice,newprice,oppomargin,factor,offset; double bid,ask; int32_t changed; double margin,minprice,newprice,oppomargin,fixedprice,factor,offset; double bid,ask; int32_t changed;
margin = basepp->margins[relpp->ind]; margin = basepp->margins[relpp->ind];
oppomargin = relpp->margins[basepp->ind]; oppomargin = relpp->margins[basepp->ind];
if ( (fixedprice= basepp->fixedprices[relpp->ind]) > SMALLVAL )
{
LP_mypriceset(&changed,relpp->symbol,basepp->symbol,fixedprice);
//printf("autoprice FIXED %s/%s <- %.8f\n",basepp->symbol,relpp->symbol,fixedprice);
LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,relpp->symbol,basepp->symbol,fixedprice);
return;
}
if ( margin != 0. || oppomargin != 0. ) if ( margin != 0. || oppomargin != 0. )
{ {
offset = basepp->offsets[relpp->ind]; offset = basepp->offsets[relpp->ind];
@ -293,8 +307,6 @@ void LP_autopriceset(void *ctx,int32_t dir,struct LP_priceinfo *basepp,struct LP
if ( dir > 0 ) if ( dir > 0 )
newprice = (1. / price) * (1. + margin); newprice = (1. / price) * (1. + margin);
else newprice = (price * (1. + margin)); else newprice = (price * (1. + margin));
//newprice = 1. / (price * (1. - margin));
if ( (minprice= basepp->minprices[relpp->ind]) == 0. || price >= minprice ) if ( (minprice= basepp->minprices[relpp->ind]) == 0. || price >= minprice )
{ {
LP_mypriceset(&changed,relpp->symbol,basepp->symbol,newprice); LP_mypriceset(&changed,relpp->symbol,basepp->symbol,newprice);
@ -468,7 +480,10 @@ void LP_autoprice_iter(void *ctx,struct LP_priceinfo *btcpp)
basepp = LP_priceinfofind(LP_autorefs[i].base); basepp = LP_priceinfofind(LP_autorefs[i].base);
relpp = LP_priceinfofind(LP_autorefs[i].rel); relpp = LP_priceinfofind(LP_autorefs[i].rel);
if ( basepp != 0 && relpp != 0 ) if ( basepp != 0 && relpp != 0 )
LP_autopriceset(ctx,1,basepp,relpp,0,LP_autorefs[i].refbase,LP_autorefs[i].refrel); {
//printf("check ref-autoprice %s/%s %f %f\n",LP_autorefs[i].refbase,LP_autorefs[i].refrel,relpp->fixedprices[basepp->ind],basepp->fixedprices[relpp->ind]);
LP_autopriceset(ctx,1,basepp,relpp,0.,LP_autorefs[i].refbase,LP_autorefs[i].refrel);
}
} }
} }
@ -593,10 +608,12 @@ void prices_loop(void *ctx)
prices_loop_stats.threshold = 91000.; prices_loop_stats.threshold = 91000.;
while ( 1 ) while ( 1 )
{ {
//printf("prices loop autoprices.%d autorefs.%d\n",LP_autoprices,num_LP_autorefs);
LP_millistats_update(&prices_loop_stats); LP_millistats_update(&prices_loop_stats);
LP_tradebots_timeslice(ctx); LP_tradebots_timeslice(ctx);
if ( (btcpp= LP_priceinfofind("BTC")) == 0 ) if ( (btcpp= LP_priceinfofind("BTC")) == 0 )
{ {
printf("prices_loop BTC not in LP_priceinfofind\n");
sleep(60); sleep(60);
continue; continue;
} }
@ -630,7 +647,7 @@ void prices_loop(void *ctx)
} }
free(retstr); free(retstr);
} }
sleep(60); sleep(30);
} }
} }

40
iguana/exchanges/LP_prices.c

@ -29,12 +29,13 @@ struct LP_priceinfo
double relvals[LP_MAXPRICEINFOS]; double relvals[LP_MAXPRICEINFOS];
double myprices[LP_MAXPRICEINFOS]; double myprices[LP_MAXPRICEINFOS];
double minprices[LP_MAXPRICEINFOS]; // autoprice double minprices[LP_MAXPRICEINFOS]; // autoprice
double fixedprices[LP_MAXPRICEINFOS]; // fixedprices
double margins[LP_MAXPRICEINFOS]; double margins[LP_MAXPRICEINFOS];
double offsets[LP_MAXPRICEINFOS]; double offsets[LP_MAXPRICEINFOS];
double factors[LP_MAXPRICEINFOS]; double factors[LP_MAXPRICEINFOS];
//double maxprices[LP_MAXPRICEINFOS]; // autofill of base/rel //double maxprices[LP_MAXPRICEINFOS]; // autofill of base/rel
//double relvols[LP_MAXPRICEINFOS]; //double relvols[LP_MAXPRICEINFOS];
FILE *fps[LP_MAXPRICEINFOS]; //FILE *fps[LP_MAXPRICEINFOS];
} LP_priceinfos[LP_MAXPRICEINFOS]; } LP_priceinfos[LP_MAXPRICEINFOS];
int32_t LP_numpriceinfos; int32_t LP_numpriceinfos;
@ -313,7 +314,7 @@ char *LP_prices()
return(jprint(array,1)); return(jprint(array,1));
} }
void LP_prices_parse(struct LP_peerinfo *peer,cJSON *obj) /*void LP_prices_parse(struct LP_peerinfo *peer,cJSON *obj)
{ {
struct LP_pubkeyinfo *pubp; struct LP_priceinfo *basepp,*relpp; uint32_t timestamp; bits256 pubkey; cJSON *asks,*item; uint8_t rmd160[20]; int32_t i,n,relid,mismatch; char *base,*rel,*hexstr; double askprice; uint32_t now; struct LP_pubkeyinfo *pubp; struct LP_priceinfo *basepp,*relpp; uint32_t timestamp; bits256 pubkey; cJSON *asks,*item; uint8_t rmd160[20]; int32_t i,n,relid,mismatch; char *base,*rel,*hexstr; double askprice; uint32_t now;
now = (uint32_t)time(NULL); now = (uint32_t)time(NULL);
@ -381,7 +382,7 @@ void LP_peer_pricesquery(struct LP_peerinfo *peer)
{ {
//printf("%s needs ping\n",peer->ipaddr); //printf("%s needs ping\n",peer->ipaddr);
} }
} }*/
double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,int32_t vout) double LP_pricecache(struct LP_quoteinfo *qp,char *base,char *rel,bits256 txid,int32_t vout)
{ {
@ -697,15 +698,14 @@ struct LP_orderbookentry *LP_orderbookentry(char *address,char *base,char *rel,d
void LP_pubkeys_query() void LP_pubkeys_query()
{ {
static uint32_t lasttime;
uint8_t zeroes[20]; bits256 zero; cJSON *reqjson; struct LP_pubkeyinfo *pubp=0,*tmp; uint8_t zeroes[20]; bits256 zero; cJSON *reqjson; struct LP_pubkeyinfo *pubp=0,*tmp;
memset(zero.bytes,0,sizeof(zero)); memset(zero.bytes,0,sizeof(zero));
memset(zeroes,0,sizeof(zeroes)); memset(zeroes,0,sizeof(zeroes));
HASH_ITER(hh,LP_pubkeyinfos,pubp,tmp) HASH_ITER(hh,LP_pubkeyinfos,pubp,tmp)
{ {
if ( memcmp(zeroes,pubp->rmd160,sizeof(pubp->rmd160)) == 0 && time(NULL) > lasttime+30 ) if ( memcmp(zeroes,pubp->rmd160,sizeof(pubp->rmd160)) == 0 && time(NULL) > pubp->lasttime+60 )
{ {
lasttime = (uint32_t)time(NULL); pubp->lasttime = (uint32_t)time(NULL);
reqjson = cJSON_CreateObject(); reqjson = cJSON_CreateObject();
jaddstr(reqjson,"method","wantnotify"); jaddstr(reqjson,"method","wantnotify");
jaddbits256(reqjson,"pub",pubp->pubkey); jaddbits256(reqjson,"pub",pubp->pubkey);
@ -813,13 +813,17 @@ char *LP_orderbook(char *base,char *rel,int32_t duration)
for (i=n=0; i<numbids; i++) for (i=n=0; i<numbids; i++)
{ {
jaddi(array,LP_orderbookjson(rel,bids[i])); jaddi(array,LP_orderbookjson(rel,bids[i]));
if ( suppress_prefetch == 0 && n < 7 && bids[i]->numutxos == 0 ) if ( suppress_prefetch == 0 && n < 3 && bids[i]->numutxos == 0 )
{ {
//printf("bid ping %s %s\n",rel,bids[i]->coinaddr); //printf("bid ping %s %s\n",rel,bids[i]->coinaddr);
LP_address(relcoin,bids[i]->coinaddr); LP_address(relcoin,bids[i]->coinaddr);
if ( relcoin->electrum == 0 ) if ( relcoin->electrum == 0 )
{
LP_listunspent_issue(rel,bids[i]->coinaddr,0); LP_listunspent_issue(rel,bids[i]->coinaddr,0);
LP_listunspent_query(rel,bids[i]->coinaddr); //else if ( (tmpjson= LP_listunspent(rel,bids[i]->coinaddr)) != 0 )
// free_json(tmpjson);
LP_listunspent_query(rel,bids[i]->coinaddr);
}
n++; n++;
} }
free(bids[i]); free(bids[i]);
@ -833,13 +837,17 @@ char *LP_orderbook(char *base,char *rel,int32_t duration)
for (i=n=0; i<numasks; i++) for (i=n=0; i<numasks; i++)
{ {
jaddi(array,LP_orderbookjson(base,asks[i])); jaddi(array,LP_orderbookjson(base,asks[i]));
if ( suppress_prefetch == 0 && n < 7 && asks[i]->numutxos == 0 ) if ( suppress_prefetch == 0 && n < 3 && asks[i]->numutxos == 0 )
{ {
//printf("ask ping %s %s\n",base,asks[i]->coinaddr); //printf("ask ping %s %s\n",base,asks[i]->coinaddr);
LP_address(basecoin,asks[i]->coinaddr); LP_address(basecoin,asks[i]->coinaddr);
if ( basecoin->electrum == 0 ) if ( basecoin->electrum == 0 )
{
LP_listunspent_issue(base,asks[i]->coinaddr,0); LP_listunspent_issue(base,asks[i]->coinaddr,0);
LP_listunspent_query(base,asks[i]->coinaddr); //else if ( (tmpjson= LP_listunspent(base,asks[i]->coinaddr)) != 0 )
// free_json(tmpjson);
LP_listunspent_query(base,asks[i]->coinaddr);
}
n++; n++;
} }
free(asks[i]); free(asks[i]);
@ -1033,10 +1041,10 @@ void LP_pricefeedupdate(bits256 pubkey,char *base,char *rel,double price)
//printf("check PRICEFEED UPDATE.(%s/%s) %.8f %s\n",base,rel,price,bits256_str(str,pubkey)); //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 ( LP_pricevalid(price) > 0 && (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 )
{ {
if ( (fp= basepp->fps[relpp->ind]) == 0 ) //if ( (fp= basepp->fps[relpp->ind]) == 0 )
{ {
LP_pricefname(fname,base,rel); LP_pricefname(fname,base,rel);
fp = basepp->fps[relpp->ind] = OS_appendfile(fname); fp = OS_appendfile(fname); //basepp->fps[relpp->ind] =
} }
if ( fp != 0 ) if ( fp != 0 )
{ {
@ -1044,12 +1052,12 @@ void LP_pricefeedupdate(bits256 pubkey,char *base,char *rel,double price)
price64 = price * SATOSHIDEN; price64 = price * SATOSHIDEN;
fwrite(&now,1,sizeof(now),fp); fwrite(&now,1,sizeof(now),fp);
fwrite(&price64,1,sizeof(price64),fp); fwrite(&price64,1,sizeof(price64),fp);
fflush(fp); fclose(fp);
} }
if ( (fp= relpp->fps[basepp->ind]) == 0 ) //if ( (fp= relpp->fps[basepp->ind]) == 0 )
{ {
sprintf(fname,"%s/PRICES/%s_%s",GLOBAL_DBDIR,rel,base); sprintf(fname,"%s/PRICES/%s_%s",GLOBAL_DBDIR,rel,base);
fp = relpp->fps[basepp->ind] = OS_appendfile(fname); fp = OS_appendfile(fname); //relpp->fps[basepp->ind] =
} }
if ( fp != 0 ) if ( fp != 0 )
{ {
@ -1057,7 +1065,7 @@ void LP_pricefeedupdate(bits256 pubkey,char *base,char *rel,double price)
price64 = (1. / price) * SATOSHIDEN; price64 = (1. / price) * SATOSHIDEN;
fwrite(&now,1,sizeof(now),fp); fwrite(&now,1,sizeof(now),fp);
fwrite(&price64,1,sizeof(price64),fp); fwrite(&price64,1,sizeof(price64),fp);
fflush(fp); fclose(fp);
} }
if ( (pubp= LP_pubkeyadd(pubkey)) != 0 ) if ( (pubp= LP_pubkeyadd(pubkey)) != 0 )
{ {

22
iguana/exchanges/LP_remember.c

@ -450,6 +450,7 @@ cJSON *LP_swap_json(struct LP_swap_remember *rswap)
{ {
cJSON *item,*array; int32_t i; cJSON *item,*array; int32_t i;
item = cJSON_CreateObject(); item = cJSON_CreateObject();
jaddnum(item,"expiration",rswap->expiration);// - INSTANTDEX_LOCKTIME*2);
jaddnum(item,"tradeid",rswap->tradeid); jaddnum(item,"tradeid",rswap->tradeid);
jaddnum(item,"requestid",rswap->requestid); jaddnum(item,"requestid",rswap->requestid);
jaddnum(item,"quoteid",rswap->quoteid); jaddnum(item,"quoteid",rswap->quoteid);
@ -476,7 +477,10 @@ cJSON *LP_swap_json(struct LP_swap_remember *rswap)
jadd(item,"values",array); jadd(item,"values",array);
jaddstr(item,"result","success"); jaddstr(item,"result","success");
if ( rswap->finishedflag != 0 ) if ( rswap->finishedflag != 0 )
{
jaddstr(item,"status","finished"); jaddstr(item,"status","finished");
jaddnum(item,"finishtime",rswap->finishtime);
}
else jaddstr(item,"status","pending"); else jaddstr(item,"status","pending");
jaddbits256(item,"bobdeposit",rswap->txids[BASILISK_BOBDEPOSIT]); jaddbits256(item,"bobdeposit",rswap->txids[BASILISK_BOBDEPOSIT]);
jaddbits256(item,"alicepayment",rswap->txids[BASILISK_ALICEPAYMENT]); jaddbits256(item,"alicepayment",rswap->txids[BASILISK_ALICEPAYMENT]);
@ -657,6 +661,7 @@ int32_t LP_swap_load(struct LP_swap_remember *rswap)
{ {
if ( (fileobj= cJSON_Parse(fstr)) != 0 ) if ( (fileobj= cJSON_Parse(fstr)) != 0 )
{ {
rswap->finishtime = juint(fileobj,"finishtime");
rswap->origfinishedflag = rswap->finishedflag = 1; rswap->origfinishedflag = rswap->finishedflag = 1;
free_json(fileobj); free_json(fileobj);
} }
@ -839,7 +844,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti
srcAdest = srcBdest = destAdest = destBdest = 0; srcAdest = srcBdest = destAdest = destBdest = 0;
if ( rswap.bobcoin[0] == 0 || rswap.alicecoin[0] == 0 || strcmp(rswap.bobcoin,rswap.src) != 0 || strcmp(rswap.alicecoin,rswap.dest) != 0 ) if ( rswap.bobcoin[0] == 0 || rswap.alicecoin[0] == 0 || strcmp(rswap.bobcoin,rswap.src) != 0 || strcmp(rswap.alicecoin,rswap.dest) != 0 )
{ {
printf("legacy DB SWAPS.(%u %u) %llu files BOB.(%s) Alice.(%s) src.(%s) dest.(%s)\n",rswap.requestid,rswap.quoteid,(long long)rswap.aliceid,rswap.bobcoin,rswap.alicecoin,rswap.src,rswap.dest); //printf("legacy DB SWAPS.(%u %u) %llu files BOB.(%s) Alice.(%s) src.(%s) dest.(%s)\n",rswap.requestid,rswap.quoteid,(long long)rswap.aliceid,rswap.bobcoin,rswap.alicecoin,rswap.src,rswap.dest);
return(cJSON_Parse("{\"error\":\"mismatched bob/alice vs src/dest coins??\"}")); return(cJSON_Parse("{\"error\":\"mismatched bob/alice vs src/dest coins??\"}"));
} }
alice = LP_coinfind(rswap.alicecoin); alice = LP_coinfind(rswap.alicecoin);
@ -1115,6 +1120,8 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti
if ( (fp= fopen(fname,"wb")) != 0 ) if ( (fp= fopen(fname,"wb")) != 0 )
{ {
jaddstr(item,"method","tradestatus"); jaddstr(item,"method","tradestatus");
jaddnum(item,"finishtime",rswap.finishtime);
jaddstr(item,"gui",G.gui);
itemstr = jprint(item,0); itemstr = jprint(item,0);
fprintf(fp,"%s\n",itemstr); fprintf(fp,"%s\n",itemstr);
LP_tradecommand_log(item); LP_tradecommand_log(item);
@ -1130,7 +1137,7 @@ cJSON *basilisk_remember(int64_t *KMDtotals,int64_t *BTCtotals,uint32_t requesti
char *basilisk_swaplist(uint32_t origrequestid,uint32_t origquoteid) char *basilisk_swaplist(uint32_t origrequestid,uint32_t origquoteid)
{ {
uint64_t ridqids[4096],ridqid; char fname[512]; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t r,q,quoteid,requestid; int64_t KMDtotals[16],BTCtotals[16],Btotal,Ktotal; int32_t i,j,count=0; uint64_t ridqids[4096],ridqid; char fname[512]; FILE *fp; cJSON *item,*retjson,*array,*totalsobj; uint32_t r,q,quoteid,requestid; int64_t KMDtotals[LP_MAXPRICEINFOS],BTCtotals[LP_MAXPRICEINFOS],Btotal,Ktotal; int32_t i,j,count=0;
portable_mutex_lock(&LP_swaplistmutex); portable_mutex_lock(&LP_swaplistmutex);
memset(ridqids,0,sizeof(ridqids)); memset(ridqids,0,sizeof(ridqids));
memset(KMDtotals,0,sizeof(KMDtotals)); memset(KMDtotals,0,sizeof(KMDtotals));
@ -1222,8 +1229,13 @@ char *basilisk_swaplist(uint32_t origrequestid,uint32_t origquoteid)
char *basilisk_swapentry(uint32_t requestid,uint32_t quoteid) char *basilisk_swapentry(uint32_t requestid,uint32_t quoteid)
{ {
char *liststr,*retstr = 0; cJSON *retjson,*array,*item; int32_t i,n; cJSON *item; int64_t KMDtotals[LP_MAXPRICEINFOS],BTCtotals[LP_MAXPRICEINFOS];
if ( (liststr= basilisk_swaplist(requestid,quoteid)) != 0 ) memset(KMDtotals,0,sizeof(KMDtotals));
memset(BTCtotals,0,sizeof(BTCtotals));
if ( (item= basilisk_remember(KMDtotals,BTCtotals,requestid,quoteid)) != 0 )
return(jprint(item,1));
else return(clonestr("{\"error\":\"cant find requestid-quoteid\"}"));
/*if ( (liststr= basilisk_swaplist(requestid,quoteid)) != 0 )
{ {
//printf("swapentry.(%s)\n",liststr); //printf("swapentry.(%s)\n",liststr);
if ( (retjson= cJSON_Parse(liststr)) != 0 ) if ( (retjson= cJSON_Parse(liststr)) != 0 )
@ -1245,7 +1257,7 @@ char *basilisk_swapentry(uint32_t requestid,uint32_t quoteid)
} }
free(liststr); free(liststr);
} }
return(retstr); return(retstr);*/
} }
extern struct LP_quoteinfo LP_Alicequery; extern struct LP_quoteinfo LP_Alicequery;

172
iguana/exchanges/LP_rpc.c

@ -18,14 +18,16 @@
// marketmaker // marketmaker
// //
char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url) /*char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url)
{ {
char *retstr = 0; int32_t maxerrs; struct LP_peerinfo *peer = 0; char *retstr = 0; int32_t maxerrs; struct LP_peerinfo *peer = 0;
peer = LP_peerfind((uint32_t)calc_ipbits(destip),port); peer = LP_peerfind((uint32_t)calc_ipbits(destip),port);
if ( strcmp(destip,"127.0.0.1") != 0 )
port--;
maxerrs = LP_MAXPEER_ERRORS; maxerrs = LP_MAXPEER_ERRORS;
if ( peer == 0 || (peer->errors < maxerrs || peer->good >= LP_MINPEER_GOOD) ) if ( peer == 0 || (peer->errors < maxerrs || peer->good >= LP_MINPEER_GOOD) )
{ {
//printf("issue.(%s)\n",url); printf("issue.(%s)\n",url);
if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 ) if ( (retstr= issue_curlt(url,LP_HTTP_TIMEOUT)) == 0 )
{ {
if ( peer != 0 ) if ( peer != 0 )
@ -38,7 +40,7 @@ char *LP_issue_curl(char *debugstr,char *destip,uint16_t port,char *url)
peer->good++; peer->good++;
} }
return(retstr); return(retstr);
} }*/
char *LP_isitme(char *destip,uint16_t destport) char *LP_isitme(char *destip,uint16_t destport)
{ {
@ -49,59 +51,6 @@ char *LP_isitme(char *destip,uint16_t destport)
} else return(0); } else return(0);
} }
char *issue_LP_getpeers(char *destip,uint16_t destport,char *ipaddr,uint16_t port,int32_t numpeers)
{
char url[512],*retstr;
sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&numpeers=%d",destip,destport,ipaddr,port,numpeers);
retstr = LP_issue_curl("getpeers",destip,port,url);
//printf("%s -> getpeers.(%s)\n",destip,retstr);
return(retstr);
}
char *issue_LP_uitem(char *destip,uint16_t destport,char *symbol,char *coinaddr,bits256 txid,int32_t vout,int32_t height,uint64_t value)
{
char url[512],*retstr,str[65];
if ( (retstr= LP_isitme(destip,destport)) != 0 )
return(retstr);
sprintf(url,"http://%s:%u/api/stats/uitem?coin=%s&coinaddr=%s&txid=%s&vout=%d&ht=%d&value=%llu",destip,destport,symbol,coinaddr,bits256_str(str,txid),vout,height,(long long)value);
retstr = LP_issue_curl("uitem",destip,destport,url);
//printf("uitem.(%s)\n",retstr);
return(retstr);
}
char *issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,int32_t numpeers,uint32_t sessionid,char *rmd160str,bits256 pub)
{
char url[512],*retstr,str[65];
if ( (retstr= LP_isitme(destip,destport)) != 0 )
return(retstr);
sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&numpeers=%d&session=%u",destip,destport,ipaddr,port,numpeers,sessionid);
if ( rmd160str != 0 && bits256_nonz(pub) != 0 )
{
sprintf(url+strlen(url),"&rmd160=%s&pub=%s",rmd160str,bits256_str(str,pub));
//printf("SEND (%s)\n",url);
}
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));
}
char *issue_LP_listunspent(char *destip,uint16_t destport,char *symbol,char *coinaddr)
{
char url[512],*retstr;
sprintf(url,"http://%s:%u/api/stats/listunspent?coin=%s&address=%s",destip,destport,symbol,coinaddr);
retstr = LP_issue_curl("listunspent",destip,destport,url);
//printf("listunspent.(%s) -> (%s)\n",url,retstr);
return(retstr);
}
char *LP_apicall(struct iguana_info *coin,char *method,char *params) char *LP_apicall(struct iguana_info *coin,char *method,char *params)
{ {
cJSON *retjson; char *retstr; cJSON *retjson; char *retstr;
@ -111,7 +60,7 @@ char *LP_apicall(struct iguana_info *coin,char *method,char *params)
{ {
if ( (retjson= electrum_submit(coin->symbol,coin->electrum,&retjson,method,params,ELECTRUM_TIMEOUT)) != 0 ) if ( (retjson= electrum_submit(coin->symbol,coin->electrum,&retjson,method,params,ELECTRUM_TIMEOUT)) != 0 )
{ {
retstr = jprint(retjson,0); retstr = jprint(retjson,1);
//printf("got.%p (%s)\n",retjson,retstr); //printf("got.%p (%s)\n",retjson,retstr);
return(retstr); return(retstr);
} return(clonestr("{\"error\":\"electrum no response\"}")); } return(clonestr("{\"error\":\"electrum no response\"}"));
@ -187,6 +136,24 @@ static char *assetids[][4] =
{ "10524562908394749924", "MGW", "1", "100000000" }, { "10524562908394749924", "MGW", "1", "100000000" },
}; };
void LP_sendtoaddress_line(char *validaddress,char *assetname,uint64_t satoshis,uint64_t txnum)
{
char line[1024],lowerstr[64];
if ( strcmp(assetname,"SUPERNETx2") == 0 )
{
sprintf(line,"fiat/supernet sendtoaddress %s %.8f # txnum.%llu",validaddress,dstr(satoshis),(long long)txnum);
printf("%s\n",line);
sprintf(line,"fiat/revs sendtoaddress %s %.8f # txnum.%llu",validaddress,dstr(satoshis),(long long)txnum);
}
else
{
strcpy(lowerstr,assetname);
tolowercase(lowerstr);
sprintf(line,"fiat/%s sendtoaddress %s %.8f # txnum.%llu",lowerstr,validaddress,dstr(satoshis),(long long)txnum);
}
printf("%s\n",line);
}
uint64_t LP_assetid_mult(int32_t *assetindp,char *name,uint64_t assetid) uint64_t LP_assetid_mult(int32_t *assetindp,char *name,uint64_t assetid)
{ {
int32_t i; uint64_t mult = 0; int32_t i; uint64_t mult = 0;
@ -292,9 +259,9 @@ char *account = "NXT-MRBN-8DFH-PFMK-A4DBM";
if ( (decjson= LP_NXT_decrypt(txnum,account,jstr(encjson,"data"),jstr(encjson,"nonce"),passphrase)) != 0 ) if ( (decjson= LP_NXT_decrypt(txnum,account,jstr(encjson,"data"),jstr(encjson,"nonce"),passphrase)) != 0 )
{ {
//printf("%s\n",jprint(decjson,0)); //printf("%s\n",jprint(decjson,0));
msgstr = jstr(decjson,"decryptedMessage"); if ( jstr(decjson,"decryptedMessage") != 0 )
msgstr = jstr(decjson,"decryptedMessage");
} }
} }
} }
} }
@ -315,12 +282,12 @@ char *account = "NXT-MRBN-8DFH-PFMK-A4DBM";
strncpy(validaddress,&msgstr[z],34); strncpy(validaddress,&msgstr[z],34);
if ( strlen(validaddress) == 34 || strlen(validaddress) == 33 ) if ( strlen(validaddress) == 34 || strlen(validaddress) == 33 )
{ {
printf("%-4d: (%34s) <- %13.5f %10s tx.%llu past_marker.%d\n",i,validaddress,dstr(qty * mult),assetname,(long long)txnum,past_marker); //printf("%-4d: (%34s) <- %13.5f %10s tx.%llu past_marker.%d\n",i,validaddress,dstr(qty * mult),assetname,(long long)txnum,past_marker);
if ( past_marker == 0 )
{
LP_sendtoaddress_line(validaddress,assetname,(qty * mult),txnum);
}
} else printf("%-4d: (%34s) <- %13.5f %10s tx.%llu\n",i,msgstr!=0?msgstr:jprint(item,0),dstr(qty * mult),assetname,(long long)txnum); } else printf("%-4d: (%34s) <- %13.5f %10s tx.%llu\n",i,msgstr!=0?msgstr:jprint(item,0),dstr(qty * mult),assetname,(long long)txnum);
if ( past_marker == 0 )
{
}
} }
if ( msgjson != 0 ) if ( msgjson != 0 )
free_json(msgjson); free_json(msgjson);
@ -480,6 +447,23 @@ uint32_t LP_locktime(char *symbol,bits256 txid)
return(locktime); return(locktime);
} }
/*uint32_t LP_txtime(char *symbol,bits256 txid)
{
struct LP_transaction *tx; struct iguana_info *coin; int32_t timestamp=0,height = 0;
char str[65]; printf("LP_txtime (%s %s)\n",symbol,bits256_str(str,txid));
if ( (timestamp= LP_locktime(symbol,txid)) != 0 )
return(timestamp);
if ( (coin= LP_coinfind(symbol)) != 0 )
{
if ( (tx= LP_transactionfind(coin,txid)) != 0 )
{
height = tx->height;
timestamp = LP_heighttime(symbol,height);
}
}
return(height);
}*/
cJSON *LP_gettxout_json(bits256 txid,int32_t vout,int32_t height,char *coinaddr,uint64_t value) cJSON *LP_gettxout_json(bits256 txid,int32_t vout,int32_t height,char *coinaddr,uint64_t value)
{ {
cJSON *retjson,*addresses,*sobj; cJSON *retjson,*addresses,*sobj;
@ -560,7 +544,7 @@ cJSON *LP_gettxout(char *symbol,char *coinaddr,bits256 txid,int32_t vout)
return(retjson); return(retjson);
} }
} }
printf("couldnt find %s/v%d\n",bits256_str(str,txid),vout); printf("couldnt find %s (%s) %s/v%d\n",symbol,coinaddr,bits256_str(str,txid),vout);
return(cJSON_Parse("{\"error\":\"couldnt get tx\"}")); return(cJSON_Parse("{\"error\":\"couldnt get tx\"}"));
} }
} }
@ -673,7 +657,7 @@ cJSON *LP_listunspent(char *symbol,char *coinaddr)
int32_t LP_listunspent_issue(char *symbol,char *coinaddr,int32_t fullflag) int32_t LP_listunspent_issue(char *symbol,char *coinaddr,int32_t fullflag)
{ {
struct iguana_info *coin; int32_t n = 0; cJSON *retjson=0; char *retstr=0,destip[64]; uint16_t destport; struct iguana_info *coin; int32_t n = 0; cJSON *retjson=0; char *retstr=0;
if ( symbol == 0 || symbol[0] == 0 ) if ( symbol == 0 || symbol[0] == 0 )
return(0); return(0);
if ( (coin= LP_coinfind(symbol)) != 0 ) if ( (coin= LP_coinfind(symbol)) != 0 )
@ -691,13 +675,14 @@ int32_t LP_listunspent_issue(char *symbol,char *coinaddr,int32_t fullflag)
if ( strcmp(coin->smartaddr,coinaddr) == 0 ) if ( strcmp(coin->smartaddr,coinaddr) == 0 )
{ {
retjson = LP_listunspent(symbol,coinaddr); retjson = LP_listunspent(symbol,coinaddr);
coin->numutxos = cJSON_GetArraySize(retjson);
//printf("SELF_LISTUNSPENT.(%s %s)\n",symbol,coinaddr); //printf("SELF_LISTUNSPENT.(%s %s)\n",symbol,coinaddr);
} }
else if ( IAMLP == 0 ) else if ( IAMLP == 0 )
{ {
//printf("LP_listunspent_query.(%s %s)\n",symbol,coinaddr); //printf("LP_listunspent_query.(%s %s)\n",symbol,coinaddr);
LP_listunspent_query(coin->symbol,coin->smartaddr); LP_listunspent_query(coin->symbol,coin->smartaddr);
if ( fullflag != 0 ) /*if ( fullflag != 0 )
{ {
if ( (destport= LP_randpeer(destip)) > 0 ) if ( (destport= LP_randpeer(destip)) > 0 )
{ {
@ -705,7 +690,7 @@ int32_t LP_listunspent_issue(char *symbol,char *coinaddr,int32_t fullflag)
//printf("issue %s %s %s -> (%s)\n",coin->symbol,coinaddr,destip,retstr); //printf("issue %s %s %s -> (%s)\n",coin->symbol,coinaddr,destip,retstr);
retjson = cJSON_Parse(retstr); retjson = cJSON_Parse(retstr);
} else printf("LP_listunspent_issue couldnt get a random peer?\n"); } else printf("LP_listunspent_issue couldnt get a random peer?\n");
} }*/
} }
if ( retjson != 0 ) if ( retjson != 0 )
{ {
@ -802,11 +787,21 @@ int32_t LP_importaddress(char *symbol,char *address)
double _LP_getestimatedrate(struct iguana_info *coin) double _LP_getestimatedrate(struct iguana_info *coin)
{ {
char buf[512],*retstr; cJSON *errjson; double rate = 0.00000020; char buf[512],*retstr=0; int32_t numblocks; cJSON *errjson,*retjson; double rate = 0.00000020;
if ( coin->rate < 0. || time(NULL) > coin->ratetime+30 ) if ( coin->rate < 0. || time(NULL) > coin->ratetime+30 )
{ {
sprintf(buf,"[%d]",strcmp(coin->symbol,"BTC") == 0 ? 6 : 2); numblocks = strcmp(coin->symbol,"BTC") == 0 ? 6 : 2;
if ( (retstr= LP_apicall(coin,coin->electrum==0?"estimatefee" : "blockchain.estimatefee",buf)) != 0 ) if ( coin->electrum == 0 )
{
sprintf(buf,"[%d]",numblocks);
retstr = LP_apicall(coin,"estimatefee",buf);
}
else
{
if ( (retjson= electrum_estimatefee(coin->symbol,coin->electrum,&retjson,numblocks)) != 0 )
retstr = jprint(retjson,1);
}
if ( retstr != 0 )
{ {
if ( retstr[0] == '{' && (errjson= cJSON_Parse(retstr)) != 0 ) if ( retstr[0] == '{' && (errjson= cJSON_Parse(retstr)) != 0 )
{ {
@ -828,7 +823,7 @@ double _LP_getestimatedrate(struct iguana_info *coin)
coin->ratetime = (uint32_t)time(NULL); coin->ratetime = (uint32_t)time(NULL);
} }
free(retstr); free(retstr);
} } else rate = coin->rate;
} else rate = coin->rate; } else rate = coin->rate;
return(rate); return(rate);
} }
@ -1003,7 +998,7 @@ bits256 LP_getbestblockhash(struct iguana_info *coin)
decode_hex(blockhash.bytes,sizeof(blockhash),retstr); decode_hex(blockhash.bytes,sizeof(blockhash),retstr);
free(retstr); free(retstr);
} }
} } else printf("electrum mode doesnt support block level scanning\n");
return(blockhash); return(blockhash);
} }
@ -1035,6 +1030,37 @@ cJSON *LP_getblockhashstr(char *symbol,char *blockhashstr)
return(bitcoin_json(coin,"getblock",buf)); return(bitcoin_json(coin,"getblock",buf));
} }
uint32_t LP_heighttime(char *symbol,int32_t height)
{
struct electrum_info *ep; uint32_t timestamp = 0; cJSON *retjson; char *blockhashstr; struct iguana_info *coin = LP_coinfind(symbol);
if ( coin != 0 )
{
if ( (ep= coin->electrum) == 0 )
{
if ( (blockhashstr= LP_blockhashstr(symbol,height)) != 0 )
{
if ( (retjson= cJSON_Parse(blockhashstr)) != 0 )
{
printf("height.(%s)\n",jprint(retjson,0));
timestamp = juint(retjson,"time");
free_json(retjson);
}
free(blockhashstr);
}
}
else
{
if ( (retjson= electrum_getheader(coin->symbol,ep,&retjson,height)) != 0 )
{
printf("%s\n",jprint(retjson,0));
timestamp = juint(retjson,"timestamp");
free_json(retjson);
}
}
}
return(timestamp);
}
cJSON *LP_blockjson(int32_t *heightp,char *symbol,char *blockhashstr,int32_t height) cJSON *LP_blockjson(int32_t *heightp,char *symbol,char *blockhashstr,int32_t height)
{ {
cJSON *json = 0; int32_t flag = 0; struct iguana_info *coin; cJSON *json = 0; int32_t flag = 0; struct iguana_info *coin;

50
iguana/exchanges/LP_signatures.c

@ -448,7 +448,7 @@ char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,char *base,char *re
{ {
struct iguana_info *basecoin,*relcoin; char pubsecpstr[67]; uint32_t timestamp; uint64_t price64; bits256 zero; cJSON *reqjson = cJSON_CreateObject(); struct iguana_info *basecoin,*relcoin; char pubsecpstr[67]; uint32_t timestamp; uint64_t price64; bits256 zero; cJSON *reqjson = cJSON_CreateObject();
// LP_addsig // LP_addsig
if ( (basecoin= LP_coinfind(base)) != 0 && (relcoin= LP_coinfind(rel)) != 0 && basecoin->electrum == 0 && relcoin->electrum == 0 ) if ( (basecoin= LP_coinfind(base)) != 0 && (relcoin= LP_coinfind(rel)) != 0 && basecoin->electrum == 0 )//&& relcoin->electrum == 0 )
{ {
memset(zero.bytes,0,sizeof(zero)); memset(zero.bytes,0,sizeof(zero));
jaddbits256(reqjson,"pubkey",G.LP_mypub25519); jaddbits256(reqjson,"pubkey",G.LP_mypub25519);
@ -559,7 +559,7 @@ int32_t LP_pubkey_sigcheck(struct LP_pubkeyinfo *pubp,cJSON *item)
void LP_notify_pubkeys(void *ctx,int32_t pubsock) void LP_notify_pubkeys(void *ctx,int32_t pubsock)
{ {
bits256 zero; uint32_t timestamp; char secpstr[67]; cJSON *reqjson = cJSON_CreateObject(); bits256 zero; uint32_t timestamp; char LPipaddr[64],secpstr[67]; cJSON *reqjson = cJSON_CreateObject();
memset(zero.bytes,0,sizeof(zero)); memset(zero.bytes,0,sizeof(zero));
jaddstr(reqjson,"method","notify"); jaddstr(reqjson,"method","notify");
jaddstr(reqjson,"rmd160",G.LP_myrmd160str); jaddstr(reqjson,"rmd160",G.LP_myrmd160str);
@ -569,17 +569,42 @@ void LP_notify_pubkeys(void *ctx,int32_t pubsock)
timestamp = (uint32_t)time(NULL); timestamp = (uint32_t)time(NULL);
jaddnum(reqjson,"timestamp",timestamp); jaddnum(reqjson,"timestamp",timestamp);
LP_pubkey_sigadd(reqjson,timestamp,G.LP_privkey,G.LP_mypub25519,G.LP_myrmd160,G.LP_pubsecp); LP_pubkey_sigadd(reqjson,timestamp,G.LP_privkey,G.LP_mypub25519,G.LP_myrmd160,G.LP_pubsecp);
if ( IAMLP != 0 )
{
if ( LP_rarestpeer(LPipaddr) != 0 )
{
jaddstr(reqjson,"isLP",LPipaddr);
if ( strcmp(LPipaddr,LP_myipaddr) == 0 )
jaddnum(reqjson,"ismine",1);
}
else printf("no LPipaddr\n");
}
jaddnum(reqjson,"session",G.LP_sessionid);
LP_reserved_msg(0,"","",zero,jprint(reqjson,1)); LP_reserved_msg(0,"","",zero,jprint(reqjson,1));
} }
char *LP_notify_recv(cJSON *argjson) char *LP_notify_recv(cJSON *argjson)
{ {
bits256 pub; struct LP_pubkeyinfo *pubp; bits256 pub; struct LP_pubkeyinfo *pubp; char *ipaddr;
pub = jbits256(argjson,"pub"); pub = jbits256(argjson,"pub");
if ( bits256_nonz(pub) != 0 ) if ( bits256_nonz(pub) != 0 )
{ {
if ( (pubp= LP_pubkeyadd(pub)) != 0 ) if ( (pubp= LP_pubkeyadd(pub)) != 0 )
LP_pubkey_sigcheck(pubp,argjson); LP_pubkey_sigcheck(pubp,argjson);
if ( (ipaddr= jstr(argjson,"isLP")) != 0 )
{
//printf("notify got isLP %s %d\n",ipaddr,jint(argjson,"ismine"));
LP_peer_recv(ipaddr,jint(argjson,"ismine"));
if ( IAMLP != 0 && G.LP_IAMLP == 0 && strcmp(ipaddr,LP_myipaddr) == 0 )
{
if ( bits256_cmp(pub,G.LP_mypub25519) != 0 )
{
char str[65]; printf("that's me! and it is from %s which isnt me\n",bits256_str(str,pub));
G.LP_IAMLP = 1;
}
}
LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,RPC_port,RPC_port+10,RPC_port+20,1,juint(argjson,"session"));
}
//char str[65]; printf("%.3f NOTIFIED pub %s rmd160 %s\n",OS_milliseconds()-millis,bits256_str(str,pub),rmd160str); //char str[65]; printf("%.3f NOTIFIED pub %s rmd160 %s\n",OS_milliseconds()-millis,bits256_str(str,pub),rmd160str);
} }
return(clonestr("{\"result\":\"success\",\"notify\":\"received\"}")); return(clonestr("{\"result\":\"success\",\"notify\":\"received\"}"));
@ -604,17 +629,6 @@ void LP_smartutxos_push(struct iguana_info *coin)
vout = jint(item,"tx_pos"); vout = jint(item,"tx_pos");
value = j64bits(item,"value"); value = j64bits(item,"value");
height = jint(item,"height"); height = jint(item,"height");
#ifdef FROM_JS
//if ( 0 && (rand() % 100) == 0 && IAMLP == 0 )
{
struct LP_peerinfo *peer,*tmp; char *retstr;
HASH_ITER(hh,LP_peerinfos,peer,tmp)
{
if ( (retstr= issue_LP_uitem(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr,txid,vout,height,value)) != 0 )
free(retstr);
}
}
#else
req = cJSON_CreateObject(); req = cJSON_CreateObject();
jaddstr(req,"method","uitem"); jaddstr(req,"method","uitem");
jaddstr(req,"coin",coin->symbol); jaddstr(req,"coin",coin->symbol);
@ -625,7 +639,6 @@ void LP_smartutxos_push(struct iguana_info *coin)
jadd64bits(req,"value",value); jadd64bits(req,"value",value);
//printf("ADDR_UNSPENTS[] <- %s\n",jprint(req,0)); //printf("ADDR_UNSPENTS[] <- %s\n",jprint(req,0));
LP_reserved_msg(0,"","",zero,jprint(req,1)); LP_reserved_msg(0,"","",zero,jprint(req,1));
#endif
} }
} }
free_json(array); free_json(array);
@ -685,11 +698,10 @@ void LP_query(void *ctx,char *myipaddr,int32_t mypubsock,char *method,struct LP_
memset(&zero,0,sizeof(zero)); memset(&zero,0,sizeof(zero));
portable_mutex_lock(&LP_reservedmutex); portable_mutex_lock(&LP_reservedmutex);
if ( num_Reserved_msgs[1] < sizeof(Reserved_msgs[1])/sizeof(*Reserved_msgs[1])-2 ) if ( num_Reserved_msgs[1] < sizeof(Reserved_msgs[1])/sizeof(*Reserved_msgs[1])-2 )
{
Reserved_msgs[1][num_Reserved_msgs[1]++] = msg; Reserved_msgs[1][num_Reserved_msgs[1]++] = msg;
//Reserved_msgs[num_Reserved_msgs++] = msg2; if ( num_Reserved_msgs[0] < sizeof(Reserved_msgs[0])/sizeof(*Reserved_msgs[0])-2 )
} Reserved_msgs[0][num_Reserved_msgs[0]++] = msg2;
LP_broadcast_message(LP_mypubsock,qp->srccoin,qp->destcoin,zero,msg2); //LP_broadcast_message(LP_mypubsock,qp->srccoin,qp->destcoin,zero,msg2);
portable_mutex_unlock(&LP_reservedmutex); portable_mutex_unlock(&LP_reservedmutex);
} }

239
iguana/exchanges/LP_socket.c

@ -124,9 +124,9 @@ int32_t LP_socket(int32_t bindflag,char *hostname,uint16_t port)
#endif #endif
if ( bindflag == 0 ) if ( bindflag == 0 )
{ {
printf("call connect sock.%d\n",sock); //printf("call connect sock.%d\n",sock);
result = connect(sock,(struct sockaddr *)&saddr,addrlen); result = connect(sock,(struct sockaddr *)&saddr,addrlen);
printf("called connect result.%d\n",result); //printf("called connect result.%d\n",result);
timeout.tv_sec = 2; timeout.tv_sec = 2;
timeout.tv_usec = 0; timeout.tv_usec = 0;
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(void *)&timeout,sizeof(timeout)); setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(void *)&timeout,sizeof(timeout));
@ -238,18 +238,7 @@ int32_t LP_socketrecv(int32_t sock,uint8_t *recvbuf,int32_t maxlen)
return(recvlen); return(recvlen);
} }
struct electrum_info struct electrum_info *Electrums[8192];
{
queue_t sendQ,pendingQ;
portable_mutex_t mutex,txmutex;
struct electrum_info *prev;
int32_t bufsize,sock,*heightp,numerrors;
struct iguana_info *coin;
uint32_t stratumid,lasttime,keepalive,pending,*heighttimep;
char ipaddr[64],symbol[16];
uint16_t port;
uint8_t buf[];
} *Electrums[8192];
int32_t Num_electrums; int32_t Num_electrums;
struct electrum_info *electrum_server(char *symbol,struct electrum_info *ep) struct electrum_info *electrum_server(char *symbol,struct electrum_info *ep)
@ -338,7 +327,12 @@ int32_t electrum_process_array(struct iguana_info *coin,struct electrum_info *ep
if (tx->height <= 0 ) if (tx->height <= 0 )
{ {
tx->height = ht; tx->height = ht;
//printf("%s %s >>>>>>>>>> set %s <- height %d\n",coin->symbol,coinaddr,bits256_str(str,txid),tx->height); if ( ep != 0 && coin != 0 && tx->SPV == 0 )
{
if ( 0 && strcmp(coinaddr,coin->smartaddr) == 0 )
tx->SPV = LP_merkleproof(coin,coin->smartaddr,ep,txid,tx->height);
//printf("%s %s >>>>>>>>>> set %s <- height %d\n",coin->symbol,coinaddr,bits256_str(str,txid),tx->height);
}
} }
if ( v >= 0 && v < tx->numvouts ) if ( v >= 0 && v < tx->numvouts )
{ {
@ -360,6 +354,53 @@ int32_t electrum_process_array(struct iguana_info *coin,struct electrum_info *ep
return(flag); return(flag);
} }
cJSON *electrum_version(char *symbol,struct electrum_info *ep,cJSON **retjsonp);
cJSON *electrum_headers_subscribe(char *symbol,struct electrum_info *ep,cJSON **retjsonp);
struct stritem *electrum_sitem(struct electrum_info *ep,char *stratumreq,int32_t timeout,cJSON **retjsonp)
{
struct stritem *sitem = (struct stritem *)queueitem(stratumreq);
sitem->expiration = timeout;
sitem->DL.type = ep->stratumid++;
sitem->retptrp = (void **)retjsonp;
queue_enqueue("sendQ",&ep->sendQ,&sitem->DL);
return(sitem);
}
void electrum_initial_requests(struct electrum_info *ep)
{
cJSON *retjson; char stratumreq[1024];
retjson = 0;
sprintf(stratumreq,"{ \"jsonrpc\":\"2.0\", \"id\": %u, \"method\":\"%s\", \"params\": %s }\n",ep->stratumid,"blockchain.headers.subscribe","[]");
electrum_sitem(ep,stratumreq,3,&retjson);
retjson = 0;
sprintf(stratumreq,"{ \"jsonrpc\":\"2.0\", \"id\": %u, \"method\":\"%s\", \"params\": %s }\n",ep->stratumid,"server.version","[\"barterDEX\", [\"1.1\", \"1.1\"]]");
electrum_sitem(ep,stratumreq,3,&retjson);
retjson = 0;
sprintf(stratumreq,"{ \"jsonrpc\":\"2.0\", \"id\": %u, \"method\":\"%s\", \"params\": %s }\n",ep->stratumid,"blockchain.estimatefee","[2]");
electrum_sitem(ep,stratumreq,3,&retjson);
}
int32_t electrum_kickstart(struct electrum_info *ep)
{
closesocket(ep->sock);//, ep->sock = -1;
if ( (ep->sock= LP_socket(0,ep->ipaddr,ep->port)) < 0 )
{
printf("error RE-connecting to %s:%u\n",ep->ipaddr,ep->port);
return(-1);
}
else
{
ep->stratumid = 0;
electrum_initial_requests(ep);
printf("RECONNECT ep.%p %s numerrors.%d too big -> new %s:%u sock.%d\n",ep,ep->symbol,ep->numerrors,ep->ipaddr,ep->port,ep->sock);
ep->numerrors = 0;
}
return(0);
}
cJSON *electrum_submit(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *method,char *params,int32_t timeout) cJSON *electrum_submit(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *method,char *params,int32_t timeout)
{ {
// queue id and string and callback // queue id and string and callback
@ -368,37 +409,28 @@ cJSON *electrum_submit(char *symbol,struct electrum_info *ep,cJSON **retjsonp,ch
ep = electrum_server(symbol,0); ep = electrum_server(symbol,0);
while ( ep != 0 ) while ( ep != 0 )
{ {
if ( strcmp(ep->symbol,symbol) != 0 )
{
printf("electrum_submit ep.%p %s %s:%u called for [%s]???\n",ep,ep->symbol,ep->ipaddr,ep->port,symbol);
}
if ( ep != 0 && ep->sock >= 0 && retjsonp != 0 ) if ( ep != 0 && ep->sock >= 0 && retjsonp != 0 )
{ {
*retjsonp = 0; *retjsonp = 0;
sprintf(stratumreq,"{ \"jsonrpc\":\"2.0\", \"id\": %u, \"method\":\"%s\", \"params\": %s }\n",ep->stratumid,method,params); sprintf(stratumreq,"{ \"jsonrpc\":\"2.0\", \"id\": %u, \"method\":\"%s\", \"params\": %s }\n",ep->stratumid,method,params);
//printf("%s %s",symbol,stratumreq); //printf("%s %s",symbol,stratumreq);
memset(ep->buf,0,ep->bufsize); memset(ep->buf,0,ep->bufsize);
sitem = (struct stritem *)queueitem(stratumreq); sitem = electrum_sitem(ep,stratumreq,timeout,retjsonp);
sitem->expiration = timeout; portable_mutex_lock(&ep->mutex); // this helps performance!
sitem->DL.type = ep->stratumid++;
sitem->retptrp = (void **)retjsonp;
portable_mutex_lock(&ep->mutex);
queue_enqueue("sendQ",&ep->sendQ,&sitem->DL);
expiration = (uint32_t)time(NULL) + timeout + 1; expiration = (uint32_t)time(NULL) + timeout + 1;
while ( *retjsonp == 0 && time(NULL) <= expiration ) while ( *retjsonp == 0 && time(NULL) <= expiration )
usleep(5000); usleep(15000);
portable_mutex_unlock(&ep->mutex); portable_mutex_unlock(&ep->mutex);
if ( *retjsonp == 0 || jobj(*retjsonp,"error") != 0 ) if ( *retjsonp == 0 || jobj(*retjsonp,"error") != 0 )
{ {
if ( ++ep->numerrors >= LP_ELECTRUM_MAXERRORS ) if ( ++ep->numerrors >= LP_ELECTRUM_MAXERRORS )
{ electrum_kickstart(ep);
closesocket(ep->sock), ep->sock = -1;
if ( (ep->sock= LP_socket(0,ep->ipaddr,ep->port)) < 0 )
printf("error RE-connecting to %s:%u\n",ep->ipaddr,ep->port);
else
{
printf("ep.%p %s numerrors.%d too big -> new %s:%u sock.%d\n",ep,ep->symbol,ep->numerrors,ep->ipaddr,ep->port,ep->sock);
ep->numerrors = 0;
}
}
} else if ( ep->numerrors > 0 ) } else if ( ep->numerrors > 0 )
ep->numerrors++; ep->numerrors--;
if ( ep->prev == 0 ) if ( ep->prev == 0 )
{ {
if ( *retjsonp == 0 ) if ( *retjsonp == 0 )
@ -555,31 +587,47 @@ cJSON *electrum_address_listunspent(char *symbol,struct electrum_info *ep,cJSON
usecache = 0; usecache = 0;
else if ( ap->unspentheight < height ) else if ( ap->unspentheight < height )
usecache = 0; usecache = 0;
else if ( G.LP_pendingswaps != 0 && time(NULL) > ap->unspenttime+20 ) else if ( G.LP_pendingswaps != 0 && time(NULL) > ap->unspenttime+30 )
usecache = 0; usecache = 0;
} }
//printf("electrum.%s/%s listunspent last.(%s lag %d)\n",ep->symbol,coin->symbol,coin->lastunspent,(int32_t)(time(NULL) - coin->unspenttime)); if ( usecache == 0 || electrumflag > 1 )
if ( usecache == 0 )
{ {
if ( (retjson= electrum_strarg(symbol,ep,retjsonp,"blockchain.address.listunspent",addr,ELECTRUM_TIMEOUT)) != 0 ) if ( (retjson= electrum_strarg(symbol,ep,retjsonp,"blockchain.address.listunspent",addr,ELECTRUM_TIMEOUT)) != 0 )
{ {
//printf("%s.%d u.%u/%d t.%ld %s LISTUNSPENT.(%d)\n",coin->symbol,height,ap->unspenttime,ap->unspentheight,time(NULL),addr,(int32_t)strlen(jprint(retjson,0))); if ( jobj(retjson,"error") == 0 && is_cJSON_Array(retjson) != 0 )
updatedflag = 0;
if ( electrum_process_array(coin,ep,addr,retjson,electrumflag) != 0 )
LP_postutxos(coin->symbol,addr), updatedflag = 1;
if ( strcmp(addr,coin->smartaddr) == 0 )
{ {
retstr = jprint(retjson,0); if ( 0 && electrumflag > 1 )
LP_unspents_cache(coin->symbol,coin->smartaddr,retstr,updatedflag); printf("%s.%d u.%u/%d t.%ld %s LISTUNSPENT.(%d)\n",coin->symbol,height,ap->unspenttime,ap->unspentheight,time(NULL),addr,(int32_t)strlen(jprint(retjson,0)));
free(retstr); updatedflag = 0;
if ( electrum_process_array(coin,ep,addr,retjson,electrumflag) != 0 )
LP_postutxos(coin->symbol,addr), updatedflag = 1;
if ( strcmp(addr,coin->smartaddr) == 0 )
{
retstr = jprint(retjson,0);
LP_unspents_cache(coin->symbol,coin->smartaddr,retstr,1);
free(retstr);
}
if ( ap != 0 )
{
ap->unspenttime = (uint32_t)time(NULL);
ap->unspentheight = height;
}
} }
if ( ap != 0 ) else
{ {
ap->unspenttime = (uint32_t)time(NULL); free_json(retjson);
ap->unspentheight = height; retjson = 0;
} }
} }
} else retjson = LP_address_utxos(coin,addr,1); }
if ( retjson == 0 )
{
if ( strcmp(addr,coin->smartaddr) == 0 && (retstr= LP_unspents_filestr(symbol,coin->smartaddr)) != 0 )
{
retjson = cJSON_Parse(retstr);
free(retstr);
} else retjson = LP_address_utxos(coin,addr,1);
}
return(retjson); return(retjson);
} }
@ -591,7 +639,11 @@ cJSON *electrum_address_getbalance(char *symbol,struct electrum_info *ep,cJSON *
cJSON *electrum_addpeer(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *endpoint) { return(electrum_strarg(symbol,ep,retjsonp,"server.add_peer",endpoint,ELECTRUM_TIMEOUT)); } cJSON *electrum_addpeer(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *endpoint) { return(electrum_strarg(symbol,ep,retjsonp,"server.add_peer",endpoint,ELECTRUM_TIMEOUT)); }
cJSON *electrum_sendrawtransaction(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *rawtx) { return(electrum_strarg(symbol,ep,retjsonp,"blockchain.transaction.broadcast",rawtx,ELECTRUM_TIMEOUT)); } cJSON *electrum_sendrawtransaction(char *symbol,struct electrum_info *ep,cJSON **retjsonp,char *rawtx) { return(electrum_strarg(symbol,ep,retjsonp,"blockchain.transaction.broadcast",rawtx,ELECTRUM_TIMEOUT)); }
cJSON *electrum_estimatefee(char *symbol,struct electrum_info *ep,cJSON **retjsonp,int32_t numblocks) { return(electrum_intarg(symbol,ep,retjsonp,"blockchain.estimatefee",numblocks,ELECTRUM_TIMEOUT)); } cJSON *electrum_estimatefee(char *symbol,struct electrum_info *ep,cJSON **retjsonp,int32_t numblocks)
{
return(electrum_intarg(symbol,ep,retjsonp,"blockchain.estimatefee",numblocks,ELECTRUM_TIMEOUT));
}
cJSON *electrum_getchunk(char *symbol,struct electrum_info *ep,cJSON **retjsonp,int32_t n) { return(electrum_intarg(symbol,ep,retjsonp,"blockchain.block.get_chunk",n,ELECTRUM_TIMEOUT)); } cJSON *electrum_getchunk(char *symbol,struct electrum_info *ep,cJSON **retjsonp,int32_t n) { return(electrum_intarg(symbol,ep,retjsonp,"blockchain.block.get_chunk",n,ELECTRUM_TIMEOUT)); }
cJSON *electrum_getheader(char *symbol,struct electrum_info *ep,cJSON **retjsonp,int32_t n) cJSON *electrum_getheader(char *symbol,struct electrum_info *ep,cJSON **retjsonp,int32_t n)
@ -599,19 +651,27 @@ cJSON *electrum_getheader(char *symbol,struct electrum_info *ep,cJSON **retjsonp
return(electrum_intarg(symbol,ep,retjsonp,"blockchain.block.get_header",n,ELECTRUM_TIMEOUT)); return(electrum_intarg(symbol,ep,retjsonp,"blockchain.block.get_header",n,ELECTRUM_TIMEOUT));
} }
cJSON *LP_transaction_fromdata(struct iguana_info *coin,bits256 txid,uint8_t *serialized,int32_t len) cJSON *LP_cache_transaction(struct iguana_info *coin,bits256 txid,uint8_t *serialized,int32_t len)
{ {
uint8_t *extraspace; cJSON *txobj; char str[65],str2[65]; struct iguana_msgtx msgtx; bits256 checktxid; cJSON *txobj; struct LP_transaction *tx;
extraspace = calloc(1,4000000); if ( (txobj= LP_transaction_fromdata(coin,txid,serialized,len)) != 0 )
memset(&msgtx,0,sizeof(msgtx)); {
txobj = bitcoin_data2json(coin->taddr,coin->pubtype,coin->p2shtype,coin->isPoS,coin->height,&checktxid,&msgtx,extraspace,4000000,serialized,len,0,0,coin->zcash); if ( (tx= LP_transactionfind(coin,txid)) == 0 || tx->serialized == 0 )
//printf("TX.(%s) match.%d\n",jprint(txobj,0),bits256_cmp(txid,checktxid)); {
free(extraspace); txobj = LP_transactioninit(coin,txid,0,txobj);
if ( bits256_cmp(txid,checktxid) != 0 ) LP_transactioninit(coin,txid,1,txobj);
{ tx = LP_transactionfind(coin,txid);
printf("%s LP_transaction_fromdata mismatched txid %s vs %s\n",coin->symbol,bits256_str(str,txid),bits256_str(str2,checktxid)); }
free_json(txobj); if ( tx != 0 )
txobj = 0; {
tx->serialized = serialized;
tx->len = len;
}
else
{
char str[65]; printf("unexpected couldnt find tx %s %s\n",coin->symbol,bits256_str(str,txid));
free(serialized);
}
} }
return(txobj); return(txobj);
} }
@ -665,26 +725,7 @@ cJSON *_electrum_transaction(char *symbol,struct electrum_info *ep,cJSON **retjs
memcpy(coin->cachedtxiddata,serialized,len); memcpy(coin->cachedtxiddata,serialized,len);
free(hexstr); free(hexstr);
//printf("DATA.(%s) from (%s)\n",hexstr+1,jprint(hexjson,0)); //printf("DATA.(%s) from (%s)\n",hexstr+1,jprint(hexjson,0));
if ( (txobj= LP_transaction_fromdata(coin,txid,serialized,len)) != 0 ) *retjsonp = LP_cache_transaction(coin,txid,serialized,len); // eats serialized
{
if ( (tx= LP_transactionfind(coin,txid)) == 0 || tx->serialized == 0 )
{
txobj = LP_transactioninit(coin,txid,0,txobj);
LP_transactioninit(coin,txid,1,txobj);
tx = LP_transactionfind(coin,txid);
}
if ( tx != 0 )
{
tx->serialized = serialized;
tx->len = len;
}
else
{
printf("unexpected couldnt find tx %s %s\n",coin->symbol,bits256_str(str,txid));
free(serialized);
}
}
*retjsonp = txobj;
free_json(hexjson); free_json(hexjson);
//printf("return from electrum_transaction\n"); //printf("return from electrum_transaction\n");
return(*retjsonp); return(*retjsonp);
@ -832,9 +873,12 @@ struct electrum_info *LP_electrum_info(int32_t *alreadyp,char *symbol,char *ipad
int32_t LP_recvfunc(struct electrum_info *ep,char *str,int32_t len) int32_t LP_recvfunc(struct electrum_info *ep,char *str,int32_t len)
{ {
cJSON *strjson,*errjson,*resultjson,*paramsjson; char *method; int32_t i,n,height; uint32_t idnum=0; struct stritem *stritem; struct iguana_info *coin; struct queueitem *tmp,*item = 0; cJSON *strjson,*errjson,*resultjson,*paramsjson; char *method; int32_t i,n,height; uint32_t idnum=0; struct stritem *stritem; struct iguana_info *coin; struct queueitem *tmp,*item = 0;
if ( str == 0 || len == 0 )
return(-1);
ep->lasttime = (uint32_t)time(NULL); ep->lasttime = (uint32_t)time(NULL);
if ( (strjson= cJSON_Parse(str)) != 0 ) if ( (strjson= cJSON_Parse(str)) != 0 )
{ {
//printf("%s RECV.(%ld) id.%d\n",ep->symbol,strlen(str),jint(strjson,"id"));
resultjson = jobj(strjson,"result"); resultjson = jobj(strjson,"result");
//printf("strjson.(%s)\n",jprint(strjson,0)); //printf("strjson.(%s)\n",jprint(strjson,0));
if ( (method= jstr(strjson,"method")) != 0 ) if ( (method= jstr(strjson,"method")) != 0 )
@ -875,9 +919,9 @@ int32_t LP_recvfunc(struct electrum_info *ep,char *str,int32_t len)
stritem = (struct stritem *)item; stritem = (struct stritem *)item;
if ( item->type == idnum ) if ( item->type == idnum )
{ {
//printf("matched idnum.%d result.%p\n",idnum,resultjson);
DL_DELETE(ep->pendingQ.list,item); DL_DELETE(ep->pendingQ.list,item);
*((cJSON **)stritem->retptrp) = (resultjson != 0 ? jduplicate(resultjson) : strjson); *((cJSON **)stritem->retptrp) = (resultjson != 0 ? jduplicate(resultjson) : jduplicate(strjson));
//printf("matched idnum.%d result.(%s)\n",idnum,jprint(*((cJSON **)stritem->retptrp),0));
resultjson = strjson = 0; resultjson = strjson = 0;
free(item); free(item);
break; break;
@ -906,14 +950,10 @@ int32_t LP_recvfunc(struct electrum_info *ep,char *str,int32_t len)
void LP_dedicatedloop(void *arg) void LP_dedicatedloop(void *arg)
{ {
struct pollfd fds; int32_t i,len,flag,timeout = 10; struct iguana_info *coin; cJSON *retjson; struct stritem *sitem; struct electrum_info *ep = arg; struct pollfd fds; int32_t i,len,flag,timeout = 10; struct iguana_info *coin; struct stritem *sitem; struct electrum_info *ep = arg;
if ( (coin= LP_coinfind(ep->symbol)) != 0 ) if ( (coin= LP_coinfind(ep->symbol)) != 0 )
ep->heightp = &coin->height, ep->heighttimep = &coin->heighttime; ep->heightp = &coin->height, ep->heighttimep = &coin->heighttime;
sleep(2); electrum_initial_requests(ep);
if ( (retjson= electrum_version(ep->symbol,ep,&retjson)) != 0 )
printf("electrum_version %s\n",jprint(retjson,1));
if ( (retjson= electrum_headers_subscribe(ep->symbol,ep,&retjson)) != 0 )
free_json(retjson);
printf("LP_dedicatedloop ep.%p sock.%d for %s:%u num.%d %p %s ht.%d\n",ep,ep->sock,ep->ipaddr,ep->port,Num_electrums,&Num_electrums,ep->symbol,*ep->heightp); printf("LP_dedicatedloop ep.%p sock.%d for %s:%u num.%d %p %s ht.%d\n",ep,ep->sock,ep->ipaddr,ep->port,Num_electrums,&Num_electrums,ep->symbol,*ep->heightp);
while ( ep->sock >= 0 ) while ( ep->sock >= 0 )
{ {
@ -979,10 +1019,12 @@ void LP_dedicatedloop(void *arg)
cJSON *LP_electrumserver(struct iguana_info *coin,char *ipaddr,uint16_t port) cJSON *LP_electrumserver(struct iguana_info *coin,char *ipaddr,uint16_t port)
{ {
struct electrum_info *ep; int32_t already; cJSON *retjson; struct electrum_info *ep; int32_t kickval,already; cJSON *retjson;
if ( ipaddr == 0 || ipaddr[0] == 0 || port == 0 ) if ( ipaddr == 0 || ipaddr[0] == 0 || port == 0 )
{ {
coin->electrum = 0; coin->electrum = 0;
coin->inactive = (uint32_t)time(NULL);
//printf("would have disabled %s electrum here\n",coin->symbol);
return(cJSON_Parse("{\"result\":\"success\",\"status\":\"electrum mode disabled, now in native coin mode\"}")); return(cJSON_Parse("{\"result\":\"success\",\"status\":\"electrum mode disabled, now in native coin mode\"}"));
} }
retjson = cJSON_CreateObject(); retjson = cJSON_CreateObject();
@ -1002,16 +1044,31 @@ cJSON *LP_electrumserver(struct iguana_info *coin,char *ipaddr,uint16_t port)
} }
else else
{ {
printf("launched electrum.(%s:%u)\n",ep->ipaddr,ep->port); //printf("launched %s electrum.(%s:%u)\n",coin->symbol,ep->ipaddr,ep->port);
jaddstr(retjson,"result","success"); jaddstr(retjson,"result","success");
ep->prev = coin->electrum; ep->prev = coin->electrum;
coin->electrum = ep; coin->electrum = ep;
if ( coin->loadedcache == 0 )
{
LP_cacheptrs_init(coin);
coin->loadedcache = (uint32_t)time(NULL);
}
} }
} }
else else
{ {
if ( coin->electrum == 0 )
{
coin->electrum = ep;
ep->prev = 0;
}
jaddstr(retjson,"result","success"); jaddstr(retjson,"result","success");
jaddstr(retjson,"status","already there"); jaddstr(retjson,"status","already there");
if ( ep->numerrors > 0 )
{
kickval = electrum_kickstart(ep);
jaddnum(retjson,"restart",kickval);
}
} }
//printf("(%s)\n",jprint(retjson,0)); //printf("(%s)\n",jprint(retjson,0));
return(retjson); return(retjson);

318
iguana/exchanges/LP_statemachine.c

@ -132,6 +132,324 @@ FILE *basilisk_swap_save(struct basilisk_swap *swap,bits256 privkey,struct basil
}*/ }*/
return(fp); return(fp);
} }
/*if ( IAMLP != 0 && time(NULL) > lasthello+600 )
{
char *hellostr,*retstr; cJSON *retjson; int32_t allgood,sock = LP_bindsock;
allgood = 0;
if ( (retstr= issue_hello(myport)) != 0 )
{
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (hellostr= jstr(retjson,"status")) != 0 && strcmp(hellostr,"got hello") == 0 )
allgood = 1;
else printf("strange return.(%s)\n",jprint(retjson,0));
free_json(retjson);
} else printf("couldnt parse hello return.(%s)\n",retstr);
free(retstr);
} else printf("issue_hello NULL return\n");
lasthello = (uint32_t)time(NULL);
if ( allgood == 0 )
{
printf("RPC port got stuck, would have close bindsocket\n");
if ( 0 )
{
LP_bindsock = -1;
closesocket(sock);
LP_bindsock_reset++;
sleep(10);
printf("launch new rpcloop\n");
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);
}
}
}
}*/
/*
now = (uint32_t)time(NULL);
numpeers = LP_numpeers();
needpings = 0;
HASH_ITER(hh,LP_peerinfos,peer,tmp)
{
if ( peer->errors >= LP_MAXPEER_ERRORS )
{
if ( (rand() % 10000) == 0 )
{
peer->errors--;
if ( peer->errors < LP_MAXPEER_ERRORS )
peer->diduquery = 0;
}
if ( IAMLP == 0 )
continue;
}
if ( now > peer->lastpeers+LP_ORDERBOOK_DURATION*.777 || (rand() % 100000) == 0 )
{
if ( strcmp(peer->ipaddr,myipaddr) != 0 )
{
nonz++;
//issue_LP_getpeers(peer->ipaddr,peer->port);
//LP_peersquery(mypeer,pubsock,peer->ipaddr,peer->port,myipaddr,myport);
//if ( peer->diduquery == 0 )
// LP_peer_pricesquery(peer);
//LP_utxos_sync(peer);
needpings++;
}
peer->lastpeers = now;
}
if ( peer->needping != 0 )
{
peer->diduquery = now;
nonz++;
if ( (retstr= issue_LP_notify(peer->ipaddr,peer->port,"127.0.0.1",0,numpeers,G.LP_sessionid,G.LP_myrmd160str,G.LP_mypub25519)) != 0 )
free(retstr);
peer->needping = 0;
needpings++;
}
}*/
#ifdef oldway
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 numpeers,i,n=0;
if ( (array= cJSON_Parse(retstr)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
if ( (argipaddr= jstr(item,"ipaddr")) != 0 && (argport= juint(item,"port")) != 0 )
{
if ( (pushport= juint(item,"push")) == 0 )
pushport = argport + 1;
if ( (subport= juint(item,"sub")) == 0 )
subport = argport + 2;
argipbits = (uint32_t)calc_ipbits(argipaddr);
if ( (peer= LP_peerfind(argipbits,argport)) == 0 )
{
numpeers = LP_numpeers();
if ( IAMLP != 0 || numpeers < LP_MIN_PEERS || (IAMLP == 0 && (rand() % LP_MAX_PEERS) > numpeers) )
peer = LP_addpeer(mypeer,mypubsock,argipaddr,argport,pushport,subport,jint(item,"numpeers"),jint(item,"numutxos"),juint(item,"session"));
}
if ( peer != 0 )
{
peer->lasttime = now;
if ( strcmp(argipaddr,destipaddr) == 0 && destport == argport && peer->numpeers != n )
peer->numpeers = n;
}
}
}
}
free_json(array);
}
return(n);
}
void issue_LP_getpeers(char *destip,uint16_t destport)
{
cJSON *reqjson = cJSON_CreateObject();
jaddstr(reqjson,"method","getpeers");
LP_peer_request(destip,destport,reqjson);
/*char url[512],*retstr;
sprintf(url,"http://%s:%u/api/stats/getpeers?ipaddr=%s&port=%u&numpeers=%d",destip,destport,ipaddr,port,numpeers);
retstr = LP_issue_curl("getpeers",destip,port,url);
//printf("%s -> getpeers.(%s)\n",destip,retstr);
return(retstr);*/
}
void LP_peer_request(char *destip,uint16_t destport,cJSON *argjson)
{
struct LP_peerinfo *peer; uint8_t *msg; int32_t msglen; uint32_t crc32;
peer = LP_peerfind((uint32_t)calc_ipbits(destip),destport);
msg = (void *)jprint(argjson,0);
msglen = (int32_t)strlen((char *)msg) + 1;
crc32 = calc_crc32(0,&msg[2],msglen - 2);
LP_queuesend(crc32,peer->pushsock,"","",msg,msglen);
free_json(argjson);
}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; bits256 zero; 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)) != 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++;
memset(&zero,0,sizeof(zero));
if ( (retstr= issue_LP_notify(destipaddr,destport,peer->ipaddr,peer->port,peer->numpeers,peer->sessionid,0,zero)) != 0 )
free(retstr);
}
}
if ( flag != 0 )
printf(" <- missing peers\n");
}
}
}
void issue_LP_notify(char *destip,uint16_t destport,char *ipaddr,uint16_t port,int32_t numpeers,uint32_t sessionid,char *rmd160str,bits256 pub)
{
cJSON *reqjson = cJSON_CreateObject();
jaddstr(reqjson,"method","notify");
jaddstr(reqjson,"coin",symbol);
jaddstr(reqjson,"coinaddr",coinaddr);
jaddbits256(reqjson,"txid",txid);
jaddnum(reqjson,"vout",vout);
jaddnum(reqjson,"ht",height);
jadd64bits(reqjson,"value",value);
LP_peer_request(destip,destport,reqjson);
/*char url[512],*retstr,str[65];
if ( (retstr= LP_isitme(destip,destport)) != 0 )
return(retstr);
sprintf(url,"http://%s:%u/api/stats/notify?ipaddr=%s&port=%u&numpeers=%d&session=%u",destip,destport,ipaddr,port,numpeers,sessionid);
if ( rmd160str != 0 && bits256_nonz(pub) != 0 )
{
sprintf(url+strlen(url),"&rmd160=%s&pub=%s",rmd160str,bits256_str(str,pub));
//printf("SEND (%s)\n",url);
}
return(LP_issue_curl("notify",destip,destport,url));
//return(issue_curlt(url,LP_HTTP_TIMEOUT));*/
}
char *issue_hello(uint16_t port)
{
char url[512];
sprintf(url,"http://127.0.0.1:%u/api/stats/hello",port);
//printf("getutxo.(%s)\n",url);
return(issue_curlt(url,600)); // might be starting a trade
}
void issue_LP_uitem(char *destip,uint16_t destport,char *symbol,char *coinaddr,bits256 txid,int32_t vout,int32_t height,uint64_t value)
{
cJSON *reqjson = cJSON_CreateObject();
jaddstr(reqjson,"method","uitem");
jaddstr(reqjson,"coin",symbol);
jaddstr(reqjson,"coinaddr",coinaddr);
jaddbits256(reqjson,"txid",txid);
jaddnum(reqjson,"vout",vout);
jaddnum(reqjson,"ht",height);
jadd64bits(reqjson,"value",value);
LP_peer_request(destip,destport,reqjson);
/*char url[512],*retstr,str[65];
if ( (retstr= LP_isitme(destip,destport)) != 0 )
return(retstr);
sprintf(url,"http://%s:%u/api/stats/uitem?coin=%s&coinaddr=%s&txid=%s&vout=%d&ht=%d&value=%llu",destip,destport,symbol,coinaddr,bits256_str(str,txid),vout,height,(long long)value);
retstr = LP_issue_curl("uitem",destip,destport,url);
//printf("uitem.(%s)\n",retstr);
return(retstr);*/
}
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));
}
void issue_LP_listunspent(char *destip,uint16_t destport,char *symbol,char *coinaddr)
{
cJSON *reqjson = cJSON_CreateObject();
jaddstr(reqjson,"method","listunspent");
jaddstr(reqjson,"coin",symbol);
jaddstr(reqjson,"address",coinaddr);
LP_peer_request(destip,destport,reqjson);
/*char url[512],*retstr;
sprintf(url,"http://%s:%u/api/stats/listunspent?coin=%s&address=%s",destip,destport,symbol,coinaddr);
retstr = LP_issue_curl("listunspent",destip,destport,url);
//printf("listunspent.(%s) -> (%s)\n",url,retstr);
return(retstr);*/
}
int32_t LP_utxos_sync(struct LP_peerinfo *peer)
{
int32_t i,j,n=0,m,v,posted=0; bits256 txid; cJSON *array,*item,*item2,*array2; uint64_t total,total2; struct iguana_info *coin,*ctmp; char *retstr,*retstr2;
if ( strcmp(peer->ipaddr,LP_myipaddr) == 0 )
return(0);
HASH_ITER(hh,LP_coins,coin,ctmp)
{
if ( IAMLP == 0 && coin->inactive != 0 )
continue;
if ( coin->smartaddr[0] == 0 )
continue;
total = 0;
if ( (j= LP_listunspent_both(coin->symbol,coin->smartaddr,0)) == 0 )
continue;
if ( (array= LP_address_utxos(coin,coin->smartaddr,1)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
total += j64bits(item,"value");
}
}
if ( n > 0 && total > 0 && (retstr= issue_LP_listunspent(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr)) != 0 )
{
//printf("UTXO sync.%d %s n.%d total %.8f -> %s (%s)\n",j,coin->symbol,n,dstr(total),peer->ipaddr,retstr);
total2 = 0;
if ( (array2= cJSON_Parse(retstr)) != 0 )
{
if ( (m= cJSON_GetArraySize(array2)) > 0 )
{
for (i=0; i<m; i++)
{
item2 = jitem(array2,i);
total2 += j64bits(item2,"value");
}
}
if ( total != total2 || n != m )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
txid = jbits256(item,"tx_hash");
v = jint(item,"tx_pos");
for (j=0; j<m; j++)
{
if ( v == jint(jitem(array2,i),"tx_pos") && bits256_cmp(txid,jbits256(jitem(array2,i),"tx_hash")) == 0 )
break;
}
if ( j == m )
{
//printf("%s missing %s %s\n",peer->ipaddr,coin->symbol,jprint(item,0));
issue_LP_uitem(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr,txid,v,jint(item,"height"),j64bits(item,"value"));
posted++;
}
}
if ( 0 && posted != 0 )
printf(">>>>>>>> %s compare %s %s (%.8f n%d) (%.8f m%d)\n",peer->ipaddr,coin->symbol,coin->smartaddr,dstr(total),n,dstr(total2),m);
} //else printf("%s matches %s\n",peer->ipaddr,coin->symbol);
free_json(array2);
} else printf("parse error (%s)\n",retstr);
free(retstr);
}
else if ( n != 0 && total != 0 )
{
//printf("no response from %s for %s %s\n",peer->ipaddr,coin->symbol,coin->smartaddr);
for (i=0; i<n; i++)
{
item = jitem(array,i);
txid = jbits256(item,"tx_hash");
v = jint(item,"tx_pos");
issue_LP_uitem(peer->ipaddr,peer->port,coin->symbol,coin->smartaddr,txid,v,jint(item,"height"),j64bits(item,"value"));
}
}
free_json(array);
}
}
return(posted);
}
/*char *issue_LP_notifyutxo(char *destip,uint16_t destport,struct LP_utxoinfo *utxo) /*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; char url[4096],str[65],str2[65],str3[65],*retstr; struct _LP_utxoinfo u; uint64_t val,val2;

31
iguana/exchanges/LP_swap.c

@ -556,7 +556,7 @@ struct basilisk_rawtx *LP_swapdata_rawtx(struct basilisk_swap *swap,uint8_t *dat
int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct basilisk_rawtx *rawtx,int32_t v,uint8_t *recvbuf,int32_t recvlen,int32_t suppress_pubkeys) 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; bits256 otherhash,myhash,txid; int64_t txfee,val; 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++) for (i=0; i<32; i++)
otherhash.bytes[i] = recvbuf[offset++]; otherhash.bytes[i] = recvbuf[offset++];
for (i=0; i<32; i++) for (i=0; i<32; i++)
@ -626,7 +626,10 @@ int32_t LP_rawtx_spendscript(struct basilisk_swap *swap,int32_t height,struct ba
txfee = swap->I.Atxfee; txfee = swap->I.Atxfee;
else txfee = LP_MIN_TXFEE; else txfee = LP_MIN_TXFEE;
} }
if ( j64bits(vout,"satoshis") >= rawtx->I.amount-txfee && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 ) if ( rawtx->I.amount > 2*txfee)
val = rawtx->I.amount-2*txfee;
else val = 1;
if ( j64bits(vout,"satoshis") >= val && (skey= jobj(vout,"scriptPubKey")) != 0 && (hexstr= jstr(skey,"hex")) != 0 )
{ {
if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) ) if ( (hexlen= (int32_t)strlen(hexstr) >> 1) < sizeof(rawtx->spendscript) )
{ {
@ -996,15 +999,31 @@ struct basilisk_swap *bitcoin_swapinit(bits256 privkey,uint8_t *pubkey33,bits256
{ {
//FILE *fp; char fname[512]; //FILE *fp; char fname[512];
uint8_t *alicepub33=0,*bobpub33=0; int32_t jumblrflag=-2,x = -1; struct iguana_info *coin; uint8_t *alicepub33=0,*bobpub33=0; int32_t jumblrflag=-2,x = -1; struct iguana_info *coin;
swap->I.Atxfee = qp->desttxfee; if ( (swap->I.Atxfee= qp->desttxfee) < 0 )
swap->I.Btxfee = qp->txfee; {
printf("bitcoin_swapinit %s Atxfee %.8f rejected\n",swap->I.req.dest,dstr(swap->I.Atxfee));
return(0);
}
if ( (swap->I.Btxfee= qp->txfee) < 0 )
{
printf("bitcoin_swapinit %s Btxfee %.8f rejected\n",swap->I.req.src,dstr(swap->I.Btxfee));
return(0);
}
swap->I.putduration = swap->I.callduration = INSTANTDEX_LOCKTIME; swap->I.putduration = swap->I.callduration = INSTANTDEX_LOCKTIME;
if ( optionduration < 0 ) if ( optionduration < 0 )
swap->I.putduration -= optionduration; swap->I.putduration -= optionduration;
else if ( optionduration > 0 ) else if ( optionduration > 0 )
swap->I.callduration += optionduration; swap->I.callduration += optionduration;
swap->I.bobsatoshis = swap->I.req.srcamount; if ( (swap->I.bobsatoshis= swap->I.req.srcamount) <= 0 )
swap->I.alicesatoshis = swap->I.req.destamount; {
printf("bitcoin_swapinit %s bobsatoshis %.8f rejected\n",swap->I.req.src,dstr(swap->I.bobsatoshis));
return(0);
}
if ( (swap->I.alicesatoshis= swap->I.req.destamount) <= 0 )
{
printf("bitcoin_swapinit %s alicesatoshis %.8f rejected\n",swap->I.req.dest,dstr(swap->I.alicesatoshis));
return(0);
}
if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < LP_MIN_TXFEE ) if ( (swap->I.bobinsurance= (swap->I.bobsatoshis / INSTANTDEX_INSURANCEDIV)) < LP_MIN_TXFEE )
swap->I.bobinsurance = LP_MIN_TXFEE; swap->I.bobinsurance = LP_MIN_TXFEE;
if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < LP_MIN_TXFEE ) if ( (swap->I.aliceinsurance= (swap->I.alicesatoshis / INSTANTDEX_INSURANCEDIV)) < LP_MIN_TXFEE )

192
iguana/exchanges/LP_tradebots.c

@ -18,16 +18,16 @@
// marketmaker // marketmaker
// //
#define TRADEBOTS_GAPTIME 60 #define TRADEBOTS_GAPTIME 120
#define LP_TRADEBOTS_MAXTRADES 100 #define LP_TRADEBOTS_MAXTRADES 10
struct LP_tradebot_trade struct LP_tradebot_trade
{ {
double maxprice,totalrelvolume,basevol,relvol; double maxprice,totalrelvolume,basevol,relvol;
uint64_t aliceid; uint64_t aliceid;
int32_t dispdir; int32_t dispdir;
uint32_t started,finished,requestid,quoteid,tradeid; uint32_t started,finished,requestid,quoteid,tradeid,expired;
char base[32],rel[32]; char base[32],rel[32],event[32];
}; };
struct LP_tradebot struct LP_tradebot
@ -36,7 +36,7 @@ struct LP_tradebot
char name[128],base[32],rel[32]; char name[128],base[32],rel[32];
int32_t numtrades,numpending,completed,dispdir; int32_t numtrades,numpending,completed,dispdir;
double maxprice,totalrelvolume,totalbasevolume,basesum,relsum,pendbasesum,pendrelsum; double maxprice,totalrelvolume,totalbasevolume,basesum,relsum,pendbasesum,pendrelsum;
uint32_t dead,pause,started,id; uint32_t lasttime,dead,pause,userpause,started,id;
struct LP_tradebot_trade *trades[LP_TRADEBOTS_MAXTRADES]; struct LP_tradebot_trade *trades[LP_TRADEBOTS_MAXTRADES];
} *LP_tradebots; } *LP_tradebots;
@ -55,18 +55,10 @@ void LP_tradebot_updatestats(struct LP_tradebot *bot,struct LP_tradebot_trade *t
{ {
if ( strcmp(status,"finished") == 0 ) if ( strcmp(status,"finished") == 0 )
{ {
flag = 1; if ( tp->finished == 0 )
bot->completed++; tp->finished = (uint32_t)time(NULL);
bot->basesum += tp->basevol;
bot->relsum += tp->relvol;
} }
} }
if ( flag == 0 )
{
bot->numpending++;
bot->pendbasesum += tp->basevol;
bot->pendrelsum += tp->relvol;
}
free_json(swapjson); free_json(swapjson);
} }
free(swapstr); free(swapstr);
@ -75,11 +67,39 @@ void LP_tradebot_updatestats(struct LP_tradebot *bot,struct LP_tradebot_trade *t
void LP_tradebot_calcstats(struct LP_tradebot *bot) void LP_tradebot_calcstats(struct LP_tradebot *bot)
{ {
int32_t i; int32_t i; struct LP_tradebot_trade *tp;
bot->basesum = bot->relsum = bot->pendbasesum = bot->pendrelsum = 0.; bot->basesum = bot->relsum = bot->pendbasesum = bot->pendrelsum = 0.;
bot->numpending = bot->completed = 0; bot->numpending = bot->completed = 0;
for (i=0; i<bot->numtrades; i++) for (i=0; i<bot->numtrades; i++)
LP_tradebot_updatestats(bot,bot->trades[i]); {
if ( (tp= bot->trades[i]) == 0 )
continue;
if ( tp->finished == 0 && time(NULL) > tp->started+INSTANTDEX_LOCKTIME*2 )
{
tp->expired = tp->finished = (uint32_t)time(NULL);
printf("tradeid.%u expired\n",tp->tradeid);
}
if ( tp->finished != 0 )
{
if ( tp->expired == 0 )
{
bot->basesum += tp->basevol;
bot->relsum += tp->relvol;
bot->completed++;
}
}
else
{
if ( tp->requestid != 0 && tp->quoteid != 0 )
{
bot->pendbasesum += tp->basevol;
bot->pendrelsum += tp->relvol;
bot->numpending++;
}
}
//LP_tradebot_updatestats(bot,bot->trades[i]);
}
//printf("completed.%d (%.8f / %.8f) pending.%d (%.8f / %.8f)\n",bot->completed,bot->basesum,bot->relsum,bot->numpending,bot->pendbasesum,bot->pendrelsum);
} }
double LP_pricevol_invert(double *basevolumep,double maxprice,double relvolume) double LP_pricevol_invert(double *basevolumep,double maxprice,double relvolume)
@ -100,11 +120,15 @@ cJSON *LP_tradebot_tradejson(struct LP_tradebot_trade *tp,int32_t dispflag)
double price,basevol; cJSON *item = cJSON_CreateObject(); double price,basevol; cJSON *item = cJSON_CreateObject();
if ( tp == 0 ) if ( tp == 0 )
return(cJSON_Parse("{}")); return(cJSON_Parse("{}"));
if ( tp->event[0] != 0 )
jaddstr(item,"status",tp->event);
if ( tp->requestid != 0 && tp->quoteid != 0 ) if ( tp->requestid != 0 && tp->quoteid != 0 )
{ {
jaddnum(item,"requestid",tp->requestid); jaddnum(item,"requestid",tp->requestid);
jaddnum(item,"quoteid",tp->quoteid); jaddnum(item,"quoteid",tp->quoteid);
} else jaddnum(item,"tradeid",tp->tradeid); } else jaddnum(item,"tradeid",tp->tradeid);
if ( tp->aliceid != 0 )
jadd64bits(item,"aliceid",tp->aliceid);
if ( tp->basevol > SMALLVAL && tp->relvol > SMALLVAL ) if ( tp->basevol > SMALLVAL && tp->relvol > SMALLVAL )
{ {
if ( dispflag > 0 ) if ( dispflag > 0 )
@ -125,13 +149,14 @@ cJSON *LP_tradebot_tradejson(struct LP_tradebot_trade *tp,int32_t dispflag)
cJSON *LP_tradebot_json(struct LP_tradebot *bot) cJSON *LP_tradebot_json(struct LP_tradebot *bot)
{ {
int32_t i; double aveprice,basevolume,vol; cJSON *json,*array; int32_t i; double aveprice,basevolume,vol; cJSON *json,*array;
LP_tradebot_calcstats(bot);
json = cJSON_CreateObject(); json = cJSON_CreateObject();
jaddstr(json,"result","success"); jaddstr(json,"result","success");
jaddstr(json,"name",bot->name); jaddstr(json,"name",bot->name);
jaddnum(json,"botid",bot->id); jaddnum(json,"botid",bot->id);
jaddnum(json,"started",bot->started); jaddnum(json,"started",bot->started);
if ( bot->pause != 0 ) if ( bot->pause != 0 || bot->userpause != 0 )
jaddnum(json,"paused",bot->pause); jaddnum(json,"paused",bot->userpause != 0 ? bot->userpause : bot->pause);
if ( bot->dead != 0 ) if ( bot->dead != 0 )
jaddnum(json,"stopped",bot->dead); jaddnum(json,"stopped",bot->dead);
if ( bot->dispdir > 0 ) if ( bot->dispdir > 0 )
@ -165,7 +190,6 @@ cJSON *LP_tradebot_json(struct LP_tradebot *bot)
} }
} }
array = cJSON_CreateArray(); array = cJSON_CreateArray();
LP_tradebot_calcstats(bot);
for (i=0; i<bot->numtrades; i++) for (i=0; i<bot->numtrades; i++)
jaddi(array,LP_tradebot_tradejson(bot->trades[i],bot->dispdir)); jaddi(array,LP_tradebot_tradejson(bot->trades[i],bot->dispdir));
jadd(json,"trades",array); jadd(json,"trades",array);
@ -251,9 +275,6 @@ struct LP_tradebot_trade *LP_tradebot_pending(struct LP_tradebot *bot,cJSON *pen
tp->basevol = jdouble(pending,"basevalue"); tp->basevol = jdouble(pending,"basevalue");
tp->relvol = jdouble(pending,"relvalue"); tp->relvol = jdouble(pending,"relvalue");
printf("tradebot pending basevol %.8f relvol %.8f\n",tp->basevol,tp->relvol); printf("tradebot pending basevol %.8f relvol %.8f\n",tp->basevol,tp->relvol);
bot->pendrelsum += tp->relvol;
bot->pendbasesum += tp->basevol;
bot->numpending++;
return(tp); return(tp);
} }
@ -287,9 +308,10 @@ double LP_orderbook_maxrel(char *base,char *rel,double maxprice)
void LP_tradebot_timeslice(void *ctx,struct LP_tradebot *bot) void LP_tradebot_timeslice(void *ctx,struct LP_tradebot *bot)
{ {
double remaining,maxrel; int32_t i,maxiters = 10; uint32_t tradeid; bits256 destpubkey; char *retstr,*liststr; cJSON *retjson,*retjson2,*pending; double remaining,maxrel; struct LP_tradebot_trade *tp; int32_t i,maxiters = 10; uint32_t tradeid; bits256 destpubkey; char *retstr,*liststr; cJSON *retjson,*retjson2,*pending;
memset(destpubkey.bytes,0,sizeof(destpubkey)); memset(destpubkey.bytes,0,sizeof(destpubkey));
if ( bot->dead == 0 && bot->pause == 0 && bot->numtrades < sizeof(bot->trades)/sizeof(*bot->trades) ) LP_tradebot_calcstats(bot);
if ( bot->dead == 0 && bot->pause == 0 && bot->userpause == 0 && bot->numtrades < sizeof(bot->trades)/sizeof(*bot->trades) )
{ {
if ( (liststr= LP_recent_swaps(0)) != 0 ) if ( (liststr= LP_recent_swaps(0)) != 0 )
{ {
@ -313,11 +335,7 @@ void LP_tradebot_timeslice(void *ctx,struct LP_tradebot *bot)
{ {
if ( (pending= jobj(retjson2,"pending")) != 0 && juint(pending,"tradeid") == tradeid ) if ( (pending= jobj(retjson2,"pending")) != 0 && juint(pending,"tradeid") == tradeid )
{ {
bot->trades[bot->numtrades++] = LP_tradebot_pending(bot,pending,tradeid); bot->trades[bot->numtrades++] = tp = LP_tradebot_pending(bot,pending,tradeid);
if ( bot->relsum >= 0.99*bot->totalrelvolume-SMALLVAL || bot->basesum >= 0.99*bot->totalbasevolume-SMALLVAL )
bot->dead = (uint32_t)time(NULL);
else if ( (bot->pendrelsum+bot->relsum) >= 0.99*bot->totalrelvolume-SMALLVAL || (bot->basesum+bot->pendbasesum) >= 0.99*bot->totalbasevolume-SMALLVAL )
bot->pause = (uint32_t)time(NULL);
printf("issued bot trade.%u %s\n",tradeid,retstr); printf("issued bot trade.%u %s\n",tradeid,retstr);
free_json(retjson2); free_json(retjson2);
free(retstr); free(retstr);
@ -328,6 +346,7 @@ void LP_tradebot_timeslice(void *ctx,struct LP_tradebot *bot)
free(retstr); free(retstr);
} }
} }
LP_tradebot_calcstats(bot);
} }
free_json(retjson); free_json(retjson);
} }
@ -338,6 +357,39 @@ void LP_tradebot_timeslice(void *ctx,struct LP_tradebot *bot)
bot->pause = (uint32_t)time(NULL); bot->pause = (uint32_t)time(NULL);
} }
void LP_aliceid(uint32_t tradeid,uint64_t aliceid,char *event,uint32_t requestid,uint32_t quoteid)
{
struct LP_tradebot *bot,*tmp; int32_t i,matched = 0; struct LP_tradebot_trade *tp;
if ( tradeid == 0 )
return;
DL_FOREACH_SAFE(LP_tradebots,bot,tmp)
{
for (i=0; i<bot->numtrades; i++)
{
if ( (tp= bot->trades[i]) != 0 )
{
if ( tp->finished == 0 && tp->tradeid == tradeid )
{
tp->aliceid = aliceid;
printf("bot event tradeid.%u aliceid.%llu (%s) r.%u q.%u\n",tradeid,(long long)aliceid,event,requestid,quoteid);
if ( requestid != 0 && quoteid != 0 )
{
tp->requestid = requestid;
tp->quoteid = quoteid;
}
strcpy(tp->event,event);
matched = 1;
break;
} else printf("tradeid.%u finished.%u\n",tp->tradeid,tp->finished);
}
}
if ( matched != 0 )
break;
}
if ( matched == 0 )
printf("NO MATCH: bot event tradeid.%u aliceid.%llu (%s) r.%u q.%u\n",tradeid,(long long)aliceid,event,requestid,quoteid);
}
void LP_tradebot_finished(uint32_t tradeid,uint32_t requestid,uint32_t quoteid) void LP_tradebot_finished(uint32_t tradeid,uint32_t requestid,uint32_t quoteid)
{ {
struct LP_tradebot *bot,*tmp; int32_t i; struct LP_tradebot_trade *tp; struct LP_tradebot *bot,*tmp; int32_t i; struct LP_tradebot_trade *tp;
@ -349,11 +401,9 @@ void LP_tradebot_finished(uint32_t tradeid,uint32_t requestid,uint32_t quoteid)
{ {
tp->requestid = requestid; tp->requestid = requestid;
tp->quoteid = quoteid; tp->quoteid = quoteid;
bot->pendbasesum -= tp->basevol, bot->basesum += tp->basevol; printf("bot.%u detected completion tradeid.%u aliceid.%llu r.%u q.%u, numpending.%d completed.%d\n",bot->id,tp->tradeid,(long long)tp->aliceid,tp->requestid,tp->quoteid,bot->numpending,bot->completed);
bot->pendrelsum -= tp->relvol, bot->relsum += tp->relvol;
bot->numpending--, bot->completed++;
printf("bot.%u detected completion tradeid.%u aliceid.%llx r.%u q.%u, numpending.%d completed.%d\n",bot->id,tp->tradeid,(long long)tp->aliceid,tp->requestid,tp->quoteid,bot->numpending,bot->completed);
tp->finished = (uint32_t)time(NULL); tp->finished = (uint32_t)time(NULL);
strcpy(tp->event,"finished");
break; break;
} }
} }
@ -363,31 +413,22 @@ void LP_tradebot_finished(uint32_t tradeid,uint32_t requestid,uint32_t quoteid)
void LP_tradebots_timeslice(void *ctx) void LP_tradebots_timeslice(void *ctx)
{ {
static uint32_t lastnumfinished = 0; static uint32_t lastnumfinished = 0;
struct LP_tradebot_trade *tp; struct iguana_info *relcoin; struct LP_tradebot *bot,*tmp; int32_t i; struct iguana_info *relcoin; struct LP_tradebot *bot,*tmp;
DL_FOREACH_SAFE(LP_tradebots,bot,tmp) DL_FOREACH_SAFE(LP_tradebots,bot,tmp)
{ {
if ( (relcoin= LP_coinfind(bot->rel)) != 0 ) if ( (relcoin= LP_coinfind(bot->rel)) != 0 )
LP_listunspent_issue(bot->rel,relcoin->smartaddr,1); LP_listunspent_issue(bot->rel,relcoin->smartaddr,1);
if ( bot->numpending > 0 && LP_numfinished > lastnumfinished ) if ( bot->relsum >= 0.99*bot->totalrelvolume-SMALLVAL || bot->basesum >= 0.99*bot->totalbasevolume-SMALLVAL )
bot->dead = (uint32_t)time(NULL);
else if ( (bot->pendrelsum+bot->relsum) >= 0.99*bot->totalrelvolume-SMALLVAL || (bot->basesum+bot->pendbasesum) >= 0.99*bot->totalbasevolume-SMALLVAL )
bot->pause = (uint32_t)time(NULL);
else if ( bot->userpause == 0 )
bot->pause = 0;
if ( bot->numpending == 0 && time(NULL) > bot->lasttime+TRADEBOTS_GAPTIME )
{ {
// expire pending trades and see if any still need their requestid/quoteid
for (i=0; i<bot->numtrades; i++)
{
if ( (tp= bot->trades[i]) != 0 && tp->finished == 0 )
{
if ( time(NULL) > tp->started+INSTANTDEX_LOCKTIME*2 )
{
bot->pendbasesum -= tp->basevol;
bot->pendrelsum -= tp->relvol;
bot->numpending--;
tp->finished = (uint32_t)time(NULL);
printf("%s trade.%d of %d expired\n",bot->name,i,bot->numtrades);
}
}
}
}
else if ( bot->numpending == 0 )
LP_tradebot_timeslice(ctx,bot); LP_tradebot_timeslice(ctx,bot);
bot->lasttime = (uint32_t)time(NULL);
}
} }
lastnumfinished = LP_numfinished; lastnumfinished = LP_numfinished;
} }
@ -402,9 +443,19 @@ char *LP_tradebot_list(void *ctx,int32_t pubsock,cJSON *argjson)
return(jprint(array,1)); return(jprint(array,1));
} }
char *LP_tradebot_statuslist(void *ctx,int32_t pubsock,cJSON *argjson)
{
struct LP_tradebot *bot,*tmp; cJSON *array = cJSON_CreateArray();
DL_FOREACH_SAFE(LP_tradebots,bot,tmp)
{
jaddi(array,LP_tradebot_json(bot));
}
return(jprint(array,1));
}
char *LP_tradebot_buy(int32_t dispdir,char *base,char *rel,double maxprice,double relvolume) char *LP_tradebot_buy(int32_t dispdir,char *base,char *rel,double maxprice,double relvolume)
{ {
struct LP_tradebot *bot; char *retstr; double shortfall; int32_t i,n; cJSON *array,*item,*retjson; uint64_t txfees,balance=0,abalance=0; struct iguana_info *basecoin,*relcoin; struct LP_tradebot *bot; char *retstr; double shortfall; int32_t i,n; cJSON *array,*item,*retjson; uint64_t sum,txfee,txfees,balance=0,abalance=0; struct iguana_info *basecoin,*relcoin;
basecoin = LP_coinfind(base); basecoin = LP_coinfind(base);
relcoin = LP_coinfind(rel); relcoin = LP_coinfind(rel);
if ( basecoin == 0 || relcoin == 0 || basecoin->inactive != 0 || relcoin->inactive != 0 ) if ( basecoin == 0 || relcoin == 0 || basecoin->inactive != 0 || relcoin->inactive != 0 )
@ -423,34 +474,40 @@ char *LP_tradebot_buy(int32_t dispdir,char *base,char *rel,double maxprice,doubl
} }
if ( (retstr= LP_orderbook(base,rel,0)) != 0 ) if ( (retstr= LP_orderbook(base,rel,0)) != 0 )
free(retstr); free(retstr);
txfees = 10 * relcoin->txfee; txfee = LP_txfeecalc(relcoin,0,0);
printf("%s inventory balance %.8f, relvolume %.8f + txfees %.8f\n",rel,dstr(abalance),relvolume,dstr(txfees)); txfees = 10 * txfee;
if ( dstr(abalance) < relvolume + dstr(txfees) ) if ( relcoin->electrum != 0 )
balance = LP_unspents_load(relcoin->symbol,relcoin->smartaddr);
else balance = LP_RTsmartbalance(relcoin);
sum = (relvolume+2*dstr(txfees)) + 3 * ((relvolume+2*dstr(txfees))/777);
printf("%s inventory balance %.8f, relvolume %.8f + txfees %.8f, utxobal %.8f sum %.8f\n",rel,dstr(abalance),relvolume,dstr(txfees),dstr(balance),dstr(sum));
if ( dstr(abalance) < relvolume + dstr(txfees) && balance > sum+txfee )
{ {
retjson = cJSON_CreateObject(); retjson = cJSON_CreateObject();
jaddstr(retjson,"error","not enough funds"); jaddstr(retjson,"error","not enough funds");
jaddstr(retjson,"coin",rel); jaddstr(retjson,"coin",rel);
jaddnum(retjson,"balance",dstr(abalance)); jaddnum(retjson,"abalance",dstr(abalance));
jaddnum(retjson,"balance",dstr(balance));
jaddnum(retjson,"relvolume",relvolume); jaddnum(retjson,"relvolume",relvolume);
jaddnum(retjson,"txfees",dstr(txfees)); jaddnum(retjson,"txfees",dstr(txfees));
shortfall = (relvolume + dstr(txfees)) - dstr(balance); shortfall = (relvolume + dstr(txfees)) - dstr(balance);
jaddnum(retjson,"shortfall",shortfall); jaddnum(retjson,"shortfall",shortfall);
if ( (balance= LP_RTsmartbalance(relcoin)) > abalance+SATOSHIDEN*(shortfall+relvolume/77.) ) if ( balance >= sum+txfee )
{ {
char *withdrawstr; cJSON *outputjson,*withdrawjson,*outputs,*item; char *withdrawstr; cJSON *outputjson,*withdrawjson,*outputs,*item;
outputjson = cJSON_CreateObject(); outputjson = cJSON_CreateObject();
outputs = cJSON_CreateArray(); outputs = cJSON_CreateArray();
item = cJSON_CreateObject(); item = cJSON_CreateObject();
jaddnum(item,relcoin->smartaddr,relvolume+dstr(txfees)); jaddnum(item,relcoin->smartaddr,relvolume+2*dstr(txfees));
jaddi(outputs,item); jaddi(outputs,item);
item = cJSON_CreateObject(); item = cJSON_CreateObject();
jaddnum(item,relcoin->smartaddr,(relvolume+dstr(txfees))/777); jaddnum(item,relcoin->smartaddr,(relvolume+2*dstr(txfees))/777);
jaddi(outputs,item); jaddi(outputs,item);
item = cJSON_CreateObject(); item = cJSON_CreateObject();
jaddnum(item,relcoin->smartaddr,(relvolume+dstr(txfees))/777); jaddnum(item,relcoin->smartaddr,(relvolume+2*dstr(txfees))/777);
jaddi(outputs,item); jaddi(outputs,item);
item = cJSON_CreateObject(); item = cJSON_CreateObject();
jaddnum(item,relcoin->smartaddr,(relvolume+dstr(txfees))/777); jaddnum(item,relcoin->smartaddr,(relvolume+2*dstr(txfees))/777);
jaddi(outputs,item); jaddi(outputs,item);
jadd(outputjson,"outputs",outputs); jadd(outputjson,"outputs",outputs);
if ( (withdrawstr= LP_withdraw(relcoin,outputjson)) != 0 ) if ( (withdrawstr= LP_withdraw(relcoin,outputjson)) != 0 )
@ -571,7 +628,7 @@ char *LP_tradebot_pause(void *ctx,int32_t pubsock,cJSON *argjson,uint32_t botid)
{ {
if ( bot->dead != 0 ) if ( bot->dead != 0 )
return(clonestr("{\"error\":\"botid aleady stopped\"}")); return(clonestr("{\"error\":\"botid aleady stopped\"}"));
bot->pause = (uint32_t)time(NULL); bot->userpause = (uint32_t)time(NULL);
return(clonestr("{\"result\":\"success\"}")); return(clonestr("{\"result\":\"success\"}"));
} }
return(clonestr("{\"error\":\"couldnt find botid\"}")); return(clonestr("{\"error\":\"couldnt find botid\"}"));
@ -584,9 +641,9 @@ char *LP_tradebot_resume(void *ctx,int32_t pubsock,cJSON *argjson,uint32_t botid
{ {
if ( bot->dead != 0 ) if ( bot->dead != 0 )
return(clonestr("{\"error\":\"botid aleady stopped\"}")); return(clonestr("{\"error\":\"botid aleady stopped\"}"));
if ( bot->pause == 0 ) if ( bot->userpause == 0 )
return(clonestr("{\"result\":\"success\",\"status\":\"botid not paused\"}")); return(clonestr("{\"result\":\"success\",\"status\":\"botid not paused\"}"));
bot->pause = 0; bot->userpause = 0;
return(clonestr("{\"result\":\"success\"}")); return(clonestr("{\"result\":\"success\"}"));
} }
return(clonestr("{\"error\":\"couldnt find botid\"}")); return(clonestr("{\"error\":\"couldnt find botid\"}"));
@ -595,10 +652,13 @@ char *LP_tradebot_resume(void *ctx,int32_t pubsock,cJSON *argjson,uint32_t botid
char *LP_istradebots_command(void *ctx,int32_t pubsock,char *method,cJSON *argjson) char *LP_istradebots_command(void *ctx,int32_t pubsock,char *method,cJSON *argjson)
{ {
uint32_t botid; uint32_t botid;
//printf("LP_istradebots_command check %s\n",method);
if ( strncmp("bot_",method,strlen("bot_")) != 0 ) if ( strncmp("bot_",method,strlen("bot_")) != 0 )
return(0); return(0);
if ( strcmp(method,"bot_list") == 0 ) if ( strcmp(method,"bot_list") == 0 )
return(LP_tradebot_list(ctx,pubsock,argjson)); return(LP_tradebot_list(ctx,pubsock,argjson));
else if ( strcmp(method,"bot_statuslist") == 0 )
return(LP_tradebot_statuslist(ctx,pubsock,argjson));
else if ( strcmp(method,"bot_buy") == 0 ) else if ( strcmp(method,"bot_buy") == 0 )
return(LP_tradebot_limitbuy(ctx,pubsock,argjson)); return(LP_tradebot_limitbuy(ctx,pubsock,argjson));
else if ( strcmp(method,"bot_sell") == 0 ) else if ( strcmp(method,"bot_sell") == 0 )

256
iguana/exchanges/LP_transaction.c

@ -247,7 +247,10 @@ int32_t iguana_msgtx_Vset(uint8_t *serialized,int32_t maxlen,struct iguana_msgtx
int32_t iguana_interpreter(struct iguana_info *coin,cJSON *logarray,int64_t nLockTime,struct vin_info *V,int32_t numvins) int32_t iguana_interpreter(struct iguana_info *coin,cJSON *logarray,int64_t nLockTime,struct vin_info *V,int32_t numvins)
{ {
uint8_t script[IGUANA_MAXSCRIPTSIZE],*activescript,savescript[IGUANA_MAXSCRIPTSIZE]; char str[IGUANA_MAXSCRIPTSIZE*2+1]; int32_t vini,scriptlen,activescriptlen,savelen,errs = 0; cJSON *spendscript,*item=0; uint8_t *script,*activescript,*savescript; char *str; int32_t vini,scriptlen,activescriptlen,savelen,errs = 0; cJSON *spendscript,*item=0;
script = calloc(1,IGUANA_MAXSCRIPTSIZE);
savescript = calloc(1,IGUANA_MAXSCRIPTSIZE);
str = calloc(1,IGUANA_MAXSCRIPTSIZE*2+1);
for (vini=0; vini<numvins; vini++) for (vini=0; vini<numvins; vini++)
{ {
savelen = V[vini].spendlen; savelen = V[vini].spendlen;
@ -297,6 +300,9 @@ int32_t iguana_interpreter(struct iguana_info *coin,cJSON *logarray,int64_t nLoc
memcpy(V[vini].spendscript,savescript,savelen); memcpy(V[vini].spendscript,savescript,savelen);
V[vini].spendlen = savelen; V[vini].spendlen = savelen;
} }
free(str);
free(script);
free(savescript);
if ( errs != 0 ) if ( errs != 0 )
return(-errs); return(-errs);
if ( logarray != 0 ) if ( logarray != 0 )
@ -475,7 +481,7 @@ int64_t iguana_lockval(int32_t finalized,int64_t locktime)
int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t wiftaddr,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,struct iguana_msgtx *msgtx,char **signedtxp,bits256 *signedtxidp,struct vin_info *V,int32_t numinputs,char *rawtx,cJSON *vins,cJSON *privkeysjson,int32_t zcash) int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t wiftaddr,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,int32_t height,struct iguana_msgtx *msgtx,char **signedtxp,bits256 *signedtxidp,struct vin_info *V,int32_t numinputs,char *rawtx,cJSON *vins,cJSON *privkeysjson,int32_t zcash)
{ {
uint8_t *serialized,*serialized2,*serialized3,*serialized4,*extraspace,pubkeys[64][33]; int32_t finalized,i,len,n,z,plen,maxsize,complete = 0,extralen = 100000; char *privkeystr,*signedtx = 0; bits256 privkeys[64],privkey,txid; cJSON *item; cJSON *txobj = 0; uint8_t *serialized,*serialized2,*serialized3,*serialized4,*extraspace,pubkeys[64][33]; int32_t finalized,i,len,n,z,plen,maxsize,complete = 0,extralen = 100000; char *privkeystr,*signedtx = 0; bits256 privkeys[LP_MAXVINS],privkey,txid; cJSON *item; cJSON *txobj = 0;
maxsize = 1000000; maxsize = 1000000;
memset(privkey.bytes,0,sizeof(privkey)); memset(privkey.bytes,0,sizeof(privkey));
if ( rawtx != 0 && rawtx[0] != 0 && (len= (int32_t)strlen(rawtx)>>1) < maxsize ) if ( rawtx != 0 && rawtx[0] != 0 && (len= (int32_t)strlen(rawtx)>>1) < maxsize )
@ -605,7 +611,7 @@ int32_t iguana_signrawtransaction(void *ctx,char *symbol,uint8_t wiftaddr,uint8_
char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t wiftaddr,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t utxovout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr,int32_t suppress_pubkeys,int32_t zcash) char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,char *symbol,uint8_t wiftaddr,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,void *ctx,bits256 privkey,bits256 *privkey2p,uint8_t *redeemscript,int32_t redeemlen,uint8_t *userdata,int32_t userdatalen,bits256 utxotxid,int32_t utxovout,char *destaddr,uint8_t *pubkey33,int32_t finalseqid,uint32_t expiration,int64_t *destamountp,uint64_t satoshis,char *changeaddr,char *vinaddr,int32_t suppress_pubkeys,int32_t zcash)
{ {
char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*obj,*vouts,*item,*privkeys; int32_t completed,spendlen,n,ignore_cltverr=1; struct vin_info V[2]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value=0,change = 0; struct iguana_msgtx msgtx; struct iguana_info *coin; char *rawtxbytes=0,*signedtx=0,str[65],tmpaddr[64],hexstr[999],wifstr[128],_destaddr[64]; uint8_t spendscript[512],addrtype,rmd160[20]; cJSON *txobj,*vins,*obj,*vouts,*item,*privkeys; int32_t completed,spendlen,n,ignore_cltverr=1; struct vin_info V[8]; uint32_t timestamp,locktime = 0,sequenceid = 0xffffffff * finalseqid; bits256 txid; uint64_t value=0,change = 0; struct iguana_msgtx msgtx; struct iguana_info *coin;
LP_mark_spent(symbol,utxotxid,utxovout); LP_mark_spent(symbol,utxotxid,utxovout);
if ( txfee > 0 && txfee < 10000 ) if ( txfee > 0 && txfee < 10000 )
txfee = 10000; txfee = 10000;
@ -617,9 +623,9 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch
if ( redeemlen < 0 ) if ( redeemlen < 0 )
return(0); return(0);
value = 0; value = 0;
#ifndef BASILISK_DISABLESENDTX
if ( (coin= LP_coinfind(symbol)) != 0 ) if ( (coin= LP_coinfind(symbol)) != 0 )
{ {
#ifndef BASILISK_DISABLESENDTX
if ( (txobj= LP_gettx(symbol,utxotxid)) != 0 ) if ( (txobj= LP_gettx(symbol,utxotxid)) != 0 )
{ {
if ( (vouts= jarray(&n,txobj,"vout")) != 0 && utxovout < n ) if ( (vouts= jarray(&n,txobj,"vout")) != 0 && utxovout < n )
@ -629,16 +635,14 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch
//printf("value in vout.%d %.8f (%s)\n",vout,dstr(value),jprint(txobj,0)); //printf("value in vout.%d %.8f (%s)\n",vout,dstr(value),jprint(txobj,0));
} }
free_json(txobj); free_json(txobj);
//if ( value != 0 )
// gettxout
} else printf("cant gettx\n"); } else printf("cant gettx\n");
if ( value == 0 ) if ( value == 0 )
{ {
printf("basilisk_swap_bobtxspend.%s %s utxo.(%s).v%d already spent or doesnt exist\n",name,symbol,bits256_str(str,utxotxid),utxovout); printf("basilisk_swap_bobtxspend.%s %s utxo.(%s).v%d already spent or doesnt exist\n",name,symbol,bits256_str(str,utxotxid),utxovout);
return(0); return(0);
} }
}
#endif #endif
}
if ( satoshis != 0 ) if ( satoshis != 0 )
{ {
if ( value < satoshis+txfee ) if ( value < satoshis+txfee )
@ -648,7 +652,7 @@ char *basilisk_swap_bobtxspend(bits256 *signedtxidp,uint64_t txfee,char *name,ch
satoshis = value - 3*txfee/4; satoshis = value - 3*txfee/4;
printf("reduce satoshis %.8f by txfee %.8f to value %.8f\n",dstr(satoshis),dstr(txfee),dstr(value)); printf("reduce satoshis %.8f by txfee %.8f to value %.8f\n",dstr(satoshis),dstr(txfee),dstr(value));
} }
else if ( value == satoshis && (double)txfee/value < 0.001 ) else if ( value == satoshis && (double)txfee/value < 0.25 )
{ {
satoshis = value - txfee; satoshis = value - txfee;
printf("txfee allocation from value %.8f identical to satoshis: %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(txfee)); printf("txfee allocation from value %.8f identical to satoshis: %.8f txfee %.8f\n",dstr(value),dstr(satoshis),dstr(txfee));
@ -854,44 +858,127 @@ int64_t LP_komodo_interest(bits256 txid,int64_t value)
return(interest); return(interest);
} }
int32_t LP_vins_select(void *ctx,struct iguana_info *coin,int64_t *totalp,int64_t amount,struct vin_info *V,struct LP_address_utxo **utxos,int32_t numunspents,int32_t suppress_pubkeys,int32_t ignore_cltverr,bits256 privkey,cJSON *privkeys,cJSON *vins,uint8_t *script,int32_t scriptlen) int32_t LP_vins_select(void *ctx,struct iguana_info *coin,int64_t *totalp,int64_t amount,struct vin_info *V,struct LP_address_utxo **utxos,int32_t numunspents,int32_t suppress_pubkeys,int32_t ignore_cltverr,bits256 privkey,cJSON *privkeys,cJSON *vins,uint8_t *script,int32_t scriptlen,bits256 utxotxid,int32_t utxovout,int32_t dustcombine)
{ {
char wifstr[128],spendscriptstr[128]; int32_t i,n,ind,abovei,belowi,maxmode=0; struct vin_info *vp; struct LP_address_utxo *up; int64_t interest,interestsum,above,below,remains = amount,total = 0; char wifstr[128],spendscriptstr[128],str[65]; int32_t i,j,maxiters,n,numpre,ind,abovei,belowi,maxmode=0; struct vin_info *vp; cJSON *txobj; struct LP_address_utxo *up,*min0,*min1,*preselected[3]; int64_t value,interest,interestsum,above,below,remains = amount,total = 0;
*totalp = 0; *totalp = 0;
interestsum = 0; interestsum = 0;
init_hexbytes_noT(spendscriptstr,script,scriptlen); init_hexbytes_noT(spendscriptstr,script,scriptlen);
bitcoin_priv2wif(coin->wiftaddr,wifstr,privkey,coin->wiftype); bitcoin_priv2wif(coin->wiftaddr,wifstr,privkey,coin->wiftype);
for (i=n=0; i<numunspents; i++) n = 0;
min0 = min1 = 0;
memset(preselected,0,sizeof(preselected));
for (j=numpre=0; j<numunspents; j++)
{ {
//printf("vinselect.%d of %d: remain %.8f amount %.8f\n",i,numunspents,dstr(remains),dstr(amount)); up = utxos[j];
below = above = 0; if ( utxovout == up->U.vout && bits256_cmp(utxotxid,up->U.txid) == 0 )
abovei = belowi = -1;
if ( LP_vin_select(&abovei,&above,&belowi,&below,utxos,numunspents,remains,maxmode) < 0 )
{ {
printf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,numunspents,dstr(remains),dstr(amount)); preselected[numpre++] = up;
return(0); printf("found utxotxid in slot.%d\n",j);
utxos[j] = 0;
continue;
} }
if ( belowi < 0 || abovei >= 0 ) if ( up->spendheight <= 0 && up->U.height > 0 && up->U.value != 0 )
ind = abovei;
else ind = belowi;
if ( ind < 0 )
{ {
printf("error finding unspent i.%d of %d, %.8f vs %.8f, abovei.%d belowi.%d ind.%d\n",i,numunspents,dstr(remains),dstr(amount),abovei,belowi,ind); if ( (txobj= LP_gettxout(coin->symbol,coin->smartaddr,up->U.txid,up->U.vout)) == 0 )
{
up->spendheight = 1;
utxos[j] = 0;
}
else
{
if ( LP_inventory_prevent(1,coin->symbol,up->U.txid,up->U.vout) == 0 )
{
if ( min1 == 0 || up->U.value < min1->U.value )
{
if ( min0 == 0 || up->U.value < min0->U.value )
{
min1 = min0;
min0 = up;
} else min1 = up;
}
} else utxos[j] = 0;
if ( 0 && utxos[j] != 0 )
printf("gettxout j.%d %s/v%d (%s)\n",j,bits256_str(str,up->U.txid),up->U.vout,jprint(txobj,0));
free_json(txobj);
}
} else utxos[j] = 0;
}
if ( bits256_nonz(utxotxid) != 0 && numpre == 0 )
{
up = LP_address_utxofind(coin,coin->smartaddr,utxotxid,utxovout);
printf("have utxotxid but wasnt found up.%p\n",up);
if ( up == 0 )
{
value = LP_txvalue(coin->smartaddr,coin->symbol,utxotxid,utxovout);
LP_address_utxoadd("withdraw",coin,coin->smartaddr,utxotxid,utxovout,value,1,-1);
printf("added after not finding\n");
}
if ( (up= LP_address_utxofind(coin,coin->smartaddr,utxotxid,utxovout)) != 0 )
preselected[numpre++] = up;
else
{
printf("couldnt add address_utxo after not finding\n");
return(0); return(0);
} }
up = utxos[ind]; }
utxos[ind] = utxos[--numunspents]; if ( dustcombine >= 1 && min0 != 0 && min0->U.value < LP_DUSTCOMBINE_THRESHOLD && (coin->electrum == 0 || min0->SPV > 0) )
utxos[numunspents] = 0; preselected[numpre++] = min0;
else min0 = 0;
if ( dustcombine >= 2 && min1 != 0 && min1->U.value < LP_DUSTCOMBINE_THRESHOLD && (coin->electrum == 0 || min1->SPV > 0) )
preselected[numpre++] = min1;
else min1 = 0;
printf("dustcombine.%d numpre.%d min0.%p min1.%p numutxos.%d amount %.8f\n",dustcombine,numpre,min0,min1,numunspents,dstr(amount));
maxiters = numunspents+numpre;
for (i=0; i<maxiters; i++)
{
if ( i < numpre )
{
up = preselected[i];
char str[65]; printf("preselected[%d]: %s/v%d %.8f\n",i,bits256_str(str,up->U.txid),up->U.vout,dstr(up->U.value));
}
else
{
below = above = 0;
abovei = belowi = -1;
if ( LP_vin_select(&abovei,&above,&belowi,&below,utxos,numunspents,remains,maxmode) < 0 )
{
printf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,numunspents,dstr(remains),dstr(amount));
return(0);
}
if ( belowi < 0 || abovei >= 0 )
ind = abovei;
else ind = belowi;
if ( ind < 0 )
{
printf("error finding unspent i.%d of %d, %.8f vs %.8f, abovei.%d belowi.%d ind.%d\n",i,numunspents,dstr(remains),dstr(amount),abovei,belowi,ind);
return(0);
}
up = utxos[ind];
utxos[ind] = utxos[--numunspents];
utxos[numunspents] = 0;
for (j=0; j<numpre; j++)
if ( up == preselected[j] )
break;
if ( j < numpre )
continue;
if ( LP_validSPV(coin->symbol,coin->smartaddr,up->U.txid,up->U.vout) < 0 )
continue;
}
up->spendheight = 1;
total += up->U.value; total += up->U.value;
remains -= up->U.value; remains -= up->U.value;
interest = 0;
if ( up->U.height < 7777777 && strcmp(coin->symbol,"KMD") == 0 ) if ( up->U.height < 7777777 && strcmp(coin->symbol,"KMD") == 0 )
{ {
if ( (interest= LP_komodo_interest(up->U.txid,up->U.value)) > 0 ) if ( 0 && (interest= LP_komodo_interest(up->U.txid,up->U.value)) > 0 )
{ {
interestsum += interest; interestsum += interest;
char str[65]; printf("%s/%d %.8f interest %.8f -> sum %.8f\n",bits256_str(str,up->U.txid),up->U.vout,dstr(up->U.value),dstr(interest),dstr(interestsum)); char str[65]; printf("%s/%d %.8f interest %.8f -> sum %.8f\n",bits256_str(str,up->U.txid),up->U.vout,dstr(up->U.value),dstr(interest),dstr(interestsum));
} }
} }
printf("numunspents.%d vini.%d value %.8f, total %.8f remains %.8f interest %.8f sum %.8f\n",numunspents,n,dstr(up->U.value),dstr(total),dstr(remains),dstr(interest),dstr(interestsum));
vp = &V[n++]; vp = &V[n++];
vp->N = vp->M = 1; vp->N = vp->M = 1;
vp->signers[0].privkey = privkey; vp->signers[0].privkey = privkey;
@ -900,9 +987,7 @@ int32_t LP_vins_select(void *ctx,struct iguana_info *coin,int64_t *totalp,int64_
vp->suppress_pubkeys = suppress_pubkeys; vp->suppress_pubkeys = suppress_pubkeys;
vp->ignore_cltverr = ignore_cltverr; vp->ignore_cltverr = ignore_cltverr;
jaddi(vins,LP_inputjson(up->U.txid,up->U.vout,spendscriptstr)); jaddi(vins,LP_inputjson(up->U.txid,up->U.vout,spendscriptstr));
//printf("wif.%s i.%d privkeys.%s vins.%s %p %p\n",wifstr,i,jprint(privkeys,0),jprint(vins,0),privkeys,vins); if ( remains <= 0 && i >= numpre-1 )
//printf("%s value %.8f -> remains %.8f\n",coinaddr,dstr(value),dstr(remains));
if ( remains <= 0 )
break; break;
if ( numunspents == 0 ) if ( numunspents == 0 )
{ {
@ -914,10 +999,10 @@ int32_t LP_vins_select(void *ctx,struct iguana_info *coin,int64_t *totalp,int64_
return(n); return(n);
} }
char *LP_createrawtransaction(cJSON **txobjp,int32_t *numvinsp,struct iguana_info *coin,struct vin_info *V,int32_t max,bits256 privkey,cJSON *outputs,cJSON *vins,cJSON *privkeys,int64_t txfee) char *LP_createrawtransaction(cJSON **txobjp,int32_t *numvinsp,struct iguana_info *coin,struct vin_info *V,int32_t max,bits256 privkey,cJSON *outputs,cJSON *vins,cJSON *privkeys,int64_t txfee,bits256 utxotxid,int32_t utxovout,uint32_t locktime)
{ {
static void *ctx; static void *ctx;
cJSON *txobj,*item; uint8_t addrtype,rmd160[20],script[64],spendscript[64]; char *coinaddr,*rawtxbytes; bits256 txid; uint32_t timestamp,locktime; int64_t change=0,adjust=0,total,value,amount = 0; int32_t i,scriptlen,spendlen,suppress_pubkeys,ignore_cltverr,numvouts=0,numvins=0,numutxos=0; struct LP_address_utxo *utxos[256]; struct LP_address *ap; cJSON *txobj,*item; uint8_t addrtype,rmd160[20],script[64],spendscript[256]; char *coinaddr,*rawtxbytes; bits256 txid; uint32_t timestamp; int64_t change=0,adjust=0,total,value,amount = 0; int32_t i,dustcombine,scriptlen,spendlen,suppress_pubkeys,ignore_cltverr,numvouts=0,numvins=0,numutxos=0; struct LP_address_utxo *utxos[LP_MAXVINS]; struct LP_address *ap;
if ( ctx == 0 ) if ( ctx == 0 )
ctx = bitcoin_ctx(); ctx = bitcoin_ctx();
*numvinsp = 0; *numvinsp = 0;
@ -932,6 +1017,11 @@ char *LP_createrawtransaction(cJSON **txobjp,int32_t *numvinsp,struct iguana_inf
printf("LP_createrawtransaction: illegal coin.%p outputs.%p or arraysize.%d, error\n",coin,outputs,numvouts); printf("LP_createrawtransaction: illegal coin.%p outputs.%p or arraysize.%d, error\n",coin,outputs,numvouts);
return(0); return(0);
} }
if ( coin->numutxos < LP_MINDESIRED_UTXOS )
dustcombine = 0;
else if ( coin->numutxos >= LP_MINDESIRED_UTXOS )
dustcombine = 2;
else dustcombine = 1;
amount = txfee; amount = txfee;
for (i=0; i<numvouts; i++) for (i=0; i<numvouts; i++)
{ {
@ -949,6 +1039,7 @@ char *LP_createrawtransaction(cJSON **txobjp,int32_t *numvinsp,struct iguana_inf
return(0); return(0);
} }
amount += value; amount += value;
printf("vout.%d %.8f -> total %.8f\n",i,dstr(value),dstr(amount));
} }
else else
{ {
@ -966,23 +1057,22 @@ char *LP_createrawtransaction(cJSON **txobjp,int32_t *numvinsp,struct iguana_inf
if ( (numutxos= LP_address_utxo_ptrs(coin,0,utxos,max,ap,coin->smartaddr)) <= 0 ) if ( (numutxos= LP_address_utxo_ptrs(coin,0,utxos,max,ap,coin->smartaddr)) <= 0 )
{ {
printf("LP_createrawtransaction: address_utxo_ptrs %d, error\n",numutxos); printf("LP_createrawtransaction: address_utxo_ptrs %d, error\n",numutxos);
return(0); //return(0);
} }
ignore_cltverr = 0; ignore_cltverr = 0;
suppress_pubkeys = 1; suppress_pubkeys = 1;
scriptlen = bitcoin_standardspend(script,0,G.LP_myrmd160); scriptlen = bitcoin_standardspend(script,0,G.LP_myrmd160);
numvins = LP_vins_select(ctx,coin,&total,amount,V,utxos,numutxos,suppress_pubkeys,ignore_cltverr,privkey,privkeys,vins,script,scriptlen); numvins = LP_vins_select(ctx,coin,&total,amount,V,utxos,numutxos,suppress_pubkeys,ignore_cltverr,privkey,privkeys,vins,script,scriptlen,utxotxid,utxovout,dustcombine);
if ( total < amount ) if ( numvins <= 0 || total < amount )
{ {
printf("change %.8f = total %.8f - amount %.8f, adjust %.8f numvouts.%d, txfee %.8f\n",dstr(change),dstr(total),dstr(amount),dstr(adjust),numvouts,dstr(txfee)); printf("change %.8f = total %.8f - amount %.8f, adjust %.8f numvouts.%d, txfee %.8f\n",dstr(change),dstr(total),dstr(amount),dstr(adjust),numvouts,dstr(txfee));
printf("not enough inputs for amount %.8f < %.8f txfee %.8f\n",dstr(total),dstr(amount),dstr(txfee)); printf("not enough inputs %.8f < for amount %.8f txfee %.8f\n",dstr(total),dstr(amount),dstr(txfee));
return(0); return(0);
} }
change = (total - amount); change = (total - amount);
timestamp = (uint32_t)time(NULL); timestamp = (uint32_t)time(NULL);
if ( strcmp("KMD",coin->symbol) == 0 ) if ( locktime == 0 && strcmp("KMD",coin->symbol) == 0 )
locktime = timestamp - 777; locktime = timestamp - 777;
else locktime = 0;
txobj = bitcoin_txcreate(coin->symbol,coin->isPoS,locktime,1,timestamp); txobj = bitcoin_txcreate(coin->symbol,coin->isPoS,locktime,1,timestamp);
jdelete(txobj,"vin"); jdelete(txobj,"vin");
jadd(txobj,"vin",jduplicate(vins)); jadd(txobj,"vin",jduplicate(vins));
@ -1003,7 +1093,9 @@ char *LP_createrawtransaction(cJSON **txobjp,int32_t *numvinsp,struct iguana_inf
return(0); return(0);
} }
bitcoin_addr2rmd160(coin->taddr,&addrtype,rmd160,coinaddr); bitcoin_addr2rmd160(coin->taddr,&addrtype,rmd160,coinaddr);
spendlen = bitcoin_standardspend(spendscript,0,rmd160); if ( addrtype == coin->pubtype )
spendlen = bitcoin_standardspend(spendscript,0,rmd160);
else spendlen = bitcoin_p2shspend(spendscript,0,rmd160);
txobj = bitcoin_txoutput(txobj,spendscript,spendlen,value + adjust); txobj = bitcoin_txoutput(txobj,spendscript,spendlen,value + adjust);
} }
else else
@ -1024,30 +1116,39 @@ char *LP_createrawtransaction(cJSON **txobjp,int32_t *numvinsp,struct iguana_inf
char *LP_withdraw(struct iguana_info *coin,cJSON *argjson) char *LP_withdraw(struct iguana_info *coin,cJSON *argjson)
{ {
static void *ctx; static void *ctx;
int32_t iter,completed=0,maxV,numvins,numvouts,datalen,suppress_pubkeys; bits256 privkey; char changeaddr[64],vinaddr[64],str[65],*signedtx=0,*rawtx=0; struct vin_info *V; cJSON *retjson,*outputs,*vins=0,*txobj=0,*privkeys=0; struct iguana_msgtx msgtx; bits256 signedtxid; uint64_t txfee,newtxfee=10000; int32_t iter,utxovout,autofee,completed=0,maxV,numvins,numvouts,datalen,suppress_pubkeys; bits256 privkey; char changeaddr[64],vinaddr[64],str[65],*signedtx=0,*rawtx=0; struct vin_info *V; uint32_t locktime; cJSON *retjson,*outputs,*vins=0,*txobj=0,*privkeys=0; struct iguana_msgtx msgtx; bits256 utxotxid,signedtxid; uint64_t txfee,newtxfee=10000;
if ( ctx == 0 )
ctx = bitcoin_ctx();
if ( (outputs= jarray(&numvouts,argjson,"outputs")) == 0 ) if ( (outputs= jarray(&numvouts,argjson,"outputs")) == 0 )
{ {
printf("no outputs in argjson (%s)\n",jprint(argjson,0)); printf("no outputs in argjson (%s)\n",jprint(argjson,0));
return(clonestr("{\"error\":\"no outputs specified\"}")); return(clonestr("{\"error\":\"no outputs specified\"}"));
} }
txfee = coin->txfee; utxotxid = jbits256(argjson,"utxotxid");
if ( ctx == 0 ) utxovout = jint(argjson,"utxovout");
ctx = bitcoin_ctx(); locktime = juint(argjson,"locktime");
if ( txfee > 0 && txfee < 10000 ) txfee = juint(argjson,"txfee");
txfee = 10000; autofee = (strcmp(coin->symbol,"BTC") == 0);
if ( txfee == 0 )
{
autofee = 1;
txfee = coin->txfee;
if ( txfee > 0 && txfee < 10000 )
txfee = 10000;
} else autofee = 0;
suppress_pubkeys = 0; suppress_pubkeys = 0;
memset(signedtxid.bytes,0,sizeof(signedtxid)); memset(signedtxid.bytes,0,sizeof(signedtxid));
safecopy(changeaddr,coin->smartaddr,sizeof(changeaddr)); safecopy(changeaddr,coin->smartaddr,sizeof(changeaddr));
safecopy(vinaddr,coin->smartaddr,sizeof(vinaddr)); safecopy(vinaddr,coin->smartaddr,sizeof(vinaddr));
privkey = LP_privkey(vinaddr,coin->taddr); privkey = LP_privkey(vinaddr,coin->taddr);
maxV = 256; maxV = LP_MAXVINS;
V = malloc(maxV * sizeof(*V)); V = malloc(maxV * sizeof(*V));
for (iter=0; iter<2; iter++) for (iter=0; iter<2; iter++)
{ {
privkeys = cJSON_CreateArray(); privkeys = cJSON_CreateArray();
vins = cJSON_CreateArray(); vins = cJSON_CreateArray();
memset(V,0,sizeof(*V) * maxV); memset(V,0,sizeof(*V) * maxV);
if ( (rawtx= LP_createrawtransaction(&txobj,&numvins,coin,V,maxV,privkey,outputs,vins,privkeys,iter == 0 ? txfee : newtxfee)) != 0 ) if ( (rawtx= LP_createrawtransaction(&txobj,&numvins,coin,V,maxV,privkey,outputs,vins,privkeys,iter == 0 ? txfee : newtxfee,utxotxid,utxovout,locktime)) != 0 )
{ {
completed = 0; completed = 0;
memset(&msgtx,0,sizeof(msgtx)); memset(&msgtx,0,sizeof(msgtx));
@ -1094,6 +1195,43 @@ char *LP_withdraw(struct iguana_info *coin,cJSON *argjson)
int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160,char *vinaddr) int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pubkey33,int32_t iambob,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf,int32_t delay,bits256 privkey,uint8_t *changermd160,char *vinaddr)
{ {
struct iguana_info *coin; int32_t len,retval=-1; char *retstr,*hexstr; cJSON *argjson,*outputs,*item,*retjson,*obj;
if ( (coin= rawtx->coin) == 0 )
return(-1);
if ( strcmp(coin->smartaddr,vinaddr) != 0 )
{
printf("basilisk_rawtx_gen mismatched vinaddr.%s != %s\n",vinaddr,coin->smartaddr);
return(-1);
}
argjson = cJSON_CreateObject();
jaddbits256(argjson,"utxotxid",rawtx->utxotxid);
jaddnum(argjson,"utxovout",rawtx->utxovout);
jaddnum(argjson,"locktime",locktime);
jadd64bits(argjson,"txfee",txfee);
outputs = cJSON_CreateArray();
item = cJSON_CreateObject();
jaddnum(item,rawtx->I.destaddr,dstr(rawtx->I.amount));
jaddi(outputs,item);
jadd(argjson,"outputs",outputs);
if ( (retstr= LP_withdraw(coin,argjson)) != 0 )
{
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (obj= jobj(retjson,"complete")) != 0 && is_cJSON_True(obj) != 0 && (hexstr= jstr(retjson,"hex")) != 0 && (len= is_hexstr(hexstr,0)) > 16 )
{
rawtx->I.datalen = len >> 1;
decode_hex(rawtx->txbytes,rawtx->I.datalen,hexstr);
rawtx->I.completed = 1;
rawtx->I.signedtxid = jbits256(retjson,"txid");
retval = 0;
}
free_json(retjson);
}
free(retstr);
}
free_json(argjson);
return(retval);
#ifdef old
int32_t retval=-1,iter; char *signedtx,*changeaddr = 0,_changeaddr[64]; struct iguana_info *coin; int64_t newtxfee=0,destamount; int32_t retval=-1,iter; char *signedtx,*changeaddr = 0,_changeaddr[64]; struct iguana_info *coin; int64_t newtxfee=0,destamount;
char str2[65]; printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str2,rawtx->utxotxid),rawtx->utxovout); char str2[65]; printf("%s rawtxgen.(%s/v%d)\n",rawtx->name,bits256_str(str2,rawtx->utxotxid),rawtx->utxovout);
if ( (coin= rawtx->coin) == 0 ) if ( (coin= rawtx->coin) == 0 )
@ -1128,6 +1266,7 @@ int32_t basilisk_rawtx_gen(void *ctx,char *str,uint32_t swapstarted,uint8_t *pub
break; break;
} }
return(retval); return(retval);
#endif
} }
int32_t basilisk_rawtx_sign(char *symbol,uint8_t wiftaddr,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160,char *vinaddr,int32_t zcash) int32_t basilisk_rawtx_sign(char *symbol,uint8_t wiftaddr,uint8_t taddr,uint8_t pubtype,uint8_t p2shtype,uint8_t isPoS,uint8_t wiftype,struct basilisk_swap *swap,struct basilisk_rawtx *dest,struct basilisk_rawtx *rawtx,bits256 privkey,bits256 *privkey2,uint8_t *userdata,int32_t userdatalen,int32_t ignore_cltverr,uint8_t *changermd160,char *vinaddr,int32_t zcash)
@ -1195,19 +1334,11 @@ char *basilisk_swap_Aspend(char *name,char *symbol,uint64_t Atxfee,uint8_t wifta
//printf("pubAm.(%s)\n",bits256_str(str,pubAm)); //printf("pubAm.(%s)\n",bits256_str(str,pubAm));
//printf("pubBn.(%s)\n",bits256_str(str,pubBn)); //printf("pubBn.(%s)\n",bits256_str(str,pubBn));
spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,taddr,p2shtype,pubAm,pubBn); spendlen = basilisk_alicescript(redeemscript,&redeemlen,spendscript,0,msigaddr,taddr,p2shtype,pubAm,pubBn);
//char str[65]; printf("%s utxo.(%s) redeemlen.%d spendlen.%d\n",msigaddr,bits256_str(str,utxotxid),redeemlen,spendlen);
/*rev = privAm;
for (i=0; i<32; i++)
privAm.bytes[i] = rev.bytes[31 - i];
rev = privBn;
for (i=0; i<32; i++)
privBn.bytes[i] = rev.bytes[31 - i];*/
if ( (txfee= Atxfee) == 0 ) if ( (txfee= Atxfee) == 0 )
{ {
if ( (txfee= LP_getestimatedrate(LP_coinfind(symbol)) * LP_AVETXSIZE) < LP_MIN_TXFEE ) if ( (txfee= LP_getestimatedrate(LP_coinfind(symbol)) * LP_AVETXSIZE) < LP_MIN_TXFEE )
txfee = LP_MIN_TXFEE; txfee = LP_MIN_TXFEE;
} }
//txfee = LP_txfee(symbol);
signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,wiftaddr,taddr,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,utxovout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr,1,zcash); signedtx = basilisk_swap_bobtxspend(&signedtxid,txfee,name,symbol,wiftaddr,taddr,pubtype,p2shtype,isPoS,wiftype,ctx,privAm,&privBn,redeemscript,redeemlen,0,0,utxotxid,utxovout,0,pubkey33,1,expiration,destamountp,0,0,vinaddr,1,zcash);
LP_mark_spent(symbol,utxotxid,utxovout); LP_mark_spent(symbol,utxotxid,utxovout);
} }
@ -1627,12 +1758,6 @@ void basilisk_alicepayment(struct basilisk_swap *swap,struct iguana_info *coin,s
{ {
char coinaddr[64]; char coinaddr[64];
alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->taddr,coin->p2shtype,pubAm,pubBn); alicepayment->I.spendlen = basilisk_alicescript(alicepayment->redeemscript,&alicepayment->I.redeemlen,alicepayment->spendscript,0,alicepayment->I.destaddr,coin->taddr,coin->p2shtype,pubAm,pubBn);
/*for (i=0; i<33; i++)
printf("%02x",swap->persistent_pubkey33[i]);
printf(" pubkey33, ");
for (i=0; i<20; i++)
printf("%02x",swap->changermd160[i]);
printf(" rmd160, ");*/
bitcoin_address(coinaddr,coin->taddr,coin->pubtype,swap->changermd160,20); bitcoin_address(coinaddr,coin->taddr,coin->pubtype,swap->changermd160,20);
//printf("%s suppress.%d fee.%d\n",coinaddr,alicepayment->I.suppress_pubkeys,swap->myfee.I.suppress_pubkeys); //printf("%s suppress.%d fee.%d\n",coinaddr,alicepayment->I.suppress_pubkeys,swap->myfee.I.suppress_pubkeys);
basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,swap->I.Atxfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr); basilisk_rawtx_gen(swap->ctx,"alicepayment",swap->I.started,swap->persistent_pubkey33,0,1,alicepayment,alicepayment->I.locktime,alicepayment->spendscript,alicepayment->I.spendlen,swap->I.Atxfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr);
@ -1662,7 +1787,7 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d
{ {
printf("generate fee %.8f\n",dstr(strcmp(swap->myfee.coin->symbol,"BTC") == 0 ? LP_MIN_TXFEE : swap->myfee.coin->txfee)); printf("generate fee %.8f\n",dstr(strcmp(swap->myfee.coin->symbol,"BTC") == 0 ? LP_MIN_TXFEE : swap->myfee.coin->txfee));
bitcoin_address(coinaddr,swap->alicecoin.taddr,swap->alicecoin.pubtype,swap->changermd160,20); bitcoin_address(coinaddr,swap->alicecoin.taddr,swap->alicecoin.pubtype,swap->changermd160,20);
if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.I.spendlen,strcmp(swap->myfee.coin->symbol,"BTC") == 0 ? LP_MIN_TXFEE : swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr) == 0 ) if ( basilisk_rawtx_gen(swap->ctx,"myfee",swap->I.started,swap->persistent_pubkey33,swap->I.iambob,1,&swap->myfee,swap->myfee.I.locktime,swap->myfee.spendscript,swap->myfee.I.spendlen,strcmp(swap->myfee.coin->symbol,"BTC") == 0 ? LP_MIN_TXFEE : swap->myfee.coin->txfee,1,0,swap->persistent_privkey,swap->changermd160,coinaddr) == 0 )
{ {
printf("rawtxsend %s %.8f\n",swap->myfee.coin->symbol,dstr(strcmp(swap->myfee.coin->symbol,"BTC") == 0 ? LP_MIN_TXFEE : swap->myfee.coin->txfee)); printf("rawtxsend %s %.8f\n",swap->myfee.coin->symbol,dstr(strcmp(swap->myfee.coin->symbol,"BTC") == 0 ? LP_MIN_TXFEE : swap->myfee.coin->txfee));
swap->I.statebits |= LP_swapdata_rawtxsend(pairsock,swap,0x80,data,maxlen,&swap->myfee,0x40,0); swap->I.statebits |= LP_swapdata_rawtxsend(pairsock,swap,0x80,data,maxlen,&swap->myfee,0x40,0);
@ -1680,18 +1805,25 @@ int32_t basilisk_alicetxs(int32_t pairsock,struct basilisk_swap *swap,uint8_t *d
} }
} }
if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 && swap->myfee.I.datalen != 0 && swap->myfee.I.spendlen > 0 ) if ( swap->alicepayment.I.datalen != 0 && swap->alicepayment.I.spendlen > 0 && swap->myfee.I.datalen != 0 && swap->myfee.I.spendlen > 0 )
{
printf("fee sent\n");
return(0); return(0);
}
return(-1); return(-1);
} }
int32_t LP_verify_otherfee(struct basilisk_swap *swap,uint8_t *data,int32_t datalen) int32_t LP_verify_otherfee(struct basilisk_swap *swap,uint8_t *data,int32_t datalen)
{ {
int32_t diff;
if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->otherfee,0,data,datalen,0) == 0 ) if ( LP_rawtx_spendscript(swap,swap->bobcoin.longestchain,&swap->otherfee,0,data,datalen,0) == 0 )
{ {
printf("otherfee amount %.8f -> %s vs %s locktime %u vs %u\n",dstr(swap->otherfee.I.amount),swap->otherfee.p2shaddr,swap->otherfee.I.destaddr,swap->otherfee.I.locktime,swap->I.started+1); printf("otherfee amount %.8f -> %s vs %s locktime %u vs %u\n",dstr(swap->otherfee.I.amount),swap->otherfee.p2shaddr,swap->otherfee.I.destaddr,swap->otherfee.I.locktime,swap->I.started+1);
if ( strcmp(swap->otherfee.I.destaddr,swap->otherfee.p2shaddr) == 0 ) if ( strcmp(swap->otherfee.I.destaddr,swap->otherfee.p2shaddr) == 0 )
{ {
if ( swap->otherfee.I.locktime == swap->I.started+1 ) diff = swap->otherfee.I.locktime - (swap->I.started+1);
if ( diff < 0 )
diff = -diff;
if ( diff < 10 )
printf("dexfee verified\n"); printf("dexfee verified\n");
else printf("locktime mismatch in otherfee, reject %u vs %u\n",swap->otherfee.I.locktime,swap->I.started+1); else printf("locktime mismatch in otherfee, reject %u vs %u\n",swap->otherfee.I.locktime,swap->I.started+1);
return(0); return(0);

350
iguana/exchanges/LP_utxo.c

@ -64,7 +64,10 @@ struct LP_address *_LP_address(struct iguana_info *coin,char *coinaddr)
{ {
struct LP_address *ap = 0; struct LP_address *ap = 0;
if ( (ap= _LP_addressfind(coin,coinaddr)) == 0 ) if ( (ap= _LP_addressfind(coin,coinaddr)) == 0 )
{
ap = _LP_addressadd(coin,coinaddr); ap = _LP_addressadd(coin,coinaddr);
//printf("LP_address %s %s\n",coin->symbol,coinaddr);
}
return(ap); return(ap);
} }
@ -118,22 +121,22 @@ struct LP_utxoinfo *LP_allocated(bits256 txid,int32_t vout)
struct LP_utxoinfo *utxo; struct LP_utxoinfo *utxo;
if ( (utxo= _LP_utxofind(0,txid,vout)) != 0 && LP_isavailable(utxo) == 0 ) if ( (utxo= _LP_utxofind(0,txid,vout)) != 0 && LP_isavailable(utxo) == 0 )
{ {
char str[65]; printf("%s/v%d not available\n",bits256_str(str,txid),vout); //char str[65]; printf("%s/v%d not available\n",bits256_str(str,txid),vout);
return(utxo); return(utxo);
} }
if ( (utxo= _LP_utxo2find(0,txid,vout)) != 0 && LP_isavailable(utxo) == 0 ) if ( (utxo= _LP_utxo2find(0,txid,vout)) != 0 && LP_isavailable(utxo) == 0 )
{ {
char str[65]; printf("%s/v%d not available2\n",bits256_str(str,txid),vout); //char str[65]; printf("%s/v%d not available2\n",bits256_str(str,txid),vout);
return(utxo); return(utxo);
} }
if ( (utxo= _LP_utxofind(1,txid,vout)) != 0 && LP_isavailable(utxo) == 0 ) if ( (utxo= _LP_utxofind(1,txid,vout)) != 0 && LP_isavailable(utxo) == 0 )
{ {
char str[65]; printf("%s/v%d not available\n",bits256_str(str,txid),vout); //char str[65]; printf("%s/v%d not available\n",bits256_str(str,txid),vout);
return(utxo); return(utxo);
} }
if ( (utxo= _LP_utxo2find(1,txid,vout)) != 0 && LP_isavailable(utxo) == 0 ) if ( (utxo= _LP_utxo2find(1,txid,vout)) != 0 && LP_isavailable(utxo) == 0 )
{ {
char str[65]; printf("%s/v%d not available2\n",bits256_str(str,txid),vout); //char str[65]; printf("%s/v%d not available2\n",bits256_str(str,txid),vout);
return(utxo); return(utxo);
} }
return(0); return(0);
@ -141,10 +144,11 @@ struct LP_utxoinfo *LP_allocated(bits256 txid,int32_t vout)
int32_t LP_address_utxo_ptrs(struct iguana_info *coin,int32_t iambob,struct LP_address_utxo **utxos,int32_t max,struct LP_address *ap,char *coinaddr) int32_t LP_address_utxo_ptrs(struct iguana_info *coin,int32_t iambob,struct LP_address_utxo **utxos,int32_t max,struct LP_address *ap,char *coinaddr)
{ {
struct LP_address_utxo *up,*tmp; struct LP_transaction *tx; cJSON *txout; int32_t n = 0; char str[65]; struct LP_address_utxo *up,*tmp; struct LP_transaction *tx; cJSON *txout; int32_t n = 0;
//printf("LP_address_utxo_ptrs for (%s).(%s)\n",ap->coinaddr,coinaddr); //printf("LP_address_utxo_ptrs for (%s).(%s)\n",ap->coinaddr,coinaddr);
if ( strcmp(ap->coinaddr,coinaddr) != 0 ) if ( strcmp(ap->coinaddr,coinaddr) != 0 )
printf("UNEXPECTED coinaddr mismatch (%s) != (%s)\n",ap->coinaddr,coinaddr); printf("UNEXPECTED coinaddr mismatch (%s) != (%s)\n",ap->coinaddr,coinaddr);
LP_listunspent_issue(coin->symbol,coin->smartaddr,2);
portable_mutex_lock(&LP_utxomutex); portable_mutex_lock(&LP_utxomutex);
DL_FOREACH_SAFE(ap->utxos,up,tmp) DL_FOREACH_SAFE(ap->utxos,up,tmp)
{ {
@ -157,7 +161,7 @@ int32_t LP_address_utxo_ptrs(struct iguana_info *coin,int32_t iambob,struct LP_a
{ {
if ( LP_value_extract(txout,0) == 0 ) if ( LP_value_extract(txout,0) == 0 )
{ {
printf("LP_address_utxo_ptrs skip zero value %s/v%d\n",bits256_str(str,up->U.txid),up->U.vout); //printf("LP_address_utxo_ptrs skip zero value %s/v%d\n",bits256_str(str,up->U.txid),up->U.vout);
free_json(txout); free_json(txout);
up->spendheight = 1; up->spendheight = 1;
if ( (tx= LP_transactionfind(coin,up->U.txid)) != 0 && up->U.vout < tx->numvouts ) if ( (tx= LP_transactionfind(coin,up->U.txid)) != 0 && up->U.vout < tx->numvouts )
@ -177,15 +181,15 @@ int32_t LP_address_utxo_ptrs(struct iguana_info *coin,int32_t iambob,struct LP_a
} }
else else
{ {
if ( up->SPV <= 0 || up->U.height == 0 ) if ( up->SPV < 0 || up->U.height == 0 )
{ {
printf("LP_address_utxo_ptrs skips %s/v%u due to SPV.%d ht.%d\n",bits256_str(str,up->U.txid),up->U.vout,up->SPV,up->U.height); //printf("LP_address_utxo_ptrs skips %s/v%u due to SPV.%d ht.%d\n",bits256_str(str,up->U.txid),up->U.vout,up->SPV,up->U.height);
if ( (tx= LP_transactionfind(coin,up->U.txid)) != 0 && up->U.vout < tx->numvouts ) if ( (tx= LP_transactionfind(coin,up->U.txid)) != 0 && up->U.vout < tx->numvouts )
tx->outpoints[up->U.vout].spendheight = 1; tx->outpoints[up->U.vout].spendheight = 1;
continue; continue;
} }
} }
if ( LP_allocated(up->U.txid,up->U.vout) == 0 ) if ( LP_allocated(up->U.txid,up->U.vout) == 0 && (iambob == 0 || (_LP_utxofind(iambob,up->U.txid,up->U.vout) == 0 && _LP_utxo2find(iambob,up->U.txid,up->U.vout) == 0)) )
{ {
utxos[n++] = up; utxos[n++] = up;
if ( n >= max ) if ( n >= max )
@ -237,7 +241,7 @@ void LP_mark_spent(char *symbol,bits256 txid,int32_t vout)
int32_t LP_address_utxoadd(char *debug,struct iguana_info *coin,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t height,int32_t spendheight) int32_t LP_address_utxoadd(char *debug,struct iguana_info *coin,char *coinaddr,bits256 txid,int32_t vout,uint64_t value,int32_t height,int32_t spendheight)
{ {
struct LP_address *ap; cJSON *txobj; struct LP_address_utxo *up,*tmp; int32_t flag,retval = 0; char str[65]; struct LP_address *ap; cJSON *txobj; struct LP_transaction *tx; struct LP_address_utxo *up,*tmp; int32_t flag,retval = 0; //char str[65];
if ( coin == 0 ) if ( coin == 0 )
return(0); return(0);
if ( spendheight > 0 ) // dont autocreate entries for spends we dont care about if ( spendheight > 0 ) // dont autocreate entries for spends we dont care about
@ -282,8 +286,11 @@ int32_t LP_address_utxoadd(char *debug,struct iguana_info *coin,char *coinaddr,b
DL_APPEND(ap->utxos,up); DL_APPEND(ap->utxos,up);
portable_mutex_unlock(&coin->addrmutex); portable_mutex_unlock(&coin->addrmutex);
retval = 1; retval = 1;
if ( value == 0 ) if ( (tx= LP_transactionfind(coin,txid)) != 0 && tx->SPV > 0 )
printf("%s ADD UTXO >> %s %s %s/v%d ht.%d %.8f\n",debug,coin->symbol,coinaddr,bits256_str(str,txid),vout,height,dstr(value)); {
up->SPV = tx->SPV;
//printf("%s ADD UTXO >> %s %s %s/v%d ht.%d %.8f\n",debug,coin->symbol,coinaddr,bits256_str(str,txid),vout,height,dstr(value));
}
} }
} // else printf("cant get ap %s %s\n",coin->symbol,coinaddr); } // else printf("cant get ap %s %s\n",coin->symbol,coinaddr);
//printf("done %s add addr.%s ht.%d\n",coin->symbol,coinaddr,height); //printf("done %s add addr.%s ht.%d\n",coin->symbol,coinaddr,height);
@ -316,107 +323,6 @@ cJSON *LP_address_item(struct iguana_info *coin,struct LP_address_utxo *up,int32
uint64_t _LP_unspents_metric(uint64_t total,int32_t n) { return((total<<16) | (n & 0xffff)); } uint64_t _LP_unspents_metric(uint64_t total,int32_t n) { return((total<<16) | (n & 0xffff)); }
bits256 iguana_merkle(bits256 *tree,int32_t txn_count)
{
int32_t i,n=0,prev; uint8_t serialized[sizeof(bits256) * 2];
if ( txn_count == 1 )
return(tree[0]);
prev = 0;
while ( txn_count > 1 )
{
if ( (txn_count & 1) != 0 )
tree[prev + txn_count] = tree[prev + txn_count-1], txn_count++;
n += txn_count;
for (i=0; i<txn_count; i+=2)
{
iguana_rwbignum(1,serialized,sizeof(*tree),tree[prev + i].bytes);
iguana_rwbignum(1,&serialized[sizeof(*tree)],sizeof(*tree),tree[prev + i + 1].bytes);
tree[n + (i >> 1)] = bits256_doublesha256(0,serialized,sizeof(serialized));
}
prev = n;
txn_count >>= 1;
}
return(tree[n]);
}
bits256 validate_merkle(int32_t pos,bits256 txid,cJSON *proofarray,int32_t proofsize)
{
int32_t i; uint8_t serialized[sizeof(bits256) * 2]; bits256 hash,proof;
hash = txid;
for (i=0; i<proofsize; i++)
{
proof = jbits256i(proofarray,i);
if ( (pos & 1) == 0 )
{
iguana_rwbignum(1,&serialized[0],sizeof(hash),hash.bytes);
iguana_rwbignum(1,&serialized[sizeof(hash)],sizeof(proof),proof.bytes);
}
else
{
iguana_rwbignum(1,&serialized[0],sizeof(proof),proof.bytes);
iguana_rwbignum(1,&serialized[sizeof(hash)],sizeof(hash),hash.bytes);
}
hash = bits256_doublesha256(0,serialized,sizeof(serialized));
pos >>= 1;
}
return(hash);
}
bits256 LP_merkleroot(struct iguana_info *coin,struct electrum_info *ep,int32_t height)
{
cJSON *hdrobj; bits256 merkleroot;
memset(merkleroot.bytes,0,sizeof(merkleroot));
if ( coin->cachedmerkleheight == height )
return(coin->cachedmerkle);
if ( (hdrobj= electrum_getheader(coin->symbol,ep,&hdrobj,height)) != 0 )
{
if ( jobj(hdrobj,"merkle_root") != 0 )
{
merkleroot = jbits256(hdrobj,"merkle_root");
if ( bits256_nonz(merkleroot) != 0 )
{
coin->cachedmerkle = merkleroot;
coin->cachedmerkleheight = height;
}
}
free_json(hdrobj);
} else printf("couldnt get header for ht.%d\n",height);
return(merkleroot);
}
int32_t LP_merkleproof(struct iguana_info *coin,struct electrum_info *ep,bits256 txid,int32_t height)
{
cJSON *merkobj,*merkles; bits256 roothash,merkleroot; int32_t m,SPV = 0;
if ( (merkobj= electrum_getmerkle(coin->symbol,ep,&merkobj,txid,height)) != 0 )
{
char str[65],str2[65],str3[65];
SPV = -1;
memset(roothash.bytes,0,sizeof(roothash));
if ( (merkles= jarray(&m,merkobj,"merkle")) != 0 )
{
roothash = validate_merkle(jint(merkobj,"pos"),txid,merkles,m);
merkleroot = LP_merkleroot(coin,ep,height);
if ( bits256_nonz(merkleroot) != 0 )
{
if ( bits256_cmp(merkleroot,roothash) == 0 )
{
SPV = height;
//printf("validated MERK %s ht.%d -> %s root.(%s)\n",bits256_str(str,up->U.txid),up->U.height,jprint(merkobj,0),bits256_str(str2,roothash));
}
else printf("ERROR MERK %s ht.%d -> %s root.(%s) vs %s\n",bits256_str(str,txid),height,jprint(merkobj,0),bits256_str(str2,roothash),bits256_str(str3,merkleroot));
} else SPV = 0;
}
if ( SPV < 0 )
{
printf("MERKLE DIDNT VERIFY.%s %s ht.%d (%s)\n",coin->symbol,bits256_str(str,txid),height,jprint(merkobj,0));
if ( jobj(merkobj,"error") != 0 )
SPV = 0; // try again later
}
free_json(merkobj);
}
return(SPV);
}
cJSON *LP_address_utxos(struct iguana_info *coin,char *coinaddr,int32_t electrumret) cJSON *LP_address_utxos(struct iguana_info *coin,char *coinaddr,int32_t electrumret)
{ {
cJSON *array,*item; int32_t n; uint64_t total; struct LP_address *ap=0,*atmp; struct LP_address_utxo *up,*tmp; cJSON *txobj; cJSON *array,*item; int32_t n; uint64_t total; struct LP_address *ap=0,*atmp; struct LP_address_utxo *up,*tmp; cJSON *txobj;
@ -472,13 +378,38 @@ cJSON *LP_address_utxos(struct iguana_info *coin,char *coinaddr,int32_t electrum
cJSON *LP_address_balance(struct iguana_info *coin,char *coinaddr,int32_t electrumret) cJSON *LP_address_balance(struct iguana_info *coin,char *coinaddr,int32_t electrumret)
{ {
cJSON *array,*retjson; int32_t i,n; uint64_t balance = 0; cJSON *array,*retjson,*item; int32_t i,n; uint64_t balance = 0;
if ( (array= LP_address_utxos(coin,coinaddr,1)) != 0 ) if ( coin->electrum == 0 )
{
if ( (array= LP_listunspent(coin->symbol,coinaddr)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
balance += LP_value_extract(item,1);
}
}
}
}
else
{ {
if ( (n= cJSON_GetArraySize(array)) > 0 ) if ( strcmp(coin->smartaddr,coinaddr) == 0 )
balance = LP_unspents_load(coin->symbol,coinaddr);
else
{ {
for (i=0; i<n; i++) if ( (array= LP_address_utxos(coin,coinaddr,1)) != 0 )
balance += j64bits(jitem(array,i),"value"); {
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
balance += j64bits(item,"value");
}
}
}
} }
} }
retjson = cJSON_CreateObject(); retjson = cJSON_CreateObject();
@ -541,26 +472,24 @@ void LP_utxosetkey(uint8_t *key,bits256 txid,int32_t vout)
struct LP_utxoinfo *_LP_utxofind(int32_t iambob,bits256 txid,int32_t vout) struct LP_utxoinfo *_LP_utxofind(int32_t iambob,bits256 txid,int32_t vout)
{ {
struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)];
/*if ( iambob != 0 )
{
static uint32_t counter;
if ( counter++ < 3 )
printf("_LP_utxofind deprecated iambob\n");
return(0);
}*/
LP_utxosetkey(key,txid,vout); LP_utxosetkey(key,txid,vout);
HASH_FIND(hh,G.LP_utxoinfos[iambob],key,sizeof(key),utxo); HASH_FIND(hh,G.LP_utxoinfos[iambob!=0],key,sizeof(key),utxo);
return(utxo); return(utxo);
} }
void _LP_utxo_delete(int32_t iambob,struct LP_utxoinfo *utxo)
{
HASH_DELETE(hh,G.LP_utxoinfos[iambob],utxo);
}
void _LP_utxo2_delete(int32_t iambob,struct LP_utxoinfo *utxo)
{
HASH_DELETE(hh,G.LP_utxoinfos2[iambob],utxo);
}
struct LP_utxoinfo *_LP_utxo2find(int32_t iambob,bits256 txid2,int32_t vout2) struct LP_utxoinfo *_LP_utxo2find(int32_t iambob,bits256 txid2,int32_t vout2)
{ {
struct LP_utxoinfo *utxo=0; uint8_t key2[sizeof(txid2) + sizeof(vout2)]; struct LP_utxoinfo *utxo=0; uint8_t key2[sizeof(txid2) + sizeof(vout2)];
/*if ( iambob != 0 )
{
printf("_LP_utxo2find deprecated iambob\n");
return(0);
}*/
LP_utxosetkey(key2,txid2,vout2); LP_utxosetkey(key2,txid2,vout2);
HASH_FIND(hh2,G.LP_utxoinfos2[iambob],key2,sizeof(key2),utxo); HASH_FIND(hh2,G.LP_utxoinfos2[iambob],key2,sizeof(key2),utxo);
return(utxo); return(utxo);
@ -605,13 +534,15 @@ struct LP_transaction *LP_transactionfind(struct iguana_info *coin,bits256 txid)
struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,int32_t height,int32_t numvouts,int32_t numvins) struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,int32_t height,int32_t numvouts,int32_t numvins)
{ {
struct LP_transaction *tx; int32_t i; static long totalsize;
struct LP_transaction *tx; int32_t i; //char str[65];
if ( (tx= LP_transactionfind(coin,txid)) == 0 ) 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 ) //if ( bits256_nonz(txid) == 0 && tx->height == 0 )
// getchar(); // getchar();
tx = calloc(1,sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts)); tx = calloc(1,sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts));
totalsize += sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts);
//char str[65]; printf("%s ht.%d NEW TXID.(%s) vouts.[%d] size.%ld total %ld\n",coin->symbol,height,bits256_str(str,txid),numvouts,sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts),totalsize);
for (i=0; i<numvouts; i++) for (i=0; i<numvouts; i++)
tx->outpoints[i].spendvini = -1; tx->outpoints[i].spendvini = -1;
tx->height = height; tx->height = height;
@ -622,7 +553,7 @@ struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,i
portable_mutex_lock(&coin->txmutex); portable_mutex_lock(&coin->txmutex);
HASH_ADD_KEYPTR(hh,coin->transactions,tx->txid.bytes,sizeof(tx->txid),tx); HASH_ADD_KEYPTR(hh,coin->transactions,tx->txid.bytes,sizeof(tx->txid),tx);
portable_mutex_unlock(&coin->txmutex); portable_mutex_unlock(&coin->txmutex);
} // else printf("warning adding already existing txid %s\n",bits256_str(str,tx->txid)); } //else printf("warning adding already existing txid %s\n",bits256_str(str,tx->txid));
return(tx); return(tx);
} }
@ -733,6 +664,11 @@ int32_t LP_numconfirms(char *symbol,char *coinaddr,bits256 txid,int32_t vout,int
} }
else if ( mempool != 0 && LP_mempoolscan(symbol,txid) >= 0 ) else if ( mempool != 0 && LP_mempoolscan(symbol,txid) >= 0 )
numconfirms = 0; numconfirms = 0;
else if ( (txobj= LP_gettx(symbol,txid)) != 0 )
{
numconfirms = jint(txobj,"confirmations");
free_json(txobj);
}
} }
else else
{ {
@ -852,7 +788,7 @@ uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout)
int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2) int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol,bits256 txid,int32_t vout,uint64_t satoshis,bits256 txid2,int32_t vout2)
{ {
uint64_t val,val2=0,txfee,threshold=0; int32_t bypass = 0; char destaddr[64],destaddr2[64]; struct LP_transaction *tx; struct LP_address_utxo *up; struct iguana_info *coin = LP_coinfind(symbol); uint64_t val,val2=0,txfee,threshold=0; cJSON *txobj; int32_t bypass = 0; char destaddr[64],destaddr2[64]; struct LP_transaction *tx; struct LP_address_utxo *up; struct iguana_info *coin = LP_coinfind(symbol);
if ( bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 ) if ( bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 )
{ {
printf("null txid not eligible\n"); printf("null txid not eligible\n");
@ -885,18 +821,42 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol
strcpy(destaddr,destaddr2); strcpy(destaddr,destaddr2);
if ( coin != 0 ) if ( coin != 0 )
{ {
if ( (tx= LP_transactionfind(coin,txid)) != 0 && vout < tx->numvouts && tx->outpoints[vout].spendheight > 0 ) if ( coin->electrum != 0 )
return(0); {
if ( (tx= LP_transactionfind(coin,txid2)) != 0 && vout2 < tx->numvouts && tx->outpoints[vout2].spendheight > 0 ) if ( (tx= LP_transactionfind(coin,txid)) != 0 && vout < tx->numvouts && tx->outpoints[vout].spendheight > 0 )
return(0); {
if ( (up= LP_address_utxofind(coin,destaddr,txid,vout)) != 0 && up->spendheight > 0 ) //printf("txid spent\n");
return(0); return(0);
if ( (up= LP_address_utxofind(coin,destaddr,txid2,vout2)) != 0 && up->spendheight > 0 ) }
return(0); if ( (tx= LP_transactionfind(coin,txid2)) != 0 && vout2 < tx->numvouts && tx->outpoints[vout2].spendheight > 0 )
{
//printf("txid2 spent\n");
return(0);
}
if ( (up= LP_address_utxofind(coin,destaddr,txid,vout)) != 0 && up->spendheight > 0 )
{
//printf("txid %s spentB\n",destaddr);
return(0);
}
if ( (up= LP_address_utxofind(coin,destaddr,txid2,vout2)) != 0 && up->spendheight > 0 )
{
//printf("txid2 %s spentB\n",destaddr);
return(0);
}
}
else
{
if ( (txobj= LP_gettxout(coin->symbol,destaddr,txid,vout)) == 0 )
return(0);
else free_json(txobj);
if ( (txobj= LP_gettxout(coin->symbol,destaddr,txid2,vout2)) == 0 )
return(0);
else free_json(txobj);
}
} }
return(1); return(1);
} }
} // else printf("no val2\n"); } else printf("no val2 %.8f < threshold %.8f\n",dstr(val),dstr(threshold));
} }
/*char str2[65]; /*char str2[65];
if ( val != 0 && val2 != 0 ) if ( val != 0 && val2 != 0 )
@ -939,10 +899,14 @@ int32_t LP_iseligible(uint64_t *valp,uint64_t *val2p,int32_t iambob,char *symbol
int32_t LP_inventory_prevent(int32_t iambob,char *symbol,bits256 txid,int32_t vout) int32_t LP_inventory_prevent(int32_t iambob,char *symbol,bits256 txid,int32_t vout)
{ {
struct LP_utxoinfo *utxo; struct LP_transaction *tx; struct iguana_info *coin; struct LP_address_utxo *up; struct LP_utxoinfo *utxo; struct LP_transaction *tx; struct iguana_info *coin;
if ( (coin= LP_coinfind(symbol)) == 0 )
return(1);
if ( LP_allocated(txid,vout) != 0 )
return(1);
if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 || (utxo= LP_utxo2find(iambob,txid,vout)) != 0 ) if ( (utxo= LP_utxofind(iambob,txid,vout)) != 0 || (utxo= LP_utxo2find(iambob,txid,vout)) != 0 )
{ {
if ( (coin= LP_coinfind(symbol)) != 0 && (tx= LP_transactionfind(coin,txid)) != 0 ) if ( coin != 0 && (tx= LP_transactionfind(coin,txid)) != 0 )
{ {
if ( tx->outpoints[vout].spendheight > 0 ) if ( tx->outpoints[vout].spendheight > 0 )
utxo->T.spentflag = tx->outpoints[vout].spendheight; utxo->T.spentflag = tx->outpoints[vout].spendheight;
@ -954,6 +918,61 @@ int32_t LP_inventory_prevent(int32_t iambob,char *symbol,bits256 txid,int32_t vo
return(1); return(1);
} }
} }
if ( (up= LP_address_utxofind(coin,coin->smartaddr,txid,vout)) != 0 && up->spendheight > 0 )
return(1);
return(0);
}
cJSON *LP_dustcombine_item(struct LP_address_utxo *up)
{
cJSON *item = cJSON_CreateObject();
jaddbits256(item,"txid",up->U.txid);
jaddnum(item,"vout",up->U.vout);
return(item);
}
uint64_t LP_dustcombine(struct LP_address_utxo *ups[2],int32_t dustcombine,struct iguana_info *coin)
{
struct LP_address *ap=0; struct LP_address_utxo *up,*tmp,*min0,*min1; cJSON *txobj;
if ( coin == 0 || coin->electrum != 0 || dustcombine <= 0 || dustcombine > 2 )
return(0);
min1 = min0 = 0;
ups[0] = ups[1] = 0;
if ( (ap= _LP_addressfind(coin,coin->smartaddr)) != 0 )
{
DL_FOREACH_SAFE(ap->utxos,up,tmp)
{
if ( up->spendheight <= 0 && up->U.height > 0 && up->U.value != 0 )
{
if ( (txobj= LP_gettxout(coin->symbol,coin->smartaddr,up->U.txid,up->U.vout)) == 0 )
up->spendheight = 1;
else
{
free_json(txobj);
if ( LP_inventory_prevent(1,coin->symbol,up->U.txid,up->U.vout) == 0 )
{
if ( min1 == 0 || up->U.value < min1->U.value )
{
if ( min0 == 0 || up->U.value < min0->U.value )
{
min1 = min0;
min0 = up;
} else min1 = up;
}
}
}
}
}
}
if ( min0 != 0 )
{
ups[0] = min0;
if ( dustcombine == 2 && min1 != 0 )
{
ups[1] = min1;
return(min0->U.value + min1->U.value);
} else return(min0->U.value);
}
return(0); return(0);
} }
@ -981,42 +1000,3 @@ int32_t LP_undospends(struct iguana_info *coin,int32_t lastheight)
} }
return(num); return(num);
} }
void LP_unspents_cache(char *symbol,char *addr,char *arraystr,int32_t updatedflag)
{
char fname[1024]; FILE *fp=0;
sprintf(fname,"%s/UNSPENTS/%s_%s",GLOBAL_DBDIR,symbol,addr), OS_portable_path(fname);
if ( updatedflag == 0 && (fp= fopen(fname,"rb")) == 0 )
updatedflag = 1;
else if ( fp != 0 )
fclose(fp);
if ( updatedflag != 0 && (fp= fopen(fname,"wb")) != 0 )
{
fwrite(arraystr,1,strlen(arraystr),fp);
fclose(fp);
}
}
void LP_unspents_load(char *symbol,char *addr)
{
char fname[1024],*arraystr; long fsize; struct iguana_info *coin; cJSON *retjson;
if ( (coin= LP_coinfind(symbol)) != 0 )
{
sprintf(fname,"%s/UNSPENTS/%s_%s",GLOBAL_DBDIR,symbol,addr), OS_portable_path(fname);
if ( (arraystr= OS_filestr(&fsize,fname)) != 0 )
{
if ( (retjson= cJSON_Parse(arraystr)) != 0 )
{
printf("PROCESS UNSPENTS %s\n",arraystr);
if ( electrum_process_array(coin,coin->electrum,coin->smartaddr,retjson,1) == 0 )
printf("error electrum_process_array\n");
else printf("processed %s\n",arraystr);
free_json(retjson);
}
free(arraystr);
}
}
}

93
iguana/exchanges/LP_utxos.c

@ -268,7 +268,6 @@ struct LP_utxoinfo *LP_utxo_bestfit(char *symbol,uint64_t destsatoshis)
{ {
if ( LP_iseligible(&srcvalue,&srcvalue2,utxo->iambob,symbol,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,utxo->fee.txid,utxo->fee.vout) == 0 ) if ( LP_iseligible(&srcvalue,&srcvalue2,utxo->iambob,symbol,utxo->payment.txid,utxo->payment.vout,utxo->S.satoshis,utxo->fee.txid,utxo->fee.vout) == 0 )
{ {
printf("not elibible\n");
//if ( utxo->T.spentflag == 0 ) //if ( utxo->T.spentflag == 0 )
// utxo->T.spentflag = (uint32_t)time(NULL); // utxo->T.spentflag = (uint32_t)time(NULL);
continue; continue;
@ -287,12 +286,12 @@ void LP_spentnotify(struct LP_utxoinfo *utxo,int32_t selector)
utxo->T.spentflag = (uint32_t)time(NULL); utxo->T.spentflag = (uint32_t)time(NULL);
} }
struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *coinaddr,bits256 pubkey,char *gui,uint32_t sessionid) struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t vout,int64_t value,bits256 txid2,int32_t vout2,int64_t value2,char *coinaddr,bits256 pubkey,char *gui,uint32_t sessionid,uint64_t satoshis)
{ {
uint64_t val,val2=0,tmpsatoshis,txfee; int32_t spendvini,numconfirms,selector; bits256 spendtxid; struct iguana_info *coin; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0; uint64_t val,val2=0,txfee; int32_t spendvini,numconfirms,selector; bits256 spendtxid; struct iguana_info *coin; struct _LP_utxoinfo u; struct LP_utxoinfo *utxo = 0;
if ( symbol == 0 || symbol[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 )//|| sessionid == 0 ) if ( symbol == 0 || symbol[0] == 0 || coinaddr == 0 || coinaddr[0] == 0 || bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 || vout < 0 || vout2 < 0 || value <= 0 || value2 <= 0 )//|| sessionid == 0 )
{ {
char str[65],str2[65]; printf("REJECT %s iambob.%d %s utxoadd.(%.8f %.8f) %s/v%d %s/v%d\n",coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),vout,bits256_str(str2,txid2),vout2); char str[65],str2[65]; printf("REJECT (%s) iambob.%d %s utxoadd.(%.8f %.8f) %s/v%d %s/v%d\n",coinaddr,iambob,symbol,dstr(value),dstr(value2),bits256_str(str,txid),vout,bits256_str(str2,txid2),vout2);
printf("session.%u addutxo %d %d %d %d %d %d %d %d\n",sessionid,symbol == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0); printf("session.%u addutxo %d %d %d %d %d %d %d %d\n",sessionid,symbol == 0,coinaddr == 0,bits256_nonz(txid) == 0,bits256_nonz(txid2) == 0,vout < 0,vout2 < 0,value <= 0,value2 <= 0);
return(0); return(0);
} }
@ -302,7 +301,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t
return(0); return(0);
} }
txfee = LP_txfeecalc(coin,0,0); txfee = LP_txfeecalc(coin,0,0);
if ( iambob != 0 && value2 < 9 * (value >> 3) + 2*txfee ) // big txfee padding /*if ( iambob != 0 && value2 < 9 * (satoshis >> 3) + 2*txfee ) // big txfee padding
{ {
if ( value2 > 2*txfee ) if ( value2 > 2*txfee )
tmpsatoshis = (((value2 - 2*txfee) / 9) << 3); tmpsatoshis = (((value2 - 2*txfee) / 9) << 3);
@ -311,7 +310,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t
printf("value2 %.8f <= 2 * %.8f\n",dstr(value2),dstr(txfee)); printf("value2 %.8f <= 2 * %.8f\n",dstr(value2),dstr(txfee));
return(0); return(0);
} }
} else tmpsatoshis = (value - txfee); } else tmpsatoshis = (satoshis - txfee);*/
char str[65],str2[65],dispflag = 0;//(iambob == 0); char str[65],str2[65],dispflag = 0;//(iambob == 0);
if ( iambob == 0 && bits256_cmp(pubkey,G.LP_mypub25519) != 0 ) if ( iambob == 0 && bits256_cmp(pubkey,G.LP_mypub25519) != 0 )
{ {
@ -320,11 +319,11 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t
} }
if ( coin->inactive == 0 ) if ( coin->inactive == 0 )
{ {
if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,tmpsatoshis,txid2,vout2) <= 0 ) if ( LP_iseligible(&val,&val2,iambob,symbol,txid,vout,satoshis,txid2,vout2) <= 0 )
{ {
static uint32_t counter; static uint32_t counter;
if ( counter++ < 3 ) if ( counter++ < 3 )
printf("iambob.%d utxoadd %s inactive.%u got ineligible txid value %.8f:%.8f, value2 %.8f:%.8f, tmpsatoshis %.8f\n",iambob,symbol,coin->inactive,dstr(value),dstr(val),dstr(value2),dstr(val2),dstr(tmpsatoshis)); printf("iambob.%d utxoadd %s inactive.%u got ineligible txid value %.8f:%.8f, value2 %.8f:%.8f, tmpsatoshis %.8f\n",iambob,symbol,coin->inactive,dstr(value),dstr(val),dstr(value2),dstr(val2),dstr(satoshis));
return(0); return(0);
} }
if ( (numconfirms= LP_numconfirms(symbol,coinaddr,txid,vout,0)) <= 0 ) if ( (numconfirms= LP_numconfirms(symbol,coinaddr,txid,vout,0)) <= 0 )
@ -352,10 +351,10 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t
if ( 0 && LP_ismine(utxo) == 0 ) if ( 0 && LP_ismine(utxo) == 0 )
{ {
char str2[65],str3[65]; printf("iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2)); char str2[65],str3[65]; printf("iambob.%d %s %s utxoadd.(%.8f %.8f) %s %s\n",iambob,bits256_str(str3,pubkey),symbol,dstr(value),dstr(value2),bits256_str(str,txid),bits256_str(str2,txid2));
printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(tmpsatoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis)); printf("duplicate %.8f %.8f %.8f vs utxo.(%.8f %.8f %.8f)\n",dstr(value),dstr(value2),dstr(satoshis),dstr(utxo->payment.value),dstr(utxo->deposit.value),dstr(utxo->S.satoshis));
} }
u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee; u = (utxo->iambob != 0) ? utxo->deposit : utxo->fee;
if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || tmpsatoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 ) if ( bits256_cmp(txid,utxo->payment.txid) != 0 || bits256_cmp(txid2,u.txid) != 0 || vout != utxo->payment.vout || value != utxo->payment.value || satoshis != utxo->S.satoshis || vout2 != u.vout || value2 != u.value || strcmp(symbol,utxo->coin) != 0 || strcmp(coinaddr,utxo->coinaddr) != 0 || bits256_cmp(pubkey,utxo->pubkey) != 0 )
{ {
utxo->T.errors++; utxo->T.errors++;
char str[65],str2[65],str3[65],str4[65],str5[65],str6[65]; char str[65],str2[65],str3[65],str4[65],str5[65],str6[65];
@ -365,7 +364,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t
// utxo->T.spentflag = (uint32_t)time(NULL); // utxo->T.spentflag = (uint32_t)time(NULL);
printf("original utxo pair not valid\n"); printf("original utxo pair not valid\n");
if ( dispflag != 0 ) if ( dispflag != 0 )
printf("error on subsequent utxo iambob.%d %.8f %.8f add.(%s %s) when.(%s %s) %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",iambob,dstr(val),dstr(val2),bits256_str(str,txid),bits256_str(str2,txid2),bits256_str(str3,utxo->payment.txid),bits256_str(str4,utxo->deposit.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,tmpsatoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str5,pubkey),bits256_str(str6,utxo->pubkey)); printf("error on subsequent utxo iambob.%d %.8f %.8f add.(%s %s) when.(%s %s) %d %d %d %d %d %d %d %d %d %d pubkeys.(%s vs %s)\n",iambob,dstr(val),dstr(val2),bits256_str(str,txid),bits256_str(str2,txid2),bits256_str(str3,utxo->payment.txid),bits256_str(str4,utxo->deposit.txid),bits256_cmp(txid,utxo->payment.txid) != 0,bits256_cmp(txid2,u.txid) != 0,vout != utxo->payment.vout,satoshis != utxo->S.satoshis,vout2 != u.vout,value2 != u.value,strcmp(symbol,utxo->coin) != 0,strcmp(coinaddr,utxo->coinaddr) != 0,bits256_cmp(pubkey,utxo->pubkey) != 0,value != utxo->payment.value,bits256_str(str5,pubkey),bits256_str(str6,utxo->pubkey));
utxo = 0; utxo = 0;
} }
} }
@ -390,7 +389,7 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t
utxo->payment.txid = txid; utxo->payment.txid = txid;
utxo->payment.vout = vout; utxo->payment.vout = vout;
utxo->payment.value = value; utxo->payment.value = value;
utxo->S.satoshis = tmpsatoshis; utxo->S.satoshis = satoshis;
if ( (utxo->iambob= iambob) != 0 ) if ( (utxo->iambob= iambob) != 0 )
{ {
utxo->deposit.txid = txid2; utxo->deposit.txid = txid2;
@ -431,6 +430,46 @@ struct LP_utxoinfo *LP_utxoadd(int32_t iambob,char *symbol,bits256 txid,int32_t
return(utxo); return(utxo);
} }
int32_t _LP_utxos_remove(bits256 txid,int32_t vout)
{
struct LP_utxoinfo *utxo,*utxo2; int32_t retval = 0,iambob = 1;
utxo = utxo2 = 0;
if ( (utxo= _LP_utxofind(iambob,txid,vout)) != 0 )
{
if ( LP_isavailable(utxo) == 0 )
retval = -1;
else
{
if ( (utxo2= _LP_utxo2find(iambob,txid,vout)) != 0 )
{
if ( LP_isavailable(utxo) == 0 )
retval = -1;
else
{
_LP_utxo_delete(iambob,utxo);
_LP_utxo2_delete(iambob,utxo2);
}
}
}
}
else if ( (utxo2= _LP_utxo2find(iambob,txid,vout)) != 0 )
{
if ( LP_isavailable(utxo2) == 0 )
retval = -1;
else _LP_utxo2_delete(iambob,utxo2);
}
return(retval);
}
int32_t LP_utxos_remove(bits256 txid,int32_t vout)
{
int32_t retval;
portable_mutex_lock(&LP_utxomutex);
retval = _LP_utxos_remove(txid,vout);
portable_mutex_unlock(&LP_utxomutex);
return(retval);
}
cJSON *LP_inventory(char *symbol) cJSON *LP_inventory(char *symbol)
{ {
struct LP_utxoinfo *utxo,*tmp; struct _LP_utxoinfo u; char *myipaddr; cJSON *array; uint64_t val,val2; int32_t iambob = 0; struct iguana_info *coin; struct LP_utxoinfo *utxo,*tmp; struct _LP_utxoinfo u; char *myipaddr; cJSON *array; uint64_t val,val2; int32_t iambob = 0; struct iguana_info *coin;
@ -503,16 +542,26 @@ int32_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypri
//printf("coin not active\n"); //printf("coin not active\n");
return(0); return(0);
} }
//printf("privkey init.(%s) %s\n",coin->symbol,coin->smartaddr); if ( bits256_cmp(myprivkey,coin->lastprivkey) == 0 && time(NULL) < coin->lastprivkeytime+60 )
return(0);
coin->lastprivkey = myprivkey;
coin->lastprivkeytime = (uint32_t)time(NULL);
if ( coin->privkeydepth > 0 )
return(0);
coin->privkeydepth++;
LP_address(coin,coin->smartaddr);
//printf("privkey init.(%s) %s depth.%d\n",coin->symbol,coin->smartaddr,coin->privkeydepth);
if ( coin->inactive == 0 ) if ( coin->inactive == 0 )
LP_listunspent_issue(coin->symbol,coin->smartaddr,0); LP_listunspent_issue(coin->symbol,coin->smartaddr,0);
LP_address(coin,coin->smartaddr); array = LP_listunspent(coin->symbol,coin->smartaddr);
if ( coin->inactive == 0 && (array= LP_listunspent(coin->symbol,coin->smartaddr)) != 0 ) //printf("unspent array %ld\n",strlen(jprint(array,0)));
if ( array != 0 )
{ {
txfee = LP_txfeecalc(coin,0,0); txfee = LP_txfeecalc(coin,0,0);
if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 )
{ {
//printf("LP_privkey_init %s %s\n",coin->symbol,jprint(array,0)); coin->numutxos = n;
//printf("LP_privkey_init %s %d\n",coin->symbol,n);
for (iambob=0; iambob<=1; iambob++) for (iambob=0; iambob<=1; iambob++)
{ {
if ( iambob == 0 ) if ( iambob == 0 )
@ -538,10 +587,9 @@ int32_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypri
} }
satoshis = LP_txvalue(destaddr,coin->symbol,txid,vout); satoshis = LP_txvalue(destaddr,coin->symbol,txid,vout);
if ( satoshis != 0 && satoshis != value ) if ( satoshis != 0 && satoshis != value )
printf("%s %s unexpected privkey_init value mismatch %.8f vs %.8f (%s) %.8f %.8f\n",coin->symbol,coin->smartaddr,dstr(satoshis),dstr(value),jprint(item,0),jdouble(item,"amount"),jdouble(item,"interest")); printf("%s %s privkey_init value %.8f vs %.8f (%s) %.8f %.8f\n",coin->symbol,coin->smartaddr,dstr(satoshis),dstr(value),jprint(item,0),jdouble(item,"amount"),jdouble(item,"interest"));
if ( LP_inventory_prevent(iambob,coin->symbol,txid,vout) == 0 && height > 0 ) if ( coin->electrum != 0 || LP_inventory_prevent(iambob,coin->symbol,txid,vout) == 0 )//&& height > 0 )
{ {
//printf("%s\n",jprint(item,0));
values[i] = satoshis; values[i] = satoshis;
//flag += LP_address_utxoadd(coin,destaddr,txid,vout,satoshis,height,-1); //flag += LP_address_utxoadd(coin,destaddr,txid,vout,satoshis,height,-1);
} else used++; } else used++;
@ -610,14 +658,14 @@ int32_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypri
portable_mutex_lock(&LP_UTXOmutex); portable_mutex_lock(&LP_UTXOmutex);
if ( iambob != 0 ) if ( iambob != 0 )
{ {
if ( (utxo= LP_utxoadd(1,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,coin->smartaddr,mypub,LP_gui,G.LP_sessionid)) != 0 ) if ( (utxo= LP_utxoadd(1,coin->symbol,txid,vout,value,deposittxid,depositvout,depositval,coin->smartaddr,mypub,LP_gui,G.LP_sessionid,value)) != 0 )
{ {
} }
} }
else else
{ {
//printf("call utxoadd\n"); //printf("call utxoadd\n");
if ( (utxo= LP_utxoadd(0,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,coin->smartaddr,mypub,LP_gui,G.LP_sessionid)) != 0 ) if ( (utxo= LP_utxoadd(0,coin->symbol,deposittxid,depositvout,depositval,txid,vout,value,coin->smartaddr,mypub,LP_gui,G.LP_sessionid,value)) != 0 )
{ {
} }
} }
@ -637,6 +685,8 @@ int32_t LP_privkey_init(int32_t mypubsock,struct iguana_info *coin,bits256 mypri
} }
if ( values != 0 ) if ( values != 0 )
free(values); free(values);
if ( coin->privkeydepth > 0 )
coin->privkeydepth--;
//printf("privkey.%s %.8f\n",symbol,dstr(total)); //printf("privkey.%s %.8f\n",symbol,dstr(total));
return(flag); return(flag);
} }
@ -825,6 +875,7 @@ int32_t LP_passphrase_init(char *passphrase,char *gui)
G.LP_sessionid = (uint32_t)time(NULL); G.LP_sessionid = (uint32_t)time(NULL);
safecopy(G.gui,gui,sizeof(G.gui)); safecopy(G.gui,gui,sizeof(G.gui));
G.USERPASS_COUNTER = counter; G.USERPASS_COUNTER = counter;
G.initializing = 0;
return(0); return(0);
} }

2
iguana/exchanges/bot_settings

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
source userpass source userpass
curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"bot_settings\",\"botid\":$1,\"newprice\":$1,\"newvolume\":$2}" curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"bot_settings\",\"botid\":$1,\"newprice\":$2,\"newvolume\":$3}"

3
iguana/exchanges/bot_statuslist

@ -0,0 +1,3 @@
#!/bin/bash
source userpass
curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"bot_statuslist\"}"

2
iguana/exchanges/coins

File diff suppressed because one or more lines are too long

4
iguana/exchanges/coins.json

File diff suppressed because one or more lines are too long

2
iguana/exchanges/install

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
cp stop millis mnzservers bot_buy bot_list bot_pause bot_resume bot_sell bot_settings bot_status bot_stop guistats pubkeystats pendings coinswaps baserelswaps setpassphrase notarizations getrawtransaction parselog statsdisp m_js trust trusted setconfirms balance listunspent electrum snapshot_balance snapshot_loop secretaddresses dividends snapshot goals goal portfolio autoprice deletemessages getmessages debug buy sell bestfit orderbook client run_osx client_osx run coins disable enable myprice myprices getcoins getpeers getpeersIP getprices help inv setprice status ../dexscripts cp sendrawtransaction processfiles stop millis mnzservers bot_buy bot_list bot_statuslist bot_pause bot_resume bot_sell bot_settings bot_status bot_stop guistats pubkeystats pendings coinswaps baserelswaps setpassphrase notarizations getrawtransaction parselog statsdisp m_js trust trusted setconfirms balance listunspent electrum snapshot_balance snapshot_loop secretaddresses dividends snapshot goals goal portfolio autoprice deletemessages getmessages debug buy sell bestfit orderbook client run_osx client_osx run coins disable enable myprice myprices getcoins getpeers getpeersIP getprices help inv setprice status ../dexscripts
cp coins.json .. cp coins.json ..
cd ../dexscripts cd ../dexscripts
#cp ../exchanges/passphrase ../exchanges/userpass . #cp ../exchanges/passphrase ../exchanges/userpass .

4
iguana/exchanges/mm.c

@ -869,7 +869,7 @@ void LP_main(void *ptr)
LP_profitratio += profitmargin; LP_profitratio += profitmargin;
if ( (port= juint(argjson,"rpcport")) < 1000 ) if ( (port= juint(argjson,"rpcport")) < 1000 )
port = LP_RPCPORT; port = LP_RPCPORT;
LPinit(port,LP_RPCPORT+1,LP_RPCPORT+2,LP_RPCPORT+3,passphrase,jint(argjson,"client"),jstr(argjson,"userhome"),argjson); LPinit(port,LP_RPCPORT+10,LP_RPCPORT+20,LP_RPCPORT+30,passphrase,jint(argjson,"client"),jstr(argjson,"userhome"),argjson);
} }
} }
@ -907,7 +907,7 @@ int main(int argc, const char * argv[])
} //else printf("(%s) launched.(%s)\n",argv[1],passphrase); } //else printf("(%s) launched.(%s)\n",argv[1],passphrase);
incr = 100.; incr = 100.;
while ( (1) ) while ( (1) )
sleep(1); sleep(100000);
profitmargin = jdouble(retjson,"profitmargin"); profitmargin = jdouble(retjson,"profitmargin");
minask = jdouble(retjson,"minask"); minask = jdouble(retjson,"minask");
maxbid = jdouble(retjson,"maxbid"); maxbid = jdouble(retjson,"maxbid");

3
iguana/exchanges/processfiles

@ -0,0 +1,3 @@
ls -l /proc/$1/fd
echo sockstat
cat /proc/$1/net/sockstat

2
iguana/exchanges/sell

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
source userpass source userpass
curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"sell\",\"base\":\"KMD\",\"rel\":\"BTC\",\"basevolume\":10.0\",price\":0.0005}" curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"sell\",\"base\":\"KMD\",\"rel\":\"BTC\",\"basevolume\":10.0\",\"price\":0.0005}"

126
iguana/exchanges/stats.c

@ -33,7 +33,7 @@ char *stats_JSON(void *ctx,char *myipaddr,int32_t mypubsock,cJSON *argjson,char
char *stats_validmethods[] = char *stats_validmethods[] =
{ {
"psock", "getprices", "listunspent", "notify", "getpeers", "uitem", // from issue_ "psock", "getprices", "listunspent", "notify", "getpeers", "uitem", // from issue_
"orderbook", "help", "getcoins", "pricearray", "balance" "orderbook", "help", "getcoins", "pricearray", "balance", "tradestatus"
}; };
int32_t LP_valid_remotemethod(cJSON *argjson) int32_t LP_valid_remotemethod(cJSON *argjson)
@ -219,7 +219,7 @@ int32_t iguana_socket(int32_t bindflag,char *hostname,uint16_t port)
return(-1); return(-1);
} }
} }
if ( listen(sock,512) != 0 ) if ( listen(sock,1) != 0 )
{ {
printf("listen(%s) port.%d failed: %s sock.%d. errno.%d\n",hostname,port,strerror(errno),sock,errno); printf("listen(%s) port.%d failed: %s sock.%d. errno.%d\n",hostname,port,strerror(errno),sock,errno);
if ( sock >= 0 ) if ( sock >= 0 )
@ -589,24 +589,31 @@ int32_t iguana_getheadersize(char *buf,int32_t recvlen)
} }
uint16_t RPC_port; uint16_t RPC_port;
extern portable_mutex_t LP_commandmutex; extern portable_mutex_t LP_commandmutex,LP_gcmutex;
extern struct rpcrequest_info *LP_garbage_collector;
void LP_rpc_processreq(void *_ptr) void LP_rpc_processreq(void *_ptr)
{ {
uint64_t arg64 = *(uint64_t *)_ptr; static uint32_t spawned,maxspawned;
char filetype[128],content_type[128]; char filetype[128],content_type[128];
int32_t recvlen,flag,postflag=0,contentlen,remains,sock,numsent,jsonflag=0,hdrsize,len; int32_t recvlen,flag,postflag=0,contentlen,remains,sock,numsent,jsonflag=0,hdrsize,len;
char helpname[512],remoteaddr[64],*buf,*retstr,*space,*jsonbuf; char helpname[512],remoteaddr[64],*buf,*retstr,*space,*jsonbuf; struct rpcrequest_info *req = _ptr;
uint32_t ipbits,i,size = 32*IGUANA_MAXPACKETSIZE + 512; uint32_t ipbits,i,size = IGUANA_MAXPACKETSIZE + 512;
ipbits = (arg64 >> 32); ipbits = req->ipbits;;
expand_ipbits(remoteaddr,ipbits); expand_ipbits(remoteaddr,ipbits);
sock = (arg64 & 0xffffffff); sock = req->sock;
recvlen = flag = 0; recvlen = flag = 0;
retstr = 0; retstr = 0;
space = calloc(1,size); space = calloc(1,size);
jsonbuf = calloc(1,size); jsonbuf = calloc(1,size);
remains = size-1; remains = size-1;
buf = jsonbuf; buf = jsonbuf;
spawned++;
if ( spawned > maxspawned )
{
printf("max rpc threads spawned and alive %d <- %d\n",maxspawned,spawned);
maxspawned = spawned;
}
while ( remains > 0 ) while ( remains > 0 )
{ {
//printf("flag.%d remains.%d recvlen.%d\n",flag,remains,recvlen); //printf("flag.%d remains.%d recvlen.%d\n",flag,remains,recvlen);
@ -651,8 +658,7 @@ void LP_rpc_processreq(void *_ptr)
else else
{ {
usleep(10000); usleep(10000);
//printf("got.(%s) %d remains.%d of total.%d\n",jsonbuf,recvlen,remains,len); printf("got.(%s) %d remains.%d of total.%d\n",jsonbuf,recvlen,remains,len);
//retstr = iguana_rpcparse(space,size,&postflag,jsonbuf);
if ( flag == 0 ) if ( flag == 0 )
break; break;
} }
@ -663,9 +669,7 @@ void LP_rpc_processreq(void *_ptr)
{ {
jsonflag = postflag = 0; jsonflag = postflag = 0;
portable_mutex_lock(&LP_commandmutex); portable_mutex_lock(&LP_commandmutex);
retstr = stats_rpcparse(space,size,&jsonflag,&postflag,jsonbuf,remoteaddr,filetype,RPC_port); retstr = stats_rpcparse(space,size,&jsonflag,&postflag,jsonbuf,remoteaddr,filetype,req->port);
//if ( strcmp("5.9.253.195",remoteaddr) == 0 )
// printf("RPC.(%s)%s\n",jsonbuf,retstr);
portable_mutex_unlock(&LP_commandmutex); portable_mutex_unlock(&LP_commandmutex);
if ( filetype[0] != 0 ) if ( filetype[0] != 0 )
{ {
@ -720,7 +724,7 @@ void LP_rpc_processreq(void *_ptr)
remains -= numsent; remains -= numsent;
i += numsent; i += numsent;
if ( remains > 0 ) if ( remains > 0 )
printf("iguana sent.%d remains.%d of len.%d\n",numsent,remains,recvlen); printf("iguana sent.%d remains.%d of recvlen.%d (%s)\n",numsent,remains,recvlen,jsonbuf);
} }
} }
if ( retstr != space) if ( retstr != space)
@ -728,67 +732,97 @@ void LP_rpc_processreq(void *_ptr)
} }
free(space); free(space);
free(jsonbuf); free(jsonbuf);
closesocket(sock);
portable_mutex_lock(&LP_gcmutex);
DL_APPEND(LP_garbage_collector,req);
spawned--;
portable_mutex_unlock(&LP_gcmutex);
} }
extern int32_t IAMLP;
//int32_t LP_bindsock_reset,LP_bindsock = -1;
void stats_rpcloop(void *args) void stats_rpcloop(void *args)
{ {
static uint32_t counter; uint16_t port; int32_t retval,sock=-1,bindsock=-1; socklen_t clilen; struct sockaddr_in cli_addr; uint32_t ipbits,localhostbits; struct rpcrequest_info *req,*req2,*rtmp;
uint16_t port; int32_t sock,bindsock=-1; socklen_t clilen; struct sockaddr_in cli_addr; uint32_t ipbits; uint64_t arg64; void *arg64ptr;
if ( (port= *(uint16_t *)args) == 0 ) if ( (port= *(uint16_t *)args) == 0 )
port = 7779; port = 7779;
RPC_port = port; printf("Start stats_rpcloop.%u\n",port);
/*while ( (bindsock= iguana_socket(1,"0.0.0.0",port)) < 0 ) localhostbits = (uint32_t)calc_ipbits("127.0.0.1");
{ //initial_bindsock_reset = LP_bindsock_reset;
//if ( coin->MAXPEERS == 1 ) while ( 1 )//LP_bindsock_reset == initial_bindsock_reset )
// break;
//exit(-1);
sleep(3);
}
printf(">>>>>>>>>> DEX stats 127.0.0.1:%d bind sock.%d DEX stats API enabled <<<<<<<<<\n",port,bindsock);*/
while ( 1 )
{ {
//printf("LP_bindsock.%d\n",LP_bindsock);
if ( bindsock < 0 ) if ( bindsock < 0 )
{ {
while ( (bindsock= iguana_socket(1,"0.0.0.0",port)) < 0 ) while ( (bindsock= iguana_socket(1,"0.0.0.0",port)) < 0 )
usleep(10000); usleep(10000);
if ( counter++ < 1 ) #ifndef _WIN32
//fcntl(bindsock, F_SETFL, fcntl(bindsock, F_GETFL, 0) | O_NONBLOCK);
#endif
//if ( counter++ < 1 )
printf(">>>>>>>>>> DEX stats 127.0.0.1:%d bind sock.%d DEX stats API enabled <<<<<<<<<\n",port,bindsock); printf(">>>>>>>>>> DEX stats 127.0.0.1:%d bind sock.%d DEX stats API enabled <<<<<<<<<\n",port,bindsock);
} }
//printf("after sock.%d\n",sock);
clilen = sizeof(cli_addr); clilen = sizeof(cli_addr);
sock = accept(bindsock,(struct sockaddr *)&cli_addr,&clilen); sock = accept(bindsock,(struct sockaddr *)&cli_addr,&clilen);
//#ifdef _WIN32
if ( sock < 0 ) if ( sock < 0 )
{ {
printf("iguana_rpcloop ERROR on accept usock.%d errno %d %s\n",sock,errno,strerror(errno)); printf("iguana_rpcloop ERROR on accept port.%u usock.%d errno %d %s\n",port,sock,errno,strerror(errno));
close(bindsock); closesocket(bindsock);
bindsock = -1; bindsock = -1;
continue; continue;
} }
memcpy(&ipbits,&cli_addr.sin_addr.s_addr,sizeof(ipbits)); /*#else
arg64 = ((uint64_t)ipbits << 32) | (sock & 0xffffffff); if ( sock < 0 )
arg64ptr = malloc(sizeof(arg64));
memcpy(arg64ptr,&arg64,sizeof(arg64));
if ( 1 )
{ {
LP_rpc_processreq((void *)&arg64); //fprintf(stderr,".");
free(arg64ptr); if ( IAMLP == 0 )
//char remoteaddr[64]; usleep(50000);
//expand_ipbits(remoteaddr,ipbits); else usleep(2500);
//printf("finished RPC request from (%s) %x\n",remoteaddr,ipbits); continue;
} }
else if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)LP_rpc_processreq,arg64ptr) != 0 ) #endif*/
memcpy(&ipbits,&cli_addr.sin_addr.s_addr,sizeof(ipbits));
if ( port == RPC_port && ipbits != localhostbits )
{ {
printf("error launching rpc handler on port %d\n",port); closesocket(sock);
// yes, small leak per command continue;
} }
close(bindsock); req = calloc(1,sizeof(*req));
closesocket(sock); req->sock = sock;
bindsock = iguana_socket(1,"0.0.0.0",port); req->ipbits = ipbits;
req->port = port;
LP_rpc_processreq(req);
continue;
// this leads to cant open file errors
if ( (retval= OS_thread_create(&req->T,NULL,(void *)LP_rpc_processreq,req)) != 0 )
{
printf("error launching rpc handler on port %d, retval.%d\n",port,retval);
closesocket(sock);
sock = -1;
portable_mutex_lock(&LP_gcmutex);
DL_FOREACH_SAFE(LP_garbage_collector,req2,rtmp)
{
DL_DELETE(LP_garbage_collector,req2);
free(req2);
}
portable_mutex_unlock(&LP_gcmutex);
if ( (retval= OS_thread_create(&req->T,NULL,(void *)LP_rpc_processreq,req)) != 0 )
{
printf("error2 launching rpc handler on port %d, retval.%d\n",port,retval);
LP_rpc_processreq(req);
}
}
} }
printf("i got killed\n");
} }
#ifndef FROM_MARKETMAKER #ifndef FROM_MARKETMAKER
portable_mutex_t LP_commandmutex; portable_mutex_t LP_commandmutex;
uint16_t LP_RPCPORT;
void stats_kvjson(FILE *logfp,int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev) void stats_kvjson(FILE *logfp,int32_t height,int32_t savedheight,uint32_t timestamp,char *key,cJSON *kvjson,bits256 pubkey,bits256 sigprev)
{ {
@ -1100,6 +1134,7 @@ char *stats_update(FILE *logfp,char *destdir,char *statefname,char *komodofname)
return(jprint(retjson,1)); return(jprint(retjson,1));
} }
#ifndef FROM_PRIVATEBET
int main(int argc, const char * argv[]) int main(int argc, const char * argv[])
{ {
struct tai T; uint32_t timestamp; struct DEXstats_disp prices[365]; int32_t i,n,seconds,leftdatenum; FILE *fp,*logfp; char *filestr,*retstr,*statefname,logfname[512],komodofile[512]; uint16_t port = LP_RPCPORT; struct tai T; uint32_t timestamp; struct DEXstats_disp prices[365]; int32_t i,n,seconds,leftdatenum; FILE *fp,*logfp; char *filestr,*retstr,*statefname,logfname[512],komodofile[512]; uint16_t port = LP_RPCPORT;
@ -1150,3 +1185,4 @@ int main(int argc, const char * argv[])
return 0; return 0;
} }
#endif #endif
#endif

1
marketmaker.vcxproj

@ -130,6 +130,7 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>Ws2_32.lib;Advapi32.lib;$(SolutionDir)OSlibs\win\release\pthreadVC2.lib;libcurl.lib;nanomsg.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

Loading…
Cancel
Save