// Copyright (c) 2016-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2020 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. * * * ******************************************************************************/ // build hushdex and put in path: git pull; gcc cc/dapps/hushdex.c -lm -o hushdex; cp hushdex /usr/bin // alice sends relcoin and gets basecoin #define DEXP2P_CHAIN ((char *)"HUSHDEX") #define DEXP2P_PUBKEYS ((char *)"hushdex") #include "dappinc.h" // for OTC mode, the following 4 functions are the only ones that should be needed to support a new "coin" //int64_t hushdex_getbalance(char *coin); //bits256 hushdex_coinpayment(int32_t OTCmode,char *coin,char *destaddr,uint64_t paytoshis,char *memostr); //cJSON *hushdex_txidwait(char *coin,bits256 txid,char *hexstr,int32_t numseconds); //int64_t hushdex_verifypayment(char *coin,cJSON *rawtx,uint64_t destsatoshis,char *destaddr); // TODO: // address conversion // new inventory types: // anonsend // bob nodes: // mutex for bob instances // "deposits" messages and approved bobs // volume caps per coin and non-notarized exposure // later: // sharded storage #define SUBATOMIC_OTCDEFAULT 1 #define SUBATOMIC_TIMEOUT 60 #define SUBATOMIC_LOCKTIME 3600 #define SUBATOMIC_TXFEE 10000 #define SUBATOMIC_PRIORITY 5 #define SUBATOMIC_OPENREQUEST 1 #define SUBATOMIC_APPROVED 2 #define SUBATOMIC_OPENED 3 #define SUBATOMIC_PAYMENT 4 #define SUBATOMIC_PAIDINFULL 5 #define SUBATOMIC_CLOSED 6 cJSON *SUBATOMIC_json; int32_t SUBATOMIC_retval = -1; struct abinfo { char pubkey[67],recvaddr[64],recvZaddr[128],secp[67]; }; struct coininfo { uint64_t satoshis,txfee,maxamount; char istoken,iszaddr,isfile,isexternal,tokenid[65],coin[16],name[16],cli[256],acname[16],coinstr[16]; }; struct msginfo { UT_hash_handle hh; bits256 bobpayment,alicepayment; double price; uint64_t gotpayment; uint32_t origid,openrequestid,approvalid,openedid,paymentids[100],paidid,closedid,locktime; int32_t bobflag,status,OTCmode; char payload[128],approval[128],senderpub[67],msigaddr[64],redeemscript[256]; struct coininfo base,rel; struct abinfo alice,bob; } *Messages; uint64_t hushdex_txfee(char *coin) { return(SUBATOMIC_TXFEE); } char *hushdex_checkname(char *tmpstr,struct msginfo *mp,int32_t baserel,char *coin) { int32_t i,n; cJSON *external,*item; char *coinstr,*clistr; struct coininfo *ptr; ptr = (baserel == 0) ? &mp->base : &mp->rel; if ( coin[0] == 0 ) return(coin); if ( (external= jarray(&n,SUBATOMIC_json,"externalcoins")) != 0 && n > 0 ) { for (i=0; icli) ) { ptr->isexternal = 1; strcpy(ptr->cli,clistr); //fprintf(stderr,"found external coin %s %s\n",coin,clistr); } } } if ( coin[0] == '#' ) { strcpy(ptr->coinstr,coin); strcpy(ptr->acname,""); ptr->isfile = 1; return(coin); } else if ( coin[0] != 'z' ) { for (i=1; coin[i]!=0; i++) if ( coin[i] == '.' ) { dpow_tokenregister(ptr->tokenid,0,coin,0); if ( ptr->tokenid[0] != 0 ) { strcpy(tmpstr,coin); tmpstr[i] = 0; //fprintf(stderr,"found a tokenmap %s -> %s %s\n",coin,tmpstr,ptr->tokenid); ptr->istoken = 1; strcpy(ptr->acname,coin); strcpy(ptr->coinstr,""); return(tmpstr); } } if ( ptr->isexternal == 0 ) { strcpy(ptr->acname,coin); strcpy(ptr->coinstr,""); strcpy(ptr->acname,""); } else { strcpy(ptr->coinstr,coin); strcpy(ptr->acname,""); } return(coin); } else { for (i=1; coin[i]!=0; i++) if ( isupper(coin[i]) == 0 ) return(coin); ptr->iszaddr = 1; return(coin+1); } } int32_t hushdex_zonly(struct coininfo *coin) { if ( strcmp(coin->coin,"HUSH3") == 0 ) return(1); if ( strcmp(coin->coin,"HUSHFILE") == 0 ) return(1); return 0; } // //////////////////////////////// the four key functions needed to support a new item for hushdexs int64_t _hushdex_getbalance(struct coininfo *coin) { cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; if ( (retjson= hushdex_cli(coin->cli,&retstr,"getbalance","","","","","","","")) != 0 ) { fprintf(stderr,"_hushdex_getbalance.(%s) %s returned json!\n",coin->coinstr,coin->cli); free_json(retjson); } else if ( retstr != 0 ) { amount = atof(retstr) * SATOSHIDEN; sprintf(cmpstr,"%.8f",dstr(amount)); if ( strcmp(retstr,cmpstr) != 0 ) amount++; //printf("retstr %s -> %.8f\n",retstr,dstr(amount)); free(retstr); } return (amount); } bits256 _hushdex_sendtoaddress(struct coininfo *coin,char *destaddr,int64_t satoshis) { char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid; memset(txid.bytes,0,sizeof(txid)); sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN); if ( (retjson= hushdex_cli(coin->cli,&retstr,"sendtoaddress",destaddr,numstr,"false","","","","")) != 0 ) { fprintf(stderr,"unexpected _hushdex_sendtoaddress json.(%s)\n",jprint(retjson,0)); free_json(retjson); } else if ( retstr != 0 ) { if ( strlen(retstr) >= 64 ) { retstr[64] = 0; decode_hex(txid.bytes,32,retstr); } fprintf(stderr,"_hushdex_sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid)); free(retstr); } return(txid); } cJSON *_hushdex_rawtransaction(struct coininfo *coin,bits256 txid) { cJSON *retjson; char *retstr,str[65]; if ( (retjson= hushdex_cli(coin->cli,&retstr,"getrawtransaction",bits256_str(str,txid),"1","","","","","")) != 0 ) { return(retjson); } else if ( retstr != 0 ) { fprintf(stderr,"_hushdex_rawtransaction.(%s) %s error.(%s)\n",coin->coin,coin->name,retstr); free(retstr); } return(0); } int64_t hushdex_getbalance(struct coininfo *coin) { char *coinstr,*acname=""; FILE *fp; int64_t retval = 0; coinstr = coin->coin; if ( coin->isfile != 0 ) { if ( (fp= fopen(coin->name+1,"rb")) != 0 ) // if alice, add bob pubkey to fname { fclose(fp); retval = SATOSHIDEN; } return(retval); } else if ( hushdex_zonly(coin) != 0 ) { return(z_getbalance(coinstr,acname,DPOW_recvZaddr)); } } bits256 hushdex_coinpayment(uint32_t origid,int32_t OTCmode,struct coininfo *coin,char *destaddr,uint64_t paytoshis,char *memostr,char *destpub,char *senderpub) { bits256 txid; char opidstr[128],opretstr[32],str[65],*status,*coinstr,*acname=""; cJSON *retjson,*retjson2,*item,*res; int32_t i,pending=0; memset(&txid,0,sizeof(txid)); if ( OTCmode == 0 ) { fprintf(stderr,"micropayment channels are not supported yet\n"); return(txid); } if ( coin->isfile != 0 ) { fprintf(stderr,"start broadcast of (%s)\n",coin->coin+1); if ( (retjson= dpow_publish(SUBATOMIC_PRIORITY,coin->coin+1)) != 0 ) // spawn thread { sprintf(opretstr,"%08x",juint(retjson,"id")); sprintf(opidstr,"%u",origid); if ( (retjson2= dpow_broadcast(SUBATOMIC_PRIORITY,opretstr,"inbox",opidstr,senderpub,"","")) != 0 ) free_json(retjson2); fprintf(stderr,"broadcast file.(%s) and send id.%u to alice (%s)\n",coin->coin+1,juint(retjson,"id"),jprint(retjson,0)); txid = jbits256(retjson,"filehash"); free_json(retjson); } fprintf(stderr,"end broadcast of (%s) to %s\n",coin->coin+1,senderpub); return(txid); } else if ( hushdex_zonly(coin) != 0 ) { if ( memostr[0] == 0 ) memostr = "beef"; z_sendmany(opidstr,"",coin->coin,DPOW_recvZaddr,destaddr,paytoshis,memostr); for (i=0; icoin,opidstr)) != 0 ) { item = jitem(retjson,0); if ( (status= jstr(item,"status")) != 0 ) { if ( strcmp(status,"executing") == 0 ) pending++; else { res = jobj(item,"result"); txid = jbits256(res,"txid"); //fprintf(stderr,"got Ztx txid.%s\n",bits256_str(str,txid)); free_json(retjson); break; } /*else if ( clearresults != 0 ) { if ( (result= z_getoperationresult(coinstr,"",jstri(array,i))) != 0 ) { free_json(result); } }*/ } free_json(retjson); } sleep(1); } if ( i == 60 ) printf("%u timed out waiting for opid to finish\n",origid); } else { coinstr = coin->coin; if ( coin->istoken != 0 ) txid = tokentransfer(coinstr,acname,coin->tokenid,destpub,paytoshis/SATOSHIDEN); else if ( coin->isexternal == 0 ) { sprintf(opretstr,"%08x",origid); txid = sendtoaddress(coinstr,acname,destaddr,paytoshis,opretstr); } else txid = _hushdex_sendtoaddress(coin,destaddr,paytoshis); printf("%u got txid.%s\n",origid,bits256_str(str,txid)); } return(txid); } cJSON *hushdex_txidwait(struct coininfo *coin,bits256 txid,char *hexstr,int32_t numseconds,char *senderpub) { int32_t i,zflag; char *coinstr,str[65],*acname=""; cJSON *rawtx; bits256 z; bits256 filehash; memset(&z,0,sizeof(z)); if ( memcmp(&z,&txid,sizeof(txid)) == 0 ) return(0); if ( hexstr != 0 && hexstr[0] != 0 ) // probably not worth doing and zaddr is a problem to decode { // compare against txid // if matches, sendrawtransaction if OTC mode, decoode and return if channels mode } zflag = (hushdex_zonly(coin) != 0); coinstr = coin->coin; for (i=0; iisfile != 0 ) { if ( (rawtx= dpow_subscribe(SUBATOMIC_PRIORITY,coin->coin+1,senderpub)) != 0 ) { filehash = jbits256(rawtx,"filehash"); if ( memcmp(&filehash,&txid,sizeof(filehash)) != 0 ) { fprintf(stderr,"waiting (%s) (%s)\n",coin->coin+1,jprint(rawtx,0)); free_json(rawtx); rawtx = 0; } else return(rawtx); } } else if ( zflag != 0 ) rawtx = get_z_viewtransaction(coinstr,acname,txid); else if ( coin->isexternal == 0 ) rawtx = get_rawtransaction(coinstr,acname,txid); else rawtx = _hushdex_rawtransaction(coin,txid); if ( rawtx != 0 ) return(rawtx); sleep(1); } printf("%s/%s timeout waiting for %s\n",coin->name,coin->coin,bits256_str(str,txid)); return(0); } int64_t hushdex_verifypayment(struct coininfo *coin,cJSON *rawtx,uint64_t destsatoshis,char *destaddr,bits256 txid) { int32_t i,n,m,valid=0; bits256 tokenid,filehash,checkhash; cJSON *array,*item,*sobj,*a; char *addr,*acname,*coinstr,tokenaddr[64],*hex; uint8_t hexbuf[512],pub33[33]; uint64_t netval,recvsatoshis = 0; if ( coin->isfile != 0 ) { filehash = jbits256(rawtx,"filehash"); checkhash = jbits256(rawtx,"checkhash"); if ( memcmp(&txid,&filehash,sizeof(txid)) == 0 && memcmp(&txid,&checkhash,sizeof(txid)) == 0 ) { fprintf(stderr,"verified file is matching the filehash (%s)\n",jprint(rawtx,0)); return(SATOSHIDEN); } else return(0); } else if ( hushdex_zonly(coin) != 0 ) { if ( (array= jarray(&n,rawtx,"outputs")) != 0 && n > 0 ) { for (i=0; iistoken != 0 ) { if ( (array= jarray(&n,rawtx,"vout")) != 0 && n > 0 ) { item = jitem(array,0); if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (a= jarray(&m,sobj,"addresses")) != 0 && m == 1 ) { coinstr = coin->coin; if ( get_tokenaddress(coinstr,acname,tokenaddr) != 0 ) { //fprintf(stderr,"tokenaddr.%s\n",tokenaddr); if ( (addr= jstri(a,0)) != 0 && strcmp(addr,tokenaddr) == 0 ) recvsatoshis += SATOSHIDEN * (uint64_t)(jdouble(item,"value")*SATOSHIDEN + 0.000000004999); else fprintf(stderr,"miscompare (%s) vs %s\n",jprint(sobj,0),addr); } } item = jitem(array,n-1); if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (hex= jstr(sobj,"hex")) != 0 && (m= is_hexstr(hex,0)) > 1 && m/2 < sizeof(hexbuf) ) { m >>= 1; decode_hex(hexbuf,m,hex); decode_hex(tokenid.bytes,32,coin->tokenid); decode_hex(pub33,33,DPOW_secpkeystr); // opret 69len EVAL_TOKENS 't' tokenid 1 33 pub33 if ( hexbuf[0] == 0x6a && hexbuf[1] == 0x45 && hexbuf[2] == 0xf2 && hexbuf[3] == 't' && memcmp(&hexbuf[4],&tokenid,sizeof(tokenid)) == 0 && hexbuf[4+32] == 1 && hexbuf[4+32+1] == 33 && memcmp(&hexbuf[4+32+2],pub33,33) == 0 ) { valid = 1; //fprintf(stderr,"validated it is a token transfer!\n"); } else fprintf(stderr,"need to validate tokentransfer.(%s) %s %d\n",hex,DPOW_secpkeystr,memcmp(&hexbuf[4+32+2],pub33,33) == 0); //6a 45 f2 74 2b1feef719ecb526b07416dd432bce603ac6dc8bfe794cddf105cb52f6aae3cd 01 21 02b27de3ee5335518b06f69f4fbabb029cfc737613b100996841d5532b324a5a61 } recvsatoshis *= valid; } } else { if ( (array= jarray(&n,rawtx,"vout")) != 0 && n > 0 ) { for (i=0; iorigid = origid; HASH_ADD(hh,Messages,origid,sizeof(origid),mp); return(mp); } int32_t hushdex_status(struct msginfo *mp,int32_t status) { static FILE *fp; if ( fp == 0 ) { int32_t i,oid,s,n,num,count; struct msginfo *m; long fsize; if ( (fp= fopen("SUBATOMIC.DB","rb+")) == 0 ) { if ( (fp= fopen("SUBATOMIC.DB","wb")) == 0 ) { fprintf(stderr,"cant create SUBATOMIC.DB\n"); exit(-1); } } else { fseek(fp,0,SEEK_END); fsize = ftell(fp); if ( (fsize % (sizeof(uint32_t)*2)) != 0 ) { fprintf(stderr,"SUBATOMIC.DB illegal filesize.%ld\n",fsize); exit(-1); } n = (int32_t)(fsize / (sizeof(uint32_t)*2)); rewind(fp); for (i=num=count=0; i SUBATOMIC_CLOSED ) { fprintf(stderr,"SUBATOMIC.DB corrupted at filepos.%ld: illegal status.%d\n",ftell(fp),s); exit(-1); } //fprintf(stderr,"%u <- %d\n",oid,s); if ( (m= hushdex_find(oid)) == 0 ) { m = hushdex_add(oid); count++; } if ( s > m->status ) { m->status = s; num++; } } fprintf(stderr,"initialized %d messages, updated %d out of total.%d\n",count,num,n); } } if ( mp->status >= status ) return(-1); if ( fwrite(&mp->origid,1,sizeof(mp->origid),fp) != sizeof(mp->origid) || fwrite(&status,1,sizeof(status),fp) != sizeof(status) ) fprintf(stderr,"error updating SUBATOMIC.DB, risk of double spends\n"); fflush(fp); mp->status = status; return(0); } struct msginfo *hushdex_tracker(uint32_t origid) { struct msginfo *mp; if ( (mp= hushdex_find(origid)) == 0 ) { mp = hushdex_add(origid); hushdex_status(mp,0); } return(mp); } char *hushdex_hexstr(char *jsonstr) { char *hexstr; int32_t i,c,n = (int32_t)strlen(jsonstr); hexstr = malloc(2*n + 3); strcpy(hexstr,jsonstr); for (i=0; iorigid); jaddnum(item,"price",mp->price); jaddnum(item,"openrequest",mp->openrequestid); jaddstr(item,"base",mp->base.name); jaddstr(item,"basecoin",mp->base.coin); jadd64bits(item,"basesatoshis",mp->base.satoshis); jadd64bits(item,"basetxfee",mp->base.txfee); jadd64bits(item,"maxbaseamount",mp->base.maxamount); jaddstr(item,"rel",mp->rel.name); jaddstr(item,"relcoin",mp->rel.coin); jadd64bits(item,"relsatoshis",mp->rel.satoshis); jadd64bits(item,"reltxfee",mp->rel.txfee); jadd64bits(item,"maxrelamount",mp->rel.maxamount); jaddstr(item,"alice",mp->alice.pubkey); jaddstr(item,"alicesecp",mp->alice.secp); jaddstr(item,"bob",mp->bob.pubkey); jaddstr(item,"bobsecp",mp->bob.secp); if ( hushdex_zonly(&mp->rel) != 0 ) jaddstr(item,"bobZaddr",mp->bob.recvZaddr); else jaddstr(item,"bobaddr",mp->bob.recvaddr); if ( mp->rel.istoken != 0 ) jaddstr(item,"bobtoken",mp->rel.tokenid); if ( hushdex_zonly(&mp->base) != 0 ) jaddstr(item,"aliceZaddr",mp->alice.recvZaddr); else jaddstr(item,"aliceaddr",mp->alice.recvaddr); if ( mp->base.istoken != 0 ) jaddstr(item,"alicetoken",mp->base.tokenid); return(item); } uint64_t hushdex_orderbook_mpset(struct msginfo *mp,char *basecheck) { cJSON *retjson; char *tagA,*tagB,*senderpub,*str,tmpstr[32]; int32_t matches=0; double volA,volB; int64_t txfee=0; strcpy(mp->base.name,basecheck); strcpy(mp->base.coin,hushdex_checkname(tmpstr,mp,0,basecheck)); mp->rel.txfee = hushdex_txfee(mp->rel.coin); if ( (retjson= dpow_get(mp->origid)) != 0 ) { //fprintf(stderr,"dpow_get.(%s) (%s/%s)\n",jprint(retjson,0),mp->base.coin,mp->rel.coin); if ( (senderpub= jstr(retjson,"senderpub")) != 0 && is_hexstr(senderpub,0) == 66 && (tagA= jstr(retjson,"tagA")) != 0 && (tagB= jstr(retjson,"tagB")) != 0 && strncmp(tagB,mp->rel.name,strlen(mp->rel.name)) == 0 && strlen(tagA) < sizeof(mp->base.name) ) { strcpy(mp->base.name,tagA); strcpy(mp->base.coin,hushdex_checkname(tmpstr,mp,0,tagA)); if ( basecheck[0] == 0 || strncmp(basecheck,tagA,strlen(basecheck)) == 0 ) matches = 1; else if ( strcmp(tagA,mp->base.name) == 0 ) matches = 1; else if ( mp->bobflag != 0 && tagA[0] == '#' && strcmp(mp->base.name,"#allfiles") == 0 ) matches = 1; if ( matches != 0 ) { if ( (str= jstr(retjson,"decrypted")) != 0 && strlen(str) < 128 ) strcpy(mp->payload,str); mp->locktime = juint(retjson,"timestamp") + SUBATOMIC_LOCKTIME; mp->base.txfee = hushdex_txfee(mp->base.coin); strcpy(mp->senderpub,senderpub); volB = jdouble(retjson,"amountB"); volA = jdouble(retjson,"amountA"); mp->base.maxamount = volA*SATOSHIDEN + 0.0000000049999; mp->rel.maxamount = volB*SATOSHIDEN + 0.0000000049999; if ( 0 && mp->rel.istoken == 0 ) txfee = mp->rel.txfee; if ( mp->base.maxamount != 0 && mp->rel.maxamount != 0 && volA > SMALLVAL && volB > SMALLVAL && mp->rel.satoshis <= mp->rel.maxamount ) { mp->price = volA / volB; mp->base.satoshis = (mp->rel.satoshis - txfee) * mp->price; //fprintf(stderr,"base satoshis.%llu\n",(long long)mp->base.satoshis); } else fprintf(stderr,"%u rel %llu vs (%llu %llu)\n",mp->origid,(long long)mp->rel.satoshis,(long long)mp->base.maxamount,(long long)mp->rel.maxamount); } else printf("%u didnt match (%s) tagA.%s %s, tagB.%s %s %d %d\n",mp->origid,basecheck,tagA,mp->base.name,tagB,mp->rel.name,tagA[0] == '#', strcmp(mp->base.name,"#allfiles") == 0); } else printf("%u didnt compare tagA.%s %s, tagB.%s %s\n",mp->origid,tagA,mp->base.name,tagB,mp->rel.name); free_json(retjson); } return(mp->base.satoshis); } char *randhashstr(char *str) { bits256 rands; int32_t i; for (i=0; i<32; i++) rands.bytes[i] = rand() >> 17; bits256_str(str,rands); return(str); } void hushdex_extrafields(cJSON *dest,cJSON *src) { char *str; if ( (str= jstr(src,"approval")) != 0 ) jaddstr(dest,"approval",str); if ( (str= jstr(src,"opened")) != 0 ) jaddstr(dest,"opened",str); if ( (str= jstr(src,"payamount")) != 0 ) jaddstr(dest,"payamount",str); if ( (str= jstr(src,"destaddr")) != 0 ) jaddstr(dest,"destaddr",str); if ( (str= jstr(src,"bobpayment")) != 0 ) jaddstr(dest,"bobpayment",str); if ( (str= jstr(src,"alicepayment")) != 0 ) jaddstr(dest,"alicepayment",str); if ( (str= jstr(src,"bobaddr")) != 0 ) jaddstr(dest,"bobaddr",str); if ( (str= jstr(src,"bobZaddr")) != 0 ) jaddstr(dest,"bobZaddr",str); if ( (str= jstr(src,"aliceaddr")) != 0 ) jaddstr(dest,"aliceaddr",str); if ( (str= jstr(src,"aliceZaddr")) != 0 ) jaddstr(dest,"aliceZaddr",str); if ( (str= jstr(src,"alicetoken")) != 0 ) jaddstr(dest,"alicetoken",str); if ( (str= jstr(src,"bobtoken")) != 0 ) jaddstr(dest,"bobtoken",str); } char *hushdex_submit(cJSON *argjson,int32_t tobob) { char *jsonstr,*hexstr; jaddnum(argjson,"tobob",tobob != 0); jsonstr = jprint(argjson,1); hexstr = hushdex_hexstr(jsonstr); free(jsonstr); return(hexstr); } #define SCRIPT_OP_IF 0x63 #define SCRIPT_OP_ELSE 0x67 #define SCRIPT_OP_DUP 0x76 #define SCRIPT_OP_ENDIF 0x68 #define SCRIPT_OP_TRUE 0x51 #define SCRIPT_OP_2 0x52 #define SCRIPT_OP_3 0x53 #define SCRIPT_OP_DROP 0x75 #define SCRIPT_OP_EQUALVERIFY 0x88 #define SCRIPT_OP_HASH160 0xa9 #define SCRIPT_OP_EQUAL 0x87 #define SCRIPT_OP_CHECKSIG 0xac #define SCRIPT_OP_CHECKMULTISIG 0xae #define SCRIPT_OP_CHECKMULTISIGVERIFY 0xaf #define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 int32_t hushdex_redeemscript(char *redeemscript,uint32_t locktime,char *pubkeyA,char *pubkeyB) // not needed { // if ( refund ) OP_HASH160 <2of2 multisig hash> OP_EQUAL // standard multisig // else CLTV OP_DROP OP_CHECKSIG // standard spend uint8_t pubkeyAbytes[33],pubkeyBbytes[33],hex[4096]; int32_t i,n = 0; decode_hex(pubkeyAbytes,33,pubkeyA); decode_hex(pubkeyBbytes,33,pubkeyB); hex[n++] = SCRIPT_OP_IF; hex[n++] = SCRIPT_OP_2; hex[n++] = 33, memcpy(&hex[n],pubkeyAbytes,33), n += 33; hex[n++] = 33, memcpy(&hex[n],pubkeyBbytes,33), n += 33; hex[n++] = SCRIPT_OP_2; hex[n++] = SCRIPT_OP_CHECKMULTISIG; hex[n++] = SCRIPT_OP_ELSE; hex[n++] = 4; hex[n++] = locktime & 0xff, locktime >>= 8; hex[n++] = locktime & 0xff, locktime >>= 8; hex[n++] = locktime & 0xff, locktime >>= 8; hex[n++] = locktime & 0xff; hex[n++] = SCRIPT_OP_CHECKLOCKTIMEVERIFY; hex[n++] = SCRIPT_OP_DROP; hex[n++] = 33; memcpy(&hex[n],pubkeyAbytes,33); n += 33; hex[n++] = SCRIPT_OP_CHECKSIG; hex[n++] = SCRIPT_OP_ENDIF; for (i=0; i>4) & 0xf); redeemscript[i*2 + 1] = hexbyte(hex[i] & 0xf); } redeemscript[n*2] = 0; /*tmpbuf[0] = SCRIPT_OP_HASH160; tmpbuf[1] = 20; calc_OP_HASH160(scriptPubKey,tmpbuf+2,redeemscript); tmpbuf[22] = SCRIPT_OP_EQUAL; init_hexbytes_noT(scriptPubKey,tmpbuf,23); if ( p2shaddr != 0 ) { p2shaddr[0] = 0; if ( (btc_addr= base58_encode_check(addrtype,true,tmpbuf+2,20)) != 0 ) { if ( strlen(btc_addr->str) < 36 ) strcpy(p2shaddr,btc_addr->str); cstr_free(btc_addr,true); } }*/ return(n); } int32_t hushdex_approved(struct msginfo *mp,cJSON *approval,cJSON *msgjson,char *senderpub) { char *hexstr,numstr[32],redeemscript[1024],*coin,*acname=""; cJSON *retjson,*decodejson; int32_t i,retval = 0; hushdex_extrafields(approval,msgjson); if ( mp->OTCmode == 0 ) { coin = (mp->bobflag != 0) ? mp->base.coin : mp->rel.coin; // the other side gets this coin if ( get_createmultisig2(coin,acname,mp->msigaddr,mp->redeemscript,mp->alice.secp,mp->bob.secp) != 0 ) { hushdex_redeemscript(redeemscript,mp->locktime,mp->alice.secp,mp->bob.secp); if ( (decodejson= get_decodescript(coin,acname,redeemscript)) != 0 ) { fprintf(stderr,"%s %s msigaddr.%s %s -> %s %s\n",mp->bobflag!=0?"bob":"alice",(mp->bobflag != 0) ? mp->base.coin : mp->rel.coin,mp->msigaddr,mp->redeemscript,redeemscript,jprint(decodejson,0)); free(decodejson); } } } sprintf(numstr,"%u",mp->origid); for (i=0; numstr[i]!=0; i++) sprintf(&mp->approval[i<<1],"%02x",numstr[i]); sprintf(&mp->approval[i<<1],"%02x",' '); i++; mp->approval[i<<1] = 0; jaddstr(approval,"approval",mp->approval); hexstr = hushdex_submit(approval,!mp->bobflag); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"approved",senderpub,"","")) != 0 ) { if ( (mp->approvalid= juint(retjson,"id")) != 0 ) retval = 1; printf("%u approvalid.%u (%s)\n",mp->origid,mp->approvalid,senderpub); hushdex_status(mp,SUBATOMIC_APPROVED); free_json(retjson); } free(hexstr); return(retval); } int32_t hushdex_opened(struct msginfo *mp,cJSON *opened,cJSON *msgjson,char *senderpub) { char *hexstr,channelstr[65]; cJSON *retjson; int32_t retval = 0; hushdex_extrafields(opened,msgjson); jaddstr(opened,"opened",randhashstr(channelstr)); hexstr = hushdex_submit(opened,!mp->bobflag); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"opened",senderpub,"","")) != 0 ) { if ( (mp->openedid= juint(retjson,"id")) != 0 ) retval = 1; printf("%u openedid.%u\n",mp->origid,mp->openedid); hushdex_status(mp,SUBATOMIC_OPENED); free_json(retjson); } free(hexstr); return(retval); } int32_t hushdex_payment(struct msginfo *mp,cJSON *payment,cJSON *msgjson,char *senderpub) { bits256 txid; uint64_t paytoshis; cJSON *retjson; char numstr[32],*coin,*dest,*hexstr; int32_t retval = 0; if ( mp->bobflag == 0 ) { coin = mp->rel.name; paytoshis = mp->rel.satoshis; if ( hushdex_zonly(&mp->rel) != 0 ) dest = mp->bob.recvZaddr; else dest = mp->bob.recvaddr; sprintf(numstr,"%llu",(long long)paytoshis); jaddstr(payment,"alicepays",numstr); jaddstr(payment,"bobdestaddr",dest); txid = hushdex_coinpayment(mp->origid,mp->OTCmode,&mp->rel,dest,paytoshis,mp->approval,mp->bob.secp,senderpub); jaddbits256(payment,"alicepayment",txid); mp->alicepayment = txid; hexstr = 0; // get it from rawtransaction of txid jaddstr(payment,"alicetx",hexstr); } else { coin = mp->base.name; paytoshis = mp->base.satoshis; if ( hushdex_zonly(&mp->base) != 0 ) dest = mp->alice.recvZaddr; else dest = mp->alice.recvaddr; sprintf(numstr,"%llu",(long long)paytoshis); jaddstr(payment,"bobpays",numstr); jaddstr(payment,"alicedestaddr",dest); txid = hushdex_coinpayment(mp->origid,mp->OTCmode,&mp->base,dest,paytoshis,mp->approval,mp->alice.secp,senderpub); jaddbits256(payment,"bobpayment",txid); mp->bobpayment = txid; hexstr = 0; // get it from rawtransaction of txid jaddstr(payment,"bobtx",hexstr); } hexstr = hushdex_submit(payment,!mp->bobflag); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"payment",senderpub,"","")) != 0 ) { if ( (mp->paymentids[0]= juint(retjson,"id")) != 0 ) retval = 1; printf("%u: %.8f %s -> %s, paymentid[0] %u\n",mp->origid,dstr(paytoshis),coin,dest,mp->paymentids[0]); hushdex_status(mp,SUBATOMIC_PAYMENT); free_json(retjson); } free(hexstr); return(retval); } int32_t hushdex_paidinfull(struct msginfo *mp,cJSON *paid,cJSON *msgjson,char *senderpub) { char *hexstr; cJSON *retjson; int32_t retval = 0; jaddstr(paid,"paid","in full"); hushdex_extrafields(paid,msgjson); hexstr = hushdex_submit(paid,!mp->bobflag); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"paid",senderpub,"","")) != 0 ) { if ( (mp->paidid= juint(retjson,"id")) != 0 ) retval = 1; printf("%u paidid.%u\n",mp->origid,mp->paidid); hushdex_status(mp,SUBATOMIC_PAIDINFULL); free_json(retjson); } free(hexstr); return(retval); } int32_t hushdex_closed(struct msginfo *mp,cJSON *closed,cJSON *msgjson,char *senderpub) { char *hexstr; cJSON *retjson; int32_t retval = 0; jaddnum(closed,"closed",mp->origid); hushdex_extrafields(closed,msgjson); hexstr = hushdex_submit(closed,!mp->bobflag); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"closed",senderpub,"","")) != 0 ) { if ( (mp->closedid= juint(retjson,"id")) != 0 ) retval = 1; hushdex_status(mp,SUBATOMIC_CLOSED); printf("%u closedid.%u\n",mp->origid,mp->closedid); free_json(retjson); } free(hexstr); return(retval); } uint32_t hushdex_alice_openrequest(struct msginfo *origmp) { struct msginfo *mp; cJSON *retjson,*openrequest; char *hexstr,*str,tmpstr[32]; mp = hushdex_tracker(origmp->origid); mp->origid = origmp->origid; mp->rel.satoshis = origmp->rel.satoshis; mp->rel.istoken = origmp->rel.istoken; strcpy(mp->rel.tokenid,origmp->rel.tokenid); strcpy(mp->rel.name,origmp->rel.name); strcpy(mp->rel.coin,hushdex_checkname(tmpstr,mp,1,origmp->rel.name)); strcpy(mp->alice.pubkey,DPOW_pubkeystr); strcpy(mp->alice.secp,DPOW_secpkeystr); strcpy(mp->alice.recvZaddr,DPOW_recvZaddr); strcpy(mp->alice.recvaddr,DPOW_recvaddr); printf("rel.%s/%s %s openrequest %u status.%d (%s/%s)\n",mp->rel.name,mp->rel.coin,mp->rel.tokenid,mp->origid,mp->status,mp->alice.recvaddr,mp->alice.recvZaddr); if ( mp->status == 0 && hushdex_orderbook_mpset(mp,"") != 0 ) { strcpy(mp->bob.pubkey,mp->senderpub); if ( hushdex_zonly(&mp->base) != 0 || hushdex_zonly(&mp->rel) != 0 ) mp->OTCmode = 1; else mp->OTCmode = SUBATOMIC_OTCDEFAULT; strcpy(origmp->base.name,mp->base.name); strcpy(origmp->base.coin,mp->base.coin); origmp->base.istoken = mp->base.istoken; strcpy(origmp->base.tokenid,mp->base.tokenid); origmp->OTCmode = mp->OTCmode; if ( mp->rel.istoken != 0 && ((mp->rel.satoshis % SATOSHIDEN) != 0 || mp->rel.iszaddr != 0) ) { printf("%u cant do zaddr or fractional rel %s.%s tokens %.8f\n",mp->origid,mp->rel.coin,mp->rel.tokenid,dstr(mp->rel.satoshis)); return(0); } else if ( mp->base.istoken != 0 && ((mp->base.satoshis % SATOSHIDEN) != 0 || mp->base.iszaddr != 0 ) ) { printf("%u cant do zaddr or fractional base %s.%s tokens %.8f\n",mp->origid,mp->base.coin,mp->base.tokenid,dstr(mp->base.satoshis)); return(0); } else if ( (openrequest= hushdex_mpjson(mp)) != 0 ) { hexstr = hushdex_submit(openrequest,!mp->bobflag); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"openrequest",mp->bob.pubkey,"","")) != 0 ) { mp->openrequestid = juint(retjson,"id"); printf("%u openrequest.%u -> (%s)\n",mp->origid,mp->openrequestid,mp->bob.pubkey); hushdex_status(mp,SUBATOMIC_OPENREQUEST); free_json(retjson); } free(hexstr); } } return(mp->openrequestid); } void hushdex_bob_gotopenrequest(uint32_t inboxid,char *senderpub,cJSON *msgjson,char *basename,char *relname) { struct msginfo *mp; cJSON *approval; int32_t origid; char *addr,tmpstr[32],*coin,*acname=""; origid = juint(msgjson,"origid"); mp = hushdex_tracker(origid); strcpy(mp->base.name,basename); strcpy(mp->base.coin,hushdex_checkname(tmpstr,mp,0,basename)); strcpy(mp->rel.name,relname); strcpy(mp->rel.coin,hushdex_checkname(tmpstr,mp,1,relname)); mp->origid = origid; mp->rel.satoshis = j64bits(msgjson,"relsatoshis"); mp->bobflag = 1; strcpy(mp->bob.pubkey,DPOW_pubkeystr); strcpy(mp->bob.secp,DPOW_secpkeystr); strcpy(mp->bob.recvZaddr,DPOW_recvZaddr); strcpy(mp->bob.recvaddr,DPOW_recvaddr); if ( (addr= jstr(msgjson,"aliceaddr")) != 0 ) strcpy(mp->alice.recvaddr,addr); if ( (addr= jstr(msgjson,"aliceZaddr")) != 0 ) strcpy(mp->alice.recvZaddr,addr); if ( (addr= jstr(msgjson,"alicesecp")) != 0 ) strcpy(mp->alice.secp,addr); if ( hushdex_zonly(&mp->base) != 0 || hushdex_zonly(&mp->rel) != 0 ) mp->OTCmode = 1; else mp->OTCmode = SUBATOMIC_OTCDEFAULT; printf("%u got open request\n",mp->origid); if ( mp->status == 0 && hushdex_orderbook_mpset(mp,basename) != 0 && (approval= hushdex_mpjson(mp)) != 0 ) { if ( mp->rel.istoken != 0 && ((mp->rel.satoshis % SATOSHIDEN) != 0 || mp->rel.iszaddr != 0) ) { printf("%u cant do zaddr or fractional rel %s.%s tokens %.8f\n",mp->origid,mp->rel.coin,mp->rel.tokenid,dstr(mp->rel.satoshis)); hushdex_closed(mp,approval,msgjson,senderpub); return; } else if ( mp->base.istoken != 0 && ((mp->base.satoshis % SATOSHIDEN) != 0 || mp->base.iszaddr != 0 ) ) { printf("%u cant do zaddr or fractional base %s.%s tokens %.8f\n",mp->origid,mp->base.coin,mp->base.tokenid,dstr(mp->base.satoshis)); hushdex_closed(mp,approval,msgjson,senderpub); return; } else if ( hushdex_getbalance(&mp->base) < mp->base.satoshis ) { printf("%u bob node low on %s funds! %.8f not enough for %.8f\n",mp->origid,mp->base.coin,dstr(hushdex_getbalance(&mp->base)),dstr(mp->base.satoshis)); hushdex_closed(mp,approval,msgjson,senderpub); } else { printf("%u bob (%s/%s) gotopenrequest origid.%u status.%d (%s/%s) SENDERPUB.(%s)\n",mp->origid,mp->base.name,mp->rel.name,mp->origid,mp->status,mp->bob.recvaddr,mp->bob.recvZaddr,senderpub); hushdex_approved(mp,approval,msgjson,senderpub); } } } int32_t hushdex_channelapproved(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) { struct msginfo *mp; cJSON *approval; char *addr,*coin,*acname; int32_t retval = 0; mp = hushdex_tracker(juint(msgjson,"origid")); if ( hushdex_orderbook_mpset(mp,mp->base.name) != 0 && (approval= hushdex_mpjson(mp)) != 0 ) { printf("%u iambob.%d (%s/%s) channelapproved origid.%u status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->origid,mp->status); if ( mp->bobflag == 0 && mp->status == SUBATOMIC_OPENREQUEST ) { if ( (addr= jstr(msgjson,"bobaddr")) != 0 ) strcpy(mp->bob.recvaddr,addr); if ( (addr= jstr(msgjson,"bobZaddr")) != 0 ) strcpy(mp->bob.recvZaddr,addr); if ( (addr= jstr(msgjson,"bobsecp")) != 0 ) strcpy(mp->bob.secp,addr); retval = hushdex_approved(mp,approval,msgjson,senderpub); } else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_APPROVED ) retval = hushdex_opened(mp,approval,msgjson,senderpub); } return(retval); } int32_t hushdex_incomingopened(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) { struct msginfo *mp; cJSON *payment; int32_t retval = 0; mp = hushdex_tracker(juint(msgjson,"origid")); if ( hushdex_orderbook_mpset(mp,mp->base.name) != 0 && (payment= hushdex_mpjson(mp)) != 0 ) { printf("%u iambob.%d (%s/%s) incomingchannel status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status); if ( mp->bobflag == 0 && mp->status == SUBATOMIC_APPROVED ) retval = hushdex_payment(mp,payment,msgjson,senderpub); else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_OPENED ) retval = 1; // nothing to do } return(retval); } int32_t hushdex_incomingpayment(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) { static FILE *fp; struct msginfo *mp; cJSON *pay,*rawtx,*retjson; bits256 txid; char str[65],*hexstr; int32_t retval = 0; mp = hushdex_tracker(juint(msgjson,"origid")); if ( hushdex_orderbook_mpset(mp,mp->base.name) != 0 && (pay= hushdex_mpjson(mp)) != 0 ) { printf("%u iambob.%d (%s/%s) incomingpayment status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status); if ( mp->bobflag == 0 ) { txid = jbits256(msgjson,"bobpayment"); jaddbits256(msgjson,"alicepayment",mp->alicepayment); printf("%u alice waits for %s.%s to be in mempool (%.8f -> %s)\n",mp->origid,mp->base.name,bits256_str(str,txid),dstr(mp->base.satoshis),hushdex_zonly(&mp->base) == 0 ? mp->alice.recvaddr : mp->alice.recvZaddr); hexstr = jstr(msgjson,"bobtx"); if ( (rawtx= hushdex_txidwait(&mp->base,txid,hexstr,SUBATOMIC_TIMEOUT,senderpub)) != 0 ) { if ( hushdex_verifypayment(&mp->base,rawtx,mp->base.satoshis,hushdex_zonly(&mp->base) == 0 ? mp->alice.recvaddr : mp->alice.recvZaddr,txid) >= 0 ) mp->gotpayment = 1; free_json(rawtx); } if ( mp->gotpayment != 0 ) { printf("%u SWAP COMPLETE <<<<<<<<<<<<<<<<\n",mp->origid); SUBATOMIC_retval = 0; if ( mp->base.iszaddr == 0 ) { sprintf(str,"%u",mp->origid); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->alicepayment),(char *)"completed",str,DPOW_pubkeystr,"","")) != 0 ) free_json(retjson); } } else { printf("%u SWAP INCOMPLETE, waiting on %s.%s\n",mp->origid,mp->base.name,bits256_str(str,txid)); if ( (fp= fopen("SUBATOMIC.incomplete","a+")) != 0 ) { char *jsonstr = jprint(msgjson,0); fwrite(jsonstr,1,strlen(jsonstr),fp); fputc('\n',fp); fclose(fp); free(jsonstr); } if ( mp->base.iszaddr == 0 ) { sprintf(str,"%u",mp->origid); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->alicepayment),(char *)"incomplete",str,DPOW_pubkeystr,"","")) != 0 ) free_json(retjson); } hushdex_closed(mp,pay,msgjson,senderpub); exit(-1); } } if ( mp->gotpayment != 0 ) retval = hushdex_paidinfull(mp,pay,msgjson,senderpub); else { if ( mp->bobflag != 0 && mp->status == SUBATOMIC_OPENED ) { txid = jbits256(msgjson,"alicepayment"); printf("%u bob waits for %s.%s to be in mempool (%.8f -> %s)\n",mp->origid,mp->rel.name,bits256_str(str,txid),dstr(mp->rel.satoshis),hushdex_zonly(&mp->rel) == 0 ? mp->bob.recvaddr : mp->bob.recvZaddr); hexstr = jstr(msgjson,"alicetx"); if ( (rawtx= hushdex_txidwait(&mp->rel,txid,hexstr,SUBATOMIC_TIMEOUT,senderpub)) != 0 ) { if ( hushdex_verifypayment(&mp->rel,rawtx,mp->rel.satoshis,hushdex_zonly(&mp->rel) == 0 ? mp->bob.recvaddr : mp->bob.recvZaddr,txid) >= 0 ) mp->gotpayment = 1; free_json(rawtx); } if ( mp->gotpayment != 0 ) { retval = hushdex_payment(mp,pay,msgjson,senderpub); jaddbits256(msgjson,"bobpayment",mp->bobpayment); if ( mp->rel.iszaddr == 0 ) { sprintf(str,"%u",mp->origid); if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->bobpayment),(char *)"completed",str,DPOW_pubkeystr,"","")) != 0 ) free_json(retjson); } printf("%u SWAP COMPLETE <<<<<<<<<<<<<<<<\n",mp->origid); if ( (fp= fopen("SUBATOMIC.proof","rb+")) == 0 ) fp = fopen("SUBATOMIC.proof","wb"); if ( fp != 0 ) { char *jsonstr = jprint(msgjson,0); fseek(fp,0,SEEK_END); fwrite(jsonstr,1,strlen(jsonstr),fp); fputc('\n',fp); fflush(fp); free(jsonstr); } } else printf("%u SWAP INCOMPLETE: %s\n",mp->origid,jprint(msgjson,0)); } } } return(retval); } int32_t hushdex_incomingfullypaid(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) { struct msginfo *mp; cJSON *closed; int32_t retval = 0; mp = hushdex_tracker(juint(msgjson,"origid")); if ( hushdex_orderbook_mpset(mp,mp->base.name) != 0 && (closed= hushdex_mpjson(mp)) != 0 ) { printf("%u iambob.%d (%s/%s) incomingfullypaid status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status); // error check msgjson vs M if ( mp->bobflag == 0 && mp->status == SUBATOMIC_PAIDINFULL ) retval = hushdex_closed(mp,closed,msgjson,senderpub); else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_PAYMENT ) retval = hushdex_paidinfull(mp,closed,msgjson,senderpub); } return(retval); } int32_t hushdex_incomingclosed(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) { struct msginfo *mp; cJSON *closed; int32_t retval = 0; mp = hushdex_tracker(juint(msgjson,"origid")); if ( hushdex_orderbook_mpset(mp,mp->base.name) != 0 && (closed= hushdex_mpjson(mp)) != 0 ) { printf("%u iambob.%d (%s/%s) incomingclose status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status); if ( mp->bobflag != 0 ) dpow_cancel(mp->origid); if ( mp->status < SUBATOMIC_CLOSED ) { retval = hushdex_closed(mp,closed,msgjson,senderpub); hushdex_status(mp,SUBATOMIC_CLOSED); } retval = 1; } return(retval); } int32_t hushdex_ismine(int32_t bobflag,cJSON *json,char *basename,char *relname) { char *base,*rel; if ( (base= jstr(json,"base")) != 0 && (rel= jstr(json,"rel")) != 0 ) { if ( strcmp(base,basename) == 0 && strcmp(rel,relname) == 0 ) return(1); if ( bobflag != 0 ) { if ( strcmp(basename,"#allfiles") == 0 && base[0] == '#' ) return(1); fprintf(stderr,"skip ismine (%s/%s) vs (%s/%s)\n",basename,relname,base,rel); } } return(0); } void hushdex_tokensregister(int32_t priority) { char *token_name,*tokenid,existing[65]; cJSON *tokens,*token; int32_t i,numtokens; if ( SUBATOMIC_json != 0 && (tokens= jarray(&numtokens,SUBATOMIC_json,"tokens")) != 0 ) { for (i=0; i 0 ) { for (j=0; j %s, %u %llu %u\n",mp->bobflag,mp->base.name,mp->rel.name,mp->origid,(long long)mp->rel.satoshis,mp->openrequestid); while ( 1 ) { if ( msgs == 0 ) { sleep(1); fflush(stdout); if ( mp->bobflag != 0 ) { dpow_pubkeyregister(SUBATOMIC_PRIORITY); hushdex_tokensregister(SUBATOMIC_PRIORITY); hushdex_filesregister(SUBATOMIC_PRIORITY); } } msgs = 0; for (iter=0; iter<(int32_t)(sizeof(tagBs)/sizeof(*tagBs)); iter++) { tagB = tagBs[iter]; if ( (ptrs= dpow_inboxcheck(&n,&stopats[iter],tagB)) != 0 ) { for (i=0; ijsonstr)) != 0 ) { if ( jint(inboxjson,"tobob") != mp->bobflag ) continue; if ( hushdex_ismine(mp->bobflag,inboxjson,mp->base.name,mp->rel.name) != 0 ) { if ( strcmp(tagB,"openrequest") == 0 && mp->bobflag != 0 ) hushdex_bob_gotopenrequest(ptr->shorthash,ptr->senderpub,inboxjson,mp->base.name,mp->rel.name); else if ( strcmp(tagB,"approved") == 0 ) mask |= hushdex_channelapproved(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 0; else if ( strcmp(tagB,"opened") == 0 ) mask |= hushdex_incomingopened(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 1; else if ( strcmp(tagB,"payment") == 0 ) mask |= hushdex_incomingpayment(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 2; else if ( strcmp(tagB,"paid") == 0 ) mask |= hushdex_incomingfullypaid(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 3; else if ( strcmp(tagB,"closed") == 0 ) mask |= hushdex_incomingclosed(ptr->shorthash,ptr->senderpub,inboxjson,mp) * 0x1f; else fprintf(stderr,"iambob.%d unknown unexpected tagB.(%s)\n",mp->bobflag,tagB); } free_json(inboxjson); } else fprintf(stderr,"hushdex iambob.%d loop got unparseable(%s)\n",mp->bobflag,ptr->jsonstr); free(ptr); ptrs[i] = 0; } } free(ptrs); } } if ( mp->bobflag == 0 && (mask & 0x1f) == 0x1f ) { printf("alice %u %llu %u finished\n",mp->origid,(long long)mp->rel.satoshis,mp->openrequestid); break; } } } int32_t main(int32_t argc,char **argv) { char *fname = "hushdex.json"; int32_t i,height; char *coin,*kcli,*hushdex,*hashstr,*acname=(char *)""; cJSON *retjson; bits256 blockhash; char checkstr[65],str[65],str2[65],tmpstr[32]; long fsize; struct msginfo M; memset(&M,0,sizeof(M)); srand((int32_t)time(NULL)); if ( (hushdex= filestr(&fsize,fname)) == 0 ) { fprintf(stderr,"cant load %s file\n",fname); exit(-1); } if ( (SUBATOMIC_json= cJSON_Parse(hushdex)) == 0 ) { fprintf(stderr,"cant parse hushdex.json file (%s)\n",hushdex); exit(-1); } free(hushdex); if ( argc >= 4 ) { if ( dpow_pubkey() < 0 ) { fprintf(stderr,"couldnt set pubkey for ZEX\n"); return(-1); } coin = (char *)argv[1]; if ( argv[2][0] != 0 ) { REFCOIN_CLI = (char *)argv[2]; } else { acname = coin; } hashstr = (char *)argv[3]; strcpy(M.rel.coin,hushdex_checkname(tmpstr,&M,1,coin)); strcpy(M.rel.name,coin); if ( argc == 4 && strlen(hashstr) == 64 ) // for blocknotify usage, seems not needed { height = get_coinheight(coin,acname,&blockhash); bits256_str(checkstr,blockhash); if ( strcmp(checkstr,hashstr) == 0 ) { fprintf(stderr,"%s: (%s) %s height.%d\n",coin,REFCOIN_CLI!=0?REFCOIN_CLI:"",checkstr,height); if ( (retjson= dpow_ntzdata(coin,SUBATOMIC_PRIORITY,height,blockhash)) != 0 ) free_json(retjson); } else fprintf(stderr,"coin.%s (%s) %s vs %s, height.%d\n",coin,REFCOIN_CLI!=0?REFCOIN_CLI:"",checkstr,hashstr,height); if ( strcmp("BTC",coin) != 0 ) { bits256 prevntzhash,ntzhash; int32_t prevntzheight,ntzheight; uint32_t ntztime,prevntztime; char hexstr[81]; cJSON *retjson2; prevntzhash = dpow_ntzhash(coin,&prevntzheight,&prevntztime); if ( (retjson= get_getinfo(coin,acname)) != 0 ) { ntzheight = juint(retjson,"notarized"); ntzhash = jbits256(retjson,"notarizedhash"); if ( ntzheight > prevntzheight ) { get_coinmerkleroot(coin,acname,ntzhash,&ntztime); fprintf(stderr,"NOTARIZATION %s.%d %s t.%u\n",coin,ntzheight,bits256_str(str,ntzhash),ntztime); bits256_str(hexstr,ntzhash); sprintf(&hexstr[64],"%08x",ntzheight); sprintf(&hexstr[72],"%08x",ntztime); hexstr[80] = 0; if ( (retjson2= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,coin,"notarizations",DPOW_pubkeystr,"","")) != 0 ) free_json(retjson2); } else if ( ntzheight == prevntzheight && memcmp(&prevntzhash,&ntzhash,32) != 0 ) fprintf(stderr,"NTZ ERROR %s.%d %s != %s\n",coin,ntzheight,bits256_str(str,ntzhash),bits256_str(str2,prevntzhash)); free_json(retjson); } } } else if ( argc == 5 && atol(hashstr) > 10000 ) { char checkstr[32]; uint64_t mult = 1; M.origid = (uint32_t)atol(hashstr); sprintf(checkstr,"%u",M.origid); if ( strcmp(checkstr,hashstr) == 0 ) // alice { M.rel.satoshis = (uint64_t)(atof(argv[4])*SATOSHIDEN+0.0000000049999); for (i=0; M.rel.name[i]!=0; i++) if ( M.rel.name[i] == '.' ) { mult = SATOSHIDEN; break; } if ( hushdex_getbalance(&M.rel) < M.rel.satoshis/mult ) { fprintf(stderr,"not enough balance %s %.8f for %.8f\n",M.rel.coin,dstr(hushdex_getbalance(&M.rel)),dstr(M.rel.satoshis/mult)); return(-1); } fprintf(stderr,"hushdex_channel_alice (%s/%s) %s %u with %.8f %llu\n",M.rel.name,M.rel.coin,hashstr,M.origid,atof(argv[4]),(long long)M.rel.satoshis); dpow_pubkeyregister(SUBATOMIC_PRIORITY); M.openrequestid = hushdex_alice_openrequest(&M); if ( M.openrequestid != 0 ) hushdex_loop(&M); } else fprintf(stderr,"checkstr mismatch %s %s != %s\n",coin,hashstr,checkstr); } else { M.bobflag = 1; strcpy(M.base.name,hashstr); strcpy(M.base.coin,hushdex_checkname(tmpstr,&M,0,hashstr)); hushdex_loop(&M); // while ( 1 ) loop for each relcoin -> basecoin } } return(SUBATOMIC_retval); }