jl777
7 years ago
8 changed files with 444 additions and 430 deletions
@ -0,0 +1,436 @@ |
|||
|
|||
/******************************************************************************
|
|||
* 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_utxo.c
|
|||
// marketmaker
|
|||
//
|
|||
|
|||
uint64_t LP_value_extract(cJSON *obj) |
|||
{ |
|||
double val = 0.; uint64_t value; |
|||
if ( (val= jdouble(obj,"amount")) < SMALLVAL ) |
|||
val = jdouble(obj,"value"); |
|||
if ( val > SMALLVAL ) |
|||
value = (val * SATOSHIDEN + 0.0000000049); |
|||
else value = 0; |
|||
return(value); |
|||
} |
|||
|
|||
void LP_utxosetkey(uint8_t *key,bits256 txid,int32_t vout) |
|||
{ |
|||
memcpy(key,txid.bytes,sizeof(txid)); |
|||
memcpy(&key[sizeof(txid)],&vout,sizeof(vout)); |
|||
} |
|||
|
|||
struct LP_utxoinfo *_LP_utxofind(int32_t iambob,bits256 txid,int32_t vout) |
|||
{ |
|||
struct LP_utxoinfo *utxo=0; uint8_t key[sizeof(txid) + sizeof(vout)]; |
|||
LP_utxosetkey(key,txid,vout); |
|||
HASH_FIND(hh,LP_utxoinfos[iambob],key,sizeof(key),utxo); |
|||
return(utxo); |
|||
} |
|||
|
|||
struct LP_utxoinfo *_LP_utxo2find(int32_t iambob,bits256 txid2,int32_t vout2) |
|||
{ |
|||
struct LP_utxoinfo *utxo=0; uint8_t key2[sizeof(txid2) + sizeof(vout2)]; |
|||
LP_utxosetkey(key2,txid2,vout2); |
|||
HASH_FIND(hh2,LP_utxoinfos2[iambob],key2,sizeof(key2),utxo); |
|||
return(utxo); |
|||
} |
|||
|
|||
struct LP_utxoinfo *LP_utxofind(int32_t iambob,bits256 txid,int32_t vout) |
|||
{ |
|||
struct LP_utxoinfo *utxo=0; |
|||
portable_mutex_lock(&LP_utxomutex); |
|||
utxo = _LP_utxofind(iambob,txid,vout); |
|||
portable_mutex_unlock(&LP_utxomutex); |
|||
return(utxo); |
|||
} |
|||
|
|||
struct LP_utxoinfo *LP_utxo2find(int32_t iambob,bits256 txid2,int32_t vout2) |
|||
{ |
|||
struct LP_utxoinfo *utxo=0; |
|||
portable_mutex_lock(&LP_utxomutex); |
|||
utxo = _LP_utxo2find(iambob,txid2,vout2); |
|||
portable_mutex_unlock(&LP_utxomutex); |
|||
return(utxo); |
|||
} |
|||
|
|||
struct LP_transaction *LP_transactionfind(struct iguana_info *coin,bits256 txid) |
|||
{ |
|||
struct LP_transaction *tx; |
|||
portable_mutex_lock(&coin->txmutex); |
|||
HASH_FIND(hh,coin->transactions,txid.bytes,sizeof(txid),tx); |
|||
portable_mutex_unlock(&coin->txmutex); |
|||
return(tx); |
|||
} |
|||
|
|||
struct LP_transaction *LP_transactionadd(struct iguana_info *coin,bits256 txid,int32_t height,int32_t numvouts,int32_t numvins) |
|||
{ |
|||
struct LP_transaction *tx; int32_t i; |
|||
if ( (tx= LP_transactionfind(coin,txid)) == 0 ) |
|||
{ |
|||
//char str[65]; printf("%s ht.%d u.%u NEW TXID.(%s) vouts.[%d]\n",coin->symbol,height,timestamp,bits256_str(str,txid),numvouts);
|
|||
//if ( bits256_nonz(txid) == 0 && tx->height == 0 )
|
|||
// getchar();
|
|||
tx = calloc(1,sizeof(*tx) + (sizeof(*tx->outpoints) * numvouts)); |
|||
for (i=0; i<numvouts; i++) |
|||
tx->outpoints[i].spendvini = -1; |
|||
tx->height = height; |
|||
tx->numvouts = numvouts; |
|||
tx->numvins = numvins; |
|||
//tx->timestamp = timestamp;
|
|||
tx->txid = txid; |
|||
portable_mutex_lock(&coin->txmutex); |
|||
HASH_ADD_KEYPTR(hh,coin->transactions,tx->txid.bytes,sizeof(tx->txid),tx); |
|||
portable_mutex_unlock(&coin->txmutex); |
|||
} // else printf("warning adding already existing txid %s\n",bits256_str(str,tx->txid));
|
|||
return(tx); |
|||
} |
|||
|
|||
uint64_t LP_txinterestvalue(uint64_t *interestp,char *destaddr,struct iguana_info *coin,bits256 txid,int32_t vout) |
|||
{ |
|||
uint64_t interest,value = 0; cJSON *txobj,*sobj,*array; int32_t n=0; |
|||
*interestp = 0; |
|||
destaddr[0] = 0; |
|||
if ( (txobj= LP_gettxout(coin->symbol,txid,vout)) != 0 ) |
|||
{ |
|||
if ( (value= LP_value_extract(txobj)) == 0 ) |
|||
{ |
|||
char str[65]; printf("%s LP_txvalue.%s strange utxo.(%s) vout.%d\n",coin->symbol,bits256_str(str,txid),jprint(txobj,0),vout); |
|||
} |
|||
else if ( strcmp(coin->symbol,"KMD") == 0 ) |
|||
{ |
|||
if ( (interest= jdouble(txobj,"interest")) != 0. ) |
|||
{ |
|||
//printf("add interest of %.8f to %.8f\n",interest,dstr(value));
|
|||
*interestp = SATOSHIDEN * interest; |
|||
} |
|||
} |
|||
if ( (sobj= jobj(txobj,"scriptPubKey")) != 0 && (array= jarray(&n,sobj,"addresses")) != 0 ) |
|||
{ |
|||
strcpy(destaddr,jstri(array,0)); |
|||
//printf("set destaddr.(%s)\n",destaddr);
|
|||
if ( n > 1 ) |
|||
printf("LP_txinterestvalue warning: violation of 1 output assumption n.%d\n",n); |
|||
} else printf("LP_txinterestvalue no addresses found?\n"); |
|||
//char str[65]; printf("dest.(%s) %.8f <- %s.(%s) txobj.(%s)\n",destaddr,dstr(value),coin->symbol,bits256_str(str,txid),jprint(txobj,0));
|
|||
free_json(txobj); |
|||
} //else { char str[65]; printf("null gettxout return %s/v%d\n",bits256_str(str,txid),vout); }
|
|||
return(value); |
|||
} |
|||
|
|||
int32_t LP_transactioninit(struct iguana_info *coin,bits256 txid,int32_t iter) |
|||
{ |
|||
struct LP_transaction *tx; char *address; int32_t i,n,height,numvouts,numvins,spentvout; cJSON *txobj,*vins,*vouts,*vout,*vin,*sobj,*addresses; bits256 spenttxid; char str[65]; |
|||
if ( (txobj= LP_gettx(coin->symbol,txid)) != 0 ) |
|||
{ |
|||
//printf("TX.(%s)\n",jprint(txobj,0));
|
|||
if ( coin->electrum == 0 ) |
|||
height = LP_txheight(coin,txid); |
|||
else height = -1; |
|||
vins = jarray(&numvins,txobj,"vin"); |
|||
vouts = jarray(&numvouts,txobj,"vout"); |
|||
if ( iter == 0 && vouts != 0 && (tx= LP_transactionadd(coin,txid,height,numvouts,numvins)) != 0 ) |
|||
{ |
|||
//printf("create txid numvouts.%d numvins.%d\n",numvouts,numvins);
|
|||
for (i=0; i<numvouts; i++) |
|||
{ |
|||
vout = jitem(vouts,i); |
|||
tx->outpoints[i].value = LP_value_extract(vout); |
|||
tx->outpoints[i].interest = SATOSHIDEN * jdouble(vout,"interest"); |
|||
if ( (sobj= jobj(vout,"scriptPubKey")) != 0 ) |
|||
{ |
|||
if ( (addresses= jarray(&n,sobj,"addresses")) != 0 && n > 0 ) |
|||
{ |
|||
if ( n > 1 ) |
|||
printf("LP_transactioninit: txid.(%s) multiple addresses.[%s]\n",bits256_str(str,txid),jprint(addresses,0)); |
|||
if ( (address= jstri(addresses,0)) != 0 && strlen(address) < sizeof(tx->outpoints[i].coinaddr) ) |
|||
{ |
|||
strcpy(tx->outpoints[i].coinaddr,address); |
|||
//printf("(%s %.8f) ",address,dstr(tx->outpoints[i].value));
|
|||
} else if ( tx->outpoints[i].value != 0 ) |
|||
printf("LP_transactioninit: unexpected address.(%s)\n",jprint(addresses,0)); |
|||
} |
|||
//else if ( tx->outpoints[i].value != 0 )
|
|||
// printf("LP_transactioninit: pax tx ht.%d i.%d (%s) n.%d\n",height,i,jprint(vout,0),n);
|
|||
} |
|||
} |
|||
//printf("numvouts.%d\n",numvouts);
|
|||
} |
|||
if ( iter == 1 && vins != 0 ) |
|||
{ |
|||
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 ) |
|||
{ |
|||
tx->outpoints[spentvout].spendtxid = txid; |
|||
tx->outpoints[spentvout].spendvini = i; |
|||
tx->outpoints[spentvout].spendheight = height; |
|||
//printf("spend %s %s/v%d at ht.%d\n",coin->symbol,bits256_str(str,tx->txid),spentvout,height);
|
|||
} else printf("LP_transactioninit: %s spentvout.%d < numvouts.%d\n",bits256_str(str,spenttxid),spentvout,tx->numvouts); |
|||
} //else printf("LP_transactioninit: couldnt find (%s) ht.%d %s\n",bits256_str(str,spenttxid),height,jprint(vin,0));
|
|||
if ( bits256_cmp(spenttxid,txid) == 0 ) |
|||
printf("spending same tx's %p vout ht.%d %s.[%d] s%d\n",tx,height,bits256_str(str,txid),tx!=0?tx->numvouts:0,spentvout); |
|||
} |
|||
} |
|||
free_json(txobj); |
|||
return(0); |
|||
} //else printf("LP_transactioninit error for %s %s\n",coin->symbol,bits256_str(str,txid));
|
|||
return(-1); |
|||
} |
|||
|
|||
int32_t LP_txheight(struct iguana_info *coin,bits256 txid) |
|||
{ |
|||
bits256 blockhash; struct LP_transaction *tx; cJSON *blockobj,*txobj; int32_t height = 0; |
|||
if ( coin == 0 ) |
|||
return(-1); |
|||
if ( coin->electrum == 0 ) |
|||
{ |
|||
if ( (txobj= LP_gettx(coin->symbol,txid)) != 0 ) |
|||
{ |
|||
//*timestampp = juint(txobj,"locktime");
|
|||
//*blocktimep = juint(txobj,"blocktime");
|
|||
blockhash = jbits256(txobj,"blockhash"); |
|||
if ( bits256_nonz(blockhash) != 0 && (blockobj= LP_getblock(coin->symbol,blockhash)) != 0 ) |
|||
{ |
|||
height = jint(blockobj,"height"); |
|||
//printf("%s LP_txheight.%d\n",coin->symbol,height);
|
|||
free_json(blockobj); |
|||
} //else printf("%s LP_txheight error (%s)\n",coin->symbol,jprint(txobj,0));
|
|||
free_json(txobj); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if ( (tx= LP_transactionfind(coin,txid)) != 0 ) |
|||
height = tx->height; |
|||
} |
|||
return(height); |
|||
} |
|||
|
|||
int32_t LP_numconfirms(char *symbol,char *coinaddr,bits256 txid,int32_t mempool) |
|||
{ |
|||
struct iguana_info *coin; int32_t ht,numconfirms = 100; |
|||
//#ifndef BASILISK_DISABLEWAITTX
|
|||
cJSON *txobj; |
|||
if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) |
|||
return(-1); |
|||
if ( coin->electrum == 0 ) |
|||
{ |
|||
numconfirms = -1; |
|||
if ( (txobj= LP_gettx(symbol,txid)) != 0 ) |
|||
{ |
|||
if ( coin->electrum == 0 ) |
|||
numconfirms = jint(txobj,"confirmations"); |
|||
else numconfirms = coin->height - jint(txobj,"height"); |
|||
free_json(txobj); |
|||
} |
|||
else if ( mempool != 0 && LP_mempoolscan(symbol,txid) >= 0 ) |
|||
numconfirms = 0; |
|||
} |
|||
else |
|||
{ |
|||
if ( (ht= LP_txheight(coin,txid)) > 0 && ht <= coin->height ) |
|||
numconfirms = (coin->height - ht); |
|||
else if ( mempool != 0 && LP_waitmempool(symbol,coinaddr,txid,-1) >= 0 ) |
|||
numconfirms = 0; |
|||
} |
|||
//#endif
|
|||
return(numconfirms); |
|||
} |
|||
|
|||
int64_t basilisk_txvalue(char *symbol,bits256 txid,int32_t vout) |
|||
{ |
|||
char destaddr[64]; uint64_t value,interest = 0; struct iguana_info *coin; |
|||
if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) |
|||
return(0); |
|||
//char str[65]; printf("%s txvalue.(%s)\n",symbol,bits256_str(str,txid));
|
|||
value = LP_txinterestvalue(&interest,destaddr,coin,txid,vout); |
|||
return(value + interest); |
|||
} |
|||
|
|||
uint64_t LP_txvalue(char *coinaddr,char *symbol,bits256 txid,int32_t vout) |
|||
{ |
|||
struct LP_transaction *tx; cJSON *txobj; uint64_t value; struct iguana_info *coin; char str[65],str2[65]; |
|||
if ( bits256_nonz(txid) == 0 ) |
|||
return(0); |
|||
if ( (coin= LP_coinfind(symbol)) == 0 || coin->inactive != 0 ) |
|||
return(0); |
|||
if ( coinaddr != 0 ) |
|||
coinaddr[0] = 0; |
|||
if ( (tx= LP_transactionfind(coin,txid)) == 0 ) |
|||
{ |
|||
LP_transactioninit(coin,txid,0); |
|||
LP_transactioninit(coin,txid,1); |
|||
tx = LP_transactionfind(coin,txid); |
|||
} |
|||
if ( tx != 0 ) |
|||
{ |
|||
if ( vout < tx->numvouts ) |
|||
{ |
|||
if ( bits256_nonz(tx->outpoints[vout].spendtxid) != 0 ) |
|||
{ |
|||
printf("LP_txvalue %s/v%d is spent at %s\n",bits256_str(str,txid),vout,bits256_str(str2,tx->outpoints[vout].spendtxid)); |
|||
return(0); |
|||
} |
|||
else |
|||
{ |
|||
if ( coinaddr != 0 ) |
|||
{ |
|||
//if ( tx->outpoints[vout].coinaddr[0] == 0 )
|
|||
// tx->outpoints[vout].value = LP_txinterestvalue(&tx->outpoints[vout].interest,tx->outpoints[vout].coinaddr,coin,txid,vout);
|
|||
strcpy(coinaddr,tx->outpoints[vout].coinaddr); |
|||
//printf("(%s) return value %.8f + interest %.8f\n",coinaddr,dstr(tx->outpoints[vout].value),dstr(tx->outpoints[vout].interest));
|
|||
} |
|||
return(tx->outpoints[vout].value + tx->outpoints[vout].interest); |
|||
} |
|||
} else printf("LP_txvalue vout.%d >= tx->numvouts.%d\n",vout,tx->numvouts); |
|||
} |
|||
else |
|||
{ |
|||
if ( (txobj= LP_gettxout(coin->symbol,txid,vout)) != 0 ) |
|||
{ |
|||
value = SATOSHIDEN * jdouble(txobj,"value"); |
|||
free_json(txobj); |
|||
printf("pruned node? LP_txvalue couldnt find %s tx %s, but gettxout %.8f\n",coin->symbol,bits256_str(str,txid),dstr(value)); |
|||
return(value); |
|||
} |
|||
printf("pruned node? LP_txvalue couldnt find %s tx %s\n",coin->symbol,bits256_str(str,txid)); |
|||
} |
|||
return(0); |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
//struct LP_utxoinfo *utxo;
|
|||
uint64_t val,val2=0,txfee,threshold=0; int32_t bypass = 0; char destaddr[64],destaddr2[64]; struct iguana_info *coin = LP_coinfind(symbol); |
|||
if ( bits256_nonz(txid) == 0 || bits256_nonz(txid2) == 0 ) |
|||
{ |
|||
printf("null txid not eligible\n"); |
|||
return(-1); |
|||
} |
|||
destaddr[0] = destaddr2[0] = 0; |
|||
if ( coin != 0 && IAMLP != 0 && coin->inactive != 0 ) |
|||
bypass = 1; |
|||
if ( bypass != 0 ) |
|||
val = satoshis; |
|||
else val = LP_txvalue(destaddr,symbol,txid,vout); |
|||
txfee = LP_txfeecalc(LP_coinfind(symbol),0); |
|||
if ( val >= satoshis && val > (1+LP_MINSIZE_TXFEEMULT)*txfee ) |
|||
{ |
|||
threshold = (iambob != 0) ? LP_DEPOSITSATOSHIS(satoshis) : (LP_DEXFEE(satoshis) + txfee); |
|||
if ( bypass != 0 ) |
|||
val2 = threshold; |
|||
else val2 = LP_txvalue(destaddr2,symbol,txid2,vout2); |
|||
if ( val2 >= threshold ) |
|||
{ |
|||
if ( bypass == 0 && strcmp(destaddr,destaddr2) != 0 ) |
|||
printf("mismatched %s destaddr (%s) vs (%s)\n",symbol,destaddr,destaddr2); |
|||
else if ( bypass == 0 && ((iambob == 0 && val2 > val) || (iambob != 0 && val2 <= satoshis)) ) |
|||
printf("iambob.%d ineligible due to offsides: val %.8f and val2 %.8f vs %.8f diff %lld\n",iambob,dstr(val),dstr(val2),dstr(satoshis),(long long)(val2 - val)); |
|||
else |
|||
{ |
|||
*valp = val; |
|||
*val2p = val2; |
|||
return(1); |
|||
} |
|||
} // else printf("no val2\n");
|
|||
} |
|||
char str[65],str2[65]; printf("spent.%d %s txid or value %.8f < %.8f or val2 %.8f < %.8f, %s/v%d %s/v%d or < 10x txfee %.8f\n",iambob,symbol,dstr(val),dstr(satoshis),dstr(val2),dstr(threshold),bits256_str(str,txid),vout,bits256_str(str2,txid2),vout2,dstr(txfee)); |
|||
/*for (iter=0; iter<2; iter++)
|
|||
{ |
|||
if ( (utxo= LP_utxofind(iter,txid,vout)) != 0 ) |
|||
{ |
|||
//printf("iambob.%d case 00\n",iter);
|
|||
if ( utxo->T.spentflag == 0 ) |
|||
utxo->T.spentflag = (uint32_t)time(NULL); |
|||
} |
|||
if ( (utxo= LP_utxo2find(iter,txid,vout)) != 0 ) |
|||
{ |
|||
//printf("iambob.%d case 01\n",iter);
|
|||
if ( utxo->T.spentflag == 0 ) |
|||
utxo->T.spentflag = (uint32_t)time(NULL); |
|||
} |
|||
if ( (utxo= LP_utxofind(iter,txid2,vout2)) != 0 ) |
|||
{ |
|||
//printf("iambob.%d case 10\n",iter);
|
|||
if ( utxo->T.spentflag == 0 ) |
|||
utxo->T.spentflag = (uint32_t)time(NULL); |
|||
} |
|||
if ( (utxo= LP_utxo2find(iter,txid2,vout2)) != 0 ) |
|||
{ |
|||
//printf("iambob.%d case 11\n",iter);
|
|||
if ( utxo->T.spentflag == 0 ) |
|||
utxo->T.spentflag = (uint32_t)time(NULL); |
|||
} |
|||
}*/ |
|||
*valp = val; |
|||
*val2p = val2; |
|||
return(0); |
|||
} |
|||
|
|||
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; |
|||
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 ( tx->outpoints[vout].spendheight > 0 ) |
|||
utxo->T.spentflag = tx->outpoints[vout].spendheight; |
|||
else utxo->T.spentflag = 0; |
|||
} |
|||
if ( utxo->T.spentflag != 0 ) |
|||
{ |
|||
char str[65]; printf("prevent adding iambob.%d %s/v%d to inventory\n",iambob,bits256_str(str,txid),vout); |
|||
return(1); |
|||
} |
|||
} |
|||
return(0); |
|||
} |
|||
|
|||
int32_t LP_undospends(struct iguana_info *coin,int32_t lastheight) |
|||
{ |
|||
int32_t i,ht,num = 0; struct LP_transaction *tx,*tmp; |
|||
HASH_ITER(hh,coin->transactions,tx,tmp) |
|||
{ |
|||
for (i=0; i<tx->numvouts; i++) |
|||
{ |
|||
if ( bits256_nonz(tx->outpoints[i].spendtxid) == 0 ) |
|||
continue; |
|||
if ( (ht= tx->outpoints[i].spendheight) == 0 ) |
|||
{ |
|||
tx->outpoints[i].spendheight = LP_txheight(coin,tx->outpoints[i].spendtxid); |
|||
} |
|||
if ( (ht= tx->outpoints[i].spendheight) != 0 && ht > lastheight ) |
|||
{ |
|||
char str[65]; printf("clear spend %s/v%d at ht.%d > lastheight.%d\n",bits256_str(str,tx->txid),i,ht,lastheight); |
|||
tx->outpoints[i].spendheight = 0; |
|||
tx->outpoints[i].spendvini = -1; |
|||
memset(tx->outpoints[i].spendtxid.bytes,0,sizeof(bits256)); |
|||
} |
|||
} |
|||
} |
|||
return(num); |
|||
} |
Loading…
Reference in new issue