/****************************************************************************** * Copyright © 2014-2016 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. * * * ******************************************************************************/ // included from basilisk.c #define SCRIPT_OP_IF 0x63 #define SCRIPT_OP_ELSE 0x67 #define SCRIPT_OP_ENDIF 0x68 int32_t basilisk_bobscript(uint8_t *script,int32_t n,uint32_t *locktimep,int32_t *secretstartp,struct basilisk_swap *swap,int32_t depositflag) { uint8_t pubkeyA[33],pubkeyB[33],*secret160; bits256 cltvpub,destpub; int32_t i; *locktimep = swap->locktime; if ( depositflag != 0 ) { *locktimep += INSTANTDEX_LOCKTIME; cltvpub = swap->pubA0; destpub = swap->pubB0; secret160 = swap->secretBn; pubkeyA[0] = 0x02; pubkeyB[0] = 0x03; } else { cltvpub = swap->pubB1; destpub = swap->pubA0; secret160 = swap->secretAm; pubkeyA[0] = 0x03; pubkeyB[0] = 0x02; } if ( bits256_nonz(cltvpub) == 0 || bits256_nonz(destpub) == 0 ) return(-1); for (i=0; i<20; i++) if ( secret160[i] != 0 ) break; if ( i == 20 ) return(-1); memcpy(pubkeyA+1,cltvpub.bytes,sizeof(cltvpub)); memcpy(pubkeyB+1,destpub.bytes,sizeof(destpub)); script[n++] = SCRIPT_OP_IF; n = bitcoin_checklocktimeverify(script,n,*locktimep); n = bitcoin_pubkeyspend(script,n,pubkeyA); script[n++] = SCRIPT_OP_ELSE; if ( secretstartp != 0 ) *secretstartp = n + 2; n = bitcoin_revealsecret160(script,n,secret160); n = bitcoin_pubkeyspend(script,n,pubkeyB); script[n++] = SCRIPT_OP_ENDIF; return(n); } int32_t basilisk_alicescript(uint8_t *script,int32_t n,char *msigaddr,uint8_t altps2h,bits256 pubAm,bits256 pubBn) { uint8_t p2sh160[20]; struct vin_info V; memset(&V,0,sizeof(V)); memcpy(&V.signers[0].pubkey[1],pubAm.bytes,sizeof(pubAm)), V.signers[0].pubkey[0] = 0x02; memcpy(&V.signers[1].pubkey[1],pubBn.bytes,sizeof(pubBn)), V.signers[1].pubkey[0] = 0x03; V.M = V.N = 2; n = bitcoin_MofNspendscript(p2sh160,script,n,&V); bitcoin_address(msigaddr,altps2h,p2sh160,sizeof(p2sh160)); return(n); } struct basilisk_rawtx *basilisk_swapdata_rawtx(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx) { if ( rawtx->txbytes != 0 && rawtx->datalen <= maxlen ) { memcpy(data,rawtx->txbytes,rawtx->datalen); return(rawtx); } return(0); } int32_t basilisk_verify_otherfee(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { // add verification swap->otherfee.txbytes = calloc(1,datalen); memcpy(swap->otherfee.txbytes,data,datalen); return(0); } int32_t basilisk_verify_bobdeposit(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { // add verification swap->bobdeposit.txbytes = calloc(1,datalen); memcpy(swap->bobdeposit.txbytes,data,datalen); return(0); } int32_t basilisk_verify_bobpaid(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { char *rawtx,*signedtx,hexstr[999],wifstr[128]; cJSON *txobj,*vins,*item,*sobj,*privkeys; int32_t retval = -1,i,len=0; struct vin_info V; // add verification swap->bobpayment.txbytes = calloc(1,datalen); memcpy(swap->bobpayment.txbytes,data,datalen); swap->bobpayment.signedtxid = bits256_doublesha256(0,data,datalen); // OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG memset(&V,0,sizeof(V)); V.signers[0].privkey = swap->myprivs[0]; privkeys = cJSON_CreateArray(); bitcoin_priv2wif(wifstr,swap->myprivs[0],swap->bobcoin->chain->wiftype); printf("wifstr.(%s)\n",wifstr); jaddistr(privkeys,wifstr); V.suppress_pubkeys = 1; V.userdata[len++] = 32; for (i=0; i<32; i++) V.userdata[len++] = swap->privAm.bytes[i]; V.userdata[len++] = 0; V.userdatalen = len; txobj = bitcoin_txcreate(swap->bobcoin->chain->isPoS,0,1); vins = cJSON_CreateArray(); item = cJSON_CreateObject(); jaddbits256(item,"txid",swap->bobpayment.signedtxid); jaddnum(item,"vout",0); jaddnum(item,"height",swap->bobcoin->blocks.hwmchain.height); jaddnum(item,"checkind",swap->bobcoin->blocks.hwmchain.height); sobj = cJSON_CreateObject(); init_hexbytes_noT(hexstr,swap->bobpayment.spendscript,swap->bobpayment.spendlen); jaddstr(sobj,"hex",hexstr); jadd(item,"scriptPubKey",sobj); jaddi(vins,item); jdelete(txobj,"vin"); jadd(txobj,"vin",vins); txobj = bitcoin_txoutput(txobj,swap->alicespend.spendscript,swap->alicespend.spendlen,swap->alicespend.amount); if ( (rawtx= bitcoin_json2hex(myinfo,swap->bobcoin,&swap->alicespend.txid,txobj,&V)) != 0 ) { printf("alice spend rawtx.(%s)\n",rawtx); if ( (signedtx= iguana_signrawtx(myinfo,swap->bobcoin,&swap->alicespend.signedtxid,&swap->alicespend.completed,vins,rawtx,privkeys,&V)) != 0 ) { printf("alice spend signedtx.(%s)\n",signedtx); swap->alicespend.datalen = (int32_t)strlen(signedtx) >> 1; swap->alicespend.txbytes = calloc(1,swap->alicespend.datalen); decode_hex(swap->alicespend.txbytes,swap->alicespend.datalen,signedtx); free(signedtx); retval = 0; } free(rawtx); } free_json(privkeys); free_json(txobj); // set alicespend return(retval); } int32_t basilisk_verify_alicepaid(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { // add verification swap->alicepayment.txbytes = calloc(1,datalen); memcpy(swap->alicepayment.txbytes,data,datalen); // set bobspend return(0); } int32_t basilisk_numconfirms(struct supernet_info *myinfo,struct basilisk_rawtx *rawtx) { return(10); } bits256 basilisk_privAm_extract(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *alicespend) { return(GENESIS_PRIVKEY); } bits256 basilisk_swap_broadcast(struct supernet_info *myinfo,struct basilisk_swap *swap,struct iguana_info *coin,uint8_t *data,int32_t datalen) { bits256 txid; memset(txid.bytes,0,sizeof(txid)); if ( data != 0 && datalen != 0 ) txid = bits256_doublesha256(0,data,datalen); return(txid); } /*reclaim_tx { find vout of (re)claim construct vin spend splice together tx }*/ // end of coin protocol dependent bits256 instantdex_derivekeypair(struct supernet_info *myinfo,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash) { bits256 sharedsecret; sharedsecret = curve25519_shared(privkey,orderhash); vcalc_sha256cat(newprivp->bytes,orderhash.bytes,sizeof(orderhash),sharedsecret.bytes,sizeof(sharedsecret)); return(bitcoin_pubkey33(myinfo->ctx,pubkey,*newprivp)); } int32_t instantdex_pubkeyargs(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t numpubs,bits256 privkey,bits256 hash,int32_t firstbyte) { char buf[3]; int32_t i,n,m,len=0; bits256 pubi; uint64_t txid; uint8_t secret160[20],pubkey[33]; sprintf(buf,"%c0",'A' - 0x02 + firstbyte); if ( numpubs > 2 ) { if ( swap->numpubs+2 >= numpubs ) return(numpubs); printf(">>>>>> start generating %s\n",buf); } for (i=n=m=0; imypubs[n]) == 0 ) { swap->myprivs[n] = privkey; memcpy(swap->mypubs[n].bytes,pubkey+1,sizeof(bits256)); if ( swap->iambob != 0 ) { if ( n == 0 ) swap->pubB0 = swap->mypubs[n]; else if ( n == 1 ) swap->pubB1 = swap->mypubs[n]; } else if ( swap->iambob == 0 ) { if ( n == 0 ) swap->pubA0 = swap->mypubs[n]; else if ( n == 1 ) swap->pubA1 = swap->mypubs[n]; } } } if ( m < INSTANTDEX_DECKSIZE ) { swap->privkeys[m] = privkey; calc_rmd160_sha256(secret160,privkey.bytes,sizeof(privkey)); memcpy(&txid,secret160,sizeof(txid)); len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][0],sizeof(txid),&txid); len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][1],sizeof(pubi.txid),&pubi.txid); m++; if ( m > swap->numpubs ) swap->numpubs = m; } n++; } if ( n > 2 || m > 2 ) printf("n.%d m.%d len.%d numpubs.%d\n",n,m,len,swap->numpubs); return(n); } int32_t basilisk_rawtx_return(struct supernet_info *myinfo,struct basilisk_rawtx *rawtx,cJSON *item,cJSON *privkeyarray,int32_t lockinputs) { char *signedtx,*txbytes; cJSON *vins; int32_t retval = -1; if ( (txbytes= jstr(item,"rawtx")) != 0 && (vins= jobj(item,"vins")) != 0 ) { if ( (signedtx= iguana_signrawtx(myinfo,rawtx->coin,&rawtx->signedtxid,&rawtx->completed,vins,txbytes,privkeyarray,0)) != 0 ) { if ( lockinputs != 0 ) iguana_unspentslock(myinfo,rawtx->coin,vins); rawtx->datalen = (int32_t)strlen(signedtx) >> 1; rawtx->txbytes = calloc(1,rawtx->datalen); decode_hex(rawtx->txbytes,rawtx->datalen,signedtx); printf("SIGNEDTX.(%s)\n",signedtx); free(signedtx); retval = 0; } else printf("error signrawtx\n"); //do a very short timeout so it finishes via local poll } return(retval); } int32_t basilisk_rawtx_gen(char *str,struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t lockinputs,struct basilisk_rawtx *rawtx,uint32_t locktime,uint8_t *script,int32_t scriptlen,int64_t txfee,int32_t minconf) { struct iguana_waddress *waddr; struct iguana_waccount *wacct; char coinaddr[64],wifstr[64],*retstr,scriptstr[1024]; uint32_t basilisktag; int32_t flag,i,n,retval = -1; cJSON *valsobj,*retarray=0,*privkeyarray,*addresses; if ( (waddr= iguana_getaccountaddress(myinfo,rawtx->coin,0,0,rawtx->coin->changeaddr,"change")) == 0 ) { printf("no change addr error\n"); return(-1); } init_hexbytes_noT(scriptstr,script,scriptlen); privkeyarray = cJSON_CreateArray(); addresses = cJSON_CreateArray(); if ( rawtx->coin->changeaddr[0] == 0 ) bitcoin_address(rawtx->coin->changeaddr,rawtx->coin->chain->pubtype,waddr->rmd160,20); bitcoin_address(coinaddr,rawtx->coin->chain->pubtype,myinfo->persistent_pubkey33,33); //printf("%s persistent.(%s) (%s) change.(%s) scriptstr.(%s)\n",coin->symbol,myinfo->myaddr.BTC,coinaddr,coin->changeaddr,scriptstr); if ( (waddr= iguana_waddresssearch(myinfo,&wacct,coinaddr)) != 0 ) { bitcoin_priv2wif(wifstr,waddr->privkey,rawtx->coin->chain->wiftype); jaddistr(privkeyarray,waddr->wifstr); } basilisktag = (uint32_t)rand(); jaddistr(addresses,coinaddr); valsobj = cJSON_CreateObject(); //jadd(valsobj,"addresses",addresses); jaddstr(valsobj,"coin",rawtx->coin->symbol); jaddstr(valsobj,"spendscript",scriptstr); jaddstr(valsobj,"changeaddr",rawtx->coin->changeaddr); jadd64bits(valsobj,"satoshis",rawtx->amount); jadd64bits(valsobj,"txfee",txfee); jaddnum(valsobj,"minconf",minconf); jaddnum(valsobj,"locktime",locktime); jaddnum(valsobj,"timeout",30000); if ( (retstr= basilisk_rawtx(myinfo,rawtx->coin,0,0,myinfo->myaddr.persistent,valsobj,"")) != 0 ) { //printf("%s got.(%s)\n",str,retstr); flag = 0; if ( (retarray= cJSON_Parse(retstr)) != 0 ) { if ( is_cJSON_Array(retarray) != 0 ) { n = cJSON_GetArraySize(retarray); for (i=0; iiambob != 0 ? "BOB" : "ALICE"); free_json(privkeyarray); free_json(valsobj); return(retval); } void basilisk_rawtx_setparms(struct supernet_info *myinfo,struct basilisk_swap *swap,struct basilisk_rawtx *rawtx,struct iguana_info *coin,int32_t numconfirms,int32_t vintype,uint64_t satoshis,int32_t vouttype,uint8_t *pubkey33) { rawtx->coin = coin; rawtx->numconfirms = numconfirms; rawtx->amount = satoshis; rawtx->vintype = vintype; // 0 -> std, 2 -> 2of2, 3 -> spend bobpayment, 4 -> spend bobdeposit rawtx->vouttype = vouttype; // 0 -> fee, 1 -> std, 2 -> 2of2, 3 -> bobpayment, 4 -> bobdeposit if ( rawtx->vouttype == 0 ) { if ( strcmp(coin->symbol,"BTC") == 0 && (swap->req.quoteid % 10) == 0 ) decode_hex(rawtx->rmd160,20,TIERNOLAN_RMD160); else decode_hex(rawtx->rmd160,20,INSTANTDEX_RMD160); bitcoin_address(rawtx->destaddr,rawtx->coin->chain->pubtype,rawtx->rmd160,20); } if ( pubkey33 != 0 ) { memcpy(rawtx->pubkey33,pubkey33,33); bitcoin_address(rawtx->destaddr,rawtx->coin->chain->pubtype,rawtx->pubkey33,33); bitcoin_addr2rmd160(&rawtx->addrtype,rawtx->rmd160,rawtx->destaddr); } if ( rawtx->vouttype <= 1 && rawtx->destaddr[0] != 0 ) { rawtx->spendlen = bitcoin_standardspend(rawtx->spendscript,0,rawtx->rmd160); if ( 0 && vintype == 0 && basilisk_rawtx_gen("setparms",myinfo,swap,1,rawtx,0,rawtx->spendscript,rawtx->spendlen,coin->chain->txfee,1) < 0 ) printf("error generating vintype.%d vouttype.%d -> %s\n",vintype,vouttype,rawtx->destaddr); } } struct basilisk_swap *bitcoin_swapinit(struct supernet_info *myinfo,struct basilisk_swap *swap) { struct iguana_info *coin; uint8_t *alicepub33=0,*bobpub33=0; int32_t x = -1; if ( strcmp("BTC",swap->req.src) == 0 ) { swap->bobcoin = iguana_coinfind("BTC"); swap->bobsatoshis = swap->req.srcamount; swap->bobconfirms = (1 + sqrt(dstr(swap->bobsatoshis) * .1)); swap->alicecoin = iguana_coinfind(swap->req.dest); swap->alicesatoshis = swap->req.destamount; swap->aliceconfirms = swap->bobconfirms * 3; } else if ( strcmp("BTC",swap->req.dest) == 0 ) { swap->bobcoin = iguana_coinfind("BTC"); swap->bobsatoshis = swap->req.destamount; swap->bobconfirms = (1 + sqrt(dstr(swap->bobsatoshis) * .1)); swap->alicecoin = iguana_coinfind(swap->req.src); swap->alicesatoshis = swap->req.srcamount; swap->aliceconfirms = swap->bobconfirms * 3; } else { if ( (coin= iguana_coinfind(swap->req.src)) != 0 ) { if ( coin->chain->havecltv != 0 ) { swap->bobcoin = coin; swap->bobsatoshis = swap->req.srcamount; swap->alicecoin = iguana_coinfind(swap->req.dest); swap->alicesatoshis = swap->req.destamount; } else if ( (coin= iguana_coinfind(swap->req.dest)) != 0 ) { if ( coin->chain->havecltv != 0 ) { swap->bobcoin = coin; swap->bobsatoshis = swap->req.destamount; swap->alicecoin = iguana_coinfind(swap->req.src); swap->alicesatoshis = swap->req.srcamount; } } } } if ( swap->bobcoin == 0 || swap->alicecoin == 0 ) { printf("missing BTC.%p or missing alicecoin.%p\n",swap->bobcoin,swap->alicecoin); free(swap); return(0); } if ( swap->bobconfirms == 0 ) swap->bobconfirms = swap->bobcoin->chain->minconfirms; if ( swap->aliceconfirms == 0 ) swap->aliceconfirms = swap->alicecoin->chain->minconfirms; if ( (swap->bobinsurance= (swap->bobsatoshis / INSTANTDEX_INSURANCEDIV)) < 10000 ) swap->bobinsurance = 10000; if ( (swap->aliceinsurance= (swap->alicesatoshis / INSTANTDEX_INSURANCEDIV)) < 10000 ) swap->aliceinsurance = 10000; strcpy(swap->bobstr,swap->bobcoin->symbol); strcpy(swap->alicestr,swap->alicecoin->symbol); swap->started = (uint32_t)time(NULL); swap->expiration = swap->req.timestamp + INSTANTDEX_LOCKTIME*2; swap->locktime = swap->expiration + INSTANTDEX_LOCKTIME; OS_randombytes((uint8_t *)&swap->choosei,sizeof(swap->choosei)); if ( swap->choosei < 0 ) swap->choosei = -swap->choosei; swap->choosei %= INSTANTDEX_DECKSIZE; swap->otherchoosei = -1; swap->myhash = myinfo->myaddr.persistent; if ( bits256_cmp(swap->myhash,swap->req.hash) == 0 ) { swap->otherhash = swap->req.desthash; if ( strcmp(swap->req.src,swap->bobstr) == 0 ) swap->iambob = 1; else if ( strcmp(swap->req.dest,swap->alicestr) == 0 ) { printf("neither bob nor alice error\n"); return(0); } } else if ( bits256_cmp(swap->myhash,swap->req.desthash) == 0 ) { swap->otherhash = swap->req.hash; if ( strcmp(swap->req.dest,swap->bobstr) == 0 ) swap->iambob = 1; else if ( strcmp(swap->req.src,swap->alicestr) != 0 ) { printf("neither alice nor bob error\n"); return(0); } } else { printf("neither src nor dest error\n"); return(0); } if ( bits256_nonz(myinfo->persistent_priv) == 0 || (x= instantdex_pubkeyargs(myinfo,swap,2 + INSTANTDEX_DECKSIZE,myinfo->persistent_priv,swap->myhash,0x02+swap->iambob)) != 2 + INSTANTDEX_DECKSIZE ) { printf("couldnt generate privkeys %d\n",x); return(0); } if ( swap->iambob != 0 ) { basilisk_rawtx_setparms(myinfo,swap,&swap->myfee,swap->bobcoin,0,0,swap->bobsatoshis/INSTANTDEX_DECKSIZE,0,0); basilisk_rawtx_setparms(myinfo,swap,&swap->otherfee,swap->alicecoin,0,0,swap->alicesatoshis/INSTANTDEX_DECKSIZE,0,0); bobpub33 = myinfo->persistent_pubkey33; } else { basilisk_rawtx_setparms(myinfo,swap,&swap->otherfee,swap->bobcoin,0,0,swap->bobsatoshis/INSTANTDEX_DECKSIZE,0,0); basilisk_rawtx_setparms(myinfo,swap,&swap->myfee,swap->alicecoin,0,0,swap->alicesatoshis/INSTANTDEX_DECKSIZE,0,0); alicepub33 = myinfo->persistent_pubkey33; } basilisk_rawtx_setparms(myinfo,swap,&swap->bobdeposit,swap->bobcoin,swap->bobconfirms,0,swap->bobsatoshis*1.1,4,0); basilisk_rawtx_setparms(myinfo,swap,&swap->bobrefund,swap->bobcoin,1,4,swap->bobsatoshis*1.1-swap->bobcoin->txfee,1,bobpub33); basilisk_rawtx_setparms(myinfo,swap,&swap->bobpayment,swap->bobcoin,swap->bobconfirms,0,swap->bobsatoshis,3,0); basilisk_rawtx_setparms(myinfo,swap,&swap->bobreclaim,swap->bobcoin,swap->bobconfirms,3,swap->bobsatoshis - swap->bobcoin->txfee,1,bobpub33); basilisk_rawtx_setparms(myinfo,swap,&swap->alicespend,swap->bobcoin,swap->bobconfirms,3,swap->bobsatoshis - swap->bobcoin->txfee,1,alicepub33); basilisk_rawtx_setparms(myinfo,swap,&swap->alicepayment,swap->alicecoin,swap->aliceconfirms,0,swap->alicesatoshis,2,0); basilisk_rawtx_setparms(myinfo,swap,&swap->alicereclaim,swap->alicecoin,swap->aliceconfirms,2,swap->alicesatoshis-swap->alicecoin->txfee,1,alicepub33); basilisk_rawtx_setparms(myinfo,swap,&swap->bobspend,swap->alicecoin,swap->aliceconfirms,2,swap->alicesatoshis-swap->alicecoin->txfee,1,bobpub33); swap->sleeptime = 3 - swap->iambob; return(swap); } // end of alice/bob code void basilisk_rawtx_purge(struct basilisk_rawtx *rawtx) { if ( rawtx->txbytes != 0 ) free(rawtx->txbytes), rawtx->txbytes = 0; } void basilisk_swap_finished(struct supernet_info *myinfo,struct basilisk_swap *swap) { swap->finished = (uint32_t)time(NULL); // save to permanent storage basilisk_rawtx_purge(&swap->bobdeposit); basilisk_rawtx_purge(&swap->bobpayment); basilisk_rawtx_purge(&swap->alicepayment); basilisk_rawtx_purge(&swap->myfee); basilisk_rawtx_purge(&swap->otherfee); basilisk_rawtx_purge(&swap->alicereclaim); basilisk_rawtx_purge(&swap->alicespend); basilisk_rawtx_purge(&swap->bobreclaim); basilisk_rawtx_purge(&swap->bobspend); basilisk_rawtx_purge(&swap->bobrefund); } void basilisk_swap_purge(struct supernet_info *myinfo,struct basilisk_swap *swap) { int32_t i,n; portable_mutex_lock(&myinfo->DEX_swapmutex); n = myinfo->numswaps; for (i=0; iswaps[i] == swap ) { myinfo->swaps[i] = myinfo->swaps[--myinfo->numswaps]; myinfo->swaps[myinfo->numswaps] = 0; basilisk_swap_finished(myinfo,swap); break; } portable_mutex_unlock(&myinfo->DEX_swapmutex); } int32_t basilisk_verify_statebits(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { iguana_rwnum(0,data,sizeof(swap->otherstatebits),&swap->otherstatebits); return(0); } int32_t basilisk_verify_choosei(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { int32_t otherchoosei=-1,i,len = 0; if ( datalen == sizeof(otherchoosei)+sizeof(bits256)*2 ) { len += iguana_rwnum(0,data,sizeof(otherchoosei),&otherchoosei); if ( otherchoosei >= 0 && otherchoosei < INSTANTDEX_DECKSIZE ) { printf("otherchoosei.%d\n",otherchoosei); swap->otherchoosei = otherchoosei; if ( swap->iambob != 0 ) { for (i=0; i<32; i++) swap->pubA0.bytes[i] = data[len++]; for (i=0; i<32; i++) swap->pubA1.bytes[i] = data[len++]; } else { for (i=0; i<32; i++) swap->pubB0.bytes[i] = data[len++]; for (i=0; i<32; i++) swap->pubB1.bytes[i] = data[len++]; } return(0); } } printf("illegal otherchoosei.%d datalen.%d vs %d\n",otherchoosei,datalen,(int32_t)(sizeof(otherchoosei)+sizeof(bits256)*2)); return(-1); } int32_t basilisk_swapdata_deck(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t maxlen) { int32_t i,datalen = 0; for (i=0; ideck)/sizeof(swap->deck[0][0]); i++) datalen += iguana_rwnum(1,&data[datalen],sizeof(swap->deck[i>>1][i&1]),&swap->deck[i>>1][i&1]); return(datalen); } int32_t basilisk_verify_otherdeck(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { int32_t i,len = 0; printf("verify otherdeck\n"); for (i=0; iotherdeck)/sizeof(swap->otherdeck[0][0]); i++) len += iguana_rwnum(0,&data[len],sizeof(swap->otherdeck[i>>1][i&1]),&swap->otherdeck[i>>1][i&1]); return(0); } int32_t basilisk_verify_pubpair(int32_t *wrongfirstbytep,struct basilisk_swap *swap,int32_t ind,uint8_t pub0,bits256 pubi,uint64_t txid) { if ( pub0 != (swap->iambob ^ 1) + 0x02 ) { (*wrongfirstbytep)++; printf("wrongfirstbyte[%d] %02x\n",ind,pub0); return(-1); } else if ( swap->otherdeck[ind][1] != pubi.txid ) { printf("otherdeck[%d] priv ->pub mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][1],(long long)pubi.txid); return(-1); } else if ( swap->otherdeck[ind][0] != txid ) { printf("otherdeck[%d] priv mismatch %llx != %llx\n",ind,(long long)swap->otherdeck[ind][0],(long long)txid); return(-1); } return(0); } int32_t basilisk_verify_privkeys(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { int32_t i,j,wrongfirstbyte=0,errs=0,len = 0; bits256 otherpriv,pubi; uint8_t secret160[20],otherpubkey[33]; uint64_t txid; printf("verify privkeys choosei.%d otherchoosei.%d datalen.%d vs %d\n",swap->choosei,swap->otherchoosei,datalen,(int32_t)sizeof(swap->privkeys)+20+32); if ( swap->cutverified == 0 && swap->otherchoosei >= 0 && datalen == sizeof(swap->privkeys)+20+32 ) { for (i=errs=0; iprivkeys)/sizeof(*swap->privkeys); i++) { for (j=0; j<32; j++) otherpriv.bytes[j] = data[len++]; if ( i != swap->choosei ) { pubi = bitcoin_pubkey33(myinfo->ctx,otherpubkey,otherpriv); calc_rmd160_sha256(secret160,otherpriv.bytes,sizeof(otherpriv)); memcpy(&txid,secret160,sizeof(txid)); errs += basilisk_verify_pubpair(&wrongfirstbyte,swap,i,otherpubkey[0],pubi,txid); } } if ( errs == 0 && wrongfirstbyte == 0 ) { swap->cutverified = 1, printf("CUT VERIFIED\n"); if ( swap->iambob != 0 ) { for (i=0; i<32; i++) swap->pubAm.bytes[i] = data[len++]; for (i=0; i<20; i++) swap->secretAm[i] = data[len++]; } else { for (i=0; i<32; i++) swap->pubBn.bytes[i] = data[len++]; for (i=0; i<20; i++) swap->secretBn[i] = data[len++]; } } else printf("failed verification: wrong firstbyte.%d errs.%d\n",wrongfirstbyte,errs); } printf("privkeys errs.%d wrongfirstbyte.%d\n",errs,wrongfirstbyte); return(errs); } int32_t basilisk_verify_privi(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen) { int32_t j,wrongfirstbyte,len = 0; bits256 privkey,pubi; uint8_t secret160[20],pubkey33[33]; uint64_t txid; if ( datalen == sizeof(bits256) ) { for (j=0; j<32; j++) privkey.bytes[j] = data[len++]; calc_rmd160_sha256(secret160,privkey.bytes,sizeof(privkey)); memcpy(&txid,secret160,sizeof(txid)); pubi = bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); printf("verify privi\n"); if ( basilisk_verify_pubpair(&wrongfirstbyte,swap,swap->choosei,pubkey33[0],pubi,txid) == 0 ) { if ( swap->iambob != 0 ) swap->privAm = privkey; else swap->privBn = privkey; printf("privi verified\n"); return(0); } } return(-1); } int32_t basilisk_swapget(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,int32_t (*basilisk_verify_func)(struct supernet_info *myinfo,struct basilisk_swap *swap,uint8_t *data,int32_t datalen)) { int32_t datalen; if ( (datalen= basilisk_channelget(myinfo,myinfo->myaddr.persistent,swap->req.quoteid,msgbits,data,maxlen)) > 0 ) return((*basilisk_verify_func)(myinfo,swap,data,datalen)); else return(-1); } uint32_t basilisk_swapsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t datalen,uint32_t nextbits) { if ( basilisk_channelsend(myinfo,swap->otherhash,swap->req.quoteid,msgbits,data,datalen) == 0 ) return(nextbits); else return(0); } uint32_t basilisk_swapdata_rawtxsend(struct supernet_info *myinfo,struct basilisk_swap *swap,uint32_t msgbits,uint8_t *data,int32_t maxlen,struct basilisk_rawtx *rawtx,uint32_t nextbits) { if ( basilisk_swapdata_rawtx(myinfo,swap,data,maxlen,rawtx) != 0 ) { rawtx->actualtxid = basilisk_swap_broadcast(myinfo,swap,rawtx->coin,rawtx->txbytes,rawtx->datalen); char str[65],str2[65]; printf("rawtxsend %s vs %s\n",bits256_str(str,rawtx->signedtxid),bits256_str(str2,rawtx->actualtxid)); if ( bits256_nonz(rawtx->actualtxid) != 0 && msgbits != 0 ) return(basilisk_swapsend(myinfo,swap,msgbits,rawtx->txbytes,rawtx->datalen,nextbits)); } return(0); } void basilisk_swaploop(void *_swap) { uint8_t *data,pubkey33[33]; int32_t i,j,maxlen,datalen; struct supernet_info *myinfo; struct basilisk_swap *swap = _swap; myinfo = swap->myinfo; fprintf(stderr,"start swap\n"); maxlen = 1024*1024 + sizeof(*swap); data = malloc(maxlen); while ( time(NULL) < swap->expiration ) { fprintf(stderr,"swapstate.%x\n",swap->statebits); if ( (swap->statebits & 0x01) == 0 ) // send pubkeys { datalen = basilisk_swapdata_deck(myinfo,swap,data,maxlen); swap->statebits |= basilisk_swapsend(myinfo,swap,0x02,data,datalen,0x01); } else if ( (swap->statebits & 0x02) == 0 ) // wait for pubkeys { if ( basilisk_swapget(myinfo,swap,0x02,data,maxlen,basilisk_verify_otherdeck) == 0 ) swap->statebits |= 0x02; } else if ( (swap->statebits & 0x04) == 0 ) // send choosei { datalen = iguana_rwnum(1,data,sizeof(swap->choosei),&swap->choosei); if ( swap->iambob != 0 ) { for (i=0; i<32; i++) data[datalen++] = swap->pubB0.bytes[i]; for (i=0; i<32; i++) data[datalen++] = swap->pubB1.bytes[i]; } else { for (i=0; i<32; i++) data[datalen++] = swap->pubA0.bytes[i]; for (i=0; i<32; i++) data[datalen++] = swap->pubA1.bytes[i]; } swap->statebits |= basilisk_swapsend(myinfo,swap,0x08,data,datalen,0x04); } else if ( (swap->statebits & 0x08) == 0 ) // wait for choosei { if ( basilisk_swapget(myinfo,swap,0x08,data,maxlen,basilisk_verify_choosei) == 0 ) { if ( swap->iambob != 0 ) { swap->privBn = swap->privkeys[swap->otherchoosei]; memset(&swap->privkeys[swap->otherchoosei],0,sizeof(swap->privkeys[swap->otherchoosei])); calc_rmd160_sha256(swap->secretBn,swap->privBn.bytes,sizeof(swap->privBn)); swap->pubBn = bitcoin_pubkey33(myinfo->ctx,pubkey33,swap->privBn); printf("set secretBn.%02x\n",pubkey33[0]); } else { swap->privAm = swap->privkeys[swap->otherchoosei]; memset(&swap->privkeys[swap->otherchoosei],0,sizeof(swap->privkeys[swap->otherchoosei])); calc_rmd160_sha256(swap->secretAm,swap->privAm.bytes,sizeof(swap->privAm)); swap->pubAm = bitcoin_pubkey33(myinfo->ctx,pubkey33,swap->privAm); printf("set secretAm.%02x\n",pubkey33[0]); } swap->statebits |= 0x08; } } else if ( (swap->statebits & 0x10) == 0 && swap->otherchoosei >= 0 && swap->otherchoosei < INSTANTDEX_DECKSIZE ) // send all but one privkeys { datalen = 0; for (i=0; iprivkeys)/sizeof(*swap->privkeys); i++) { for (j=0; j<32; j++) data[datalen++] = (i == swap->otherchoosei) ? 0 : swap->privkeys[i].bytes[j]; } if ( swap->iambob != 0 ) { for (i=0; i<32; i++) data[datalen++] = swap->pubBn.bytes[i]; for (i=0; i<20; i++) data[datalen++] = swap->secretBn[i]; } else { for (i=0; i<32; i++) data[datalen++] = swap->pubAm.bytes[i]; for (i=0; i<20; i++) data[datalen++] = swap->secretAm[i]; } swap->statebits |= basilisk_swapsend(myinfo,swap,0x20,data,datalen,0x10); } else if ( (swap->statebits & 0x20) == 0 ) // wait for all but one privkeys { if ( basilisk_swapget(myinfo,swap,0x20,data,maxlen,basilisk_verify_privkeys) == 0 ) swap->statebits |= 0x20; } else if ( (swap->statebits & 0x40) == 0 ) // send fee { if ( swap->myfee.txbytes == 0 ) { for (i=0; i<20; i++) printf("%02x",swap->secretAm[i]); printf(" <- secretAm\n"); for (i=0; i<32; i++) printf("%02x",swap->pubAm.bytes[i]); printf(" <- pubAm\n"); for (i=0; i<20; i++) printf("%02x",swap->secretBn[i]); printf(" <- secretBn\n"); for (i=0; i<32; i++) printf("%02x",swap->pubBn.bytes[i]); printf(" <- pubBn\n"); for (i=0; i<32; i++) printf("%02x",swap->pubA0.bytes[i]); printf(" <- pubA0\n"); for (i=0; i<32; i++) printf("%02x",swap->pubA1.bytes[i]); printf(" <- pubA1\n"); for (i=0; i<32; i++) printf("%02x",swap->pubB0.bytes[i]); printf(" <- pubB0\n"); for (i=0; i<32; i++) printf("%02x",swap->pubB1.bytes[i]); printf(" <- pubB1\n"); swap->bobpayment.spendlen = basilisk_bobscript(swap->bobpayment.spendscript,0,&swap->bobpayment.locktime,&swap->bobpayment.secretstart,swap,0); if ( swap->iambob != 0 ) { swap->bobdeposit.spendlen = basilisk_bobscript(swap->bobdeposit.spendscript,0,&swap->bobdeposit.locktime,&swap->bobdeposit.secretstart,swap,1); basilisk_rawtx_gen("deposit",myinfo,swap,1,&swap->bobdeposit,swap->bobdeposit.locktime,swap->bobdeposit.spendscript,swap->bobdeposit.spendlen,swap->bobdeposit.coin->chain->txfee,1); basilisk_rawtx_gen("payment",myinfo,swap,1,&swap->bobpayment,swap->bobpayment.locktime,swap->bobpayment.spendscript,swap->bobpayment.spendlen,swap->bobpayment.coin->chain->txfee,1); if ( swap->bobdeposit.txbytes == 0 || swap->bobdeposit.spendlen == 0 || swap->bobpayment.txbytes == 0 || swap->bobpayment.spendlen == 0 ) { printf("error bob generating deposit.%d or payment.%d\n",swap->bobdeposit.spendlen,swap->bobpayment.spendlen); break; } } else { swap->alicepayment.spendlen = basilisk_alicescript(swap->alicepayment.spendscript,0,swap->alicepayment.destaddr,swap->alicepayment.coin->chain->p2shtype,swap->pubAm,swap->pubBn); basilisk_rawtx_gen("alicepayment",myinfo,swap,1,&swap->alicepayment,swap->alicepayment.locktime,swap->alicepayment.spendscript,swap->alicepayment.spendlen,swap->alicepayment.coin->chain->txfee,1); if ( swap->alicepayment.txbytes == 0 || swap->alicepayment.spendlen == 0 ) { printf("error alice generating payment.%d\n",swap->alicepayment.spendlen); break; } } if ( basilisk_rawtx_gen("myfee",myinfo,swap,1,&swap->myfee,0,swap->myfee.spendscript,swap->myfee.spendlen,swap->myfee.coin->chain->txfee,1) == 0 ) swap->statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x80,data,maxlen,&swap->myfee,0x40); else { printf("error creating myfee\n"); break; } } } else if ( (swap->statebits & 0x80) == 0 ) // wait for fee { if ( basilisk_swapget(myinfo,swap,0x80,data,maxlen,basilisk_verify_otherfee) == 0 ) { // verify and submit otherfee swap->statebits |= 0x80; swap->sleeptime = 1; } else if ( swap->sleeptime < 60 ) swap->sleeptime++; } else // both sides have setup required data and paid txfee { if ( swap->sleeptime < 60 ) swap->sleeptime++; if ( swap->iambob != 0 ) { if ( (swap->statebits & 0x100) == 0 ) { swap->statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x200,data,maxlen,&swap->bobdeposit,0x100); swap->sleeptime = 1; } // [BLOCKING: altfound] make sure altpayment is confirmed and send payment else if ( (swap->statebits & 0x1000) == 0 ) { // set bobrefund from bobdeposit if ( basilisk_swapget(myinfo,swap,0x1000,data,maxlen,basilisk_verify_alicepaid) == 0 ) { // verify alicepayment and submit, set confirmed height swap->statebits |= 0x1000; swap->sleeptime = 1; } } else if ( (swap->statebits & 0x2000) == 0 ) { // set bobspend if ( basilisk_numconfirms(myinfo,&swap->alicepayment) >= swap->aliceconfirms ) { swap->statebits |= 0x2000; swap->sleeptime = 1; } } else if ( (swap->statebits & 0x4000) == 0 ) { swap->statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x8000,data,maxlen,&swap->bobpayment,0x4000); swap->sleeptime = 1; } // [BLOCKING: privM] Bob waits for privAm either from Alice or alice blockchain else if ( (swap->statebits & 0x40000) == 0 ) { // set bobreclaim from bobpayment // set alicespend from bobpayment if ( basilisk_numconfirms(myinfo,&swap->alicespend) >= 0 || basilisk_swapget(myinfo,swap,0x40000,data,maxlen,basilisk_verify_privi) == 0 ) // divulges privAm { swap->sleeptime = 1; if ( bits256_nonz(swap->privAm) == 0 ) swap->privAm = basilisk_privAm_extract(myinfo,swap,&swap->alicespend); swap->statebits |= 0x40000; if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobspend,0) == 0 ) { printf("Bob error spending alice payment\n"); break; } } else if ( time(NULL) > swap->bobpayment.locktime ) { // submit reclaim of payment swap->sleeptime = 1; swap->statebits |= (0x40000 | 0x80000); if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobreclaim,0) == 0 ) { printf("Bob error reclaiming own payment after alice timed out\n"); break; } } } else if ( (swap->statebits & 0x80000) == 0 ) { if ( basilisk_numconfirms(myinfo,&swap->bobspend) >= swap->aliceconfirms ) { swap->sleeptime = 1; swap->statebits |= 0x80000 | 0x100000; printf("Bob confirms spend of Alice's payment\n"); break; } } else if ( (swap->statebits & 0x100000) == 0 ) { if ( basilisk_numconfirms(myinfo,&swap->bobreclaim) >= 1 ) { swap->sleeptime = 1; swap->statebits |= 0x100000; printf("Bob confirms reclain of payment\n"); break; } } } else { // [BLOCKING: depfound] Alice waits for deposit to confirm and sends altpayment if ( (swap->statebits & 0x200) == 0 ) { swap->sleeptime = 1; if ( basilisk_swapget(myinfo,swap,0x200,data,maxlen,basilisk_verify_bobdeposit) == 0 ) { // verify deposit and submit, set confirmed height swap->statebits |= 0x200; } } else if ( (swap->statebits & 0x400) == 0 ) { if ( basilisk_numconfirms(myinfo,&swap->bobdeposit) >= swap->bobconfirms ) { swap->statebits |= 0x400; swap->sleeptime = 1; } } else if ( (swap->statebits & 0x800) == 0 ) { // set alicerefund from bobdeposit swap->sleeptime = 1; swap->statebits |= basilisk_swapdata_rawtxsend(myinfo,swap,0x1000,data,maxlen,&swap->alicepayment,0x800); } // [BLOCKING: payfound] make sure payment is confrmed and send in claim or see bob's reclaim and reclaim else if ( (swap->statebits & 0x8000) == 0 ) { if ( basilisk_swapget(myinfo,swap,0x8000,data,maxlen,basilisk_verify_bobpaid) == 0 ) { // verify payment and submit, set confirmed height swap->sleeptime = 1; swap->statebits |= 0x8000; } /*else if ( basilisk_numconfirms(myinfo,&swap->bobreclaim) >= 0 ) { // reclaim and exit swap->reclaimed = 1; swap->statebits |= 0x8000; }*/ } else if ( (swap->statebits & 0x10000) == 0 ) { /*if ( swap->reclaimed != 0 ) { if ( basilisk_numconfirms(myinfo,&swap->bobreclaim) >= swap->bobconfirms ) swap->statebits |= 0x10000; } else */ if ( basilisk_numconfirms(myinfo,&swap->bobpayment) >= swap->bobconfirms ) { swap->statebits |= 0x10000; swap->sleeptime = 1; } } else if ( (swap->statebits & 0x20000) == 0 ) { if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->alicespend,0x20000) != 0 ) { for (j=datalen=0; j<32; j++) data[datalen++] = swap->privAm.bytes[j]; swap->statebits |= basilisk_swapsend(myinfo,swap,0x40000,data,datalen,0x20000); swap->sleeptime = 1; } } else if ( (swap->statebits & 0x40000) == 0 ) { if ( basilisk_numconfirms(myinfo,&swap->alicespend) >= swap->bobconfirms ) { swap->sleeptime = 1; swap->statebits |= 0x40000; printf("Alice confirms spend of Bob's payment\n"); break; } } } } if ( swap->sleeptime > 0 ) sleep(swap->sleeptime); } if ( swap->iambob != 0 ) { if ( basilisk_swapdata_rawtxsend(myinfo,swap,0,data,maxlen,&swap->bobrefund,0) == 0 ) // use secretBn { printf("Bob submit error getting refund of deposit\n"); } } printf("%s swap finished statebits %x\n",swap->iambob!=0?"BOB":"ALICE",swap->statebits); basilisk_swap_purge(myinfo,swap); } struct basilisk_swap *basilisk_thread_start(struct supernet_info *myinfo,struct basilisk_request *rp) { int32_t i; struct basilisk_swap *swap = 0; portable_mutex_lock(&myinfo->DEX_swapmutex); for (i=0; inumswaps; i++) if ( myinfo->swaps[i]->req.requestid == rp->requestid ) { printf("basilisk_thread_start error trying to start requestid.%u which is already started\n",rp->requestid); break; } if ( i == myinfo->numswaps && i < sizeof(myinfo->swaps)/sizeof(*myinfo->swaps) ) { swap = calloc(1,sizeof(*swap)); swap->req = *rp; swap->myinfo = myinfo; printf("START swap requestid.%u\n",rp->requestid); if ( bitcoin_swapinit(myinfo,swap) != 0 ) { fprintf(stderr,"launch.%d %d\n",myinfo->numswaps,(int32_t)(sizeof(myinfo->swaps)/sizeof(*myinfo->swaps))); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)basilisk_swaploop,(void *)swap) != 0 ) { } myinfo->swaps[myinfo->numswaps++] = swap; } } portable_mutex_unlock(&myinfo->DEX_swapmutex); return(swap); } struct basilisk_swap *basilisk_request_started(struct supernet_info *myinfo,uint32_t requestid) { int32_t i; struct basilisk_swap *active = 0; portable_mutex_lock(&myinfo->DEX_swapmutex); for (i=0; inumswaps; i++) if ( myinfo->swaps[i]->req.requestid == requestid ) { //printf("REQUEST STARTED.[%d] <- req.%u\n",i,requestid); active = myinfo->swaps[i]; break; } portable_mutex_unlock(&myinfo->DEX_swapmutex); return(active); }