diff --git a/basilisk/basilisk.c b/basilisk/basilisk.c index d31cf1459..98b98a9b1 100755 --- a/basilisk/basilisk.c +++ b/basilisk/basilisk.c @@ -102,7 +102,7 @@ uint8_t *basilisk_jsondata(int32_t extraoffset,uint8_t **ptrp,uint8_t *space,int } data += extraoffset + BASILISK_HDROFFSET; memcpy(data,sendstr,datalen); - printf("jsondata.(%s) + hexlen.%d\n",sendstr,hexlen); + //printf("jsondata.(%s) + hexlen.%d\n",sendstr,hexlen); free(sendstr); if ( hexlen > 0 ) { @@ -286,7 +286,7 @@ void basilisk_p2p(void *_myinfo,void *_addr,char *senderip,uint8_t *data,int32_t void basilisk_sendback(struct supernet_info *myinfo,char *origCMD,char *symbol,char *remoteaddr,uint32_t basilisktag,char *retstr) { uint8_t *data,space[4096],*allocptr; cJSON *valsobj; int32_t datalen,encryptflag=0,delaymillis=0; - printf("retstr.(%s) -> remote.(%s) basilisktag.%u\n",retstr,remoteaddr,basilisktag); + printf("%s retstr.(%s) -> remote.(%s) basilisktag.%u\n",origCMD,retstr,remoteaddr,basilisktag); if ( retstr != 0 && remoteaddr != 0 && remoteaddr[0] != 0 && strcmp(remoteaddr,"127.0.0.1") != 0 ) { if ( (valsobj= cJSON_Parse(retstr)) != 0 ) @@ -309,11 +309,11 @@ char *basilisk_waitresponse(struct supernet_info *myinfo,char *CMD,char *symbol, if ( (retstr= Lptr->retstr) == 0 ) retstr = clonestr("{\"result\":\"null return from local basilisk_issuecmd\"}"); ptr = basilisk_itemcreate(myinfo,CMD,symbol,Lptr->basilisktag,Lptr->numrequired,Lptr->vals,OS_milliseconds() - Lptr->expiration,Lptr->metricfunc); - //queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); + queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); } else { - //queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); + queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); while ( OS_milliseconds() < ptr->expiration ) { //if ( (retstr= basilisk_iscomplete(ptr)) != 0 ) @@ -387,7 +387,6 @@ char *basilisk_standardservice(char *CMD,struct supernet_info *myinfo,bits256 ha ptr->vals = jduplicate(valsobj); strcpy(ptr->symbol,"BTCD"); strcpy(ptr->CMD,CMD); - queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); return(basilisk_waitresponse(myinfo,CMD,"BTCD",0,&Lptr,ptr)); } else if ( ptr->numsent > 0 ) @@ -536,7 +535,6 @@ char *basilisk_standardcmd(struct supernet_info *myinfo,char *CMD,char *activeco { if ( (ptr= basilisk_issuecmd(&Lptr,func,metric,myinfo,remoteaddr,basilisktag,activecoin,timeoutmillis,vals)) != 0 ) { - queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); return(basilisk_waitresponse(myinfo,CMD,coin->symbol,remoteaddr,&Lptr,ptr)); } else return(clonestr("{\"error\":\"null return from basilisk_issuecmd\"}")); @@ -599,6 +597,48 @@ char *basilisk_checkrawtx(int32_t *timeoutmillisp,uint32_t *basilisktagp,char *s } } +int32_t basilisk_relays_send(struct supernet_info *myinfo,struct iguana_peer *addr) +{ + int32_t i,len = 0; uint8_t serialized[sizeof(myinfo->relaybits)]; cJSON *vals; bits256 hash; char *retstr,hexstr[sizeof(myinfo->relaybits)*2 + 1]; + if ( myinfo != 0 ) + { + memset(hash.bytes,0,sizeof(hash)); + for (i=0; inumrelays; i++) + len += iguana_rwnum(1,&serialized[len],sizeof(uint32_t),&myinfo->relaybits[i]); + init_hexbytes_noT(hexstr,serialized,len); + vals = cJSON_CreateObject(); + if ( (retstr= basilisk_standardservice("REL",myinfo,hash,vals,hexstr,1)) != 0 ) + free(retstr); + free_json(vals); + return(0); + } else return(-1); +} + +int32_t basilisk_headers_send(struct supernet_info *myinfo,struct iguana_info *virt,struct iguana_peer *addr,bits256 *txids,int32_t num) +{ + bits256 hash; uint8_t *serialized; int32_t i,len = 0; char *str=0,*retstr,*hexstr,*allocptr=0,space[8192]; bits256 txid; cJSON *vals; + if ( virt != 0 && addr != 0 ) + { + memset(hash.bytes,0,sizeof(hash)); + serialized = (void *)txids; + for (i=0; inumrequired = 1; ptr->uniqueflag = 1; ptr->metricdir = -1; - queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); return(basilisk_waitresponse(myinfo,"RAW",coin->symbol,remoteaddr,&Lptr,ptr)); } else return(clonestr("{\"error\":\"error issuing basilisk rawtx\"}")); } else return(retstr); @@ -652,6 +691,11 @@ HASH_ARRAY_STRING(basilisk,addrelay,hash,vals,hexstr) return(basilisk_standardservice("ADD",myinfo,hash,vals,hexstr,1)); } +HASH_ARRAY_STRING(basilisk,relays,hash,vals,hexstr) +{ + return(basilisk_standardservice("REL",myinfo,hash,vals,hexstr,1)); +} + HASH_ARRAY_STRING(basilisk,dispatch,hash,vals,hexstr) { return(basilisk_standardservice("RUN",myinfo,hash,vals,hexstr,1)); @@ -724,6 +768,8 @@ void basilisk_geckoresult(struct supernet_info *myinfo,struct basilisk_item *ptr hash2 = jbits256(retjson,"hash"); if ( strcmp(type,"HDR") == 0 ) str = gecko_headersarrived(myinfo,virt,ptr->remoteaddr,data,datalen,hash2); + else if ( strcmp(type,"MEM") == 0 ) + str = gecko_mempoolarrived(myinfo,virt,ptr->remoteaddr,data,datalen,hash2); else if ( strcmp(type,"BLK") == 0 ) str = gecko_blockarrived(myinfo,virt,ptr->remoteaddr,data,datalen,hash2); else if ( strcmp(type,"GTX") == 0 ) @@ -834,10 +880,10 @@ void basilisks_loop(void *arg) printf("HASH_DELETE free ptr.%u\n",pending->basilisktag); for (i=0; inumresults; i++) if ( pending->results[i] != 0 ) - free(pending->results[i]); + free(pending->results[i]), pending->results[i] = 0; if ( pending->vals != 0 ) - free_json(pending->vals); - free(pending); + free_json(pending->vals), pending->vals = 0; + //free(pending); flag++; } } @@ -949,11 +995,13 @@ void basilisk_msgprocess(struct supernet_info *myinfo,void *addr,uint32_t sender { (void *)"GET", &basilisk_respond_geckoget }, // requests headers, block or tx { (void *)"HDR", &basilisk_respond_geckoheaders }, // reports headers { (void *)"BLK", &basilisk_respond_geckoblock }, // reports block + { (void *)"MEM", &basilisk_respond_mempool }, // reports mempool { (void *)"GTX", &basilisk_respond_geckotx }, // reports tx { (void *)"SEQ", &basilisk_respond_hashstamps }, // BTCD and BTC recent hashes from timestamp // unencrypted low level functions, used by higher level protocols and virtual network funcs { (void *)"ADD", &basilisk_respond_addrelay }, // relays register with each other bus + { (void *)"REL", &basilisk_respond_relays }, { (void *)"DEX", &basilisk_respond_instantdex }, // encrypted data for jumblr @@ -1088,11 +1136,16 @@ void basilisk_msgprocess(struct supernet_info *myinfo,void *addr,uint32_t sender } else // basilisk node { - if ( strcmp(type,"ADD") == 0 ) + if ( strcmp(type,"REL") == 0 ) { - printf("new relay ADD.(%s) datalen.%d\n",jprint(valsobj,0),datalen); + printf("relays REL.(%s) datalen.%d\n",jprint(valsobj,0),datalen); + basilisk_respond_relays(myinfo,type,addr,remoteaddr,basilisktag,valsobj,data,datalen,hash,from_basilisk); } - else printf("basilisk node doenst handle.(%s)\n",type); + else if ( strcmp(type,"ADD") == 0 ) + { + printf("new relay ADD.(%s) datalen.%d\n",jprint(valsobj,0),datalen); + basilisk_respond_addrelay(myinfo,type,addr,remoteaddr,basilisktag,valsobj,data,datalen,hash,from_basilisk); + } else printf("basilisk node doenst handle.(%s)\n",type); } } else printf("basilisk_msgprocess no coin\n"); } diff --git a/basilisk/basilisk.h b/basilisk/basilisk.h index 07ef41baf..c3f6ae3b7 100755 --- a/basilisk/basilisk.h +++ b/basilisk/basilisk.h @@ -45,6 +45,12 @@ struct basilisk_info struct basilisk_value values[8192]; int32_t numvalues; }; +struct basilisk_relay +{ + bits256 pubkey; uint32_t ipbits; struct iguana_peer *addr; + char btcdaddr[64],sigstr[168]; +}; + void basilisk_msgprocess(struct supernet_info *myinfo,void *addr,uint32_t senderipbits,char *type,uint32_t basilisktag,uint8_t *data,int32_t datalen); int32_t basilisk_sendcmd(struct supernet_info *myinfo,char *destipaddr,char *type,uint32_t *basilisktagp,int32_t encryptflag,int32_t delaymillis,uint8_t *data,int32_t datalen,int32_t fanout,uint32_t nBits); // data must be offset by sizeof(iguana_msghdr)+sizeof(basilisktag) @@ -57,7 +63,7 @@ void *SuperNET_deciphercalc(void **ptrp,int32_t *msglenp,bits256 privkey,bits256 uint8_t *get_dataptr(int32_t hdroffset,uint8_t **ptrp,int32_t *datalenp,uint8_t *space,int32_t spacesize,char *hexstr); char *basilisk_addhexstr(char **ptrp,cJSON *valsobj,char *strbuf,int32_t strsize,uint8_t *data,int32_t datalen); char *basilisk_standardservice(char *CMD,struct supernet_info *myinfo,bits256 hash,cJSON *valsobj,char *hexstr,int32_t blockflag); // client side - +char *basilisk_respond_mempool(struct supernet_info *myinfo,char *CMD,void *_addr,char *remoteaddr,uint32_t basilisktag,cJSON *valsobj,uint8_t *data,int32_t datalen,bits256 hash,int32_t from_basilisk); void basilisk_request_goodbye(struct supernet_info *myinfo); int32_t basilisk_update(char *symbol,uint32_t reftimestamp); diff --git a/basilisk/basilisk_CMD.c b/basilisk/basilisk_CMD.c index 3d62cf33b..ac3642b45 100755 --- a/basilisk/basilisk_CMD.c +++ b/basilisk/basilisk_CMD.c @@ -15,6 +15,67 @@ // included from basilisk.c +struct iguana_peer *basilisk_ensurerelay(struct iguana_info *btcd,uint32_t ipbits) +{ + struct iguana_peer *addr; + if ( (addr= iguana_peerfindipbits(btcd,ipbits,0)) == 0 ) + { + if ( (addr= iguana_peerslot(btcd,ipbits,0)) != 0 ) + { + printf("launch peer for relay\n"); + addr->isrelay = 1; + iguana_launch(btcd,"addrelay",iguana_startconnection,addr,IGUANA_CONNTHREAD); + } else printf("error getting peerslot\n"); + } else addr->isrelay = 1; + return(addr); +} + +char *basilisk_addrelay_info(struct supernet_info *myinfo,char *btcdaddr,uint32_t ipbits,bits256 pubkey,char *sigstr) +{ + int32_t i; struct basilisk_relay *rp; struct iguana_info *btcd; + if ( (btcd= iguana_coinfind("BTCD")) == 0 ) + return(clonestr("{\"error\":\"add relay needs BTCD\"}")); + for (i=0; inumrelays; i++) + { + rp = &myinfo->relays[i]; + if ( ipbits == rp->ipbits ) + return(clonestr("{\"error\":\"relay already there\"}")); + } + if ( i >= sizeof(myinfo->relays)/sizeof(*myinfo->relays) ) + i = (rand() % (sizeof(myinfo->relays)/sizeof(*myinfo->relays))); + rp = &myinfo->relays[i]; + printf("verify relay sig\n"); + rp->ipbits = ipbits; + rp->pubkey = pubkey; + safecopy(rp->btcdaddr,btcdaddr,sizeof(rp->btcdaddr)); + safecopy(rp->sigstr,sigstr,sizeof(rp->sigstr)); + rp->addr = basilisk_ensurerelay(btcd,rp->ipbits); + for (i=0; inumrelays; i++) + myinfo->relaybits[i] = myinfo->relays[i].ipbits; + revsort32(&myinfo->relaybits[0],myinfo->numrelays,sizeof(myinfo->relaybits[0])); + return(clonestr("{\"result\":\"relay added\"}")); +} + +char *basilisk_respond_relays(struct supernet_info *myinfo,char *CMD,void *_addr,char *remoteaddr,uint32_t basilisktag,cJSON *valsobj,uint8_t *data,int32_t datalen,bits256 hash,int32_t from_basilisk) +{ + uint32_t *ipbits = (uint32_t *)data; int32_t num,i,j,n = datalen >> 2; + for (i=num=0; inumrelays; j++) + if ( ipbits[i] == myinfo->relays[j].ipbits ) + break; + if ( j == myinfo->numrelays ) + { + num++; + printf("ensure unknown relay\n"); + basilisk_ensurerelay(iguana_coinfind("BTCD"),ipbits[i]); + } + } + if ( num == 0 ) + return(clonestr("{\"result\":\"no new relays found\"}")); + else return(clonestr("{\"result\":\"relay added\"}")); +} + char *basilisk_respond_goodbye(struct supernet_info *myinfo,char *CMD,void *_addr,char *remoteaddr,uint32_t basilisktag,cJSON *valsobj,uint8_t *data,int32_t datalen,bits256 hash,int32_t from_basilisk) { struct iguana_peer *addr = _addr; @@ -42,7 +103,11 @@ char *basilisk_respond_instantdex(struct supernet_info *myinfo,char *CMD,void *a char *basilisk_respond_dispatch(struct supernet_info *myinfo,char *CMD,void *addr,char *remoteaddr,uint32_t basilisktag,cJSON *valsobj,uint8_t *data,int32_t datalen,bits256 hash,int32_t from_basilisk) { - char *retstr=0; + char *ipaddr,*btcdaddr,*sigstr,*retstr=0; + printf("from.(%s) ADD.(%s) datalen.%d\n",remoteaddr,jprint(valsobj,0),datalen); + if ( (ipaddr= jstr(valsobj,"ipaddr")) != 0 && (btcdaddr= jstr(valsobj,"btcdaddr")) != 0 && (sigstr= jstr(valsobj,"sigstr")) != 0 ) + retstr = basilisk_addrelay_info(myinfo,btcdaddr,(uint32_t)calc_ipbits(ipaddr),hash,sigstr); + else retstr = clonestr("{\"error\":\"need rmd160, address and ipaddr\"}"); return(retstr); } diff --git a/basilisk/basilisk_bitcoin.c b/basilisk/basilisk_bitcoin.c index 2c059d2a1..566dc595b 100755 --- a/basilisk/basilisk_bitcoin.c +++ b/basilisk/basilisk_bitcoin.c @@ -334,7 +334,7 @@ double basilisk_bitcoin_valuemetric(struct supernet_info *myinfo,struct basilisk void *basilisk_bitcoinvalue(struct basilisk_item *Lptr,struct supernet_info *myinfo,struct iguana_info *coin,char *remoteaddr,uint32_t basilisktag,int32_t timeoutmillis,cJSON *valsobj) { - int32_t i,height,vout,numsent; char *coinaddr; struct basilisk_value *v; uint64_t value = 0; bits256 txid; + int32_t i,height,vout,numsent; struct basilisk_item *ptr; char *coinaddr; struct basilisk_value *v; uint64_t value = 0; bits256 txid; txid = jbits256(valsobj,"txid"); vout = jint(valsobj,"vout"); coinaddr = jstr(valsobj,"address"); @@ -342,7 +342,7 @@ void *basilisk_bitcoinvalue(struct basilisk_item *Lptr,struct supernet_info *myi { if ( (coin->VALIDATENODE != 0 || coin->RELAYNODE != 0) && coinaddr != 0 && coinaddr[0] != 0 ) { - if ( iguana_unspentindfind(coin,coinaddr,0,0,&value,&height,txid,vout,coin->bundlescount) > 0 ) + if ( iguana_unspentindfind(coin,coinaddr,0,0,&value,&height,txid,vout,coin->bundlescount,0) > 0 ) { printf("bitcoinvalue found iguana\n"); Lptr->retstr = basilisk_valuestr(coin,coinaddr,value,height,txid,vout); @@ -360,12 +360,16 @@ void *basilisk_bitcoinvalue(struct basilisk_item *Lptr,struct supernet_info *myi if ( v->vout == vout && bits256_cmp(txid,v->txid) == 0 && strcmp(v->coinaddr,coinaddr) == 0 ) { printf("bitcoinvalue local ht.%d %s %.8f\n",v->height,v->coinaddr,dstr(v->value)); - return(basilisk_issueremote(myinfo,&numsent,"VAL",coin->symbol,valsobj,juint(valsobj,"fanout"),juint(valsobj,"minresults"),basilisktag,timeoutmillis,coin->basilisk_valuemetric,basilisk_valuestr(coin,v->coinaddr,v->value,v->height,txid,vout),0,0,BASILISK_DEFAULTDIFF)); + ptr = basilisk_issueremote(myinfo,&numsent,"VAL",coin->symbol,valsobj,juint(valsobj,"fanout"),juint(valsobj,"minresults"),basilisktag,timeoutmillis,coin->basilisk_valuemetric,basilisk_valuestr(coin,v->coinaddr,v->value,v->height,txid,vout),0,0,BASILISK_DEFAULTDIFF); + queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); + return(ptr); } } } printf("bitcoinvalue issue remote tag.%u\n",basilisktag); - return(basilisk_issueremote(myinfo,&numsent,"VAL",coin->symbol,valsobj,juint(valsobj,"fanout"),juint(valsobj,"minresults"),basilisktag,timeoutmillis,coin->basilisk_valuemetric,0,0,0,BASILISK_DEFAULTDIFF)); + ptr = basilisk_issueremote(myinfo,&numsent,"VAL",coin->symbol,valsobj,juint(valsobj,"fanout"),juint(valsobj,"minresults"),basilisktag,timeoutmillis,coin->basilisk_valuemetric,0,0,0,BASILISK_DEFAULTDIFF); + queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); + return(ptr); } double basilisk_bitcoin_rawtxmetric_dependents(struct supernet_info *myinfo,struct iguana_info *coin,struct basilisk_item *ptr,struct bitcoin_rawtxdependents *dependents) @@ -421,7 +425,7 @@ double basilisk_bitcoin_rawtxmetric_dependents(struct supernet_info *myinfo,stru printf("spend of invalid input address.(%s)\n",coinaddr); metric = -(3. + i); } - printf("Valid spend %.8f to %s\n",dstr(value),coinaddr); + printf("Valid spend %.8f sum.(%.8f) to %s\n",dstr(value),dstr(inputsum),coinaddr); } free_json(childjson); } diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index 422a8314a..dac36c990 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -373,6 +373,11 @@ int32_t btc_priv2pub(uint8_t pubkey[33],uint8_t privkey[32]); void calc_shares(unsigned char *shares,unsigned char *secret,int32_t size,int32_t width,int32_t M,int32_t N,unsigned char *sharenrs); int32_t OS_portable_rmdir(char *dirname,int32_t diralso); void calc_hmac_sha256(uint8_t *mac,int32_t maclen,uint8_t *key,int32_t key_size,uint8_t *message,int32_t len); +int32_t revsort32(uint32_t *buf,uint32_t num,int32_t size); + +bits256 bits256_sha256(bits256 data); +void bits256_rmd160(uint8_t rmd160[20],bits256 data); +void bits256_rmd160_sha256(uint8_t rmd160[20],bits256 data); extern char *Iguana_validcommands[]; extern bits256 GENESIS_PUBKEY,GENESIS_PRIVKEY; diff --git a/crypto777/curve25519.c b/crypto777/curve25519.c index 62ac83bd0..ec23175f8 100755 --- a/crypto777/curve25519.c +++ b/crypto777/curve25519.c @@ -1540,6 +1540,25 @@ void calc_rmd160(char hexstr[41],uint8_t buf[20],uint8_t *msg,int32_t len) init_hexbytes_noT(hexstr,buf,20); } +bits256 bits256_sha256(bits256 data) +{ + bits256 hash; + vcalc_sha256(0,hash.bytes,data.bytes,sizeof(data)); + return(hash); +} + +void bits256_rmd160(uint8_t rmd160[20],bits256 data) +{ + calc_rmd160(0,rmd160,data.bytes,sizeof(data)); +} + +void bits256_rmd160_sha256(uint8_t rmd160[20],bits256 data) +{ + bits256 hash; + hash = bits256_sha256(data); + bits256_rmd160(rmd160,hash); +} + #ifdef ENABLE_RMDTEST int rmd160_test(void) { diff --git a/crypto777/iguana_utils.c b/crypto777/iguana_utils.c index b449fd66d..a253f722a 100755 --- a/crypto777/iguana_utils.c +++ b/crypto777/iguana_utils.c @@ -538,6 +538,19 @@ static int _decreasing_uint64(const void *a,const void *b) #undef uint64_b } +static int _decreasing_uint32(const void *a,const void *b) +{ +#define uint32_a (*(uint32_t *)a) +#define uint32_b (*(uint32_t *)b) + if ( uint32_b > uint32_a ) + return(1); + else if ( uint32_b < uint32_a ) + return(-1); + return(0); +#undef uint32_a +#undef uint32_b +} + int32_t sortds(double *buf,uint32_t num,int32_t size) { qsort(buf,num,size,_increasing_double); @@ -556,6 +569,12 @@ int32_t revsort64s(uint64_t *buf,uint32_t num,int32_t size) return(0); } +int32_t revsort32(uint32_t *buf,uint32_t num,int32_t size) +{ + qsort(buf,num,size,_decreasing_uint32); + return(0); +} + /*int32_t iguana_sortbignum(void *buf,int32_t size,uint32_t num,int32_t structsize,int32_t dir) { int32_t retval = 0; diff --git a/gecko/gecko.c b/gecko/gecko.c index 8ab5ae8a2..f089996d1 100755 --- a/gecko/gecko.c +++ b/gecko/gecko.c @@ -34,6 +34,7 @@ #include "../iguana/iguana777.h" #include "gecko_delayedPoW.c" +#include "gecko_mempool.c" #include "gecko_miner.c" #include "gecko_blocks.c" @@ -483,6 +484,14 @@ char *basilisk_respond_geckoget(struct supernet_info *myinfo,char *CMD,void *add } else return(clonestr("{\"error\":\"invalid geckoget type, mustbe (HDR or BLK or GTX)\"}")); } +char *basilisk_respond_mempool(struct supernet_info *myinfo,char *CMD,void *_addr,char *remoteaddr,uint32_t basilisktag,cJSON *valsobj,uint8_t *data,int32_t datalen,bits256 hash,int32_t from_basilisk) +{ + char *symbol; struct iguana_info *virt; + if ( (symbol= jstr(valsobj,"symbol")) != 0 && (virt= iguana_coinfind(symbol)) != 0 ) + return(gecko_mempoolarrived(myinfo,virt,_addr,data,datalen,hash)); + else return(clonestr("{\"error\":\"couldt find gecko chain\"}")); +} + char *basilisk_respond_geckoheaders(struct supernet_info *myinfo,char *CMD,void *addr,char *remoteaddr,uint32_t basilisktag,cJSON *valsobj,uint8_t *data,int32_t datalen,bits256 hash2,int32_t from_basilisk) { char *symbol; struct iguana_info *virt; @@ -568,7 +577,6 @@ HASH_ARRAY_STRING(basilisk,newgeckochain,hash,vals,hexstr) { if ( basilisk_geckochain(myinfo,symbol,chainname,argvals) != 0 ) jaddstr(argvals,"status","active"); - //free_json(argvals); } else jaddstr(argvals,"error","couldnt initialize geckochain"); free(retstr); return(jprint(argvals,1)); diff --git a/gecko/gecko.h b/gecko/gecko.h index 26067bef4..22cc02f49 100755 --- a/gecko/gecko.h +++ b/gecko/gecko.h @@ -36,12 +36,20 @@ struct hashstamp { bits256 hash2; uint32_t timestamp; int32_t height; }; struct gecko_sequence { struct hashstamp *stamps; int32_t lastupdate,maxstamps,numstamps,lasti,longestchain; }; struct gecko_sequences { struct gecko_sequence BTC,BTCD; }; -struct gecko_mempooltx { bits256 txid; char *rawtx; int64_t txfee; int32_t pending; uint32_t ipbits; }; +struct gecko_memtx +{ + double feeperkb; + bits256 txid; + uint32_t ipbits; + int64_t txfee,inputsum,outputsum; int32_t pending,numinputs,numoutputs,datalen; + uint8_t data[]; +}; struct gecko_mempool { - int32_t numtx; - struct gecko_mempooltx txs[100]; + int32_t numtx; uint32_t ipbits; + bits256 txids[0xffff]; + struct gecko_memtx **txs; }; struct gecko_chain @@ -66,7 +74,10 @@ void gecko_seqresult(struct supernet_info *myinfo,char *retstr); int32_t gecko_sequpdate(char *symbol,uint32_t reftimestamp); char *gecko_blockarrived(struct supernet_info *myinfo,struct iguana_info *virt,char *remoteaddr,uint8_t *data,int32_t datalen,bits256 hash2); char *gecko_txarrived(struct supernet_info *myinfo,struct iguana_info *virt,char *remoteaddr,uint8_t *data,int32_t datalen,bits256 hash2); +char *gecko_mempoolarrived(struct supernet_info *myinfo,struct iguana_info *virt,char *remoteaddr,uint8_t *data,int32_t datalen,bits256 hash2); char *gecko_headersarrived(struct supernet_info *myinfo,struct iguana_info *virt,char *remoteaddr,uint8_t *data,int32_t datalen,bits256 hash2); char *gecko_sendrawtransaction(struct supernet_info *myinfo,struct iguana_info *virt,uint8_t *data,int32_t datalen,bits256 txid,cJSON *vals,char *signedtx); +struct gecko_mempool *gecko_mempoolfind(struct supernet_info *myinfo,struct iguana_info *virt,int32_t *numotherp,uint32_t ipbits); + #endif diff --git a/gecko/gecko_blocks.c b/gecko/gecko_blocks.c index 8e8eddb6d..77a513b47 100755 --- a/gecko/gecko_blocks.c +++ b/gecko/gecko_blocks.c @@ -20,49 +20,61 @@ char *gecko_headersarrived(struct supernet_info *myinfo,struct iguana_info *virt return(clonestr("{\"result\":\"gecko headers queued\"}")); } -char *gecko_txarrived(struct supernet_info *myinfo,struct iguana_info *virt,char *remoteaddr,uint8_t *serialized,int32_t datalen,bits256 txid) +char *gecko_mempoolarrived(struct supernet_info *myinfo,struct iguana_info *virt,char *remoteaddr,uint8_t *data,int32_t datalen,bits256 hash2) { - struct gecko_mempool *pool; int64_t txfee,vinstotal,voutstotal; uint64_t hdrsi_unspentind,value; int32_t i,numvins,numvouts,txlen,spentheight,minconf,maxconf,unspentind,hdrsi; struct gecko_mempooltx *mtx; struct iguana_msgtx msg; - memset(&msg,0,sizeof(msg)); - iguana_memreset(&virt->TXMEM); - txlen = iguana_rwtx(virt->chain->zcash,0,&virt->TXMEM,serialized,&msg,datalen,&txid,virt->chain->isPoS,strcmp("VPN",virt->symbol) == 0); - vinstotal = voutstotal = 0; - maxconf = virt->longestchain; - minconf = virt->chain->minconfirms; - if ( (numvins= msg.tx_in) > 0 ) + int32_t i,j,numother,len = 0; struct gecko_mempool *otherpool; bits256 txid; + if ( (otherpool= gecko_mempoolfind(myinfo,virt,&numother,(uint32_t)calc_ipbits(remoteaddr))) != 0 ) + { + if ( numother > 0 ) + { + for (i=0; inumtx; j++) + if ( bits256_cmp(txid,otherpool->txids[j]) == 0 ) + break; + if ( j == otherpool->numtx ) + { + otherpool->txids[otherpool->numtx++] = txid; + printf("if first time, submit request for txid\n"); + } + } + } + } + return(clonestr("{\"result\":\"gecko mempool queued\"}")); +} + +void gecko_txidpurge(struct iguana_info *virt,bits256 txid) +{ + struct gecko_mempool *pool; int32_t i,n; struct gecko_memtx *memtx; + if ( (pool= virt->mempool) != 0 && pool->txs != 0 && (n= pool->numtx) ) + { + for (i=0; itxs[i]) != 0 && bits256_cmp(txid,memtx->txid) == 0 ) + { + free(pool->txs[i]); + pool->txs[i] = pool->txs[--pool->numtx]; + } + } + } + if ( virt->RELAYNODE != 0 ) { - for (i=0; ibundlescount-1)) != 0 ) + if ( (pool= virt->mempools[i]) != 0 && (n= pool->numtx) != 0 ) { - hdrsi = spentheight / virt->chain->bundlesize; - hdrsi_unspentind = ((uint64_t)hdrsi << 32) | unspentind; - if ( iguana_unspentavail(virt,hdrsi_unspentind,minconf,maxconf) != value ) + for (i=0; itxids[i]) == 0 ) + { + pool->txids[i] = pool->txids[--pool->numtx]; + memset(pool->txids[pool->numtx].bytes,0,sizeof(pool->txids[pool->numtx])); + } } - vinstotal += value; } } } - if ( (numvouts= msg.tx_out) > 0 ) - for (i=0; imempool) == 0 ) - pool = virt->mempool = calloc(1,sizeof(*pool)); - mtx = &pool->txs[pool->numtx]; - memset(mtx,0,sizeof(*mtx)); - mtx->txid = txid; - mtx->txfee = txfee; - mtx->ipbits = (uint32_t)calc_ipbits(remoteaddr); - mtx->rawtx = calloc(1,datalen*2 + 1); - init_hexbytes_noT(mtx->rawtx,serialized,datalen); - return(clonestr("{\"result\":\"gecko tx queued\"}")); } struct iguana_bundle *gecko_ensurebundle(struct iguana_info *virt,struct iguana_block *block,int32_t origheight,int32_t depth) @@ -131,7 +143,7 @@ struct iguana_bundle *gecko_ensurebundle(struct iguana_info *virt,struct iguana_ int32_t gecko_hwmset(struct iguana_info *virt,struct iguana_txblock *txdata,struct iguana_msgtx *txarray,uint8_t *data,int32_t datalen,int32_t depth) { - struct iguana_peer *addr; int32_t hdrsi; struct iguana_bundle *bp,*prevbp; struct iguana_block *block; + struct iguana_peer *addr; int32_t i,hdrsi; struct iguana_bundle *bp,*prevbp; struct iguana_block *block; if ( (block= iguana_blockhashset("gecko_hwmset",virt,txdata->zblock.height,txdata->zblock.RO.hash2,1)) != 0 ) { iguana_blockcopy(virt->chain->zcash,virt->chain->auxpow,virt,block,(struct iguana_block *)&txdata->zblock); @@ -156,6 +168,8 @@ int32_t gecko_hwmset(struct iguana_info *virt,struct iguana_txblock *txdata,stru iguana_bundlepurgefiles(virt,prevbp); iguana_savehdrs(virt); iguana_bundlevalidate(virt,prevbp,1); + for (i=0; iRO.txn_count; i++) + gecko_txidpurge(virt,txarray[i].txid); } } //printf("created block.%d [%d:%d] %d\n",block->height,bp!=0?bp->hdrsi:-1,block->height%virt->chain->bundlesize,bp->numsaved); diff --git a/gecko/gecko_mempool.c b/gecko/gecko_mempool.c new file mode 100755 index 000000000..9b8db2a7f --- /dev/null +++ b/gecko/gecko_mempool.c @@ -0,0 +1,293 @@ +/****************************************************************************** + * 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 gecko.c +// struct gecko_memtx { bits256 txid; char *rawtx; int64_t txfee; int32_t pending; uint32_t ipbits; }; + +struct gecko_mempool *gecko_mempoolfind(struct supernet_info *myinfo,struct iguana_info *virt,int32_t *numotherp,uint32_t ipbits) +{ + int32_t j,firstz,numother; bits256 *othertxids; struct gecko_mempool *otherpool = 0; + othertxids = 0; + numother = firstz = 0; + for (j=0; jnumrelays; j++) + { + if ( (otherpool= virt->mempools[j]) != 0 ) + { + if ( otherpool->ipbits == ipbits ) + { + othertxids = otherpool->txids; + numother = otherpool->numtx; + break; + } + } else firstz = j; + } + if ( j == myinfo->numrelays ) + { + virt->mempools[firstz] = otherpool = calloc(1,sizeof(struct gecko_mempool)); + otherpool->ipbits = (uint32_t)ipbits; + } + return(otherpool); +} + +void gecko_mempool_sync(struct supernet_info *myinfo,struct iguana_info *virt,bits256 *reftxids,int32_t numtx) +{ + int32_t i,j,k,n,num,numother; struct iguana_peer *addr; bits256 txid,*txids; struct gecko_mempool *pool,*otherpool; + if ( (pool= virt->mempool) == 0 ) + return; + n = sqrt(myinfo->numrelays) + 2; + i = (myinfo->myaddr.myipbits % n); + txids = calloc(pool->numtx,sizeof(bits256)); + for (; inumrelays; i+=n) + { + if ( (addr= iguana_peerfindipbits(virt,myinfo->relaybits[i],1)) != 0 ) + { + if ( (otherpool= gecko_mempoolfind(myinfo,virt,&numother,myinfo->relaybits[i])) != 0 ) + { + for (j=num=0; jnumtx; j++) + { + txid = reftxids[j]; + if ( numother > 0 ) + { + for (k=0; ktxids[k]) == 0 ) + break; + if ( k != numother ) + continue; + } + txids[num++] = txid; + } + if ( num > 0 ) + basilisk_headers_send(myinfo,virt,addr,txids,num); + } + } + } + free(txids); +} + +uint8_t *gecko_txdata(struct gecko_memtx *memtx) +{ + return(&memtx->data[memtx->numoutputs * sizeof(int64_t) + memtx->numinputs * sizeof(bits256)]); +} + +int64_t *gecko_valueptr(struct gecko_memtx *memtx,int32_t vout) +{ + return((int64_t *)&memtx->data[memtx->numinputs * sizeof(bits256) + vout*sizeof(int64_t)]); +} + +int32_t gecko_memtxcmp(struct gecko_memtx *memtxA,struct gecko_memtx *memtxB) +{ + int32_t i,numdiff; int64_t valA,valB,diff; + if ( memtxA->numinputs == memtxB->numinputs && memtxA->numoutputs == memtxB->numoutputs ) + { + for (i=0; inuminputs; i++) + { + if ( bits256_cmp(*(bits256 *)&memtxA->data[i * sizeof(bits256)],*(bits256 *)&memtxB->data[i * sizeof(bits256)]) != 0 ) + return(-1 - 2*i); + } + for (i=numdiff=0; inumoutputs; i++) + { + valA = *gecko_valueptr(memtxA,i); + valB = *gecko_valueptr(memtxB,i); + if ( (diff= valA - valB) < 0 ) + diff = -diff; + if ( diff > 100000 ) + return(-1); + if ( valA != valB ) + numdiff++; + } + if ( numdiff > 1 ) + return(-memtxA->numinputs*2 - 2); + + return(0); + } + return(-1); +} + +struct gecko_memtx *gecko_unspentfind(struct gecko_memtx ***ptrpp,struct iguana_info *virt,bits256 txid) +{ + struct gecko_mempool *pool; int32_t i; struct gecko_memtx *memtx; + if ( (pool= virt->mempool) != 0 ) + { + for (i=0; inumtx; i++) + if ( (memtx= pool->txs[i]) != 0 && bits256_cmp(memtx->txid,txid) == 0 ) + { + if ( ptrpp != 0 ) + *ptrpp = &pool->txs[i]; + return(memtx); + } + } + return(0); +} + +struct gecko_memtx *gecko_mempool_txadd(struct supernet_info *myinfo,struct iguana_info *virt,char *rawtx,uint32_t senderbits) +{ + struct gecko_memtx *spentmemtx,**ptrp,*memtx = 0; uint8_t *extraspace; char *str; struct iguana_msgtx msgtx; int32_t i,len,extralen = 65536; cJSON *retjson; int64_t *amountptr; + extraspace = calloc(1,extralen); + if ( (str= iguana_validaterawtx(myinfo,virt,&msgtx,extraspace,extralen,rawtx,1)) != 0 ) + { + if ( (retjson= cJSON_Parse(str)) != 0 ) + { + if ( jobj(retjson,"error") == 0 ) + { + len = (int32_t)strlen(rawtx) >> 1; + memtx = calloc(1,sizeof(*memtx) + len + msgtx.numoutputs * sizeof(int64_t) + msgtx.numinputs * sizeof(bits256)); + memtx->numinputs = msgtx.numinputs; + memtx->numoutputs = msgtx.numoutputs; + memtx->inputsum = msgtx.inputsum; + memtx->outputsum = msgtx.outputsum; + memtx->txfee = msgtx.txfee; + memtx->txid = msgtx.txid; + memtx->ipbits = senderbits; + memtx->datalen = len; + memtx->feeperkb = dstr(memtx->txfee) / (memtx->datalen / 1024.); + for (i=0; idata[i * sizeof(bits256)],msgtx.vins[i].prev_hash.bytes,sizeof(bits256)); + for (i=0; imempool,msgtx.vins[i].prev_hash)) != 0 ) + { + amountptr = gecko_valueptr(spentmemtx,msgtx.vins[i].prev_vout); + if ( *amountptr < 0 ) + { + if ( gecko_memtxcmp(spentmemtx,memtx) != 0 || memtx->txfee <= spentmemtx->txfee ) + { + printf("already spent mempool error\n"); // check for replacment! + free(memtx); + } + else + { + printf("replace identical vins/vouts with higher txfee\n"); + free(spentmemtx); + *ptrp = memtx; + } + memtx = 0; + free_json(retjson); + free(extraspace); + free(str); + return(0); + } + } + } + for (i=0; imempool,msgtx.vins[i].prev_hash)) != 0 ) + { + amountptr = gecko_valueptr(spentmemtx,msgtx.vins[i].prev_vout); + *amountptr = -(*amountptr); + } + } + } else printf("gecko_mempool_txadd had error.(%s)\n",str); + free_json(retjson); + } else printf("gecko_mempool_txadd couldnt parse.(%s)\n",str); + free(str); + } + free(extraspace); + return(memtx); +} + +char *gecko_txarrived(struct supernet_info *myinfo,struct iguana_info *virt,char *remoteaddr,uint8_t *serialized,int32_t datalen,bits256 txid) +{ + struct gecko_mempool *pool; int64_t txfee,vinstotal,voutstotal; uint64_t hdrsi_unspentind,value; int32_t i,numvins,numvouts,txlen,spentheight,minconf,maxconf,unspentind,hdrsi; struct iguana_msgtx msg; char *rawtx; struct gecko_memtx *memtx; + memset(&msg,0,sizeof(msg)); + iguana_memreset(&virt->TXMEM); + txlen = iguana_rwtx(virt->chain->zcash,0,&virt->TXMEM,serialized,&msg,datalen,&txid,virt->chain->isPoS,strcmp("VPN",virt->symbol) == 0); + vinstotal = voutstotal = 0; + maxconf = virt->longestchain; + minconf = virt->chain->minconfirms; + if ( (numvins= msg.tx_in) > 0 ) + { + for (i=0; ibundlescount-1,1)) != 0 ) + { + hdrsi = spentheight / virt->chain->bundlesize; + hdrsi_unspentind = ((uint64_t)hdrsi << 32) | unspentind; + if ( iguana_unspentavail(virt,hdrsi_unspentind,minconf,maxconf) != value ) + { + printf("vin.%d already spent\n",i); + return(clonestr("{\"error\":\"gecko tx has double spend\"}")); + } + vinstotal += value; + } + } + } + if ( (numvouts= msg.tx_out) > 0 ) + for (i=0; imempool) == 0 ) + { + pool = virt->mempool = calloc(1,sizeof(*pool)); + pool->txs = calloc(0xffff,sizeof(*pool->txs)); + } + rawtx = calloc(1,datalen*2 + 1); + init_hexbytes_noT(rawtx,serialized,datalen); + if ( (memtx= gecko_mempool_txadd(myinfo,virt,rawtx,(uint32_t)calc_ipbits(remoteaddr))) != 0 ) + { + for (i=0; inumtx; i++) + { + if ( memtx->feeperkb >= pool->txs[i]->feeperkb ) + break; + } + pool->txs[pool->numtx++] = pool->txs[i]; + pool->txs[i] = memtx; + for (i=0; inumtx; i++) + pool->txids[i] = pool->txs[i]->txid; + if ( myinfo->IAMRELAY != 0 ) + gecko_mempool_sync(myinfo,virt,pool->txids,pool->numtx); + } + free(rawtx); + return(clonestr("{\"result\":\"gecko tx queued\"}")); +} + +struct gecko_memtx **gecko_mempool_txptrs(struct supernet_info *myinfo,struct iguana_info *virt,int64_t *rewardp,int32_t *txn_countp,void **ptrp,void *space,int32_t max,int32_t height) +{ + int32_t i,n; struct gecko_memtx **txptrs; struct gecko_mempool *pool; int64_t txfees = 0,reward = virt->chain->initialreward; + if ( virt->chain->halvingduration != 0 && (n= (height / virt->chain->halvingduration)) != 0 ) + { + for (i=0; i>= 1; + } + *ptrp = 0; + *txn_countp = 0; + if ( (pool= virt->mempool) == 0 ) + pool = virt->mempool = calloc(1,sizeof(*pool)); + if ( pool->numtx*sizeof(char *) <= max ) + txptrs = space; + else + { + txptrs = calloc(pool->numtx,sizeof(char *)); + *ptrp = (void *)txptrs; + } + for (i=n=0; inumtx; i++) + { + if ( pool->txs[i]->pending == 0 ) + { + txfees += pool->txs[i]->txfee; + txptrs[n++] = pool->txs[i]; + pool->txs[i]->pending = height; + } + } + *rewardp = (reward + txfees); + if ( (*txn_countp= n) != 0 ) + return(txptrs); + else return(0); +} diff --git a/gecko/gecko_miner.c b/gecko/gecko_miner.c index c1a7618e3..50826ef26 100755 --- a/gecko/gecko_miner.c +++ b/gecko/gecko_miner.c @@ -137,10 +137,9 @@ char *gecko_coinbasestr(struct supernet_info *myinfo,struct iguana_info *virt,bi return(rawtx); } -char *gecko_block(struct supernet_info *myinfo,struct iguana_info *virt,struct iguana_block *newblock,uint32_t *noncep,char **txptrs,int32_t txn_count,uint8_t *coinbase,int32_t coinbaselen,bits256 coinbasespend,double expiration,uint8_t *minerpubkey,int64_t blockreward) +char *gecko_blockconstruct(struct supernet_info *myinfo,struct iguana_info *virt,struct iguana_block *newblock,uint32_t *noncep,struct gecko_memtx **txptrs,int32_t txn_count,uint8_t *coinbase,int32_t coinbaselen,bits256 coinbasespend,double expiration,uint8_t *minerpubkey,int64_t blockreward) { - struct iguana_info *btcd; uint8_t serialized[sizeof(*newblock)],space[16384],*txdata,*allocptr = 0; int32_t i,n,totaltxlen=0,txlen; char *coinbasestr,*blockstr=0; bits256 *txids=0,txspace[256],threshold; - //char str[65]; printf("prevblock.%s\n",bits256_str(str,newblock->RO.prev_block)); + struct iguana_info *btcd; uint8_t serialized[sizeof(*newblock)],space[16384]; int32_t i,n,len,totaltxlen=0; char *coinbasestr,*blockstr=0; bits256 *txids=0,txspace[256],threshold; struct gecko_memtx *memtx; if ( (btcd= iguana_coinfind("BTCD")) == 0 ) { printf("basilisk needs BTCD\n"); @@ -155,17 +154,11 @@ char *gecko_block(struct supernet_info *myinfo,struct iguana_info *virt,struct i { for (i=0; idatalen; + txids[i + 1] = memtx->txid; } - totaltxlen += txlen; - txids[i+1] = bits256_doublesha256(0,txdata,txlen); - if ( allocptr != 0 ) - free(allocptr); } } if ( (coinbasestr= gecko_coinbasestr(myinfo,virt,&txids[0],newblock->RO.timestamp,minerpubkey,blockreward,coinbase,coinbaselen,coinbasespend)) != 0 ) @@ -194,8 +187,15 @@ char *gecko_block(struct supernet_info *myinfo,struct iguana_info *virt,struct i init_hexbytes_noT(blockstr,serialized,n); //printf("block.(%s) coinbase.(%s) lens.%ld\n",blockstr,coinbasestr,(strlen(blockstr)+strlen(coinbasestr))/2); strcat(blockstr,coinbasestr); + len = (int32_t)strlen(blockstr); for (i=0; idatalen); + len += memtx->datalen << 1; + } + } } free(coinbasestr); } @@ -204,7 +204,7 @@ char *gecko_block(struct supernet_info *myinfo,struct iguana_info *virt,struct i return(blockstr); } -char *gecko_createblock(struct supernet_info *myinfo,struct iguana_info *btcd,int32_t isPoS,struct iguana_block *newblock,char *symbol,char **txptrs,int32_t txn_count,int32_t maxmillis,uint8_t *minerpubkey,int64_t blockreward) +char *gecko_createblock(struct supernet_info *myinfo,struct iguana_info *btcd,int32_t isPoS,struct iguana_block *newblock,char *symbol,struct gecko_memtx **txptrs,int32_t txn_count,int32_t maxmillis,uint8_t *minerpubkey,int64_t blockreward) { bits256 btcdhash; uint8_t coinbase[512]; int32_t coinbaselen; uint32_t nonce; double expiration = OS_milliseconds() + maxmillis; //char str[65]; printf("create prev.(%s) %p\n",bits256_str(str,newblock->RO.prev_block),&newblock->RO.prev_block); @@ -217,7 +217,7 @@ char *gecko_createblock(struct supernet_info *myinfo,struct iguana_info *btcd,in return(0); } nonce = 0; - return(gecko_block(myinfo,btcd,newblock,&nonce,txptrs,txn_count,coinbase,coinbaselen,btcdhash,expiration,minerpubkey,blockreward)); + return(gecko_blockconstruct(myinfo,btcd,newblock,&nonce,txptrs,txn_count,coinbase,coinbaselen,btcdhash,expiration,minerpubkey,blockreward)); } else return(0); } @@ -275,40 +275,6 @@ cJSON *gecko_paymentsobj(struct supernet_info *myinfo,cJSON *txjson,cJSON *valso return(txjson); } -void **gecko_mempool(struct supernet_info *myinfo,struct iguana_info *virt,int64_t *rewardp,int32_t *txn_countp,void **ptrp,void *space,int32_t max,int32_t height) -{ - int32_t i,n; void **txptrs; struct gecko_mempool *pool; int64_t txfees = 0,reward = virt->chain->initialreward; - if ( virt->chain->halvingduration != 0 && (n= (height / virt->chain->halvingduration)) != 0 ) - { - for (i=0; i>= 1; - } - *ptrp = 0; - *txn_countp = 0; - if ( (pool= virt->mempool) == 0 ) - pool = virt->mempool = calloc(1,sizeof(*pool)); - if ( pool->numtx*sizeof(char *) <= max ) - txptrs = space; - else - { - txptrs = calloc(pool->numtx,sizeof(char *)); - *ptrp = (void *)txptrs; - } - for (i=n=0; inumtx; i++) - { - if ( pool->txs[i].pending == 0 ) - { - txfees += pool->txs[i].txfee; - txptrs[n++] = pool->txs[i].rawtx; - pool->txs[i].pending = height; - } - } - *rewardp = (reward + txfees); - if ( (*txn_countp= n) != 0 ) - return(txptrs); - else return(0); -} - void gecko_blocksubmit(struct supernet_info *myinfo,struct iguana_info *virt,char *blockstr,bits256 hash2) { uint8_t *data,space[16384],*allocptr=0; int32_t i,len,numranked=0; struct iguana_peers *peers; struct iguana_peer *addr; @@ -331,7 +297,7 @@ void gecko_blocksubmit(struct supernet_info *myinfo,struct iguana_info *virt,cha void gecko_miner(struct supernet_info *myinfo,struct iguana_info *btcd,struct iguana_info *virt,int32_t maxmillis,uint8_t *minerpubkey33) { - struct iguana_zblock newblock; uint32_t nBits; int64_t reward = 0; int32_t txn_count; char *blockstr,*space[256]; void **txptrs,*ptr; //struct iguana_bundle *bp; + struct iguana_zblock newblock; uint32_t nBits; int64_t reward = 0; int32_t txn_count; char *blockstr,*space[256]; struct gecko_memtx **txptrs; void *ptr; //struct iguana_bundle *bp; if ( virt->virtualchain == 0 ) return; memset(&newblock,0,sizeof(newblock)); @@ -343,9 +309,9 @@ void gecko_miner(struct supernet_info *myinfo,struct iguana_info *btcd,struct ig { newblock.RO.bits = nBits; //printf("mine.%s nBits.%x ht.%d\n",virt->symbol,nBits,newblock.height); - txptrs = gecko_mempool(myinfo,virt,&reward,&txn_count,&ptr,space,(int32_t)(sizeof(space)/sizeof(*space)),newblock.height); + txptrs = gecko_mempool_txptrs(myinfo,virt,&reward,&txn_count,&ptr,space,(int32_t)(sizeof(space)/sizeof(*space)),newblock.height); //char str[65]; printf("HWM.%s %p\n",bits256_str(str,newblock.RO.prev_block),&newblock.RO.prev_block); - if ( (blockstr= gecko_createblock(myinfo,btcd,virt->chain->isPoS,(void *)&newblock,virt->symbol,(char **)txptrs,txn_count,maxmillis,minerpubkey33,reward)) != 0 ) + if ( (blockstr= gecko_createblock(myinfo,btcd,virt->chain->isPoS,(void *)&newblock,virt->symbol,txptrs,txn_count,maxmillis,minerpubkey33,reward)) != 0 ) { char str[65]; printf("%s.%x %s %u %d %.8f\n",virt->symbol,newblock.RO.bits,bits256_str(str,newblock.RO.hash2),newblock.RO.timestamp,newblock.height,dstr(reward)); gecko_blocksubmit(myinfo,virt,blockstr,newblock.RO.hash2); diff --git a/iguana/coins/btcd b/iguana/coins/btcd index ed7bbb59b..c43c6da79 100755 --- a/iguana/coins/btcd +++ b/iguana/coins/btcd @@ -1 +1 @@ -curl --url "http://127.0.0.1:7778" --data "{\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"newcoin\":\"BTCD\",\"startpend\":18,\"endpend\":4,\"services\":129,\"maxpeers\":256,\"RELAY\":1,\"VALIDATE\":1,\"portp2p\":14631}" +curl --url "http://127.0.0.1:7778" --data "{\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"newcoin\":\"BTCD\",\"startpend\":18,\"endpend\":4,\"services\":129,\"maxpeers\":256,\"RELAY\":1,\"VALIDATE\":1,\"portp2p\":14631,"rpc":14632}" diff --git a/iguana/coins/genltc b/iguana/coins/genltc index 9d56d05c5..457e57e10 100755 --- a/iguana/coins/genltc +++ b/iguana/coins/genltc @@ -1,2 +1,2 @@ -curl --url "http://127.0.0.1:7778" --data "{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":8,\"endpend\":8,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9334,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7778" --data "{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"poll\":10,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":8,\"endpend\":8,\"services\":129,\"maxpeers\":256,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" diff --git a/iguana/coins/ltc b/iguana/coins/ltc index ae7dc09ba..5d9f79d14 100755 --- a/iguana/coins/ltc +++ b/iguana/coins/ltc @@ -1,2 +1,2 @@ -curl --url "http://127.0.0.1:7778" --data "{\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":11,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":1,\"endpend\":1,\"services\":128,\"maxpeers\":16,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9334,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" +curl --url "http://127.0.0.1:7778" --data "{\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":11,\"poll\":100,\"active\":1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":1,\"endpend\":1,\"services\":128,\"maxpeers\":16,\"newcoin\":\"LTC\",\"name\":\"Litecoin\",\"hasheaders\":1,\"useaddmultisig\":0,\"netmagic\":\"fbc0b6db\",\"p2p\":9333,\"rpc\":9332,\"pubval\":48,\"p2shval\":5,\"wifval\":176,\"txfee_satoshis\":\"100000\",\"isPoS\":0,\"minoutput\":10000,\"minconfirms\":2,\"genesishash\":\"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2\",\"genesis\":{\"version\":1,\"timestamp\":1317972665,\"nBits\":\"1e0ffff0\",\"nonce\":2084524493,\"merkle_root\":\"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9\"},\"alertpubkey\":\"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9\",\"protover\":70002}" diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index 1dda1a288..3be259271 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -22,15 +22,6 @@ char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *meth return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params)); } -int32_t bitcoin_pubkeylen(const uint8_t *pubkey) -{ - if ( pubkey[0] == 2 || pubkey[0] == 3 ) - return(33); - else if ( pubkey[0] == 4 ) - return(65); - else return(-1); -} - int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr) { bits256 hash; uint8_t *buf,_buf[25]; int32_t len; diff --git a/iguana/iguana777.c b/iguana/iguana777.c index c68759a0a..200855044 100755 --- a/iguana/iguana777.c +++ b/iguana/iguana777.c @@ -750,7 +750,7 @@ void iguana_coinloop(void *arg) { //fprintf(stderr,"check possible\n"); if ( coin->peers->numranked > 0 && (now % 60) == 0 ) - iguana_send_ping(coin,coin->peers->ranked[rand() % coin->peers->numranked]); + iguana_send_ping(myinfo,coin,coin->peers->ranked[rand() % coin->peers->numranked]); coin->lastpossible = iguana_possible_peer(coin,0); // tries to connect to new peers } } @@ -759,7 +759,7 @@ void iguana_coinloop(void *arg) if ( coin->MAXPEERS > 1 && coin->peers->numranked < ((7*coin->MAXPEERS)>>3) && now > coin->lastpossible ) { if ( coin->peers->numranked > 0 && (now % 60) == 0 ) - iguana_send_ping(coin,coin->peers->ranked[rand() % coin->peers->numranked]); + iguana_send_ping(myinfo,coin,coin->peers->ranked[rand() % coin->peers->numranked]); coin->lastpossible = iguana_possible_peer(coin,0); // tries to connect to new peers } } diff --git a/iguana/iguana_accept.c b/iguana/iguana_accept.c index a518f797b..b7ee495fb 100755 --- a/iguana/iguana_accept.c +++ b/iguana/iguana_accept.c @@ -306,7 +306,7 @@ int32_t iguana_headerget(struct iguana_info *coin,uint8_t *serialized,int32_t ma int32_t iguana_peerhdrrequest(struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_peer *addr,bits256 hash2) { int32_t len=0,i,flag=0,height,n,hdrsi,bundlei,bundlesize,firstvout,retval=-1; struct iguana_block *block; struct iguana_bundle *bp; - if ( (firstvout= iguana_unspentindfind(coin,0,0,0,0,&height,hash2,0,coin->bundlescount-1)) != 0 ) + if ( (firstvout= iguana_unspentindfind(coin,0,0,0,0,&height,hash2,0,coin->bundlescount-1,0)) != 0 ) { bundlesize = coin->chain->bundlesize; hdrsi = (height / bundlesize); diff --git a/iguana/iguana_interpreter.c b/iguana/iguana_interpreter.c index a3d009e02..9a11f9a54 100755 --- a/iguana/iguana_interpreter.c +++ b/iguana/iguana_interpreter.c @@ -100,6 +100,14 @@ #define IGUANA_OP_CHECKSEQUENCEVERIFY 0xb2 #define IGUANA_OP_NOP10 0xb9 +#define IGUANA_OP_COMBINEPUBKEYS 0xc0 +#define IGUANA_OP_CHECKSCHNORR 0xc1 +#define IGUANA_OP_CHECKSCHNORRVERIFY 0xc2 + +// https://github.com/TierNolan/bips/blob/cpkv/bip-cprkv.mediawiki +#define IGUANA_OP_CHECKPRIVATEKEY 0xc3 +#define IGUANA_OP_CHECKPRIVATEKEYVERIFY 0xc4 + #define IGUANA_NOPFLAG 1 #define IGUANA_ALWAYSILLEGAL 2 #define IGUANA_EXECUTIONILLEGAL 4 @@ -243,6 +251,12 @@ enum opcodetype OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, + OP_COMBINEPUBKEYS = 0xc0, + OP_CHECKSCHNORR = 0xc1, + OP_CHECKSCHNORRVERIFY = 0xc2, + OP_CHECKPRIVATEKEY = 0xc3, + OP_CHECKPRIVATEKEYVERIFY = 0xc4, + // template matching params //OP_SMALLINTEGER = 0xfa, //OP_PUBKEYS = 0xfb, @@ -371,6 +385,11 @@ const char *get_opname(uint8_t *stackitemsp,uint8_t *flagsp,int32_t *extralenp,e case OP_CHECKSIGVERIFY: *stackitemsp = 2; *flagsp = IGUANA_CRYPTOFLAG | IGUANA_POSTVERIFY; return "OP_CHECKSIGVERIFY"; case OP_CHECKMULTISIG: *flagsp = IGUANA_CRYPTOFLAG; return "OP_CHECKMULTISIG"; case OP_CHECKMULTISIGVERIFY: *flagsp = IGUANA_CRYPTOFLAG | IGUANA_POSTVERIFY; return "OP_CHECKMULTISIGVERIFY"; + case OP_COMBINEPUBKEYS: *flagsp = IGUANA_CRYPTOFLAG; return "OP_COMBINEPUBKEYS"; + case OP_CHECKSCHNORR: *stackitemsp = 3; *flagsp = IGUANA_CRYPTOFLAG; return "OP_CHECKSCHNORR"; + case OP_CHECKSCHNORRVERIFY: *stackitemsp = 3; *flagsp = IGUANA_CRYPTOFLAG | IGUANA_POSTVERIFY; return "OP_CHECKSCHNORRVERIFY"; + case OP_CHECKPRIVATEKEY: *stackitemsp = 2; *flagsp = IGUANA_CRYPTOFLAG; return "OP_CHECKPRIVATEKEY"; + case OP_CHECKPRIVATEKEYVERIFY: *stackitemsp = 2; *flagsp = IGUANA_CRYPTOFLAG | IGUANA_POSTVERIFY; return "OP_CHECKPRIVATEKEYVERIFY"; // expanson case OP_NOP1 : *flagsp = IGUANA_NOPFLAG; return "OP_NOP1"; @@ -706,16 +725,39 @@ int32_t iguana_checksig(struct iguana_info *coin,struct iguana_stackdata pubkeya plen = iguana_databuf(pubkey,pubkeyarg); siglen = iguana_databuf(sig,sigarg); /*int32_t i; for (i=0; i 0 && siglen > 0 && siglen < 74 ) return(bitcoin_verify(coin->ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0); return(0); } +int32_t iguana_checkprivatekey(struct iguana_info *coin,struct iguana_stackdata pubkeyarg,struct iguana_stackdata privkeyarg) +{ + uint8_t pubkey[MAX_SCRIPT_ELEMENT_SIZE],privkey[MAX_SCRIPT_ELEMENT_SIZE],checkpub[33]; int32_t plen,privlen; + plen = iguana_databuf(pubkey,pubkeyarg); + privlen = iguana_databuf(privkey,privkeyarg); + if ( bitcoin_pubkeylen(pubkey) == plen && plen > 0 && privlen == 32 ) + { + bitcoin_pubkey33(coin->ctx,checkpub,*(bits256 *)privkey); + return(memcmp(checkpub,pubkey,33) == 0); + } + return(0); +} + +int32_t iguana_checkschnorrsig(struct iguana_info *coin,int32_t M,struct iguana_stackdata pubkeyarg,struct iguana_stackdata sigarg,bits256 sigtxid) +{ + uint8_t combined_pub[MAX_SCRIPT_ELEMENT_SIZE],sig[MAX_SCRIPT_ELEMENT_SIZE]; int32_t plen,siglen; + plen = iguana_databuf(combined_pub,pubkeyarg); + siglen = iguana_databuf(sig,sigarg); + if ( bitcoin_pubkeylen(combined_pub) == 33 && siglen == 64 ) + return(bitcoin_schnorr_verify(coin->ctx,sig,sigtxid,combined_pub,33) == 0); + return(0); +} + int32_t iguana_checkmultisig(struct iguana_info *coin,struct iguana_interpreter *stacks,int32_t M,int32_t N,bits256 txhash2) { int32_t i,j=0,len,valid=0,numsigners = 0,siglens[MAX_PUBKEYS_PER_MULTISIG]; uint8_t pubkeys[MAX_PUBKEYS_PER_MULTISIG][MAX_SCRIPT_ELEMENT_SIZE],sigs[MAX_PUBKEYS_PER_MULTISIG][MAX_SCRIPT_ELEMENT_SIZE]; @@ -1180,6 +1222,12 @@ int32_t bitcoin_assembler(struct iguana_info *coin,cJSON *logarray,uint8_t scrip case IGUANA_OP_CHECKMULTISIG: case IGUANA_OP_CHECKMULTISIGVERIFY: iguana_pushdata(stacks,iguana_checkmultisig(coin,stacks,V->M,V->N,V->sigtxid),0,0); break; + case IGUANA_OP_CHECKSCHNORR: case IGUANA_OP_CHECKSCHNORRVERIFY: + iguana_pushdata(stacks,iguana_checkschnorrsig(coin,iguana_num(args[2]),args[1],args[0],V->sigtxid),0,0); + break; + case IGUANA_OP_CHECKPRIVATEKEY: case IGUANA_OP_CHECKPRIVATEKEYVERIFY: + iguana_pushdata(stacks,iguana_checkprivatekey(coin,args[1],args[0]),0,0); + break; } } else if ( op->opcode == IGUANA_OP_CHECKLOCKTIMEVERIFY ) // former OP_NOP2 @@ -1388,1184 +1436,3 @@ int32_t bitcoin_assembler(struct iguana_info *coin,cJSON *logarray,uint8_t scrip else return(-errs); } - -#ifdef reference -/** - * Script is a stack machine (like Forth) that evaluates a predicate - * returning a bool indicating valid or not. There are no loops. - */ -#define stacktop(i) (stack.at(stack.size()+(i))) -#define altstacktop(i) (altstack.at(altstack.size()+(i))) -static inline void popstack(vector& stack) -{ - if (stack.empty()) - throw runtime_error("popstack(): stack empty"); - stack.pop_back(); -} - -bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { - if (vchPubKey.size() < 33) { - // Non-canonical public key: too short - return false; - } - if (vchPubKey[0] == 0x04) { - if (vchPubKey.size() != 65) { - // Non-canonical public key: invalid length for uncompressed key - return false; - } - } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) { - if (vchPubKey.size() != 33) { - // Non-canonical public key: invalid length for compressed key - return false; - } - } else { - // Non-canonical public key: neither compressed nor uncompressed - return false; - } - return true; -} - -/** - * A canonical signature exists of: <30> <02> <02> - * Where R and S are not negative (their first byte has its highest bit not set), and not - * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, - * in which case a single 0 byte is necessary and even required). - * - * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 - * - * This function is consensus-critical since BIP66. - */ -bool static IsValidSignatureEncoding(const std::vector &sig) { - // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash] - // * total-length: 1-byte length descriptor of everything that follows, - // excluding the sighash byte. - // * R-length: 1-byte length descriptor of the R value that follows. - // * R: arbitrary-length big-endian encoded R value. It must use the shortest - // possible encoding for a positive integers (which means no null bytes at - // the start, except a single one when the next byte has its highest bit set). - // * S-length: 1-byte length descriptor of the S value that follows. - // * S: arbitrary-length big-endian encoded S value. The same rules apply. - // * sighash: 1-byte value indicating what data is hashed (not part of the DER - // signature) - - // Minimum and maximum size constraints. - if (sig.size() < 9) return false; - if (sig.size() > 73) return false; - - // A signature is of type 0x30 (compound). - if (sig[0] != 0x30) return false; - - // Make sure the length covers the entire signature. - if (sig[1] != sig.size() - 3) return false; - - // Extract the length of the R element. - unsigned int lenR = sig[3]; - - // Make sure the length of the S element is still inside the signature. - if (5 + lenR >= sig.size()) return false; - - // Extract the length of the S element. - unsigned int lenS = sig[5 + lenR]; - - // Verify that the length of the signature matches the sum of the length - // of the elements. - if ((size_t)(lenR + lenS + 7) != sig.size()) return false; - - // Check whether the R element is an integer. - if (sig[2] != 0x02) return false; - - // Zero-length integers are not allowed for R. - if (lenR == 0) return false; - - // Negative numbers are not allowed for R. - if (sig[4] & 0x80) return false; - - // Null bytes at the start of R are not allowed, unless R would - // otherwise be interpreted as a negative number. - if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false; - - // Check whether the S element is an integer. - if (sig[lenR + 4] != 0x02) return false; - - // Zero-length integers are not allowed for S. - if (lenS == 0) return false; - - // Negative numbers are not allowed for S. - if (sig[lenR + 6] & 0x80) return false; - - // Null bytes at the start of S are not allowed, unless S would otherwise be - // interpreted as a negative number. - if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false; - - return true; -} - -bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { - if (!IsValidSignatureEncoding(vchSig)) { - return set_error(serror, SCRIPT_ERR_SIG_DER); - } - std::vector vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1); - if (!CPubKey::CheckLowS(vchSigCopy)) { - return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); - } - return true; -} - -bool static IsDefinedHashtypeSignature(const valtype &vchSig) { - if (vchSig.size() == 0) { - return false; - } - unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); - if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) - return false; - - return true; -} - -bool CheckSignatureEncoding(const vector &vchSig, unsigned int flags, ScriptError* serror) { - // Empty signature. Not strictly DER encoded, but allowed to provide a - // compact way to provide an invalid signature for use with CHECK(MULTI)SIG - if (vchSig.size() == 0) { - return true; - } - if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsValidSignatureEncoding(vchSig)) { - return set_error(serror, SCRIPT_ERR_SIG_DER); - } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) { - // serror is set - return false; - } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) { - return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); - } - return true; -} - -bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) { - if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) { - return set_error(serror, SCRIPT_ERR_PUBKEYTYPE); - } - return true; -} - -bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { - if (data.size() == 0) { - // Could have used OP_0. - return opcode == OP_0; - } else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) { - // Could have used OP_1 .. OP_16. - return opcode == OP_1 + (data[0] - 1); - } else if (data.size() == 1 && data[0] == 0x81) { - // Could have used OP_1NEGATE. - return opcode == OP_1NEGATE; - } else if (data.size() <= 75) { - // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). - return opcode == data.size(); - } else if (data.size() <= 255) { - // Could have used OP_PUSHDATA. - return opcode == OP_PUSHDATA1; - } else if (data.size() <= 65535) { - // Could have used OP_PUSHDATA2. - return opcode == OP_PUSHDATA2; - } - return true; -} - -bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) -{ - static const CScriptNum bnZero(0); - static const CScriptNum bnOne(1); - static const CScriptNum bnFalse(0); - static const CScriptNum bnTrue(1); - static const valtype vchFalse(0); - static const valtype vchZero(0); - static const valtype vchTrue(1, 1); - - CScript::const_iterator pc = script.begin(); - CScript::const_iterator pend = script.end(); - CScript::const_iterator pbegincodehash = script.begin(); - opcodetype opcode; - valtype vchPushValue; - vector vfExec; - vector altstack; - set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); - if (script.size() > 10000) - return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); - int nOpCount = 0; - bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; - - try - { - while (pc < pend) - { - bool fExec = !count(vfExec.begin(), vfExec.end(), false); - - // - // Read instruction - // - if (!script.GetOp(pc, opcode, vchPushValue)) - return set_error(serror, SCRIPT_ERR_BAD_OPCODE); - if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) - return set_error(serror, SCRIPT_ERR_PUSH_SIZE); - - // Note how OP_RESERVED does not count towards the opcode limit. - if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) - return set_error(serror, SCRIPT_ERR_OP_COUNT); - - if (opcode == OP_CAT || - opcode == OP_SUBSTR || - opcode == OP_LEFT || - opcode == OP_RIGHT || - opcode == OP_INVERT || - opcode == OP_AND || - opcode == OP_OR || - opcode == OP_XOR || - opcode == OP_2MUL || - opcode == OP_2DIV || - opcode == OP_MUL || - opcode == OP_DIV || - opcode == OP_MOD || - opcode == OP_LSHIFT || - opcode == OP_RSHIFT) - return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes. - - if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { - if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { - return set_error(serror, SCRIPT_ERR_MINIMALDATA); - } - stack.push_back(vchPushValue); - } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) - switch (opcode) - { - // - // Push value - // - case OP_1NEGATE: - case OP_1: - case OP_2: - case OP_3: - case OP_4: - case OP_5: - case OP_6: - case OP_7: - case OP_8: - case OP_9: - case OP_10: - case OP_11: - case OP_12: - case OP_13: - case OP_14: - case OP_15: - case OP_16: - { - // ( -- value) - CScriptNum bn((int)opcode - (int)(OP_1 - 1)); - stack.push_back(bn.getvch()); - // The result of these opcodes should always be the minimal way to push the data - // they push, so no need for a CheckMinimalPush here. - } - break; - - - // - // Control - // - case OP_NOP: - break; - - case OP_CHECKLOCKTIMEVERIFY: - { - if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { - // not enabled; treat as a NOP2 - if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { - return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); - } - break; - } - - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - - // Note that elsewhere numeric opcodes are limited to - // operands in the range -2**31+1 to 2**31-1, however it is - // legal for opcodes to produce results exceeding that - // range. This limitation is implemented by CScriptNum's - // default 4-byte limit. - // - // If we kept to that limit we'd have a year 2038 problem, - // even though the nLockTime field in transactions - // themselves is uint32 which only becomes meaningless - // after the year 2106. - // - // Thus as a special case we tell CScriptNum to accept up - // to 5-byte bignums, which are good until 2**39-1, well - // beyond the 2**32-1 limit of the nLockTime field itself. - const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5); - - // In the rare event that the argument may be < 0 due to - // some arithmetic being done first, you can always use - // 0 MAX CHECKLOCKTIMEVERIFY. - if (nLockTime < 0) - return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); - - // Actually compare the specified lock time with the transaction. - if (!checker.CheckLockTime(nLockTime)) - return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME); - - break; - } - - case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5: - case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: - { - if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) - return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); - } - break; - - case OP_IF: - case OP_NOTIF: - { - // if [statements] [else [statements]] endif - bool fValue = false; - if (fExec) - { - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); - valtype& vch = stacktop(-1); - fValue = CastToBool(vch); - if (opcode == OP_NOTIF) - fValue = !fValue; - popstack(stack); - } - vfExec.push_back(fValue); - } - break; - - case OP_ELSE: - { - if (vfExec.empty()) - return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); - vfExec.back() = !vfExec.back(); - } - break; - - case OP_ENDIF: - { - if (vfExec.empty()) - return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); - vfExec.pop_back(); - } - break; - - case OP_VERIFY: - { - // (true -- ) or - // (false -- false) and return - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - bool fValue = CastToBool(stacktop(-1)); - if (fValue) - popstack(stack); - else - return set_error(serror, SCRIPT_ERR_VERIFY); - } - break; - - case OP_RETURN: - { - return set_error(serror, SCRIPT_ERR_OP_RETURN); - } - break; - - - // - // Stack ops - // - case OP_TOALTSTACK: - { - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - altstack.push_back(stacktop(-1)); - popstack(stack); - } - break; - - case OP_FROMALTSTACK: - { - if (altstack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION); - stack.push_back(altstacktop(-1)); - popstack(altstack); - } - break; - - case OP_2DROP: - { - // (x1 x2 -- ) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - popstack(stack); - popstack(stack); - } - break; - - case OP_2DUP: - { - // (x1 x2 -- x1 x2 x1 x2) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch1 = stacktop(-2); - valtype vch2 = stacktop(-1); - stack.push_back(vch1); - stack.push_back(vch2); - } - break; - - case OP_3DUP: - { - // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) - if (stack.size() < 3) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch1 = stacktop(-3); - valtype vch2 = stacktop(-2); - valtype vch3 = stacktop(-1); - stack.push_back(vch1); - stack.push_back(vch2); - stack.push_back(vch3); - } - break; - - case OP_2OVER: - { - // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) - if (stack.size() < 4) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch1 = stacktop(-4); - valtype vch2 = stacktop(-3); - stack.push_back(vch1); - stack.push_back(vch2); - } - break; - - case OP_2ROT: - { - // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) - if (stack.size() < 6) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch1 = stacktop(-6); - valtype vch2 = stacktop(-5); - stack.erase(stack.end()-6, stack.end()-4); - stack.push_back(vch1); - stack.push_back(vch2); - } - break; - - case OP_2SWAP: - { - // (x1 x2 x3 x4 -- x3 x4 x1 x2) - if (stack.size() < 4) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - swap(stacktop(-4), stacktop(-2)); - swap(stacktop(-3), stacktop(-1)); - } - break; - - case OP_IFDUP: - { - // (x - 0 | x x) - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch = stacktop(-1); - if (CastToBool(vch)) - stack.push_back(vch); - } - break; - - case OP_DEPTH: - { - // -- stacksize - CScriptNum bn(stack.size()); - stack.push_back(bn.getvch()); - } - break; - - case OP_DROP: - { - // (x -- ) - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - popstack(stack); - } - break; - - case OP_DUP: - { - // (x -- x x) - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch = stacktop(-1); - stack.push_back(vch); - } - break; - - case OP_NIP: - { - // (x1 x2 -- x2) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - stack.erase(stack.end() - 2); - } - break; - - case OP_OVER: - { - // (x1 x2 -- x1 x2 x1) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch = stacktop(-2); - stack.push_back(vch); - } - break; - - case OP_PICK: - case OP_ROLL: - { - // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) - // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - int n = CScriptNum(stacktop(-1), fRequireMinimal).getint(); - popstack(stack); - if (n < 0 || n >= (int)stack.size()) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch = stacktop(-n-1); - if (opcode == OP_ROLL) - stack.erase(stack.end()-n-1); - stack.push_back(vch); - } - break; - - case OP_ROT: - { - // (x1 x2 x3 -- x2 x3 x1) - // x2 x1 x3 after first swap - // x2 x3 x1 after second swap - if (stack.size() < 3) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - swap(stacktop(-3), stacktop(-2)); - swap(stacktop(-2), stacktop(-1)); - } - break; - - case OP_SWAP: - { - // (x1 x2 -- x2 x1) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - swap(stacktop(-2), stacktop(-1)); - } - break; - - case OP_TUCK: - { - // (x1 x2 -- x2 x1 x2) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype vch = stacktop(-1); - stack.insert(stack.end()-2, vch); - } - break; - - - case OP_SIZE: - { - // (in -- in size) - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - CScriptNum bn(stacktop(-1).size()); - stack.push_back(bn.getvch()); - } - break; - - - // - // Bitwise logic - // - case OP_EQUAL: - case OP_EQUALVERIFY: - //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL - { - // (x1 x2 - bool) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype& vch1 = stacktop(-2); - valtype& vch2 = stacktop(-1); - bool fEqual = (vch1 == vch2); - // OP_NOTEQUAL is disabled because it would be too easy to say - // something like n != 1 and have some wiseguy pass in 1 with extra - // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001) - //if (opcode == OP_NOTEQUAL) - // fEqual = !fEqual; - popstack(stack); - popstack(stack); - stack.push_back(fEqual ? vchTrue : vchFalse); - if (opcode == OP_EQUALVERIFY) - { - if (fEqual) - popstack(stack); - else - return set_error(serror, SCRIPT_ERR_EQUALVERIFY); - } - } - break; - - - // - // Numeric - // - case OP_1ADD: - case OP_1SUB: - case OP_NEGATE: - case OP_ABS: - case OP_NOT: - case OP_0NOTEQUAL: - { - // (in -- out) - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - CScriptNum bn(stacktop(-1), fRequireMinimal); - switch (opcode) - { - case OP_1ADD: bn += bnOne; break; - case OP_1SUB: bn -= bnOne; break; - case OP_NEGATE: bn = -bn; break; - case OP_ABS: if (bn < bnZero) bn = -bn; break; - case OP_NOT: bn = (bn == bnZero); break; - case OP_0NOTEQUAL: bn = (bn != bnZero); break; - default: assert(!"invalid opcode"); break; - } - popstack(stack); - stack.push_back(bn.getvch()); - } - break; - - case OP_ADD: - case OP_SUB: - case OP_BOOLAND: - case OP_BOOLOR: - case OP_NUMEQUAL: - case OP_NUMEQUALVERIFY: - case OP_NUMNOTEQUAL: - case OP_LESSTHAN: - case OP_GREATERTHAN: - case OP_LESSTHANOREQUAL: - case OP_GREATERTHANOREQUAL: - case OP_MIN: - case OP_MAX: - { - // (x1 x2 -- out) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - CScriptNum bn1(stacktop(-2), fRequireMinimal); - CScriptNum bn2(stacktop(-1), fRequireMinimal); - CScriptNum bn(0); - switch (opcode) - { - case OP_ADD: - bn = bn1 + bn2; - break; - - case OP_SUB: - bn = bn1 - bn2; - break; - - case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; - case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; - case OP_NUMEQUAL: bn = (bn1 == bn2); break; - case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; - case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; - case OP_LESSTHAN: bn = (bn1 < bn2); break; - case OP_GREATERTHAN: bn = (bn1 > bn2); break; - case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; - case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; - case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; - case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; - default: assert(!"invalid opcode"); break; - } - popstack(stack); - popstack(stack); - stack.push_back(bn.getvch()); - - if (opcode == OP_NUMEQUALVERIFY) - { - if (CastToBool(stacktop(-1))) - popstack(stack); - else - return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY); - } - } - break; - - case OP_WITHIN: - { - // (x min max -- out) - if (stack.size() < 3) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - CScriptNum bn1(stacktop(-3), fRequireMinimal); - CScriptNum bn2(stacktop(-2), fRequireMinimal); - CScriptNum bn3(stacktop(-1), fRequireMinimal); - bool fValue = (bn2 <= bn1 && bn1 < bn3); - popstack(stack); - popstack(stack); - popstack(stack); - stack.push_back(fValue ? vchTrue : vchFalse); - } - break; - - - // - // Crypto - // - case OP_RIPEMD160: - case OP_SHA1: - case OP_SHA256: - case OP_HASH160: - case OP_HASH256: - { - // (in -- hash) - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype& vch = stacktop(-1); - valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); - if (opcode == OP_RIPEMD160) - CRIPEMD160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); - else if (opcode == OP_SHA1) - CSHA1().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); - else if (opcode == OP_SHA256) - CSHA256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); - else if (opcode == OP_HASH160) - CHash160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); - else if (opcode == OP_HASH256) - CHash256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); - popstack(stack); - stack.push_back(vchHash); - } - break; - - case OP_CODESEPARATOR: - { - // Hash starts after the code separator - pbegincodehash = pc; - } - break; - - case OP_CHECKSIG: - case OP_CHECKSIGVERIFY: - { - // (sig pubkey -- bool) - if (stack.size() < 2) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - - valtype& vchSig = stacktop(-2); - valtype& vchPubKey = stacktop(-1); - - // Subset of script starting at the most recent codeseparator - CScript scriptCode(pbegincodehash, pend); - - // Drop the signature, since there's no way for a signature to sign itself - scriptCode.FindAndDelete(CScript(vchSig)); - - if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { - //serror is set - return false; - } - bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode); - - popstack(stack); - popstack(stack); - stack.push_back(fSuccess ? vchTrue : vchFalse); - if (opcode == OP_CHECKSIGVERIFY) - { - if (fSuccess) - popstack(stack); - else - return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY); - } - } - break; - - case OP_CHECKMULTISIG: - case OP_CHECKMULTISIGVERIFY: - { - // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) - - int i = 1; - if ((int)stack.size() < i) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - - int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); - if (nKeysCount < 0 || nKeysCount > MAX_PUBKEYS_PER_MULTISIG) - return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT); - nOpCount += nKeysCount; - if (nOpCount > MAX_OPS_PER_SCRIPT) - return set_error(serror, SCRIPT_ERR_OP_COUNT); - int ikey = ++i; - i += nKeysCount; - if ((int)stack.size() < i) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - - int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); - if (nSigsCount < 0 || nSigsCount > nKeysCount) - return set_error(serror, SCRIPT_ERR_SIG_COUNT); - int isig = ++i; - i += nSigsCount; - if ((int)stack.size() < i) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - - // Subset of script starting at the most recent codeseparator - CScript scriptCode(pbegincodehash, pend); - - // Drop the signatures, since there's no way for a signature to sign itself - for (int k = 0; k < nSigsCount; k++) - { - valtype& vchSig = stacktop(-isig-k); - scriptCode.FindAndDelete(CScript(vchSig)); - } - - bool fSuccess = true; - while (fSuccess && nSigsCount > 0) - { - valtype& vchSig = stacktop(-isig); - valtype& vchPubKey = stacktop(-ikey); - - // Note how this makes the exact order of pubkey/signature evaluation - // distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set. - // See the script_(in)valid tests for details. - if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { - // serror is set - return false; - } - - // Check signature - bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode); - - if (fOk) { - isig++; - nSigsCount--; - } - ikey++; - nKeysCount--; - - // If there are more signatures left than keys left, - // then too many signatures have failed. Exit early, - // without checking any further signatures. - if (nSigsCount > nKeysCount) - fSuccess = false; - } - - // Clean up stack of actual arguments - while (i-- > 1) - popstack(stack); - - // A bug causes CHECKMULTISIG to consume one extra argument - // whose contents were not checked in any way. - // - // Unfortunately this is a potential source of mutability, - // so optionally verify it is exactly equal to zero prior - // to removing it from the stack. - if (stack.size() < 1) - return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) - return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); - popstack(stack); - - stack.push_back(fSuccess ? vchTrue : vchFalse); - - if (opcode == OP_CHECKMULTISIGVERIFY) - { - if (fSuccess) - popstack(stack); - else - return set_error(serror, SCRIPT_ERR_CHECKMULTISIGVERIFY); - } - } - break; - - default: - return set_error(serror, SCRIPT_ERR_BAD_OPCODE); - } - - // Size limits - if (stack.size() + altstack.size() > 1000) - return set_error(serror, SCRIPT_ERR_STACK_SIZE); - } - } - catch (...) - { - return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); - } - - if (!vfExec.empty()) - return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); - - return set_success(serror); -} - -namespace { - - /** - * Wrapper that serializes like CTransaction, but with the modifications - * required for the signature hash done in-place - */ - class CTransactionSignatureSerializer { - private: - const CTransaction &txTo; //! reference to the spending transaction (the one being serialized) - const CScript &scriptCode; //! output script being consumed - const unsigned int nIn; //! input index of txTo being signed - const bool fAnyoneCanPay; //! whether the hashtype has the SIGHASH_ANYONECANPAY flag set - const bool fHashSingle; //! whether the hashtype is SIGHASH_SINGLE - const bool fHashNone; //! whether the hashtype is SIGHASH_NONE - - public: - CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : - txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), - fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)), - fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE), - fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {} - - /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */ - template - void SerializeScriptCode(S &s, int nType, int nVersion) const { - CScript::const_iterator it = scriptCode.begin(); - CScript::const_iterator itBegin = it; - opcodetype opcode; - unsigned int nCodeSeparators = 0; - while (scriptCode.GetOp(it, opcode)) { - if (opcode == OP_CODESEPARATOR) - nCodeSeparators++; - } - ::WriteCompactSize(s, scriptCode.size() - nCodeSeparators); - it = itBegin; - while (scriptCode.GetOp(it, opcode)) { - if (opcode == OP_CODESEPARATOR) { - s.write((char*)&itBegin[0], it-itBegin-1); - itBegin = it; - } - } - if (itBegin != scriptCode.end()) - s.write((char*)&itBegin[0], it-itBegin); - } - - /** Serialize an input of txTo */ - template - void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const { - // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized - if (fAnyoneCanPay) - nInput = nIn; - // Serialize the prevout - ::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion); - // Serialize the script - if (nInput != nIn) - // Blank out other inputs' signatures - ::Serialize(s, CScriptBase(), nType, nVersion); - else - SerializeScriptCode(s, nType, nVersion); - // Serialize the nSequence - if (nInput != nIn && (fHashSingle || fHashNone)) - // let the others update at will - ::Serialize(s, (int)0, nType, nVersion); - else - ::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion); - } - - /** Serialize an output of txTo */ - template - void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const { - if (fHashSingle && nOutput != nIn) - // Do not lock-in the txout payee at other indices as txin - ::Serialize(s, CTxOut(), nType, nVersion); - else - ::Serialize(s, txTo.vout[nOutput], nType, nVersion); - } - - /** Serialize txTo */ - template - void Serialize(S &s, int nType, int nVersion) const { - // Serialize nVersion - ::Serialize(s, txTo.nVersion, nType, nVersion); - // Serialize vin - unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size(); - ::WriteCompactSize(s, nInputs); - for (unsigned int nInput = 0; nInput < nInputs; nInput++) - SerializeInput(s, nInput, nType, nVersion); - // Serialize vout - unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size()); - ::WriteCompactSize(s, nOutputs); - for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) - SerializeOutput(s, nOutput, nType, nVersion); - // Serialize nLockTime - ::Serialize(s, txTo.nLockTime, nType, nVersion); - } - }; - -} // anon namespace - -uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, size_t* nHashedOut) -{ - static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); - if (nIn >= txTo.vin.size()) { - // nIn out of range - return one; - } - - // Check for invalid use of SIGHASH_SINGLE - if ((nHashType & 0x1f) == SIGHASH_SINGLE) { - if (nIn >= txTo.vout.size()) { - // nOut out of range - return one; - } - } - - // Wrapper to serialize only the necessary parts of the transaction being signed - CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); - - // Serialize and hash - CHashWriter ss(SER_GETHASH, 0); - ss << txTmp << nHashType; - if (nHashedOut != NULL) - *nHashedOut = ss.GetNumBytesHashed(); - return ss.GetHash(); -} - -bool TransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const -{ - return pubkey.Verify(sighash, vchSig); -} - -bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn, const vector& vchPubKey, - const CScript& scriptCode) const -{ - CPubKey pubkey(vchPubKey); - if (!pubkey.IsValid()) - return false; - - // Hash type is one byte tacked on to the end of the signature - vector vchSig(vchSigIn); - if (vchSig.empty()) - return false; - int nHashType = vchSig.back(); - vchSig.pop_back(); - - size_t nHashed = 0; - uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, &nHashed); - nBytesHashed += nHashed; - ++nSigops; - - if (!VerifySignature(vchSig, pubkey, sighash)) - return false; - - return true; -} - -bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const -{ - // There are two kinds of nLockTime: lock-by-blockheight - // and lock-by-blocktime, distinguished by whether - // nLockTime < LOCKTIME_THRESHOLD. - // - // We want to compare apples to apples, so fail the script - // unless the type of nLockTime being tested is the same as - // the nLockTime in the transaction. - if (!( - (txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) || - (txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD) - )) - return false; - - // Now that we know we're comparing apples-to-apples, the - // comparison is a simple numeric one. - if (nLockTime > (int64_t)txTo->nLockTime) - return false; - - // Finally the nLockTime feature can be disabled and thus - // CHECKLOCKTIMEVERIFY bypassed if every txin has been - // finalized by setting nSequence to maxint. The - // transaction would be allowed into the blockchain, making - // the opcode ineffective. - // - // Testing if this vin is not final is sufficient to - // prevent this condition. Alternatively we could test all - // inputs, but testing just this input minimizes the data - // required to prove correct CHECKLOCKTIMEVERIFY execution. - if (txTo->vin[nIn].IsFinal()) - return false; - - return true; -} - - -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) -{ - set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); - - if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { - return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); - } - - vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker, serror)) - // serror is set - return false; - if (flags & SCRIPT_VERIFY_P2SH) - stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) - // serror is set - return false; - if (stack.empty()) - return set_error(serror, SCRIPT_ERR_EVAL_FALSE); - if (CastToBool(stack.back()) == false) - return set_error(serror, SCRIPT_ERR_EVAL_FALSE); - - // Additional validation for spend-to-script-hash transactions: - if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) - { - // scriptSig must be literals-only or validation fails - if (!scriptSig.IsPushOnly()) - return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); - - // Restore stack. - swap(stack, stackCopy); - - // stack cannot be empty here, because if it was the - // P2SH HASH <> EQUAL scriptPubKey would be evaluated with - // an empty stack and the EvalScript above would return false. - assert(!stack.empty()); - - const valtype& pubKeySerialized = stack.back(); - CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); - popstack(stack); - - if (!EvalScript(stack, pubKey2, flags, checker, serror)) - // serror is set - return false; - if (stack.empty()) - return set_error(serror, SCRIPT_ERR_EVAL_FALSE); - if (!CastToBool(stack.back())) - return set_error(serror, SCRIPT_ERR_EVAL_FALSE); - } - - // The CLEANSTACK check is only performed after potential P2SH evaluation, - // as the non-P2SH evaluation of a P2SH script will obviously not result in - // a clean stack (the P2SH inputs remain). - if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { - // Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK - // would be possible, which is not a softfork (and P2SH should be one). - assert((flags & SCRIPT_VERIFY_P2SH) != 0); - if (stack.size() != 1) { - return set_error(serror, SCRIPT_ERR_CLEANSTACK); - } - } - - return set_success(serror); -} -#endif - diff --git a/iguana/iguana_msg.c b/iguana/iguana_msg.c index 779d55e17..eaa16f37e 100755 --- a/iguana/iguana_msg.c +++ b/iguana/iguana_msg.c @@ -429,7 +429,7 @@ void iguana_gotping(struct iguana_info *coin,struct iguana_peer *addr,uint64_t n iguana_supernet_ping(addr); } -int32_t iguana_send_ping(struct iguana_info *coin,struct iguana_peer *addr) +int32_t iguana_send_ping(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr) { int32_t len; uint64_t nonce; uint8_t serialized[sizeof(struct iguana_msghdr) + sizeof(nonce)]; if ( (nonce= addr->pingnonce) == 0 ) @@ -442,6 +442,8 @@ int32_t iguana_send_ping(struct iguana_info *coin,struct iguana_peer *addr) iguana_queue_send(addr,0,serialized,"getaddr",0); len = iguana_rwnum(1,&serialized[sizeof(struct iguana_msghdr)],sizeof(uint64_t),&nonce); iguana_supernet_ping(addr); + if ( myinfo->IAMRELAY != 0 ) + basilisk_relays_send(myinfo,addr); return(iguana_queue_send(addr,0,serialized,"ping",len)); } diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index 83ec947bd..31f57a78a 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -237,7 +237,7 @@ cJSON *iguana_inputsjson(struct supernet_info *myinfo,struct iguana_info *coin,i u = &U[unspentind]; if ( (txidind= u->txidind) > 0 && txidind < rdata->numtxids ) { - if ( iguana_unspentindfind(coin,coinaddr,spendscript,&spendlen,&amount,&height,T[txidind].txid,u->vout,coin->bundlescount-1) == unspentind && spendlen > 0 ) + if ( iguana_unspentindfind(coin,coinaddr,spendscript,&spendlen,&amount,&height,T[txidind].txid,u->vout,coin->bundlescount-1,0) == unspentind && spendlen > 0 ) { item = cJSON_CreateObject(); jaddbits256(item,"txid",T[txidind].txid); @@ -631,7 +631,7 @@ HASH_AND_TWOINTS(bitcoinrpc,gettxout,txid,vout,mempool) if ( coin != 0 ) { minconf = (mempool != 0) ? 0 : 1; - if ( (unspentind= iguana_unspentindfind(coin,0,0,0,0,&height,txid,vout,coin->bundlescount-1)) != 0 ) + if ( (unspentind= iguana_unspentindfind(coin,0,0,0,0,&height,txid,vout,coin->bundlescount-1,0)) != 0 ) { if ( height >= 0 && height < coin->longestchain && (bp= coin->bundles[height / coin->chain->bundlesize]) != 0 ) { @@ -816,19 +816,17 @@ HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose) return(clonestr("{\"error\":\"cant find txid\"}")); } -STRING_ARG(bitcoinrpc,validaterawtransaction,rawtx) +char *iguana_validaterawtx(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_msgtx *msgtx,uint8_t *extraspace,int32_t extralen,char *rawtx,int32_t mempool) { - bits256 txid,signedtxid; struct iguana_msgtx msgtx; struct iguana_msgvin vin; cJSON *log,*vins,*txobj,*retjson; char *checkstr,*signedtx; int32_t i,len,maxsize,numinputs,complete,extralen=65536; struct vin_info *V; uint8_t *serialized,*serialized2,*extraspace; uint32_t sigsize,pubkeysize,p2shsize,suffixlen; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); + bits256 txid,signedtxid; struct iguana_msgvin vin; cJSON *log,*vins,*vouts,*txobj,*retjson; char *checkstr,*signedtx; int32_t i,len,maxsize,numinputs,numoutputs,complete; struct vin_info *V; uint8_t *serialized,*serialized2; uint32_t sigsize,pubkeysize,p2shsize,suffixlen; int64_t inputsum,outputsum; retjson = cJSON_CreateObject(); + inputsum = outputsum = numinputs = numoutputs = 0; if ( rawtx != 0 && rawtx[0] != 0 && coin != 0 ) { if ( (strlen(rawtx) & 1) != 0 ) return(clonestr("{\"error\":\"rawtx hex has odd length\"}")); - memset(&msgtx,0,sizeof(msgtx)); - extraspace = calloc(1,extralen); - if ( (txobj= bitcoin_hex2json(coin,&txid,&msgtx,rawtx,extraspace,extralen,0)) != 0 ) + memset(msgtx,0,sizeof(*msgtx)); + if ( (txobj= bitcoin_hex2json(coin,&txid,msgtx,rawtx,extraspace,extralen,0)) != 0 ) { //printf("txobj.(%s)\n",jprint(txobj,0)); if ( (checkstr= bitcoin_json2hex(myinfo,coin,&txid,txobj,0)) != 0 ) @@ -843,7 +841,7 @@ STRING_ARG(bitcoinrpc,validaterawtransaction,rawtx) break; jaddnum(retjson,"mismatch position",i); jadd(retjson,"origtx",txobj); - if ( (txobj= bitcoin_hex2json(coin,&txid,&msgtx,checkstr,extraspace,extralen,0)) != 0 ) + if ( (txobj= bitcoin_hex2json(coin,&txid,msgtx,checkstr,extraspace,extralen,0)) != 0 ) jadd(retjson,"checktx",txobj); free(checkstr); free(extraspace); @@ -851,6 +849,15 @@ STRING_ARG(bitcoinrpc,validaterawtransaction,rawtx) } free(checkstr); } + if ( (vouts= jarray(&numoutputs,txobj,"vout")) > 0 ) + { + struct iguana_msgvout vout; uint8_t voutdata[IGUANA_MAXSCRIPTSIZE]; + for (i=0; i 0 ) + outputsum += vout.value; + } + } if ( (vins= jarray(&numinputs,txobj,"vin")) > 0 ) { maxsize = (int32_t)strlen(rawtx); @@ -861,18 +868,19 @@ STRING_ARG(bitcoinrpc,validaterawtransaction,rawtx) for (i=0; ibundlescount-1)) > 0 ) + if ( (V[i].unspentind= iguana_unspentindfind(coin,V[i].coinaddr,V[i].spendscript,&V[i].spendlen,&V[i].amount,&V[i].height,msgtx->vins[i].prev_hash,msgtx->vins[i].prev_vout,coin->bundlescount-1,mempool)) > 0 ) { - msgtx.vins[i].spendscript = V[i].spendscript; - msgtx.vins[i].spendlen = V[i].spendlen; - V[i].hashtype = iguana_vinscriptparse(coin,&V[i],&sigsize,&pubkeysize,&p2shsize,&suffixlen,msgtx.vins[i].vinscript,msgtx.vins[i].scriptlen); + inputsum += V[i].amount; + msgtx->vins[i].spendscript = V[i].spendscript; + msgtx->vins[i].spendlen = V[i].spendlen; + V[i].hashtype = iguana_vinscriptparse(coin,&V[i],&sigsize,&pubkeysize,&p2shsize,&suffixlen,msgtx->vins[i].vinscript,msgtx->vins[i].scriptlen); V[i].suffixlen = suffixlen; - memcpy(V[i].spendscript,msgtx.vins[i].spendscript,msgtx.vins[i].spendlen); - V[i].spendlen = msgtx.vins[i].spendlen; + memcpy(V[i].spendscript,msgtx->vins[i].spendscript,msgtx->vins[i].spendlen); + V[i].spendlen = msgtx->vins[i].spendlen; //printf("V %.8f (%s) spendscript.[%d] scriptlen.%d\n",dstr(V[i].amount),V[i].coinaddr,V[i].spendlen,V[i].spendlen); } } - if ( (complete= bitcoin_verifyvins(coin,&signedtxid,&signedtx,&msgtx,serialized2,maxsize,V,1)) > 0 && signedtx != 0 ) + if ( (complete= bitcoin_verifyvins(coin,&signedtxid,&signedtx,msgtx,serialized2,maxsize,V,1,0)) > 0 && signedtx != 0 ) { log = cJSON_CreateArray(); if ( iguana_interpreter(coin,log,j64bits(txobj,"locktime"),V,numinputs) < 0 ) @@ -883,14 +891,29 @@ STRING_ARG(bitcoinrpc,validaterawtransaction,rawtx) } jaddnum(retjson,"complete",complete); free(serialized), free(serialized2); - free(extraspace); } } //char str[65]; printf("got txid.(%s)\n",bits256_str(str,txid)); } + msgtx->inputsum = inputsum; + msgtx->numinputs = numinputs; + msgtx->outputsum = outputsum; + msgtx->numoutputs = numoutputs; + msgtx->txfee = (inputsum - outputsum); return(jprint(retjson,1)); } +STRING_ARG(bitcoinrpc,validaterawtransaction,rawtx) +{ + uint8_t *extraspace; char *retstr; struct iguana_msgtx msgtx; int32_t extralen=65536; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + extraspace = calloc(1,extralen); + retstr = iguana_validaterawtx(myinfo,coin,&msgtx,extraspace,extralen,rawtx,0); + free(extraspace); + return(retstr); +} + STRING_ARG(bitcoinrpc,decoderawtransaction,rawtx) { cJSON *txobj = 0; bits256 txid; uint8_t *extraspace; int32_t extralen = 65536; @@ -943,7 +966,7 @@ cJSON *iguana_createvins(struct supernet_info *myinfo,struct iguana_info *coin,c spendlen = (int32_t)strlen(hexstr) >> 1; decode_hex(spendscript,spendlen,hexstr); } - if ( (unspentind= iguana_unspentindfind(coin,coinaddr,spendscript,&spendlen,&satoshis,&height,txid,vout,coin->bundlescount-1)) > 0 ) + if ( (unspentind= iguana_unspentindfind(coin,coinaddr,spendscript,&spendlen,&satoshis,&height,txid,vout,coin->bundlescount-1,0)) > 0 ) { //printf("[%d] unspentind.%d (%s) spendlen.%d %.8f\n",height/coin->chain->bundlesize,unspentind,coinaddr,spendlen,dstr(satoshis)); if ( coinaddr[0] != 0 && (waddr= iguana_waddresssearch(myinfo,&wacct,coinaddr)) != 0 ) @@ -1099,7 +1122,7 @@ INT_AND_ARRAY(bitcoinrpc,lockunspent,flag,array) { txid = jbits256(item,"txid"); vout = jint(item,"vout"); - if ( (unspentind= iguana_unspentindfind(coin,0,0,0,0,&height,txid,vout,coin->bundlescount-1)) != 0 ) + if ( (unspentind= iguana_unspentindfind(coin,0,0,0,0,&height,txid,vout,coin->bundlescount-1,0)) != 0 ) { hdrsi = height / coin->chain->bundlesize; iguana_utxofind(coin,hdrsi,unspentind,&RTspendflag,!flag); diff --git a/iguana/iguana_peers.c b/iguana/iguana_peers.c index 9ff489482..4d979e6b8 100755 --- a/iguana/iguana_peers.c +++ b/iguana/iguana_peers.c @@ -46,6 +46,31 @@ int32_t iguana_validatehdr(char *symbol,struct iguana_msghdr *H) return(len); } +struct iguana_peer *iguana_peeralive(struct iguana_peer *addr,int32_t needalive) +{ + if ( needalive == 0 || (addr->usock >= 0 && addr->dead == 0) ) + return(addr); + else return(0); +} + +struct iguana_peer *iguana_peerfindipaddr(struct iguana_info *coin,char *ipaddr,int32_t needalive) +{ + int32_t i; + for (i=0; ipeers->active[i].ipaddr) == 0 ) + return(iguana_peeralive(&coin->peers->active[i],needalive)); + return(0); +} + +struct iguana_peer *iguana_peerfindipbits(struct iguana_info *coin,uint32_t ipbits,int32_t needalive) +{ + int32_t i; + for (i=0; ipeers->active[i].ipbits ) + return(iguana_peeralive(&coin->peers->active[i],needalive)); + return(0); +} + struct iguana_iAddr *_iguana_hashset(struct iguana_info *coin,uint32_t ipbits,int32_t itemind) { struct iguana_iAddr *ptr = 0; int32_t allocsize; char str[65]; struct OS_memspace *mem = 0; @@ -699,7 +724,7 @@ void iguana_startconnection(void *arg) if ( coin->peers != 0 ) { coin->peers->lastpeer = (uint32_t)time(NULL); - for (i=n=0; iMAXPEERS; i++) + for (i=n=0; ipeers->active[i].usock > 0 ) n++; coin->peers->numconnected++; @@ -827,7 +852,7 @@ uint32_t iguana_possible_peer(struct iguana_info *coin,char *ipaddr) { if ( strcmp(ipaddr,"0.0.0.0") == 0 || strcmp(ipaddr,"127.0.0.1") == 0 ) return(0); - for (i=n=0; iMAXPEERS; i++) + for (i=n=0; ipeers->active[i].ipaddr) == 0 ) { printf("%s possible peer.(%s) %x already there\n",coin->symbol,ipaddr,(uint32_t)coin->peers->active[i].ipbits); @@ -852,7 +877,7 @@ uint32_t iguana_possible_peer(struct iguana_info *coin,char *ipaddr) //printf("check possible peer.(%s)\n",ipaddr); if ( iguana_peerslot(coin,(uint32_t)ipbits,0) != 0 ) return((uint32_t)time(NULL)); - for (i=n=0; iMAXPEERS; i++) + for (i=n=0; ipeers->active[i].ipaddr) == 0 ) { diff --git a/iguana/iguana_ramchain.c b/iguana/iguana_ramchain.c index d795649ab..d8935a1c5 100755 --- a/iguana/iguana_ramchain.c +++ b/iguana/iguana_ramchain.c @@ -607,7 +607,7 @@ uint32_t iguana_ramchain_addspend256(struct iguana_info *coin,struct iguana_peer int64_t iguana_hashmemsize(int64_t numtxids,int64_t numunspents,int64_t numspends,int64_t numpkinds,int64_t numexternaltxids,int64_t scriptspace) { int64_t allocsize = 0; - allocsize += 1.25 * (scriptspace + IGUANA_MAXSCRIPTSIZE + ((numtxids + numpkinds) * (sizeof(UT_hash_handle)*2)) + (((sizeof(struct iguana_account)) * 2 * numpkinds)) + (2 * numunspents * sizeof(struct iguana_spendvector))); + allocsize += 1.5 * (scriptspace + IGUANA_MAXSCRIPTSIZE + ((numtxids + numpkinds) * (sizeof(UT_hash_handle)*2)) + (((sizeof(struct iguana_account)) * 2 * numpkinds)) + (2 * numunspents * sizeof(struct iguana_spendvector))); if ( allocsize >= (1LL << 32) ) { printf("REALLY big hashmemsize %llu, truncate and hope for best\n",(long long)allocsize); diff --git a/iguana/iguana_recv.c b/iguana/iguana_recv.c index 02d0c75cf..9401a2f04 100755 --- a/iguana/iguana_recv.c +++ b/iguana/iguana_recv.c @@ -152,7 +152,7 @@ int32_t iguana_txidreq(struct iguana_info *coin,char **retstrp,bits256 txid) coin->reqtxids[coin->numreqtxids++] = txid; if ( coin->peers != 0 ) { - for (i=0; iMAXPEERS; i++) + for (i=0; ipeers->active[i].usock >= 0 ) iguana_sendtxidreq(coin,coin->peers->ranked[i],txid); } diff --git a/iguana/iguana_rpc.c b/iguana/iguana_rpc.c index f50827196..8da5046b8 100755 --- a/iguana/iguana_rpc.c +++ b/iguana/iguana_rpc.c @@ -23,7 +23,7 @@ char *sglue(GLUEARGS,char *agent,char *method) { - char *retstr,*rpcretstr,*walletstr; cJSON *retjson,*tmpjson,*result,*error,*wallet; int32_t i,j,len; + char *retstr,*rpcretstr,*walletstr,checkstr[64]; cJSON *retjson,*tmpjson,*result,*error,*wallet; int32_t i,j,len; int64_t val; if ( json == 0 ) json = cJSON_CreateObject(); //printf("sglue.(%s)\n",jprint(json,0)); @@ -78,6 +78,17 @@ char *sglue(GLUEARGS,char *agent,char *method) free(retstr); return(rpcretstr); } + else + { + val = atol(rpcretstr); + sprintf(checkstr,"%lld",(long long)val); + if ( strcmp(checkstr,rpcretstr) == 0 ) + { + free_json(retjson); + free(retstr); + return(rpcretstr); + } + } free(rpcretstr); } else if ( (error->type&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) @@ -682,6 +693,8 @@ char *iguana_bitcoinRPC(struct supernet_info *myinfo,char *method,cJSON *json,ch } if ( coin == 0 && symbol[0] != 0 ) coin = iguana_coinfind(symbol); + if ( coin != 0 ) + safecopy(symbol,coin->symbol,sizeof(symbol)); //printf("method.(%s) (%s) remote.(%s) symbol.(%s)\n",method,jprint(json,0),remoteaddr,symbol); if ( method != 0 && symbol[0] != 0 && (coin != 0 || (coin= iguana_coinfind(symbol)) != 0) ) { diff --git a/iguana/iguana_secp.c b/iguana/iguana_secp.c index 5814706a0..2d1a53242 100755 --- a/iguana/iguana_secp.c +++ b/iguana/iguana_secp.c @@ -31,6 +31,15 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc #define SECP_ENSURE_CTX int32_t flag = 0; if ( ctx == 0 ) { ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); secp256k1_pedersen_context_initialize(ctx); secp256k1_rangeproof_context_initialize(ctx); flag++; } else flag = 0; if ( ctx != 0 ) #define ENDSECP_ENSURE_CTX if ( flag != 0 ) secp256k1_context_destroy(ctx); +int32_t bitcoin_pubkeylen(const uint8_t *pubkey) +{ + if ( pubkey[0] == 2 || pubkey[0] == 3 ) + return(33); + else if ( pubkey[0] == 4 ) + return(65); + else return(-1); +} + bits256 bitcoin_randkey(secp256k1_context *ctx) { int32_t i; bits256 privkey; @@ -39,7 +48,7 @@ bits256 bitcoin_randkey(secp256k1_context *ctx) for (i=0; i<100; i++) { privkey = rand256(0); - if ( secp256k1_ec_seckey_verify(ctx,privkey.bytes) > 0 ) + if ( secp256k1_ec_seckey_verify(ctx,privkey.bytes) != 0 ) { ENDSECP_ENSURE_CTX return(privkey); @@ -62,7 +71,7 @@ bits256 bitcoin_pubkey33(secp256k1_context *ctx,uint8_t *data,bits256 privkey) printf("bitcoin_sign illegal privkey\n"); return(pubkey); } - if ( secp256k1_ec_pubkey_create(ctx,&secppub,privkey.bytes) > 0 ) + if ( secp256k1_ec_pubkey_create(ctx,&secppub,privkey.bytes) != 0 ) { plen = 33; secp256k1_ec_pubkey_serialize(ctx,data,&plen,&secppub,SECP256K1_EC_COMPRESSED); @@ -74,6 +83,21 @@ bits256 bitcoin_pubkey33(secp256k1_context *ctx,uint8_t *data,bits256 privkey) return(pubkey); } +bits256 bitcoin_pub256(void *ctx,bits256 *privkeyp,uint8_t odd_even) +{ + bits256 pub256; uint8_t pubkey[33]; int32_t i; + for (i=0; i<100; i++) + { + *privkeyp = rand256(0); + pub256 = bitcoin_pubkey33(ctx,pubkey,*privkeyp); + if ( pubkey[0] == odd_even+2 ) + return(pub256); + } + printf("bitcoin_pub256 couldnt generate pubkey.%d\n",odd_even+2); + memset(pub256.bytes,0,sizeof(pub256)); + return(pub256); +} + int32_t bitcoin_sign(void *ctx,char *symbol,uint8_t *sig,bits256 txhash2,bits256 privkey,int32_t recoverflag) { int32_t fCompressed = 1; @@ -87,17 +111,17 @@ int32_t bitcoin_sign(void *ctx,char *symbol,uint8_t *sig,bits256 txhash2,bits256 printf("bitcoin_sign illegal privkey\n"); return(-1); } - if ( secp256k1_context_randomize(ctx,seed.bytes) > 0 ) + if ( secp256k1_context_randomize(ctx,seed.bytes) != 0 ) { if ( recoverflag != 0 ) { - if ( secp256k1_ecdsa_sign_recoverable(ctx,&rSIG,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,extra_entropy.bytes) > 0 ) + if ( secp256k1_ecdsa_sign_recoverable(ctx,&rSIG,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,extra_entropy.bytes) != 0 ) { recid = -1; secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx,sig+1,&recid,&rSIG); - if ( secp256k1_ecdsa_recover(ctx,&SECPUB,&rSIG,txhash2.bytes) > 0 ) + if ( secp256k1_ecdsa_recover(ctx,&SECPUB,&rSIG,txhash2.bytes) != 0 ) { - if ( secp256k1_ec_pubkey_create(ctx,&CHECKPUB,privkey.bytes) > 0 ) + if ( secp256k1_ec_pubkey_create(ctx,&CHECKPUB,privkey.bytes) != 0 ) { if ( memcmp(&SECPUB,&CHECKPUB,sizeof(SECPUB)) == 0 ) { @@ -111,9 +135,9 @@ int32_t bitcoin_sign(void *ctx,char *symbol,uint8_t *sig,bits256 txhash2,bits256 } else { - if ( secp256k1_ecdsa_sign(ctx,&SIG,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,extra_entropy.bytes) > 0 ) + if ( secp256k1_ecdsa_sign(ctx,&SIG,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,extra_entropy.bytes) != 0 ) { - if ( secp256k1_ecdsa_signature_serialize_der(ctx,sig,&siglen,&SIG) > 0 ) + if ( secp256k1_ecdsa_signature_serialize_der(ctx,sig,&siglen,&SIG) != 0 ) retval = (int32_t)siglen; } } @@ -132,10 +156,10 @@ int32_t bitcoin_recoververify(void *ctx,char *symbol,uint8_t *sig65,bits256 mess plen = (sig65[0] <= 31) ? 65 : 33; secp256k1_ecdsa_recoverable_signature_parse_compact(ctx,&rSIG,sig65 + 1,0); secp256k1_ecdsa_recoverable_signature_convert(ctx,&SIG,&rSIG); - if ( secp256k1_ecdsa_recover(ctx,&PUB,&rSIG,messagehash2.bytes) > 0 ) + if ( secp256k1_ecdsa_recover(ctx,&PUB,&rSIG,messagehash2.bytes) != 0 ) { secp256k1_ec_pubkey_serialize(ctx,pubkey,&plen,&PUB,plen == 65 ? SECP256K1_EC_UNCOMPRESSED : SECP256K1_EC_COMPRESSED); - if ( secp256k1_ecdsa_verify(ctx,&SIG,messagehash2.bytes,&PUB) > 0 ) + if ( secp256k1_ecdsa_verify(ctx,&SIG,messagehash2.bytes,&PUB) != 0 ) retval = 0; else printf("secp256k1_ecdsa_verify error\n"); } else printf("secp256k1_ecdsa_recover error\n"); @@ -149,10 +173,10 @@ int32_t bitcoin_verify(void *ctx,uint8_t *sig,int32_t siglen,bits256 txhash2,uin int32_t retval = -1; secp256k1_pubkey PUB; secp256k1_ecdsa_signature SIG; SECP_ENSURE_CTX { - if ( secp256k1_ec_pubkey_parse(ctx,&PUB,pubkey,plen) > 0 ) + if ( secp256k1_ec_pubkey_parse(ctx,&PUB,pubkey,plen) != 0 ) { secp256k1_ecdsa_signature_parse_der(ctx,&SIG,sig,siglen); - if ( secp256k1_ecdsa_verify(ctx,&SIG,txhash2.bytes,&PUB) > 0 ) + if ( secp256k1_ecdsa_verify(ctx,&SIG,txhash2.bytes,&PUB) != 0 ) retval = 0; } ENDSECP_ENSURE_CTX @@ -166,9 +190,9 @@ bits256 bitcoin_sharedsecret(void *ctx,bits256 privkey,uint8_t *pubkey,int32_t p memset(shared.bytes,0,sizeof(shared)); SECP_ENSURE_CTX { - if ( secp256k1_ec_pubkey_parse(ctx,&PUB,pubkey,plen) > 0 ) + if ( secp256k1_ec_pubkey_parse(ctx,&PUB,pubkey,plen) != 0 ) { - if ( secp256k1_ecdh(ctx,shared.bytes,&PUB,privkey.bytes) > 0 ) + if ( secp256k1_ecdh(ctx,shared.bytes,&PUB,privkey.bytes) != 0 ) retval = 0; else memset(shared.bytes,0,sizeof(shared)); } @@ -183,7 +207,7 @@ int32_t bitcoin_schnorr_sign(void *ctx,uint8_t *sig64,bits256 txhash2,bits256 pr SECP_ENSURE_CTX { seed = rand256(0); - if ( secp256k1_schnorr_sign(ctx,sig64,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,seed.bytes) > 0 ) + if ( secp256k1_schnorr_sign(ctx,sig64,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,seed.bytes) != 0 ) retval = 0; ENDSECP_ENSURE_CTX } @@ -195,9 +219,9 @@ int32_t bitcoin_schnorr_verify(void *ctx,uint8_t *sig64,bits256 txhash2,uint8_t int32_t retval = -1; secp256k1_pubkey PUB; SECP_ENSURE_CTX { - if ( secp256k1_ec_pubkey_parse(ctx,&PUB,pubkey,plen) > 0 ) + if ( secp256k1_ec_pubkey_parse(ctx,&PUB,pubkey,plen) != 0 ) { - if ( secp256k1_schnorr_verify(ctx,sig64,txhash2.bytes,&PUB) > 0 ) + if ( secp256k1_schnorr_verify(ctx,sig64,txhash2.bytes,&PUB) != 0 ) retval = 0; } ENDSECP_ENSURE_CTX @@ -210,7 +234,7 @@ int32_t bitcoin_schnorr_recover(void *ctx,uint8_t *pubkey,uint8_t *sig64,bits256 int32_t retval = -1; secp256k1_pubkey PUB; size_t plen; SECP_ENSURE_CTX { - if ( secp256k1_schnorr_recover(ctx,&PUB,sig64,txhash2.bytes) > 0 ) + if ( secp256k1_schnorr_recover(ctx,&PUB,sig64,txhash2.bytes) != 0 ) { plen = 33; secp256k1_ec_pubkey_serialize(ctx,pubkey,&plen,&PUB,SECP256K1_EC_COMPRESSED); @@ -229,7 +253,7 @@ bits256 bitcoin_schnorr_noncepair(void *ctx,uint8_t *pubnonce,bits256 txhash2,bi SECP_ENSURE_CTX { seed = rand256(0); - if ( secp256k1_schnorr_generate_nonce_pair(ctx,&PUB,privnonce.bytes,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,seed.bytes) > 0 ) + if ( secp256k1_schnorr_generate_nonce_pair(ctx,&PUB,privnonce.bytes,txhash2.bytes,privkey.bytes,secp256k1_nonce_function_rfc6979,seed.bytes) != 0 ) { plen = 33; secp256k1_ec_pubkey_serialize(ctx,pubnonce,&plen,&PUB,SECP256K1_EC_COMPRESSED); @@ -240,6 +264,50 @@ bits256 bitcoin_schnorr_noncepair(void *ctx,uint8_t *pubnonce,bits256 txhash2,bi return(privnonce); } +int32_t bitcoin_pubkey_combine(void *ctx,uint8_t *combined_pub,uint8_t *skipkey,bits256 *evenkeys,int32_t n,bits256 *oddkeys,int32_t m) +{ + int32_t i,num,iter,max,retval = -1; uint8_t pubkey[33]; size_t plen; secp256k1_pubkey PUBall,*PUBptrs[256],PUBkeys[256]; + SECP_ENSURE_CTX + { + if ( n+m > 0 && n+m < sizeof(PUBptrs)/sizeof(*PUBptrs) ) + { + for (iter=num=0; iter<2; iter++) + { + if ( (max= (iter == 0) ? n : m) != 0 ) + { + for (i=0; i 0 && secp256k1_ec_pubkey_combine(ctx,&PUBall,(void *)PUBptrs,n) > 0 ) + if ( n > 0 && secp256k1_ec_pubkey_combine(ctx,&PUBall,(void *)PUBptrs,n) != 0 ) { plen = 33; - if ( secp256k1_schnorr_partial_sign(ctx,sig64,txhash2.bytes,privkey.bytes,&PUBall,privnonce.bytes) > 0 ) + if ( secp256k1_schnorr_partial_sign(ctx,sig64,txhash2.bytes,privkey.bytes,&PUBall,privnonce.bytes) != 0 ) { secp256k1_ec_pubkey_serialize(ctx,combined_pub,&plen,&PUBall,SECP256K1_EC_COMPRESSED); retval = 0; @@ -273,7 +341,7 @@ int32_t bitcoin_schnorr_combine(void *ctx,uint8_t *sig64,uint8_t *allpub,uint8_t int32_t rc,retval = -1; SECP_ENSURE_CTX { - if ( (rc= secp256k1_schnorr_partial_combine(ctx,sig64,(void *)sigs,n)) > 0 ) + if ( (rc= secp256k1_schnorr_partial_combine(ctx,sig64,(void *)sigs,n)) != 0 ) { if ( bitcoin_schnorr_recover(ctx,allpub,sig64,txhash2) == 0 ) { @@ -291,7 +359,7 @@ int32_t bitcoin_pederson_commit(void *ctx,uint8_t *commit,bits256 blind,uint64_t int32_t retval = -1; SECP_ENSURE_CTX { - if ( secp256k1_pedersen_commit(ctx,commit,blind.bytes,value) > 0 ) + if ( secp256k1_pedersen_commit(ctx,commit,blind.bytes,value) != 0 ) retval = 0; ENDSECP_ENSURE_CTX } @@ -316,7 +384,7 @@ int32_t bitcoin_pederson_tally(void *ctx,uint8_t **commits,int32_t n,int32_t num int32_t retval = -1; SECP_ENSURE_CTX { - if ( secp256k1_pedersen_verify_tally(ctx,(void *)commits,numpos,(void *)&commits[numpos],n - numpos,excess) > 0 ) + if ( secp256k1_pedersen_verify_tally(ctx,(void *)commits,numpos,(void *)&commits[numpos],n - numpos,excess) != 0 ) retval = 0; ENDSECP_ENSURE_CTX } @@ -328,7 +396,7 @@ int32_t bitcoin_rangeproof_message(void *ctx,uint8_t *blind_out,uint8_t *message int32_t outlen = 0,retval = -1; SECP_ENSURE_CTX { - if ( secp256k1_rangeproof_rewind(ctx,blind_out,valuep,message,&outlen,nonce.bytes,min_valuep,max_valuep,commit,proof,prooflen) > 0 ) + if ( secp256k1_rangeproof_rewind(ctx,blind_out,valuep,message,&outlen,nonce.bytes,min_valuep,max_valuep,commit,proof,prooflen) != 0 ) retval = outlen; ENDSECP_ENSURE_CTX } @@ -339,11 +407,11 @@ uint64_t bitcoin_rangeverify(void *ctx,int32_t *exponentp,int32_t *mantissap,uin { uint64_t max_value,retval = 0; max_value = *min_valuep = *exponentp = *mantissap = 0; - if ( secp256k1_rangeproof_info(ctx,exponentp,mantissap,min_valuep,&max_value,proof,prooflen) > 0 ) + if ( secp256k1_rangeproof_info(ctx,exponentp,mantissap,min_valuep,&max_value,proof,prooflen) != 0 ) { if ( commit != 0 ) { - if ( secp256k1_rangeproof_verify(ctx,min_valuep,&max_value,commit,proof,prooflen) > 0 ) + if ( secp256k1_rangeproof_verify(ctx,min_valuep,&max_value,commit,proof,prooflen) != 0 ) retval = max_value; } else retval = max_value; } @@ -355,7 +423,7 @@ int32_t bitcoin_rangeproof(void *ctx,uint8_t *proof,uint8_t *commit,bits256 blin int32_t prooflen=0 ,retval = -1; SECP_ENSURE_CTX { - if ( secp256k1_rangeproof_sign(ctx,proof,&prooflen,min_value,commit,blind.bytes,nonce.bytes,exponent,min_bits,value) > 0 ) + if ( secp256k1_rangeproof_sign(ctx,proof,&prooflen,min_value,commit,blind.bytes,nonce.bytes,exponent,min_bits,value) != 0 ) retval = prooflen; ENDSECP_ENSURE_CTX } diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index fcf0f80cb..ee68fe950 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -127,10 +127,6 @@ cJSON *iguana_vinjson(struct iguana_info *coin,struct iguana_msgvin *vin,bits256 int32_t iguana_parsevinobj(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvin *vin,cJSON *vinobj,struct vin_info *V) { struct iguana_waddress *waddr; struct iguana_waccount *wacct; int32_t i,n,plen,len = 0; char *suffixstr,*pubkeystr,*hexstr = 0,*redeemstr = 0,*spendstr = 0; cJSON *scriptjson = 0,*obj,*pubkeysjson = 0; - if ( serialized == 0 ) - { - ; - } //printf("PARSEVIN.(%s) vin.%p\n",jprint(vinobj,0),vin); if ( V == 0 ) memset(vin,0,sizeof(*vin)); @@ -167,7 +163,7 @@ int32_t iguana_parsevinobj(struct supernet_info *myinfo,struct iguana_info *coin { if ( vin->vinscript == 0 ) { - if ( (V->unspentind= iguana_unspentindfind(coin,V->coinaddr,V->spendscript,&V->spendlen,&V->amount,&V->height,vin->prev_hash,vin->prev_vout,coin->bundlescount-1)) > 0 ) + if ( (V->unspentind= iguana_unspentindfind(coin,V->coinaddr,V->spendscript,&V->spendlen,&V->amount,&V->height,vin->prev_hash,vin->prev_vout,coin->bundlescount-1,0)) > 0 ) { if ( V->coinaddr[0] != 0 && (waddr= iguana_waddresssearch(myinfo,&wacct,V->coinaddr)) != 0 ) { @@ -645,7 +641,7 @@ int32_t iguana_msgtx_Vset(struct iguana_info *coin,uint8_t *serialized,int32_t m return(len); } -int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxlen,struct vin_info *V,int32_t sighash) +int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxlen,struct vin_info *V,int32_t sighash,int32_t signtx) { bits256 sigtxid; uint8_t *sig; struct vin_info *vp; char vpnstr[64]; int32_t complete=0,plen,j,vini=0,flag=0,siglen,numvouts,numsigs; numvouts = msgtx->tx_out; @@ -663,7 +659,7 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** { sig = vp->signers[j].sig; siglen = vp->signers[j].siglen; - if ( bits256_nonz(vp->signers[j].privkey) != 0 ) + if ( signtx != 0 && bits256_nonz(vp->signers[j].privkey) != 0 ) { siglen = bitcoin_sign(coin->ctx,coin->symbol,sig,sigtxid,vp->signers[j].privkey,0); if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) <= 0 ) @@ -722,7 +718,7 @@ int32_t iguana_vininfo_create(struct supernet_info *myinfo,struct iguana_info *c len += iguana_parsevinobj(myinfo,coin,&serialized[len],maxsize,&msgtx->vins[i],jitem(vins,i),vp); if ( msgtx->vins[i].spendscript == 0 ) { - if ( (vp->unspentind= iguana_unspentindfind(coin,vp->coinaddr,vp->spendscript,&vp->spendlen,&vp->amount,&vp->height,msgtx->vins[i].prev_hash,msgtx->vins[i].prev_vout,coin->bundlescount-1)) > 0 ) + if ( (vp->unspentind= iguana_unspentindfind(coin,vp->coinaddr,vp->spendscript,&vp->spendlen,&vp->amount,&vp->height,msgtx->vins[i].prev_hash,msgtx->vins[i].prev_vout,coin->bundlescount-1,0)) > 0 ) { msgtx->vins[i].spendscript = vp->spendscript; msgtx->vins[i].spendlen = vp->spendlen; @@ -1032,7 +1028,7 @@ P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount bitcoin_txinput(active,txobj,vintxid,vinvout,0xffffffff,spendscript,spendlen,V.p2shscript,V.p2shlen,pubkeyptrs,N); bitcoin_address(msigaddr,active->chain->p2shtype,V.p2shscript,V.p2shlen); retjson = cJSON_CreateObject(); - if ( bitcoin_verifyvins(active,&signedtxid,&signedtx,&msgtx,serialized,sizeof(serialized),&V,SIGHASH_ALL) == 0 ) + if ( bitcoin_verifyvins(active,&signedtxid,&signedtx,&msgtx,serialized,sizeof(serialized),&V,SIGHASH_ALL,1) == 0 ) { jaddstr(retjson,"result","msigtx"); if ( signedtx != 0 ) @@ -1091,7 +1087,7 @@ int32_t iguana_signrawtransaction(struct supernet_info *myinfo,struct iguana_inf } } iguana_vininfo_create(myinfo,coin,serialized2,maxsize,msgtx,vins,numinputs,V); - if ( (complete= bitcoin_verifyvins(coin,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL)) > 0 && signedtx != 0 ) + if ( (complete= bitcoin_verifyvins(coin,signedtxidp,&signedtx,msgtx,serialized3,maxsize,V,SIGHASH_ALL,1)) > 0 && signedtx != 0 ) { if ( iguana_interpreter(coin,0,j64bits(txobj,"locktime"),V,numinputs) < 0 ) { diff --git a/iguana/iguana_spendvectors.c b/iguana/iguana_spendvectors.c index aaa000cb4..e0a72b017 100755 --- a/iguana/iguana_spendvectors.c +++ b/iguana/iguana_spendvectors.c @@ -203,7 +203,7 @@ struct iguana_bundle *iguana_fastexternalspent(struct iguana_info *coin,bits256 X = RAMCHAIN_PTR(rdata,Xoffset); //X = (void *)(long)((long)rdata + rdata->Xoffset); *prevhashp = prev_hash = X[ind]; - if ( (unspentind= iguana_unspentindfind(coin,0,0,0,0,&height,prev_hash,prev_vout,spent_hdrsi-1)) != 0 ) + if ( (unspentind= iguana_unspentindfind(coin,0,0,0,0,&height,prev_hash,prev_vout,spent_hdrsi-1,0)) != 0 ) //if ( (firstvout= iguana_txidfastfind(coin,&height,prev_hash,spent_hdrsi-1)) >= 0 ) { /*duration = (OS_milliseconds() - startmillis); diff --git a/iguana/iguana_txidfind.c b/iguana/iguana_txidfind.c index dba007d33..10fd514a2 100755 --- a/iguana/iguana_txidfind.c +++ b/iguana/iguana_txidfind.c @@ -653,7 +653,7 @@ double iguana_txidstatus(struct iguana_info *coin,bits256 txid) int32_t height,firstvout,numranked; struct iguana_monitorinfo *ptr; char str[65]; if ( coin != 0 && coin->peers != 0 && (numranked= coin->peers->numranked) > 0 ) { - if ( (firstvout= iguana_unspentindfind(coin,0,0,0,0,&height,txid,0,coin->bundlescount-1)) != 0 ) + if ( (firstvout= iguana_unspentindfind(coin,0,0,0,0,&height,txid,0,coin->bundlescount-1,0)) != 0 ) { if ( (ptr= iguana_monitorfind(coin,txid)) != 0 ) memset(ptr,0,sizeof(*ptr)); diff --git a/iguana/iguana_unspents.c b/iguana/iguana_unspents.c index 2910cce34..2bf512f3a 100755 --- a/iguana/iguana_unspents.c +++ b/iguana/iguana_unspents.c @@ -20,9 +20,9 @@ #include "iguana777.h" #include "exchanges/bitcoin.h" -int32_t iguana_unspentindfind(struct iguana_info *coin,char *coinaddr,uint8_t *spendscript,int32_t *spendlenp,uint64_t *valuep,int32_t *heightp,bits256 txid,int32_t vout,int32_t lasthdrsi) +int32_t iguana_unspentindfind(struct iguana_info *coin,char *coinaddr,uint8_t *spendscript,int32_t *spendlenp,uint64_t *valuep,int32_t *heightp,bits256 txid,int32_t vout,int32_t lasthdrsi,int32_t mempool) { - struct iguana_txid *tp,TX; struct iguana_pkhash *P; struct iguana_unspent *U; struct iguana_bundle *bp; struct iguana_ramchaindata *rdata; int64_t RTspend; int32_t pkind,hdrsi,firstvout,spentheight,unspentind = -1; + struct iguana_txid *tp,TX; struct gecko_memtx *memtx; struct iguana_pkhash *P; struct iguana_unspent *U; struct iguana_bundle *bp; struct iguana_ramchaindata *rdata; int64_t RTspend; int32_t pkind,hdrsi,firstvout,spentheight,flag=0,unspentind = -1; if ( valuep != 0 ) *valuep = 0; if ( coinaddr != 0 ) @@ -35,12 +35,11 @@ int32_t iguana_unspentindfind(struct iguana_info *coin,char *coinaddr,uint8_t *s { U = RAMCHAIN_PTR(rdata,Uoffset); P = RAMCHAIN_PTR(rdata,Poffset); - //U = (void *)(long)((long)rdata + rdata->Uoffset); - //P = (void *)(long)((long)rdata + rdata->Poffset); pkind = U[unspentind].pkind; if ( pkind > 0 && pkind < rdata->numpkinds ) { RTspend = 0; + flag++; if ( iguana_spentflag(coin,&RTspend,&spentheight,&bp->ramchain,bp->hdrsi,unspentind,0,1,coin->longestchain,U[unspentind].value) == 0 ) //bp == coin->current ? &coin->RTramchain : { if ( valuep != 0 ) @@ -51,6 +50,22 @@ int32_t iguana_unspentindfind(struct iguana_info *coin,char *coinaddr,uint8_t *s } } } + if ( flag == 0 && mempool != 0 ) + { + if ( (memtx= gecko_unspentfind(0,coin,txid)) != 0 && vout < memtx->numoutputs ) + { + if ( *gecko_valueptr(memtx,vout) > 0 ) + { + *valuep = *gecko_valueptr(memtx,vout); + if ( spendlenp != 0 ) + { + *spendlenp = 1; + spendscript = 0; + printf("mempool unspentind doesnt support scriptlenp yet\n"); + } + } + } + } return(unspentind); } @@ -63,7 +78,7 @@ char *iguana_inputaddress(struct iguana_info *coin,char *coinaddr,int16_t *spent { txid = jbits256(vinobj,"txid"); vout = jint(vinobj,"vout"); - if ( (checkind= iguana_unspentindfind(coin,coinaddr,0,0,0,&height,txid,vout,coin->bundlescount-1)) > 0 ) + if ( (checkind= iguana_unspentindfind(coin,coinaddr,0,0,0,&height,txid,vout,coin->bundlescount-1,0)) > 0 ) { *spent_hdrsip = (height / coin->chain->bundlesize); *unspentindp = checkind; @@ -116,7 +131,7 @@ cJSON *iguana_unspentjson(struct supernet_info *myinfo,struct iguana_info *coin, if ( iguana_scriptget(coin,scriptstr,asmstr,sizeof(scriptstr),hdrsi,unspentind,T[up->txidind].txid,up->vout,rmd160,up->type,pubkey33) != 0 ) jaddstr(item,"scriptPubKey",scriptstr); jaddnum(item,"amount",dstr(up->value)); - if ( (checkind= iguana_unspentindfind(coin,0,0,0,0,&height,T[up->txidind].txid,up->vout,coin->bundlescount-1)) != 0 ) + if ( (checkind= iguana_unspentindfind(coin,0,0,0,0,&height,T[up->txidind].txid,up->vout,coin->bundlescount-1,0)) != 0 ) { jaddnum(item,"confirmations",coin->blocks.hwmchain.height - height + 1); jaddnum(item,"checkind",checkind); diff --git a/iguana/main.c b/iguana/main.c index 6ca24a3ed..dace60bb3 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -1150,7 +1150,7 @@ void iguana_appletests(struct supernet_info *myinfo) bitcoin_sharedsecret(myinfo->ctx,hash2,pubkey,33); printf("secp256k1 elapsed %.3f for %d iterations\n",OS_milliseconds() - startmillis,i); getchar();**/ - if ( 1 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"protover\":70002,\"RELAY\":0,\"VALIDATE\":0,\"portp2p\":14631,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":64,\"endpend\":64,\"services\":129,\"maxpeers\":128,\"newcoin\":\"BTCD\",\"active\":1,\"numhelpers\":4,\"poll\":1}"),0,myinfo->rpcport)) != 0 ) + if ( 1 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"protover\":70002,\"RELAY\":1,\"VALIDATE\":1,\"portp2p\":14631,\"rpc\":14632,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":64,\"endpend\":64,\"services\":129,\"maxpeers\":128,\"newcoin\":\"BTCD\",\"active\":1,\"numhelpers\":4,\"poll\":1}"),0,myinfo->rpcport)) != 0 ) { free(str); if ( 1 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"portp2p\":8333,\"RELAY\":0,\"VALIDATE\":0,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":1,\"endpend\":1,\"services\":128,\"maxpeers\":64,\"newcoin\":\"BTC\",\"active\":0,\"numhelpers\":4,\"poll\":100}"),0,myinfo->rpcport)) != 0 ) @@ -1309,6 +1309,116 @@ int32_t iguana_isbigendian() else return(-1); } +#define SECP_ENSURE_CTX int32_t flag = 0; if ( ctx == 0 ) { ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); secp256k1_pedersen_context_initialize(ctx); secp256k1_rangeproof_context_initialize(ctx); flag++; } else flag = 0; if ( ctx != 0 ) +#define ENDSECP_ENSURE_CTX if ( flag != 0 ) secp256k1_context_destroy(ctx); + +int32_t iguana_schnorr_peersign(void *ctx,uint8_t *allpub33,uint8_t *partialsig64,int32_t peeri,bits256 mypriv,bits256 privnonce,bits256 *nonces,int32_t n,bits256 msg256) +{ + secp256k1_pubkey Rall,ALL,PUBS[256],*PUBptrs[256]; int32_t i,num,retval = -1; size_t plen; uint8_t pubkey[33]; + pubkey[0] = 2; + SECP_ENSURE_CTX + { + for (i=num=0; ibytes,pubkey33+1,32); + break; + } + } + if ( j == maxj ) + { + printf("couldnt generate even noncepair\n"); + exit(-1); + } + return(privnonce); +} + +void iguana_schnorr(struct supernet_info *myinfo) +{ + uint8_t allpubs[256][33],allpub[33],sig64s[256][64],sig64[64],*sigs[256]; bits256 msg256,privnonces[256],signers,privkeys[256],pubkeys[256],pubkeysB[256],nonces[256]; int32_t i,iter,n,k,maxj = 100; + OS_randombytes((void *)&n,sizeof(n)); + srand(n); + n = 64;//(rand() % 200); + // generate onetime keypairs + for (i=0; ictx,&privkeys[i],0); + msg256 = rand256(0); + for (i=0; ictx,&nonces[i],0,msg256,privkeys[i],maxj); + for (i=0; ictx,allpubs[i],sig64s[i],i,privkeys[i],privnonces[i],nonces,n,msg256); + for (iter=0; iter<1; iter++) + { + memset(signers.bytes,0,sizeof(signers)); + for (i=k=0; ictx,sig64,allpub,sigs,k,msg256) < 0 ) + printf("error combining k.%d sig64 iter.%d\n",k,iter); + else if ( bitcoin_schnorr_verify(myinfo->ctx,sig64,msg256,allpub,33) < 0 ) + printf("error verifying combined sig k.%d\n",k); + else if ( 0 ) + { + if ( bitcoin_pubkey_combine(myinfo->ctx,allpub,0,pubkeys,n,0,0) == 0 ) + { + if ( memcmp(allpub,allpubs[0],33) != 0 ) + { + printf("\n"); + for (k=0; k<33; k++) + printf("%02x",allpubs[0][k]); + printf(" combined\n"); + for (k=0; k<33; k++) + printf("%02x",allpub[k]); + printf(" allpub, "); + printf("allpub mismatch iter.%d i.%d n.%d\n",iter,i,n); + } else printf("validated iter.%d k.%d %llx\n",iter,k,(long long)signers.txid); + } //else printf("error combining\n"); + } else printf("passed\n"); + } +} + void iguana_main(void *arg) { int32_t usessl = 0, ismainnet = 1; struct supernet_info *myinfo; cJSON *argjson = 0; @@ -1320,9 +1430,50 @@ void iguana_main(void *arg) mycalloc(0,0,0); if ( 0 ) iguana_signalsinit(); + if ( 0 ) + { + int32_t i,max=10000000; FILE *fp; bits256 check,val,hash = rand256(0); + if ( (fp= fopen("/tmp/seeds2","rb")) != 0 ) + { + fread(&check,1,sizeof(check),fp); + for (i=1; irpcport = IGUANA_RPCPORT; strcpy(myinfo->rpcsymbol,"BTCD"); iguana_urlinit(myinfo,ismainnet,usessl); diff --git a/iguana/ramchain_api.c b/iguana/ramchain_api.c index 9e9aa9d86..da6438e98 100755 --- a/iguana/ramchain_api.c +++ b/iguana/ramchain_api.c @@ -171,6 +171,7 @@ ZERO_ARGS(bitcoinrpc,getbestblockhash) ZERO_ARGS(bitcoinrpc,getblockcount) { cJSON *retjson = cJSON_CreateObject(); + //printf("result %d\n",coin->blocks.hwmchain.height); jaddnum(retjson,"result",coin->blocks.hwmchain.height); return(jprint(retjson,1)); } diff --git a/iguana/tests/getblock b/iguana/tests/getblock new file mode 100755 index 000000000..b051ba6a5 --- /dev/null +++ b/iguana/tests/getblock @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:14632" --data "{\"method\":\"getblock\",\"params\":[\"0000044966f40703b516c5af180582d53f783bfd319bb045e2dc3e05ea695d46\"]}" diff --git a/iguana/tests/getblockcount b/iguana/tests/getblockcount new file mode 100755 index 000000000..ca9ec4b9f --- /dev/null +++ b/iguana/tests/getblockcount @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:14632" --data "{\"method\":\"getblockcount\",\"params\":[]}" diff --git a/iguana/tests/getblockhash b/iguana/tests/getblockhash new file mode 100755 index 000000000..9537a87d3 --- /dev/null +++ b/iguana/tests/getblockhash @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:14632" --data "{\"method\":\"getblockhash\",\"params\":[0]}" diff --git a/iguana/tests/new b/iguana/tests/new index 0d20cab9f..59ff44b82 100755 --- a/iguana/tests/new +++ b/iguana/tests/new @@ -1 +1 @@ -curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"basilisk\",\"method\":\"newgeckochain\",\"vals\":{\"RELAY\":1,\"blocktime\":0,\"chain\":\"InstantDEX\",\"symbol\":\"DEX\"}}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"basilisk\",\"method\":\"newgeckochain\",\"vals\":{\"RELAY\":1,\"blocktime\":10,\"chain\":\"InstantDEX\",\"symbol\":\"DEX\"}}" diff --git a/includes/iguana_funcs.h b/includes/iguana_funcs.h index b63104ca8..f018ba3d1 100755 --- a/includes/iguana_funcs.h +++ b/includes/iguana_funcs.h @@ -401,10 +401,10 @@ int32_t iguana_bundleready(struct iguana_info *coin,struct iguana_bundle *bp,int int32_t iguana_blast(struct iguana_info *coin,struct iguana_peer *addr); int32_t iguana_validated(struct iguana_info *coin); void iguana_volatilesalloc(struct iguana_info *coin,struct iguana_ramchain *ramchain,int32_t copyflag); -int32_t iguana_send_ping(struct iguana_info *coin,struct iguana_peer *addr); +int32_t iguana_send_ping(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr); int32_t iguana_process_msgrequestQ(struct supernet_info *myinfo,struct iguana_info *coin); uint32_t iguana_fastfindinit(struct iguana_info *coin); -int32_t iguana_unspentindfind(struct iguana_info *coin,char *coinaddr,uint8_t *spendscript,int32_t *scriptlenp,uint64_t *valuep,int32_t *heightp,bits256 txid,int32_t vout,int32_t lasthdrsi); +int32_t iguana_unspentindfind(struct iguana_info *coin,char *coinaddr,uint8_t *spendscript,int32_t *scriptlenp,uint64_t *valuep,int32_t *heightp,bits256 txid,int32_t vout,int32_t lasthdrsi,int32_t mempool); int32_t iguana_addressvalidate(struct iguana_info *coin,uint8_t *addrtypep,char *address); int32_t bitcoin_sign(void *ctx,char *symbol,uint8_t *sig,bits256 txhash2,bits256 privkey,int32_t recoverflag); bits256 iguana_str2priv(struct supernet_info *myinfo,struct iguana_info *coin,char *str); @@ -420,7 +420,8 @@ int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t cJSON *iguana_p2shjson(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *retjson,struct iguana_waddress *waddr); char *setaccount(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waddress **waddrp,char *account,char *coinaddr,char *redeemScript); char *iguana_APIrequest(struct iguana_info *coin,bits256 blockhash,bits256 txid,int32_t seconds); -int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t sighash); +int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t sighash,int32_t signtx); +char *iguana_validaterawtx(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_msgtx *msgtx,uint8_t *extraspace,int32_t extralen,char *rawtx,int32_t mempool); int64_t iguana_fastfindcreate(struct iguana_info *coin); int32_t bitcoin_validaddress(struct iguana_info *coin,char *coinaddr); int32_t iguana_volatileupdate(struct iguana_info *coin,int32_t incremental,struct iguana_ramchain *spentchain,int16_t spent_hdrsi,uint32_t spent_unspentind,uint32_t spent_pkind,uint64_t spent_value,uint32_t spendind,uint32_t fromheight); @@ -506,6 +507,18 @@ bits256 iguana_parsetxobj(struct supernet_info *myinfo,struct iguana_info *coin, int32_t iguana_ROallocsize(struct iguana_info *virt); long iguana_bundlesload(struct supernet_info *myinfo,struct iguana_info *coin); void basilisk_wait(struct supernet_info *myinfo,struct iguana_info *coin); +int32_t bitcoin_pubkey_combine(void *ctx,uint8_t *combined_pub,uint8_t *skipkey,bits256 *evenkeys,int32_t n,bits256 *oddkeys,int32_t m); +bits256 bitcoin_pub256(void *ctx,bits256 *privkeyp,uint8_t odd_even); +bits256 bitcoin_schnorr_noncepair(void *ctx,uint8_t *pubnonce,bits256 txhash2,bits256 privkey); +int32_t bitcoin_schnorr_combine(void *ctx,uint8_t *sig64,uint8_t *allpub,uint8_t **sigs,int32_t n,bits256 txhash2); +int32_t bitcoin_schnorr_verify(void *ctx,uint8_t *sig64,bits256 txhash2,uint8_t *pubkey,int32_t plen); +int32_t iguana_parsevoutobj(struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvout *vout,cJSON *voutobj); +struct gecko_memtx *gecko_unspentfind(struct gecko_memtx ***ptrpp,struct iguana_info *virt,bits256 txid); +int64_t *gecko_valueptr(struct gecko_memtx *memtx,int32_t vout); +struct iguana_peer *iguana_peerfindipaddr(struct iguana_info *coin,char *ipaddr,int32_t needalive); +struct iguana_peer *iguana_peerfindipbits(struct iguana_info *coin,uint32_t ipbits,int32_t needalive); +int32_t basilisk_relays_send(struct supernet_info *myinfo,struct iguana_peer *addr); +int32_t basilisk_headers_send(struct supernet_info *myinfo,struct iguana_info *virt,struct iguana_peer *addr,bits256 *txids,int32_t num); #include "../includes/iguana_api.h" diff --git a/includes/iguana_structs.h b/includes/iguana_structs.h index 3a1146747..ef34b2e6f 100755 --- a/includes/iguana_structs.h +++ b/includes/iguana_structs.h @@ -16,6 +16,7 @@ #ifndef H_IGUANASTRUCTS_H #define H_IGUANASTRUCTS_H +#define IGUANA_MAXRELAYS 64 struct iguana_thread { @@ -136,7 +137,8 @@ struct iguana_msgtx struct iguana_msgvin *vins; struct iguana_msgvout *vouts; bits256 txid; - int32_t allocsize,timestamp; + int32_t allocsize,timestamp,numinputs,numoutputs; + int64_t inputsum,outputsum,txfee; } __attribute__((packed)); struct iguana_msgjoinsplit @@ -307,7 +309,7 @@ struct iguana_peer char ipaddr[64],lastcommand[16],coinname[64],symbol[64]; uint64_t pingnonce,totalsent,totalrecv,ipbits; double pingtime,sendmillis,pingsum,getdatamillis; uint32_t lastcontact,sendtime,ready,startsend,startrecv,pending,lastgotaddr,lastblockrecv,pendtime,lastflush,lastpoll,myipbits,persistent_peer,protover; - int32_t supernet,basilisk,dead,addrind,usock,lastheight,relayflag,numpackets,numpings,ipv6,height,rank,pendhdrs,pendblocks,recvhdrs,lastlefti,validpub,othervalid,dirty[2],laggard,headerserror,lastsent; + int32_t supernet,basilisk,dead,addrind,usock,lastheight,relayflag,numpackets,numpings,ipv6,height,rank,pendhdrs,pendblocks,recvhdrs,lastlefti,validpub,othervalid,dirty[2],laggard,headerserror,lastsent,isrelay; double recvblocks,recvtotal; int64_t allocated,freed; bits256 RThashes[IGUANA_MAXBUNDLESIZE]; int32_t numRThashes; @@ -414,7 +416,7 @@ struct iguana_info double txidfind_totalmillis,txidfind_num,spendtxid_totalmillis,spendtxid_num; struct iguana_monitorinfo monitoring[256]; struct gecko_sequences SEQ; - struct iguana_blocks blocks; void *mempool; + struct iguana_blocks blocks; void *mempool; void *mempools[IGUANA_MAXRELAYS]; }; struct vin_signer { bits256 privkey; char coinaddr[64]; uint8_t siglen,sig[80],rmd160[20],pubkey[66]; }; @@ -468,6 +470,7 @@ struct supernet_info void *ctx; // compatibility bits256 pangea_category,instantdex_category; + uint32_t relaybits[IGUANA_MAXRELAYS]; struct basilisk_relay relays[IGUANA_MAXRELAYS]; int32_t numrelays; }; #endif