/****************************************************************************** * 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. * * * ******************************************************************************/ // Todo list: // a) updating latest notarized height based on the notarized tx data // b) prevent overwriting blocks below notarized height // c) detection of special transactions to update list of current notaries // d) award 5% APR for utxo older than a week when they are spent // e) round robin mining difficulty #include "iguana777.h" #include "notaries.h" struct dpow_entry { bits256 prev_hash; uint64_t mask; int32_t prev_vout,height; uint8_t pubkey[33],k,siglen,sig[76]; }; bits256 dpow_getbestblockhash(struct supernet_info *myinfo,struct iguana_info *coin) { char *retstr; bits256 blockhash; memset(blockhash.bytes,0,sizeof(blockhash)); if ( coin->FULLNODE < 0 ) { if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"getbestblockhash","")) != 0 ) { //printf("%s getbestblockhash.(%s)\n",coin->symbol,retstr); if ( is_hexstr(retstr,0) == sizeof(blockhash)*2 ) decode_hex(blockhash.bytes,sizeof(blockhash),retstr); free(retstr); } } else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) { blockhash = coin->blocks.hwmchain.RO.hash2; } else { } return(blockhash); } cJSON *dpow_getblock(struct supernet_info *myinfo,struct iguana_info *coin,bits256 blockhash) { char buf[128],str[65],*retstr=0; cJSON *json = 0; if ( coin->FULLNODE < 0 ) { sprintf(buf,"\"%s\"",bits256_str(str,blockhash)); retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"getblock",buf); //printf("%s getblock.(%s)\n",coin->symbol,retstr); } else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) { retstr = bitcoinrpc_getblock(myinfo,coin,0,0,blockhash,1,0); } else { return(0); } if ( retstr != 0 ) { json = cJSON_Parse(retstr); free(retstr); } return(json); } char *dpow_decoderawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx) { char *retstr,*paramstr; cJSON *array; if ( coin->FULLNODE < 0 ) { array = cJSON_CreateArray(); jaddistr(array,rawtx); paramstr = jprint(array,1); retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"decoderawtransaction",paramstr); printf("%s decoderawtransaction.(%s) <- (%s)\n",coin->symbol,retstr,paramstr); free(paramstr); } else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) { retstr = bitcoinrpc_decoderawtransaction(myinfo,coin,0,0,rawtx,1); } else { return(0); } return(retstr); } cJSON *dpow_gettransaction(struct supernet_info *myinfo,struct iguana_info *coin,bits256 txid) { char buf[128],str[65],*retstr=0,*rawtx=0; cJSON *json = 0; if ( coin->FULLNODE < 0 ) { sprintf(buf,"[\"%s\", 1]",bits256_str(str,txid)); if ( (rawtx= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"getrawtransaction",buf)) != 0 ) { retstr = dpow_decoderawtransaction(myinfo,coin,rawtx); free(rawtx); } } else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) { retstr = bitcoinrpc_getrawtransaction(myinfo,coin,0,0,txid,1); } else { return(0); } if ( retstr != 0 ) { json = cJSON_Parse(retstr); free(retstr); } return(json); } cJSON *dpow_listunspent(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr) { char buf[128],*retstr; cJSON *json = 0; if ( coin->FULLNODE < 0 ) { sprintf(buf,"0, 99999999, [\"%s\"]",coinaddr); if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listunspent",buf)) != 0 ) { json = cJSON_Parse(retstr); //printf("%s (%s) listunspent.(%s)\n",coin->symbol,buf,retstr); free(retstr); } else printf("%s null retstr from (%s)n",coin->symbol,buf); } else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) { json = iguana_listunspents(myinfo,coin,0,1,coin->longestchain,""); } else { return(0); } return(json); } char *dpow_signrawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *rawtx,cJSON *vins) { cJSON *array,*privkeys,*item; char *wifstr,*str,*paramstr,*retstr; uint8_t script[256]; int32_t i,n,len,hashtype; struct vin_info V; struct iguana_waddress *waddr; struct iguana_waccount *wacct; if ( 0 && coin->FULLNODE < 0 ) { array = cJSON_CreateArray(); jaddistr(array,rawtx); jaddi(array,vins); paramstr = jprint(array,1); retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"signrawtransaction",paramstr); //printf("%s signrawtransaction.(%s) params.(%s)\n",coin->symbol,retstr,paramstr); free(paramstr); return(retstr); } else if ( 1 )//coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) { privkeys = cJSON_CreateArray(); if ( (n= cJSON_GetArraySize(vins)) > 0 ) { for (i=0; i 0 && strlen(str) < sizeof(script)*2 ) { len = (int32_t)strlen(str) >> 1; decode_hex(script,len,str); V.spendlen = len; memcpy(V.spendscript,script,len); if ( (hashtype= _iguana_calcrmd160(coin,&V)) >= 0 && V.coinaddr[0] != 0 ) { if ( (waddr= iguana_waddresssearch(myinfo,&wacct,V.coinaddr)) != 0 ) { if ( bits256_nonz(waddr->privkey) != 0 ) { if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->chain->wiftype) > 0 ) { wifstr = waddr->wifstr; } } } } } jaddistr(privkeys,wifstr); } } retstr = bitcoinrpc_signrawtransaction(myinfo,coin,0,0,rawtx,vins,privkeys,"ALL"); free_json(privkeys); return(retstr); } else { return(0); } } char *dpow_sendrawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *signedtx) { bits256 txid; cJSON *json,*array; char *paramstr,*retstr; if ( coin->FULLNODE < 0 ) { array = cJSON_CreateArray(); jaddistr(array,signedtx); paramstr = jprint(array,1); //printf("%s sendrawtransaction.(%s)\n",coin->symbol,paramstr); retstr = bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"sendrawtransaction",paramstr); free(paramstr); return(retstr); } else if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 ) { txid = iguana_sendrawtransaction(myinfo,coin,signedtx); json = cJSON_CreateObject(); jaddbits256(json,"result",txid); return(jprint(json,1)); } else { return(0); } } int32_t dpow_getchaintip(struct supernet_info *myinfo,bits256 *blockhashp,uint32_t *blocktimep,bits256 *txs,uint32_t *numtxp,struct iguana_info *coin) { int32_t n,i,height = -1,maxtx = *numtxp; bits256 besthash; cJSON *array,*json; *numtxp = *blocktimep = 0; *blockhashp = besthash = dpow_getbestblockhash(myinfo,coin); if ( bits256_nonz(besthash) != 0 ) { if ( (json= dpow_getblock(myinfo,coin,besthash)) != 0 ) { if ( (height= juint(json,"height")) != 0 && (*blocktimep= juint(json,"time")) != 0 ) { if ( (array= jarray(&n,json,"tx")) != 0 ) { for (i=0; isymbol,height,*blocktimep,n); *numtxp = n; } } else height = -1; free_json(json); } } return(height); } int32_t dpow_haveutxo(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *txidp,int32_t *voutp,char *coinaddr) { int32_t i,n,vout,haveutxo = 0; bits256 txid; cJSON *unspents,*item; uint64_t satoshis; char *str; uint8_t script[35]; memset(txidp,0,sizeof(*txidp)); *voutp = -1; if ( (unspents= dpow_listunspent(myinfo,coin,coinaddr)) != 0 ) { if ( (n= cJSON_GetArraySize(unspents)) > 0 ) { /*{ "txid" : "34bc21b40d6baf38e2db5be5353dd0bcc9fe416485a2a68753541ed2f9c194b1", "vout" : 0, "address" : "RFBmvBaRybj9io1UpgWM4pzgufc3E4yza7", "scriptPubKey" : "21039a3f7373ae91588b9edd76a9088b2871f62f3438d172b9f18e0581f64887404aac", "amount" : 3.00000000, "confirmations" : 4282, "spendable" : true },*/ for (i=0; iDPOW.minerkey33,33) == 0 ) { txid = jbits256(item,"txid"); vout = jint(item,"vout"); if ( bits256_nonz(txid) != 0 && vout >= 0 ) { if ( *voutp < 0 ) { *voutp = vout; *txidp = txid; } haveutxo++; } } } } } } // else printf("null array size\n"); free_json(unspents); } else printf("null return from dpow_listunspent\n"); if ( haveutxo > 0 ) printf("%s haveutxo.%d\n",coin->symbol,haveutxo); return(haveutxo); } int32_t dpow_message_utxo(bits256 *hashmsgp,bits256 *txidp,int32_t *voutp,cJSON *json) { cJSON *msgobj,*item; uint8_t key[BASILISK_KEYSIZE],data[sizeof(bits256)*2+1]; char *keystr,*hexstr,str[65],str2[65]; int32_t i,j,n,datalen,retval = -1; *voutp = -1; memset(txidp,0,sizeof(*txidp)); if ( (msgobj= jarray(&n,json,"messages")) != 0 ) { //printf("messages.(%s)\n",jprint(msgobj,0)); for (i=0; i 0 ) { decode_hex(key,BASILISK_KEYSIZE,keystr); datalen >>= 1; if ( datalen <= sizeof(data) ) { decode_hex(data,datalen,hexstr); if ( datalen == sizeof(data) ) { for (j=0; jbytes[j] = data[j]; txidp->bytes[j] = data[j + sizeof(bits256)]; } *voutp = data[sizeof(bits256) * 2]; retval = datalen; printf("notary.%d hashmsg.(%s) txid.(%s) v%d\n",i,bits256_str(str,*hashmsgp),bits256_str(str2,*txidp),*voutp); } } else printf("datalen.%d >= maxlen.%d\n",datalen,(int32_t)sizeof(data)); } } } return(retval); } int32_t dpow_message_most(uint8_t *k_masks,int32_t num,cJSON *json,int32_t lastflag) { cJSON *msgobj,*item; uint8_t key[BASILISK_KEYSIZE],data[128]; char *keystr,*hexstr; int32_t duplicate,i,j,n,datalen,most = 0; if ( (msgobj= jarray(&n,json,"messages")) != 0 ) { for (i=0; i 0 ) { decode_hex(key,BASILISK_KEYSIZE,keystr); datalen >>= 1; if ( datalen < sizeof(data) ) { decode_hex(data,datalen,hexstr); for (j=duplicate=0; j= maxlen.%d\n",datalen,(int32_t)sizeof(data)); } } } if ( lastflag != 0 && num > 0 ) { for (j=0; j most ) { most = n; memcpy(&k_masks[num << 7],&k_masks[i << 7],1 << 7); } } } printf("most.%d n.%d\n",most,n); return(num); } cJSON *dpow_createtx(struct iguana_info *coin,cJSON **vinsp,struct dpow_entry notaries[DPOW_MAXRELAYS],int32_t numnotaries,int32_t height,int32_t lastk,uint64_t mask,int32_t usesigs,bits256 hashmsg,bits256 btctxid) { int32_t i,j,m=0; char scriptstr[256]; cJSON *txobj=0,*vins=0,*item; uint64_t satoshis; uint8_t script[35]; if ( (txobj= bitcoin_txcreate(coin->chain->isPoS,0,1,0)) != 0 ) { vins = cJSON_CreateArray(); for (j=0; j 0 ) { init_hexbytes_noT(scriptstr,notaries[i].sig,notaries[i].siglen); jaddstr(item,"scriptSig",scriptstr); } jaddi(vins,item); bitcoin_txinput(coin,txobj,notaries[i].prev_hash,notaries[i].prev_vout,0xffffffff,script,sizeof(script),0,0,0,0); m++; if ( m == numnotaries/2+1 && i == lastk ) break; } } satoshis = DPOW_UTXOSIZE * m * .76; script[0] = 33; decode_hex(script+1,33,CRYPTO777_PUBSECPSTR); script[34] = 0xac; txobj = bitcoin_txoutput(txobj,script,sizeof(script),satoshis); } *vinsp = vins; //printf("%s createtx.(%s)\n",coin->symbol,jprint(txobj,0)); return(txobj); } int32_t dpow_signedtxgen(struct supernet_info *myinfo,struct dpow_info *dp,struct iguana_info *coin,bits256 *signedtxidp,char *signedtx,uint64_t mask,int32_t lastk,struct dpow_entry notaries[DPOW_MAXRELAYS],int32_t numnotaries,int32_t height,int32_t myind,bits256 hashmsg,bits256 btctxid) { int32_t i,j,siglen,m=0,retval=-1; char *rawtx,*rawtx2,*sigstr; cJSON *txobj,*sigobj,*txobj2,*vins,*item,*vin; uint8_t data[128]; bits256 txid,srchash,desthash; uint32_t channel; channel = 's' | ('i' << 8) | ('g' << 16) | ('s' << 24); for (j=0; jDPOW.minerkey33[j+1]; if ( (txobj= dpow_createtx(coin,&vins,notaries,numnotaries,height,lastk,mask,1,hashmsg,btctxid)) != 0 ) { if ( (rawtx= bitcoin_json2hex(myinfo,coin,&txid,txobj,0)) != 0 ) { if ( (signedtx= dpow_signrawtransaction(myinfo,coin,rawtx,vins)) != 0 ) { if ( (rawtx2= dpow_decoderawtransaction(myinfo,coin,signedtx)) != 0 ) { if ( (txobj2= cJSON_Parse(rawtx2)) != 0 ) { printf("txobj2.(%s)\n",jprint(txobj2,0)); if ( (vin= jarray(&m,txobj2,"vin")) != 0 && myind < m ) { item = jitem(vin,myind); printf("myvin.(%s)\n",jprint(item,0)); if ( (sigobj= jobj(item,"scriptSig")) != 0 && (sigstr= jstr(sigobj,"hex")) != 0 ) { siglen = (int32_t)strlen(sigstr) >> 1; data[0] = myind; data[1] = lastk; iguana_rwnum(1,&data[2],sizeof(mask),(uint8_t *)&mask); data[10] = siglen; decode_hex(data+11,siglen,sigstr); for (i=0; iDPOW.minerkey33[j+1]; num = 0; k_masks = calloc(4096,128); for (i=0; i 0 ) { k = k_masks[(num << 7) + 1]; iguana_rwnum(0,&k_masks[(num << 7) + 2],sizeof(mask),(uint8_t *)&mask); *lastkp = k; *maskp = mask; if ( (most= dpow_k_masks_match(notaries,numnotaries,k_masks,num,k,mask,height)) >= numnotaries/2+1 ) { if ( (txobj= dpow_createtx(coin,&vins,notaries,numnotaries,height,k,mask,1,hashmsg,btctxid)) != 0 ) { if ( (rawtx= bitcoin_json2hex(myinfo,coin,signedtxidp,txobj,0)) != 0 ) { strcpy(signedtx,rawtx); free(rawtx); } free_json(txobj); free_json(vins); } } } free(k_masks); return(most); } void dpow_txidupdate(struct supernet_info *myinfo,struct dpow_info *dp,struct iguana_info *coin,uint64_t *recvmaskp,uint32_t channel,int32_t height,struct dpow_entry notaries[DPOW_MAXRELAYS],int32_t numnotaries,int32_t myind,bits256 hashmsg) { int32_t i,j,k,m; cJSON *item,*retarray; bits256 desthash,srchash,checkmsg; for (j=0; jDPOW.minerkey33[j+1]; for (i=0; i 8 ) incr = sqrt(numnotaries) + 1; else incr = 1; channel = 'd' | ('P' << 8) | ('o' << 16) | ('W' << 24); bitcoin_address(coinaddr,coin->chain->pubtype,myinfo->DPOW.minerkey33,33); if ( bits256_nonz(hashmsg) == 0 ) return(0xffffffff); for (j=0; jDPOW.minerkey33[j+1]; printf("%s statemachine state.%d %s\n",coin->symbol,state,coinaddr); switch ( state ) { case 0: if ( (haveutxo= dpow_haveutxo(myinfo,coin,&txid,&vout,coinaddr)) != 0 ) state = 1; if ( haveutxo < 10 ) { addresses = cJSON_CreateArray(); jaddistr(addresses,coinaddr); if ( (rawtx= iguana_utxoduplicates(myinfo,coin,myinfo->DPOW.minerkey33,DPOW_UTXOSIZE,10,&completed,&signedtxid,0,addresses)) != 0 ) { if ( (sendtx= dpow_sendrawtransaction(myinfo,coin,rawtx)) != 0 ) { printf("sendrawtransaction.(%s)\n",sendtx); free(sendtx); } free(rawtx); } free_json(addresses); } break; case 1: // wait for utxo, send utxo to all other nodes if ( (haveutxo= dpow_haveutxo(myinfo,coin,&txid,&vout,coinaddr)) != 0 && vout >= 0 && vout < 0x100 ) { i = (myind % incr); for (; isymbol,bits256_str(str,hashmsg),bits256_str(str2,txid),vout); basilisk_channelsend(myinfo,srchash,desthash,channel,heightmsg,data,sizeof(data),600); } state = 2; } break; case 2: dpow_txidupdate(myinfo,dp,coin,recvmaskp,channel,heightmsg,notaries,numnotaries,myind,hashmsg); printf("STATE2: RECVMASK.%llx\n",(long long)*recvmaskp); if ( bitweight(*recvmaskp) > numnotaries/2 ) state = 3; break; case 3: // create rawtx, sign, send rawtx + sig to all other nodes dpow_txidupdate(myinfo,dp,coin,recvmaskp,channel,heightmsg,notaries,numnotaries,myind,hashmsg); k = 0; printf("STATE3: RECVMASK.%llx\n",(long long)*recvmaskp); if ( bitweight(*recvmaskp) > numnotaries/2+1 ) { printf("too many entries, prune to %d\n",numnotaries/2+1); mask = 0; for (j=m=0; j= numnotaries/2+1 ) break; } } } else mask = *recvmaskp; if ( bitweight(mask) == numnotaries/2+1 ) { printf("signtxgen\n"); if ( dpow_signedtxgen(myinfo,dp,coin,signedtxidp,signedtx,mask,k,notaries,numnotaries,heightmsg,myind,hashmsg,btctxid) == 0 ) { dp->destupdated = 0; state = 4; } } else printf("mask.%llx wt.%d\n",(long long)mask,bitweight(mask)); break; case 4: // wait for N/2+1 signed tx and broadcast dpow_txidupdate(myinfo,dp,coin,recvmaskp,channel,heightmsg,notaries,numnotaries,myind,hashmsg); printf("STATE4\n"); if ( (m= dpow_mostsignedtx(myinfo,dp,coin,signedtxidp,signedtx,&mask,&k,notaries,numnotaries,heightmsg,myind,hashmsg,btctxid)) > 0 ) { if ( m >= numnotaries/2+1 ) { if ( (retstr= dpow_sendrawtransaction(myinfo,coin,signedtx)) != 0 ) { printf("sendrawtransaction.(%s)\n",retstr); free(retstr); } state = 0xffffffff; } else { dpow_signedtxgen(myinfo,dp,coin,signedtxidp,signedtx,mask,k,notaries,numnotaries,heightmsg,myind,hashmsg,btctxid); } } break; } return(state); } void dpow_statemachinestart(void *ptr) { struct supernet_info *myinfo; struct dpow_info *dp; struct dpow_checkpoint checkpoint; void **ptrs = ptr; int32_t i,n,myind = -1; uint64_t recvmask = 0; uint32_t srcstate=0,deststate=0; struct iguana_info *src,*dest; struct dpow_hashheight srchash,desthash; char signedtx[16384],signedtx2[16384],str[65],coinaddr[64]; bits256 signedtxid,signedtxid2,zero; struct dpow_entry notaries[DPOW_MAXRELAYS]; memset(&zero,0,sizeof(zero)); memset(notaries,0,sizeof(notaries)); myinfo = ptrs[0]; dp = ptrs[1]; memcpy(&checkpoint,&ptrs[2],sizeof(checkpoint)); printf("statemachinestart %s->%s %s ht.%d\n",dp->symbol,dp->dest,bits256_str(str,checkpoint.blockhash.hash),checkpoint.blockhash.height); src = iguana_coinfind(dp->symbol); dest = iguana_coinfind(dp->dest); n = (int32_t)(sizeof(Notaries)/sizeof(*Notaries)); for (i=0; ichain->pubtype,notaries[i].pubkey,33); printf("%s.%d ",coinaddr,i); if ( memcmp(notaries[i].pubkey,myinfo->DPOW.minerkey33,33) == 0 ) myind = i; } bitcoin_address(coinaddr,src->chain->pubtype,myinfo->DPOW.minerkey33,33); printf(" myaddr.%s\n",coinaddr); if ( myind < 0 ) { printf("statemachinestart this node %s is not official notary\n",coinaddr); free(ptr); return; } dp->checkpoint = checkpoint; srchash = checkpoint.blockhash; desthash = dp->notarized[0]; printf("DPOW statemachine checkpoint.%d %s\n",checkpoint.blockhash.height,bits256_str(str,checkpoint.blockhash.hash)); while ( src != 0 && dest != 0 && (srcstate != 0xffffffff || deststate != 0xffffffff) ) { sleep(1); if ( dp->checkpoint.blockhash.height > checkpoint.blockhash.height ) { printf("abort ht.%d due to new checkpoint.%d\n",checkpoint.blockhash.height,dp->checkpoint.blockhash.height); break; } if ( deststate != 0xffffffff ) { printf("DEST.%08x %s\n",deststate,bits256_str(str,srchash.hash)); deststate = dpow_statemachineiterate(myinfo,dp,dest,deststate,srchash.hash,srchash.height,zero,notaries,n,myind,&recvmask,&signedtxid,signedtx); } else printf("deststate.%08x\n",deststate); if ( deststate == 0xffffffff ) { if ( srcstate != 0xffffffff ) { printf("SRC.%08x\n",srcstate); srcstate = dpow_statemachineiterate(myinfo,dp,src,srcstate,srchash.hash,srchash.height,signedtxid,notaries,n,myind,&recvmask,&signedtxid2,signedtx2); } } } free(ptr); } void dpow_fifoupdate(struct supernet_info *myinfo,struct dpow_checkpoint *fifo,struct dpow_checkpoint tip) { int32_t i; struct dpow_checkpoint newfifo[DPOW_FIFOSIZE]; char str[65]; memset(newfifo,0,sizeof(newfifo)); for (i=DPOW_FIFOSIZE-1; i>0; i--) { /*if ( (offset= (tip.blockhash.height - fifo[i].blockhash.height)) >= 0 && offset < DPOW_FIFOSIZE ) { newfifo[offset] = fifo[i]; } printf("[offset %d = (%d - %d)] <- i.%d\n",offset,tip.blockhash.height,fifo[i].blockhash.height,i);*/ newfifo[i] = fifo[i-1]; } newfifo[0] = tip; memcpy(fifo,newfifo,sizeof(newfifo)); for (i=0; itimestamp = timestamp; checkpoint->blocktime = blocktime; checkpoint->blockhash.hash = hash; checkpoint->blockhash.height = height; } void dpow_srcupdate(struct supernet_info *myinfo,struct dpow_info *dp,int32_t height,bits256 hash,uint32_t timestamp,uint32_t blocktime) { void **ptrs; char str[65]; struct dpow_checkpoint checkpoint; dpow_checkpointset(myinfo,&dp->last,height,hash,timestamp,blocktime); checkpoint = dp->srcfifo[dp->srcconfirms]; printf("%s srcupdate ht.%d destupdated.%u nonz.%d %s\n",dp->symbol,height,dp->destupdated,bits256_nonz(checkpoint.blockhash.hash),bits256_str(str,dp->last.blockhash.hash)); dpow_fifoupdate(myinfo,dp->srcfifo,dp->last); if ( dp->destupdated != 0 && bits256_nonz(checkpoint.blockhash.hash) != 0 ) { ptrs = calloc(1,sizeof(void *)*2 + sizeof(struct dpow_checkpoint)); ptrs[0] = (void *)myinfo; ptrs[1] = (void *)dp; memcpy(&ptrs[2],&checkpoint,sizeof(checkpoint)); if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,(void *)dpow_statemachinestart,(void *)ptrs) != 0 ) { } } } void dpow_approvedset(struct supernet_info *myinfo,struct dpow_info *dp,struct dpow_checkpoint *checkpoint,bits256 *txs,int32_t numtx) { int32_t i,j; bits256 txid; if ( txs != 0 ) { for (i=0; iapproved[j].hash) == 0 ) { if ( bits256_nonz(checkpoint->approved.hash) == 0 || dp->approved[j].height >= checkpoint->approved.height ) checkpoint->approved = dp->approved[j]; } } } } } } void dpow_destconfirm(struct supernet_info *myinfo,struct dpow_info *dp,struct dpow_checkpoint *checkpoint) { int32_t i; if ( bits256_nonz(checkpoint->approved.hash) != 0 ) { for (i=DPOW_FIFOSIZE-1; i>0; i--) dp->notarized[i] = dp->notarized[i-1]; dp->notarized[0] = checkpoint->approved; } } void dpow_destupdate(struct supernet_info *myinfo,struct dpow_info *dp,int32_t height,bits256 hash,uint32_t timestamp,uint32_t blocktime) { printf("%s destupdate ht.%d\n",dp->dest,height); dp->destupdated = timestamp; dpow_checkpointset(myinfo,&dp->destchaintip,height,hash,timestamp,blocktime); dpow_approvedset(myinfo,dp,&dp->destchaintip,dp->desttx,dp->numdesttx); dpow_fifoupdate(myinfo,dp->destfifo,dp->destchaintip); if ( strcmp(dp->dest,DPOW_BTCSTR) == 0 ) dpow_destconfirm(myinfo,dp,&dp->destfifo[DPOW_BTCCONFIRMS]); else { dpow_destconfirm(myinfo,dp,&dp->destfifo[DPOW_KOMODOCONFIRMS * 2]); // todo: change to notarized KMD depth } } void iguana_dPoWupdate(struct supernet_info *myinfo) { int32_t height; char str[65]; uint32_t blocktime; bits256 blockhash; struct iguana_info *src,*dest; struct dpow_info *dp = &myinfo->DPOW; if ( strcmp(dp->symbol,"KMD") == 0 ) { strcpy(dp->dest,DPOW_BTCSTR); dp->srcconfirms = DPOW_KOMODOCONFIRMS; } else { strcpy(dp->dest,"KMD"); dp->srcconfirms = DPOW_THIRDPARTY_CONFIRMS; } if ( dp->srcconfirms > DPOW_FIFOSIZE ) dp->srcconfirms = DPOW_FIFOSIZE; src = iguana_coinfind(dp->symbol); dest = iguana_coinfind(dp->dest); if ( src != 0 && dest != 0 ) { dp->numdesttx = sizeof(dp->desttx)/sizeof(*dp->desttx); if ( (height= dpow_getchaintip(myinfo,&blockhash,&blocktime,dp->desttx,&dp->numdesttx,dest)) != dp->destchaintip.blockhash.height && height >= 0 ) { printf("%s %s height.%d vs last.%d\n",dp->dest,bits256_str(str,blockhash),height,dp->destchaintip.blockhash.height); if ( height <= dp->destchaintip.blockhash.height ) { printf("iguana_dPoWupdate dest.%s reorg detected %d vs %d\n",dp->dest,height,dp->destchaintip.blockhash.height); if ( height == dp->destchaintip.blockhash.height && bits256_cmp(blockhash,dp->destchaintip.blockhash.hash) != 0 ) printf("UNEXPECTED ILLEGAL BLOCK in dest chaintip\n"); } else dpow_destupdate(myinfo,dp,height,blockhash,(uint32_t)time(NULL),blocktime); } dp->numsrctx = sizeof(dp->srctx)/sizeof(*dp->srctx); if ( (height= dpow_getchaintip(myinfo,&blockhash,&blocktime,dp->srctx,&dp->numsrctx,src)) != dp->last.blockhash.height && height >= 0 ) { printf("%s %s height.%d vs last.%d\n",dp->symbol,bits256_str(str,blockhash),height,dp->last.blockhash.height); if ( height < dp->last.blockhash.height ) { printf("iguana_dPoWupdate src.%s reorg detected %d vs %d approved.%d notarized.%d\n",dp->symbol,height,dp->last.blockhash.height,dp->approved[0].height,dp->notarized[0].height); if ( height <= dp->approved[0].height ) { if ( bits256_cmp(blockhash,dp->last.blockhash.hash) != 0 ) printf("UNEXPECTED ILLEGAL BLOCK in src chaintip\n"); } else dpow_srcupdate(myinfo,dp,height,blockhash,(uint32_t)time(NULL),blocktime); } else dpow_srcupdate(myinfo,dp,height,blockhash,(uint32_t)time(NULL),blocktime); } } else printf("iguana_dPoWupdate missing src.(%s) %p or dest.(%s) %p\n",dp->symbol,src,dp->dest,dest); } #include "../includes/iguana_apidefs.h" TWO_STRINGS(iguana,dpow,symbol,pubkey) { if ( myinfo->NOTARY.RELAYID < 0 ) return(clonestr("{\"error\":\"must be running as notary node\"}")); if ( myinfo->DPOW.symbol[0] != 0 ) return(clonestr("{\"error\":\"cant dPoW more than one coin at a time\"}")); if ( pubkey == 0 || pubkey[0] == 0 || is_hexstr(pubkey,0) != 66 ) return(clonestr("{\"error\":\"need 33 byte pubkey\"}")); if ( symbol == 0 || symbol[0] == 0 ) symbol = "KMD"; if ( iguana_coinfind(symbol) == 0 ) return(clonestr("{\"error\":\"cant dPoW an inactive coin\"}")); if ( strcmp(symbol,"KMD") == 0 && iguana_coinfind(DPOW_BTCSTR) == 0 ) return(clonestr("{\"error\":\"cant dPoW KMD without BTC\"}")); else if ( strcmp(symbol,"KMD") != 0 && iguana_coinfind("KMD") == 0 ) return(clonestr("{\"error\":\"cant dPoW without KMD\"}")); decode_hex(myinfo->DPOW.minerkey33,33,pubkey); if ( bitcoin_pubkeylen(myinfo->DPOW.minerkey33) <= 0 ) return(clonestr("{\"error\":\"illegal pubkey\"}")); strcpy(myinfo->DPOW.symbol,symbol); return(clonestr("{\"result\":\"success\"}")); } #include "../includes/iguana_apiundefs.h"