/****************************************************************************** * Copyright © 2014-2017 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ // // LP_statemachine.c // marketmaker // int32_t basilisk_process_swapverify(void *ptr,int32_t (*internal_func)(void *ptr,uint8_t *data,int32_t datalen),uint32_t channel,uint32_t msgid,uint8_t *data,int32_t datalen,uint32_t expiration,uint32_t duration) { struct basilisk_swap *swap = ptr; if ( internal_func != 0 ) return((*internal_func)(swap,data,datalen)); else return(0); } int32_t basilisk_priviextract(struct iguana_info *coin,char *name,bits256 *destp,uint8_t secret160[20],bits256 srctxid,int32_t srcvout) { /*bits256 txid; char str[65]; int32_t i,vini,scriptlen; uint8_t rmd160[20],scriptsig[IGUANA_MAXSCRIPTSIZE]; memset(privkey.bytes,0,sizeof(privkey)); // use dex_listtransactions! if ( (vini= iguana_vinifind(coin,&txid,srctxid,srcvout)) >= 0 ) { if ( (scriptlen= iguana_scriptsigextract(coin,scriptsig,sizeof(scriptsig),txid,vini)) > 32 ) { for (i=0; i<32; i++) privkey.bytes[i] = scriptsig[scriptlen - 33 + i]; revcalc_rmd160_sha256(rmd160,privkey);//.bytes,sizeof(privkey)); if ( memcmp(secret160,rmd160,sizeof(rmd160)) == sizeof(rmd160) ) { *destp = privkey; printf("basilisk_priviextract found privi %s (%s)\n",name,bits256_str(str,privkey)); return(0); } } }*/ return(-1); } int32_t basilisk_verify_privi(void *ptr,uint8_t *data,int32_t datalen); int32_t basilisk_privBn_extract(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { if ( basilisk_priviextract(&swap->bobcoin,"privBn",&swap->I.privBn,swap->I.secretBn,swap->bobrefund.I.actualtxid,0) == 0 ) { printf("extracted privBn from blockchain\n"); } else if ( basilisk_swapget(swap,0x40000000,data,maxlen,basilisk_verify_privi) == 0 ) { } if ( bits256_nonz(swap->I.privBn) != 0 && swap->alicereclaim.I.datalen == 0 ) { char str[65]; printf("got privBn.%s\n",bits256_str(str,swap->I.privBn)); return(basilisk_alicepayment_spend(swap,&swap->alicereclaim)); } return(-1); } int32_t basilisk_privAm_extract(struct basilisk_swap *swap) { if ( basilisk_priviextract(&swap->bobcoin,"privAm",&swap->I.privAm,swap->I.secretAm,swap->bobpayment.I.actualtxid,0) == 0 ) { printf("extracted privAm from blockchain\n"); } if ( bits256_nonz(swap->I.privAm) != 0 && swap->bobspend.I.datalen == 0 ) { char str[65]; printf("got privAm.%s\n",bits256_str(str,swap->I.privAm)); return(basilisk_alicepayment_spend(swap,&swap->bobspend)); } return(-1); } int32_t basilisk_verify_otherstatebits(void *ptr,uint8_t *data,int32_t datalen) { int32_t retval; struct basilisk_swap *swap = ptr; if ( datalen == sizeof(swap->I.otherstatebits) ) { retval = iguana_rwnum(0,data,sizeof(swap->I.otherstatebits),&swap->I.otherstatebits); return(retval); } else return(-1); } int32_t basilisk_verify_statebits(void *ptr,uint8_t *data,int32_t datalen) { int32_t retval = -1; uint32_t statebits; struct basilisk_swap *swap = ptr; if ( datalen == sizeof(swap->I.statebits) ) { retval = iguana_rwnum(0,data,sizeof(swap->I.statebits),&statebits); if ( statebits != swap->I.statebits ) { printf("statebits.%x != %x\n",statebits,swap->I.statebits); return(-1); } } return(retval); } void basilisk_sendstate(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t datalen=0; datalen = iguana_rwnum(1,data,sizeof(swap->I.statebits),&swap->I.statebits); LP_swapsend(swap,0x80000000,data,datalen,0,0); } int32_t basilisk_swapiteration(struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t j,datalen,retval = 0; uint32_t savestatebits=0,saveotherbits=0; if ( swap->I.iambob != 0 ) swap->I.statebits |= 0x80; while ( swap->aborted == 0 && ((swap->I.otherstatebits & 0x80) == 0 || (swap->I.statebits & 0x80) == 0) && retval == 0 && time(NULL) < swap->I.expiration ) { if ( swap->connected == 0 ) basilisk_psockinit(swap,swap->I.iambob != 0); printf("D r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); if ( swap->I.iambob != 0 && (swap->I.statebits & 0x80) == 0 ) // wait for fee { if ( basilisk_swapget(swap,0x80,data,maxlen,basilisk_verify_otherfee) == 0 ) { // verify and submit otherfee swap->I.statebits |= 0x80; basilisk_sendstate(swap,data,maxlen); } } else if ( swap->I.iambob == 0 ) swap->I.statebits |= 0x80; basilisk_sendstate(swap,data,maxlen); basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); if ( (swap->I.otherstatebits & 0x80) != 0 && (swap->I.statebits & 0x80) != 0 ) break; if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); basilisk_sendstate(swap,data,maxlen); if ( (swap->I.otherstatebits & 0x80) == 0 ) LP_swapdata_rawtxsend(swap,0x80,data,maxlen,&swap->myfee,0x40,0); } basilisk_swap_saveupdate(swap); while ( swap->aborted == 0 && retval == 0 && time(NULL) < swap->I.expiration ) // both sides have setup required data and paid txfee { basilisk_swap_saveupdate(swap); if ( swap->connected == 0 ) basilisk_psockinit(swap,swap->I.iambob != 0); //if ( (rand() % 30) == 0 ) printf("E r%u/q%u swapstate.%x otherstate.%x remaining %d\n",swap->I.req.requestid,swap->I.req.quoteid,swap->I.statebits,swap->I.otherstatebits,(int32_t)(swap->I.expiration-time(NULL))); if ( swap->I.iambob != 0 ) { //printf("BOB\n"); if ( (swap->I.statebits & 0x100) == 0 ) { printf("send bobdeposit\n"); swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x200,data,maxlen,&swap->bobdeposit,0x100,0); } // [BLOCKING: altfound] make sure altpayment is confirmed and send payment else if ( (swap->I.statebits & 0x1000) == 0 ) { printf("check alicepayment\n"); if ( basilisk_swapget(swap,0x1000,data,maxlen,basilisk_verify_alicepaid) == 0 ) { swap->I.statebits |= 0x1000; printf("got alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); } } else if ( (swap->I.statebits & 0x2000) == 0 ) { if ( (swap->I.aliceconfirms == 0 && swap->aliceunconf != 0) || LP_numconfirms(swap,&swap->alicepayment) >= swap->I.aliceconfirms ) { swap->I.statebits |= 0x2000; printf("alicepayment confirmed\n"); } } else if ( (swap->I.statebits & 0x4000) == 0 ) { basilisk_bobscripts_set(swap,0,1); printf("send bobpayment\n"); swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x8000,data,maxlen,&swap->bobpayment,0x4000,0); } // [BLOCKING: privM] Bob waits for privAm either from Alice or alice blockchain else if ( (swap->I.statebits & 0xc0000) != 0xc0000 ) { if ( basilisk_swapget(swap,0x40000,data,maxlen,basilisk_verify_privi) == 0 || basilisk_privAm_extract(swap) == 0 ) // divulges privAm { //printf("got privi spend alicepayment, dont divulge privBn until bobspend propagated\n"); basilisk_alicepayment_spend(swap,&swap->bobspend); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobspend,0x40000,1) == 0 ) printf("Bob error spending alice payment\n"); else { tradebot_swap_balancingtrade(swap,1); printf("Bob spends alicepayment aliceconfirms.%d\n",swap->I.aliceconfirms); swap->I.statebits |= 0x40000; if ( LP_numconfirms(swap,&swap->bobspend) >= swap->I.aliceconfirms ) { printf("bobspend confirmed\n"); swap->I.statebits |= 0x80000; printf("Bob confirming spend of Alice's payment\n"); sleep(DEX_SLEEP); } retval = 1; } } } if ( swap->bobpayment.I.locktime != 0 && time(NULL) > swap->bobpayment.I.locktime ) { // submit reclaim of payment printf("bob reclaims bobpayment\n"); swap->I.statebits |= (0x40000 | 0x80000); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->bobreclaim,0,0) == 0 ) printf("Bob error reclaiming own payment after alice timed out\n"); else { printf("Bob reclaimed own payment\n"); while ( 0 && (swap->I.statebits & 0x100000) == 0 ) // why wait for own tx? { if ( LP_numconfirms(swap,&swap->bobreclaim) >= 1 ) { printf("bobreclaim confirmed\n"); swap->I.statebits |= 0x100000; printf("Bob confirms reclain of payment\n"); break; } } retval = 1; } } } else { //printf("ALICE\n"); // [BLOCKING: depfound] Alice waits for deposit to confirm and sends altpayment if ( (swap->I.statebits & 0x200) == 0 ) { printf("checkfor deposit\n"); if ( basilisk_swapget(swap,0x200,data,maxlen,basilisk_verify_bobdeposit) == 0 ) { // verify deposit and submit, set confirmed height printf("got bobdeposit\n"); swap->I.statebits |= 0x200; } else printf("no valid deposit\n"); } else if ( (swap->I.statebits & 0x400) == 0 ) { if ( basilisk_istrustedbob(swap) != 0 || (swap->I.bobconfirms == 0 && swap->depositunconf != 0) || LP_numconfirms(swap,&swap->bobdeposit) >= swap->I.bobconfirms ) { printf("bobdeposit confirmed\n"); swap->I.statebits |= 0x400; } } else if ( (swap->I.statebits & 0x800) == 0 ) { printf("send alicepayment\n"); swap->I.statebits |= LP_swapdata_rawtxsend(swap,0x1000,data,maxlen,&swap->alicepayment,0x800,0); } // [BLOCKING: payfound] make sure payment is confrmed and send in spend or see bob's reclaim and claim else if ( (swap->I.statebits & 0x8000) == 0 ) { if ( basilisk_swapget(swap,0x8000,data,maxlen,basilisk_verify_bobpaid) == 0 ) { printf("got bobpayment\n"); tradebot_swap_balancingtrade(swap,0); // verify payment and submit, set confirmed height swap->I.statebits |= 0x8000; } } else if ( (swap->I.statebits & 0x10000) == 0 ) { if ( basilisk_istrustedbob(swap) != 0 || (swap->I.bobconfirms == 0 && swap->paymentunconf != 0) || LP_numconfirms(swap,&swap->bobpayment) >= swap->I.bobconfirms ) { printf("bobpayment confirmed\n"); swap->I.statebits |= 0x10000; } } else if ( (swap->I.statebits & 0x20000) == 0 ) { printf("alicespend bobpayment\n"); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->alicespend,0x20000,0) != 0 )//&& (swap->aliceunconf != 0 || basilisk_numconfirms(swap,&swap->alicespend) > 0) ) { swap->I.statebits |= 0x20000; } } else if ( (swap->I.statebits & 0x40000) == 0 ) { int32_t numconfs; if ( (numconfs= LP_numconfirms(swap,&swap->alicespend)) >= swap->I.bobconfirms ) { for (j=datalen=0; j<32; j++) data[datalen++] = swap->I.privAm.bytes[j]; printf("send privAm %x\n",swap->I.statebits); swap->I.statebits |= LP_swapsend(swap,0x40000,data,datalen,0x20000,swap->I.crcs_mypriv); printf("Alice confirms spend of Bob's payment\n"); retval = 1; } else printf("alicespend numconfs.%d < %d\n",numconfs,swap->I.bobconfirms); } if ( swap->bobdeposit.I.locktime != 0 && time(NULL) > swap->bobdeposit.I.locktime ) { printf("Alice claims deposit\n"); if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->aliceclaim,0,0) == 0 ) printf("Alice couldnt claim deposit\n"); else { printf("Alice claimed deposit\n"); retval = 1; } } else if ( swap->aborted != 0 || basilisk_privBn_extract(swap,data,maxlen) == 0 ) { printf("Alice reclaims her payment\n"); swap->I.statebits |= 0x40000000; if ( LP_swapdata_rawtxsend(swap,0,data,maxlen,&swap->alicereclaim,0x40000000,0) == 0 ) printf("Alice error sending alicereclaim\n"); else { printf("Alice reclaimed her payment\n"); retval = 1; } } } if ( (rand() % 30) == 0 ) printf("finished swapstate.%x other.%x\n",swap->I.statebits,swap->I.otherstatebits); if ( swap->I.statebits == savestatebits && swap->I.otherstatebits == saveotherbits ) sleep(DEX_SLEEP + (swap->I.iambob == 0)*1); savestatebits = swap->I.statebits; saveotherbits = swap->I.otherstatebits; basilisk_sendstate(swap,data,maxlen); basilisk_swapget(swap,0x80000000,data,maxlen,basilisk_verify_otherstatebits); } return(retval); } int32_t swapcompleted(struct basilisk_swap *swap) { if ( swap->I.iambob != 0 ) return(swap->I.bobspent); else return(swap->I.alicespent); } cJSON *swapjson(struct basilisk_swap *swap) { cJSON *retjson = cJSON_CreateObject(); return(retjson); } int32_t basilisk_rwDEXquote(int32_t rwflag,uint8_t *serialized,struct basilisk_request *rp) { int32_t len = 0; len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->requestid),&rp->requestid); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->timestamp),&rp->timestamp); // must be 2nd len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->quoteid),&rp->quoteid); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->quotetime),&rp->quotetime); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->optionhours),&rp->optionhours); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->srcamount),&rp->srcamount); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->unused),&rp->unused); len += iguana_rwbignum(rwflag,&serialized[len],sizeof(rp->srchash),rp->srchash.bytes); len += iguana_rwbignum(rwflag,&serialized[len],sizeof(rp->desthash),rp->desthash.bytes); len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->destamount),&rp->destamount); if ( rwflag != 0 ) { memcpy(&serialized[len],rp->src,sizeof(rp->src)), len += sizeof(rp->src); memcpy(&serialized[len],rp->dest,sizeof(rp->dest)), len += sizeof(rp->dest); } else { memcpy(rp->src,&serialized[len],sizeof(rp->src)), len += sizeof(rp->src); memcpy(rp->dest,&serialized[len],sizeof(rp->dest)), len += sizeof(rp->dest); } //len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->DEXselector),&rp->DEXselector); //len += iguana_rwnum(rwflag,&serialized[len],sizeof(rp->extraspace),&rp->extraspace); if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) printf(" basilisk_rwDEXquote.%d: quoteid.%u mismatch calc %u rp.%p\n",rwflag,rp->quoteid,basilisk_quoteid(rp),rp); if ( basilisk_requestid(rp) != rp->requestid ) printf(" basilisk_rwDEXquote.%d: requestid.%u mismatch calc %u rp.%p\n",rwflag,rp->requestid,basilisk_requestid(rp),rp); return(len); } struct basilisk_request *basilisk_parsejson(struct basilisk_request *rp,cJSON *reqjson) { uint32_t requestid,quoteid; memset(rp,0,sizeof(*rp)); rp->srchash = jbits256(reqjson,"srchash"); rp->desthash = jbits256(reqjson,"desthash"); rp->srcamount = j64bits(reqjson,"srcamount"); //rp->minamount = j64bits(reqjson,"minamount"); //rp->destamount = j64bits(reqjson,"destamount"); rp->destamount = j64bits(reqjson,"destsatoshis"); //printf("parse DESTSATOSHIS.%llu (%s)\n",(long long)rp->destamount,jprint(reqjson,0)); requestid = juint(reqjson,"requestid"); quoteid = juint(reqjson,"quoteid"); //if ( jstr(reqjson,"relay") != 0 ) // rp->relaybits = (uint32_t)calc_ipbits(jstr(reqjson,"relay")); rp->timestamp = juint(reqjson,"timestamp"); rp->quotetime = juint(reqjson,"quotetime"); safecopy(rp->src,jstr(reqjson,"src"),sizeof(rp->src)); safecopy(rp->dest,jstr(reqjson,"dest"),sizeof(rp->dest)); if ( quoteid != 0 ) { rp->quoteid = basilisk_quoteid(rp); if ( quoteid != rp->quoteid ) printf("basilisk_parsejson quoteid.%u != %u error\n",quoteid,rp->quoteid); } rp->requestid = basilisk_requestid(rp); if ( requestid != rp->requestid ) { int32_t i; for (i=0; irequestid); } return(rp); } cJSON *basilisk_requestjson(struct basilisk_request *rp) { cJSON *item = cJSON_CreateObject(); /*if ( rp->relaybits != 0 ) { expand_ipbits(ipaddr,rp->relaybits); jaddstr(item,"relay",ipaddr); }*/ jaddbits256(item,"srchash",rp->srchash); if ( bits256_nonz(rp->desthash) != 0 ) jaddbits256(item,"desthash",rp->desthash); jaddstr(item,"src",rp->src); if ( rp->srcamount != 0 ) jadd64bits(item,"srcamount",rp->srcamount); //if ( rp->minamount != 0 ) // jadd64bits(item,"minamount",rp->minamount); jaddstr(item,"dest",rp->dest); if ( rp->destamount != 0 ) { //jadd64bits(item,"destamount",rp->destamount); jadd64bits(item,"destsatoshis",rp->destamount); //printf("DESTSATOSHIS.%llu\n",(long long)rp->destamount); } jaddnum(item,"quotetime",rp->quotetime); jaddnum(item,"timestamp",rp->timestamp); jaddnum(item,"requestid",rp->requestid); jaddnum(item,"quoteid",rp->quoteid); //jaddnum(item,"DEXselector",rp->DEXselector); jaddnum(item,"optionhours",rp->optionhours); //jaddnum(item,"profit",(double)rp->profitmargin / 1000000.); if ( rp->quoteid != 0 && basilisk_quoteid(rp) != rp->quoteid ) printf("quoteid mismatch %u vs %u\n",basilisk_quoteid(rp),rp->quoteid); if ( basilisk_requestid(rp) != rp->requestid ) printf("requestid mismatch %u vs calc %u\n",rp->requestid,basilisk_requestid(rp)); { int32_t i; struct basilisk_request R; if ( basilisk_parsejson(&R,item) != 0 ) { if ( memcmp(&R,rp,sizeof(*rp)-sizeof(uint32_t)) != 0 ) { for (i=0; iI.req.requestid); jaddnum(item,"quoteid",swap->I.req.quoteid); jaddnum(item,"state",swap->I.statebits); jaddnum(item,"otherstate",swap->I.otherstatebits); jadd(item,"request",basilisk_requestjson(&swap->I.req)); return(item); } #ifdef later cJSON *basilisk_privkeyarray(struct iguana_info *coin,cJSON *vins) { cJSON *privkeyarray,*item,*sobj; struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],account[128],wifstr[64],str[65],typestr[64],*hexstr; uint8_t script[1024]; int32_t i,n,len,vout; bits256 txid,privkey; double bidasks[2]; privkeyarray = cJSON_CreateArray(); //printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr); if ( (n= cJSON_GetArraySize(vins)) > 0 ) { for (i=0; i= 0 ) { iguana_txidcategory(coin,account,coinaddr,txid,vout); if ( coinaddr[0] == 0 && (sobj= jobj(item,"scriptPubKey")) != 0 && (hexstr= jstr(sobj,"hex")) != 0 && is_hexstr(hexstr,0) > 0 ) { len = (int32_t)strlen(hexstr) >> 1; if ( len < (sizeof(script) << 1) ) { decode_hex(script,len,hexstr); if ( len == 25 && script[0] == 0x76 && script[1] == 0xa9 && script[2] == 0x14 ) bitcoin_address(coinaddr,coin->chain->pubtype,script+3,20); } } if ( coinaddr[0] != 0 ) { if ( (waddr= iguana_waddresssearch(&wacct,coinaddr)) != 0 ) { bitcoin_priv2wif(wifstr,waddr->privkey,coin->chain->wiftype); jaddistr(privkeyarray,waddr->wifstr); } else if ( smartaddress(typestr,bidasks,&privkey,coin->symbol,coinaddr) >= 0 ) { bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); jaddistr(privkeyarray,wifstr); } else printf("cant find (%s) in wallet\n",coinaddr); } else printf("cant coinaddr from (%s).v%d\n",bits256_str(str,txid),vout); } else printf("invalid txid/vout %d of %d\n",i,n); } } return(privkeyarray); } #endif /*void basilisk_swap_purge(struct basilisk_swap *swap) { int32_t i,n; // while still in orderbook, wait //return; portable_mutex_lock(&myinfo->DEX_swapmutex); n = myinfo->numswaps; for (i=0; iswaps[i] == swap ) { myinfo->swaps[i] = myinfo->swaps[--myinfo->numswaps]; myinfo->swaps[myinfo->numswaps] = 0; basilisk_swap_finished(swap); break; } portable_mutex_unlock(&myinfo->DEX_swapmutex); }*/