diff --git a/src/Makefile.am b/src/Makefile.am index 303ba17fa..6152ffb40 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,7 +31,7 @@ LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBBITCOIN_UNIVALUE=univalue/libbitcoin_univalue.a LIBBITCOINQT=qt/libbitcoinqt.a LIBSECP256K1=secp256k1/libsecp256k1.la -LIBZCASH=libzcash.a +LIBZCASH=libzcash.a -lcurl $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) diff --git a/src/cJSON.c b/src/cJSON.c new file mode 100755 index 000000000..43aec68bf --- /dev/null +++ b/src/cJSON.c @@ -0,0 +1,1136 @@ + +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ + +/* cJSON */ +/* JSON parser in C. */ +#include + +#include "cJSON.h" + +#ifndef DBL_EPSILON +#define DBL_EPSILON 2.2204460492503131E-16 +#endif + +static const char *ep; + +long stripquotes(char *str) +{ + long len,offset; + if ( str == 0 ) + return(0); + len = strlen(str); + if ( str[0] == '"' && str[len-1] == '"' ) + str[len-1] = 0, offset = 1; + else offset = 0; + return(offset); +} + +const char *cJSON_GetErrorPtr(void) {return ep;} + +static int32_t cJSON_strcasecmp(const char *s1,const char *s2) +{ + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; + for(; tolower((int32_t)(*s1)) == tolower((int32_t)(*s2)); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower((int32_t)(*(const unsigned char *)s1)) - tolower((int32_t)(*(const unsigned char *)s2)); +} + +static void *(*cJSON_malloc)(size_t sz) = malloc; +static void (*cJSON_free)(void *ptr) = free; + +static char* cJSON_strdup(const char* str) +{ + size_t len; + char* copy; + + len = strlen(str) + 1; + if (!(copy = (char*)cJSON_malloc(len+1))) return 0; + memcpy(copy,str,len); + return copy; +} + +void cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (!hooks) { /* Reset hooks */ + cJSON_malloc = malloc; + cJSON_free = free; + return; + } + + cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; + cJSON_free = (hooks->free_fn)?hooks->free_fn:free; +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(void) +{ + cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); + if (node) memset(node,0,sizeof(cJSON)); + return node; +} + +/* Delete a cJSON structure. */ +void cJSON_Delete(cJSON *c) +{ + cJSON *next; + while (c) + { + next=c->next; + if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); + if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); + if (c->string) cJSON_free(c->string); + cJSON_free(c); + c=next; + } +} + +/* Parse the input text to generate a number, and populate the result into item. */ +static const char *parse_number(cJSON *item,const char *num) +{ + double n=0,sign=1,scale=0;int32_t subscale=0,signsubscale=1; + + if (*num=='-') sign=-1,num++; /* Has sign? */ + if (*num=='0') num++; /* is zero */ + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ + if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='e' || *num=='E') /* Exponent? */ + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ + } + + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ + + item->valuedouble=n; + item->valueint=(int64_t)n; + item->type=cJSON_Number; + return num; +} + +/* Render the number nicely from the given item into a string. */ +static char *print_number(cJSON *item) +{ + char *str; + double d = item->valuedouble; + if ( fabs(((double)item->valueint) - d) <= DBL_EPSILON && d >= (1. - DBL_EPSILON) && d < (1LL << 62) )//d <= INT_MAX && d >= INT_MIN ) + { + str = (char *)cJSON_malloc(24); /* 2^64+1 can be represented in 21 chars + sign. */ + if ( str != 0 ) + sprintf(str,"%lld",(long long)item->valueint); + } + else + { + str = (char *)cJSON_malloc(66); /* This is a nice tradeoff. */ + if ( str != 0 ) + { + if ( fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60 ) + sprintf(str,"%.0f",d); + //else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else + sprintf(str,"%.8f",d); + } + } + return str; +} + +static unsigned parse_hex4(const char *str) +{ + unsigned h=0; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + return h; +} + +/* Parse the input text into an unescaped cstring, and populate item. */ +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const char *parse_string(cJSON *item,const char *str) +{ + const char *ptr=str+1;char *ptr2;char *out;int32_t len=0;unsigned uc,uc2; + if (*str!='\"') {ep=str;return 0;} /* not a string! */ + + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes + + out=(char*)cJSON_malloc(len+2); /* This is how long we need for the string, roughly. */ + if (!out) return 0; + + ptr=str+1;ptr2=out; + while (*ptr!='\"' && *ptr) + { + if (*ptr!='\\') + { + if ( *ptr == '%' && is_hexstr((char *)&ptr[1],2) && isprint(_decode_hex((char *)&ptr[1])) != 0 ) + *ptr2++ = _decode_hex((char *)&ptr[1]), ptr += 3; + else *ptr2++ = *ptr++; + } + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++='\b'; break; + case 'f': *ptr2++='\f'; break; + case 'n': *ptr2++='\n'; break; + case 'r': *ptr2++='\r'; break; + case 't': *ptr2++='\t'; break; + case 'u': // transcode utf16 to utf8 + uc=parse_hex4(ptr+1);ptr+=4; // get the unicode char + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid + + if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs + { + if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. + uc2=parse_hex4(ptr+3);ptr+=6; + if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate + uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); + } + + len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; + + switch (len) { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 1: *--ptr2 =(uc | firstByteMark[len]); + } + ptr2+=len; + break; + default: *ptr2++=*ptr; break; + } + ptr++; + } + } + *ptr2=0; + if (*ptr=='\"') ptr++; + item->valuestring=out; + item->type=cJSON_String; + return ptr; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static char *print_string_ptr(const char *str) +{ + const char *ptr;char *ptr2,*out;int32_t len=0;unsigned char token; + + if (!str) return cJSON_strdup(""); + ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} + + out=(char*)cJSON_malloc(len+3+1); + if (!out) return 0; + + ptr2=out;ptr=str; + *ptr2++='\"'; + while (*ptr) + { + if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (token=*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ + } + } + } + *ptr2++='\"';*ptr2++=0; + return out; +} +/* Invote print_string_ptr (which is useful) on an item. */ +static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} + +/* Predeclare these prototypes. */ +static const char *parse_value(cJSON *item,const char *value); +static char *print_value(cJSON *item,int32_t depth,int32_t fmt); +static const char *parse_array(cJSON *item,const char *value); +static char *print_array(cJSON *item,int32_t depth,int32_t fmt); +static const char *parse_object(cJSON *item,const char *value); +static char *print_object(cJSON *item,int32_t depth,int32_t fmt); + +/* Utility to jump whitespace and cr/lf */ +static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} + +/* Parse an object - create a new root, and populate. */ +cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int32_t require_null_terminated) +{ + const char *end=0; + cJSON *c=cJSON_New_Item(); + ep=0; + if (!c) return 0; /* memory fail */ + + end=parse_value(c,skip(value)); + if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} + if (return_parse_end) *return_parse_end=end; + return c; +} +/* Default options for cJSON_Parse */ +cJSON *cJSON_Parse(const char *value) +{ + return(cJSON_ParseWithOpts(value,0,0)); +} + +/* Render a cJSON item/entity/structure to text. */ +char *cJSON_Print(cJSON *item) +{ + return(print_value(item,0,1)); +} +char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} + +/* Parser core - when encountering text, process appropriately. */ +static const char *parse_value(cJSON *item,const char *value) +{ + if (!value) return 0; /* Fail on null. */ + if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } + if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } + if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } + if (*value=='\"') { return parse_string(item,value); } + if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } + if (*value=='[') { return parse_array(item,value); } + if (*value=='{') { return parse_object(item,value); } + + ep=value;return 0; /* failure. */ +} + +/* Render a value to text. */ +static char *print_value(cJSON *item,int32_t depth,int32_t fmt) +{ + char *out=0; + if (!item) return 0; + switch ((item->type)&255) + { + case cJSON_NULL: out=cJSON_strdup("null"); break; + case cJSON_False: out=cJSON_strdup("false");break; + case cJSON_True: out=cJSON_strdup("true"); break; + case cJSON_Number: out=print_number(item);break; + case cJSON_String: out=print_string(item);break; + case cJSON_Array: out=print_array(item,depth,fmt);break; + case cJSON_Object: out=print_object(item,depth,fmt);break; + } + return out; +} + +/* Build an array from input text. */ +static const char *parse_array(cJSON *item,const char *value) +{ + cJSON *child; + if (*value!='[') {ep=value;return 0;} /* not an array! */ + + item->type=cJSON_Array; + value=skip(value+1); + if (*value==']') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; /* memory fail */ + value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_value(child,skip(value+1))); + if (!value) return 0; /* memory fail */ + } + + if (*value==']') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an array to text */ +static char *print_array(cJSON *item,int32_t depth,int32_t fmt) +{ + char **entries; + char *out=0,*ptr,*ret;int32_t len=5; + cJSON *child=item->child; + int32_t numentries=0,i=0,fail=0; + + /* How many entries in the array? */ + while (child) numentries++,child=child->next; + /* Explicitly handle numentries==0 */ + if (!numentries) + { + out=(char*)cJSON_malloc(3+1); + if (out) strcpy(out,"[]"); + return out; + } + /* Allocate an array to hold the values for each */ + entries=(char**)cJSON_malloc((1+numentries)*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + /* Retrieve all the results: */ + child=item->child; + while (child && !fail) + { + ret=print_value(child,depth+1,fmt); + entries[i++]=ret; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; + child=child->next; + } + + /* If we didn't fail, try to malloc the output string */ + if (!fail) out=(char*)cJSON_malloc(len+1); + /* If that fails, we fail. */ + if (!out) fail=1; + + /* Handle failure. */ + if (fail) + { + for (i=0;itype=cJSON_Object; + value=skip(value+1); + if (*value=='}') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; + value=skip(parse_string(child,skip(value))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_string(child,skip(value+1))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + } + + if (*value=='}') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an object to text. */ +static char *print_object(cJSON *item,int32_t depth,int32_t fmt) +{ + char **entries=0,**names=0; + char *out=0,*ptr,*ret,*str;int32_t len=7,i=0,j; + cJSON *child=item->child,*firstchild; + int32_t numentries=0,fail=0; + // Count the number of entries + firstchild = child; + while ( child ) + { + numentries++; + child = child->next; + if ( child == firstchild ) + { + printf("cJSON infinite loop detected\n"); + break; + } + } + /* Explicitly handle empty object case */ + if (!numentries) + { + out=(char*)cJSON_malloc(fmt?depth+4+1:3+1); + if (!out) return 0; + ptr=out;*ptr++='{'; + if (fmt) {*ptr++='\n';for (i=0;ichild;depth++;if (fmt) len+=depth; + while ( child ) + { + names[i]=str=print_string_ptr(child->string); + entries[i++]=ret=print_value(child,depth,fmt); + if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; + child=child->next; + if ( child == firstchild ) + break; + } + + /* Try to allocate the output string */ + if (!fail) out=(char*)cJSON_malloc(len+1); + if (!out) fail=1; + + /* Handle failure */ + if (fail) + { + for (i=0;ichild;int32_t i=0;while(c)i++,c=c->next;return i;} +cJSON *cJSON_GetArrayItem(cJSON *array,int32_t item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} +/* Utility for handling references. */ +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} + +/* Add item to array/object. */ +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} +void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} + +cJSON *cJSON_DetachItemFromArray(cJSON *array,int32_t which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; + if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} +void cJSON_DeleteItemFromArray(cJSON *array,int32_t which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int32_t i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} + +/* Replace array/object items with new ones. */ +void cJSON_ReplaceItemInArray(cJSON *array,int32_t which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; + newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; + if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} +void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int32_t i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} + +/* Create basic types: */ +cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateBool(int32_t b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} +cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int64_t)num;}return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} + +/* Create Arrays: */ +cJSON *cJSON_CreateIntArray(int64_t *numbers,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(float *numbers,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(double *numbers,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(char **strings,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} + +/* Duplication */ +cJSON *cJSON_Duplicate(cJSON *item,int32_t recurse) +{ + cJSON *newitem,*cptr,*nptr=0,*newchild; + /* Bail on bad ptr */ + if (!item) return 0; + /* Create new item */ + newitem=cJSON_New_Item(); + if (!newitem) return 0; + /* Copy over all vars */ + newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; + if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} + if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} + /* If non-recursive, then we're done! */ + if (!recurse) return newitem; + /* Walk the ->next chain for the child. */ + cptr=item->child; + while (cptr) + { + newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) {cJSON_Delete(newitem);return 0;} + if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ + cptr=cptr->next; + } + return newitem; +} + +void cJSON_Minify(char *json) +{ + char *into=json; + while (*json) + { + if (*json==' ') json++; + else if (*json=='\t') json++; // Whitespace characters. + else if (*json=='\r') json++; + else if (*json=='\n') json++; + else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line. + else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments. + else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive. + else *into++=*json++; // All other characters. + } + *into=0; // and null-terminate. +} + +// the following written by jl777 +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ + +void copy_cJSON(struct destbuf *dest,cJSON *obj) +{ + char *str; + int i; + long offset; + dest->buf[0] = 0; + if ( obj != 0 ) + { + str = cJSON_Print(obj); + if ( str != 0 ) + { + offset = stripquotes(str); + //strcpy(dest,str+offset); + for (i=0; ibuf[i]= str[offset+i]) == 0 ) + break; + dest->buf[i] = 0; + free(str); + } + } +} + +void copy_cJSON2(char *dest,int32_t maxlen,cJSON *obj) +{ + struct destbuf tmp; + maxlen--; + dest[0] = 0; + if ( maxlen > sizeof(tmp.buf) ) + maxlen = sizeof(tmp.buf); + copy_cJSON(&tmp,obj); + if ( strlen(tmp.buf) < maxlen ) + strcpy(dest,tmp.buf); + else dest[0] = 0; +} + +int64_t _get_cJSON_int(cJSON *json) +{ + struct destbuf tmp; + if ( json != 0 ) + { + copy_cJSON(&tmp,json); + if ( tmp.buf[0] != 0 ) + return(calc_nxt64bits(tmp.buf)); + } + return(0); +} + +int64_t get_cJSON_int(cJSON *json,char *field) +{ + cJSON *numjson; + if ( json != 0 ) + { + numjson = cJSON_GetObjectItem(json,field); + if ( numjson != 0 ) + return(_get_cJSON_int(numjson)); + } + return(0); +} + +int64_t conv_floatstr(char *numstr) +{ + double val,corr; + val = atof(numstr); + corr = (val < 0.) ? -0.50000000001 : 0.50000000001; + return((int64_t)(val * SATOSHIDEN + corr)); +} + +int64_t _conv_cJSON_float(cJSON *json) +{ + int64_t conv_floatstr(char *); + struct destbuf tmp; + if ( json != 0 ) + { + copy_cJSON(&tmp,json); + return(conv_floatstr(tmp.buf)); + } + return(0); +} + +int64_t conv_cJSON_float(cJSON *json,char *field) +{ + if ( json != 0 ) + return(_conv_cJSON_float(cJSON_GetObjectItem(json,field))); + return(0); +} + +int32_t extract_cJSON_str(char *dest,int32_t max,cJSON *json,char *field) +{ + int32_t safecopy(char *dest,char *src,long len); + char *str; + cJSON *obj; + int32_t len; + long offset; + dest[0] = 0; + obj = cJSON_GetObjectItem(json,field); + if ( obj != 0 ) + { + str = cJSON_Print(obj); + offset = stripquotes(str); + len = safecopy(dest,str+offset,max); + free(str); + return(len); + } + return(0); +} + +cJSON *gen_list_json(char **list) +{ + cJSON *array,*item; + array = cJSON_CreateArray(); + while ( list != 0 && *list != 0 && *list[0] != 0 ) + { + item = cJSON_CreateString(*list++); + cJSON_AddItemToArray(array,item); + } + return(array); +} + +uint64_t get_API_nxt64bits(cJSON *obj) +{ + uint64_t nxt64bits = 0; + struct destbuf tmp; + if ( obj != 0 ) + { + if ( is_cJSON_Number(obj) != 0 ) + return((uint64_t)obj->valuedouble); + copy_cJSON(&tmp,obj); + nxt64bits = calc_nxt64bits(tmp.buf); + } + return(nxt64bits); +} +uint64_t j64bits(cJSON *json,char *field) { if ( field == 0 ) return(get_API_nxt64bits(json)); return(get_API_nxt64bits(cJSON_GetObjectItem(json,field))); } +uint64_t j64bitsi(cJSON *json,int32_t i) { return(get_API_nxt64bits(cJSON_GetArrayItem(json,i))); } + +uint64_t get_satoshi_obj(cJSON *json,char *field) +{ + int32_t i,n; + uint64_t prev,satoshis,mult = 1; + struct destbuf numstr,checkstr; + cJSON *numjson; + numjson = cJSON_GetObjectItem(json,field); + copy_cJSON(&numstr,numjson); + satoshis = prev = 0; mult = 1; n = (int32_t)strlen(numstr.buf); + for (i=n-1; i>=0; i--,mult*=10) + { + satoshis += (mult * (numstr.buf[i] - '0')); + if ( satoshis < prev ) + printf("get_satoshi_obj numstr.(%s) i.%d prev.%llu vs satoshis.%llu\n",numstr.buf,i,(unsigned long long)prev,(unsigned long long)satoshis); + prev = satoshis; + } + sprintf(checkstr.buf,"%llu",(long long)satoshis); + if ( strcmp(checkstr.buf,numstr.buf) != 0 ) + { + printf("SATOSHI GREMLIN?? numstr.(%s) -> %.8f -> (%s)\n",numstr.buf,dstr(satoshis),checkstr.buf); + } + return(satoshis); +} + +void add_satoshis_json(cJSON *json,char *field,uint64_t satoshis) +{ + cJSON *obj; + char numstr[64]; + sprintf(numstr,"%lld",(long long)satoshis); + obj = cJSON_CreateString(numstr); + cJSON_AddItemToObject(json,field,obj); + if ( satoshis != get_satoshi_obj(json,field) ) + printf("error adding satoshi obj %ld -> %ld\n",(unsigned long)satoshis,(unsigned long)get_satoshi_obj(json,field)); +} + +char *cJSON_str(cJSON *json) +{ + if ( json != 0 && is_cJSON_String(json) != 0 ) + return(json->valuestring); + return(0); +} + +void jadd(cJSON *json,char *field,cJSON *item) { if ( json != 0 )cJSON_AddItemToObject(json,field,item); } +void jaddstr(cJSON *json,char *field,char *str) { if ( json != 0 && str != 0 ) cJSON_AddItemToObject(json,field,cJSON_CreateString(str)); } +void jaddnum(cJSON *json,char *field,double num) { if ( json != 0 )cJSON_AddItemToObject(json,field,cJSON_CreateNumber(num)); } +void jadd64bits(cJSON *json,char *field,uint64_t nxt64bits) { char numstr[64]; sprintf(numstr,"%llu",(long long)nxt64bits), jaddstr(json,field,numstr); } +void jaddi(cJSON *json,cJSON *item) { if ( json != 0 ) cJSON_AddItemToArray(json,item); } +void jaddistr(cJSON *json,char *str) { if ( json != 0 ) cJSON_AddItemToArray(json,cJSON_CreateString(str)); } +void jaddinum(cJSON *json,double num) { if ( json != 0 ) cJSON_AddItemToArray(json,cJSON_CreateNumber(num)); } +void jaddi64bits(cJSON *json,uint64_t nxt64bits) { char numstr[64]; sprintf(numstr,"%llu",(long long)nxt64bits), jaddistr(json,numstr); } +char *jstr(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(cJSON_str(json)); return(cJSON_str(cJSON_GetObjectItem(json,field))); } + +char *jstri(cJSON *json,int32_t i) { return(cJSON_str(cJSON_GetArrayItem(json,i))); } +char *jprint(cJSON *json,int32_t freeflag) +{ + char *str; + /*static portable_mutex_t mutex; static int32_t initflag; + if ( initflag == 0 ) + { + portable_mutex_init(&mutex); + initflag = 1; + }*/ + if ( json == 0 ) + return(clonestr((char *)"{}")); + //portable_mutex_lock(&mutex); + //usleep(5000); + str = cJSON_Print(json), _stripwhite(str,' '); + if ( freeflag != 0 ) + free_json(json); + //portable_mutex_unlock(&mutex); + return(str); +} + +bits256 get_API_bits256(cJSON *obj) +{ + bits256 hash; char *str; + memset(hash.bytes,0,sizeof(hash)); + if ( obj != 0 ) + { + if ( is_cJSON_String(obj) != 0 && (str= obj->valuestring) != 0 && strlen(str) == 64 ) + decode_hex(hash.bytes,sizeof(hash),str); + } + return(hash); +} +bits256 jbits256(cJSON *json,char *field) { if ( field == 0 ) return(get_API_bits256(json)); return(get_API_bits256(cJSON_GetObjectItem(json,field))); } +bits256 jbits256i(cJSON *json,int32_t i) { return(get_API_bits256(cJSON_GetArrayItem(json,i))); } +void jaddbits256(cJSON *json,char *field,bits256 hash) { char str[65]; bits256_str(str,hash), jaddstr(json,field,str); } +void jaddibits256(cJSON *json,bits256 hash) { char str[65]; bits256_str(str,hash), jaddistr(json,str); } + +char *get_cJSON_fieldname(cJSON *obj) +{ + if ( obj != 0 ) + { + if ( obj->child != 0 && obj->child->string != 0 ) + return(obj->child->string); + else if ( obj->string != 0 ) + return(obj->string); + } + return((char *)""); +} + +int32_t jnum(cJSON *obj,char *field) +{ + char *str; int32_t polarity = 1; + if ( field != 0 ) + obj = jobj(obj,field); + if ( obj != 0 ) + { + if ( is_cJSON_Number(obj) != 0 ) + return(obj->valuedouble); + else if ( is_cJSON_String(obj) != 0 && (str= jstr(obj,0)) != 0 ) + { + if ( str[0] == '-' ) + polarity = -1, str++; + return(polarity * (int32_t)calc_nxt64bits(str)); + } + } + return(0); +} + +void ensure_jsonitem(cJSON *json,char *field,char *value) +{ + cJSON *obj = cJSON_GetObjectItem(json,field); + if ( obj == 0 ) + cJSON_AddItemToObject(json,field,cJSON_CreateString(value)); + else cJSON_ReplaceItemInObject(json,field,cJSON_CreateString(value)); +} + +int32_t in_jsonarray(cJSON *array,char *value) +{ + int32_t i,n; + struct destbuf remote; + if ( array != 0 && is_cJSON_Array(array) != 0 ) + { + n = cJSON_GetArraySize(array); + for (i=0; i= range ) + x = (range - 1); + return((int32_t)x); +} + +int32_t get_API_int(cJSON *obj,int32_t val) +{ + struct destbuf buf; + if ( obj != 0 ) + { + if ( is_cJSON_Number(obj) != 0 ) + return((int32_t)obj->valuedouble); + copy_cJSON(&buf,obj); + val = myatoi(buf.buf,0); + if ( val < 0 ) + val = 0; + } + return(val); +} +int32_t jint(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(get_API_int(json,0)); return(get_API_int(cJSON_GetObjectItem(json,field),0)); } +int32_t jinti(cJSON *json,int32_t i) { if ( json == 0 ) return(0); return(get_API_int(cJSON_GetArrayItem(json,i),0)); } + +uint32_t get_API_uint(cJSON *obj,uint32_t val) +{ + struct destbuf buf; + if ( obj != 0 ) + { + if ( is_cJSON_Number(obj) != 0 ) + return((uint32_t)obj->valuedouble); + copy_cJSON(&buf,obj); + val = myatoi(buf.buf,0); + } + return(val); +} +uint32_t juint(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(get_API_uint(json,0)); return(get_API_uint(cJSON_GetObjectItem(json,field),0)); } +uint32_t juinti(cJSON *json,int32_t i) { if ( json == 0 ) return(0); return(get_API_uint(cJSON_GetArrayItem(json,i),0)); } + +double get_API_float(cJSON *obj) +{ + double val = 0.; + struct destbuf buf; + if ( obj != 0 ) + { + if ( is_cJSON_Number(obj) != 0 ) + return(obj->valuedouble); + copy_cJSON(&buf,obj); + val = atof(buf.buf); + } + return(val); +} + +double jdouble(cJSON *json,char *field) +{ + if ( json != 0 ) + { + if ( field == 0 ) + return(get_API_float(json)); + else return(get_API_float(cJSON_GetObjectItem(json,field))); + } else return(0.); +} + +double jdoublei(cJSON *json,int32_t i) +{ + if ( json != 0 ) + return(get_API_float(cJSON_GetArrayItem(json,i))); + else return(0.); +} + +cJSON *jobj(cJSON *json,char *field) { if ( json != 0 ) return(cJSON_GetObjectItem(json,field)); return(0); } + +void jdelete(cJSON *json,char *field) +{ + if ( jobj(json,field) != 0 ) + cJSON_DeleteItemFromObject(json,field); +} + +cJSON *jduplicate(cJSON *json) { return(cJSON_Duplicate(json,1)); } + +cJSON *jitem(cJSON *array,int32_t i) { if ( array != 0 && is_cJSON_Array(array) != 0 && cJSON_GetArraySize(array) > i ) return(cJSON_GetArrayItem(array,i)); return(0); } +cJSON *jarray(int32_t *nump,cJSON *json,char *field) +{ + cJSON *array; + if ( json != 0 ) + { + if ( field == 0 ) + array = json; + else array = cJSON_GetObjectItem(json,field); + if ( array != 0 && is_cJSON_Array(array) != 0 && (*nump= cJSON_GetArraySize(array)) > 0 ) + return(array); + } + *nump = 0; + return(0); +} + +int32_t expand_nxt64bits(char *NXTaddr,uint64_t nxt64bits) +{ + int32_t i,n; + uint64_t modval; + char rev[64]; + for (i=0; nxt64bits!=0; i++) + { + modval = nxt64bits % 10; + rev[i] = (char)(modval + '0'); + nxt64bits /= 10; + } + n = i; + for (i=0; i= 22 ) + { + printf("calc_nxt64bits: illegal NXTaddr.(%s) too long\n",NXTaddr); + return(0); + } + else if ( strcmp(NXTaddr,"0") == 0 || strcmp(NXTaddr,"false") == 0 ) + { + // printf("zero address?\n"); getchar(); + return(0); + } + if ( NXTaddr[0] == '-' ) + polarity = -1, NXTaddr++, n--; + mult = 1; + lastval = 0; + for (i=n-1; i>=0; i--,mult*=10) + { + c = NXTaddr[i]; + if ( c < '0' || c > '9' ) + { + printf("calc_nxt64bits: illegal char.(%c %d) in (%s).%d\n",c,c,NXTaddr,(int32_t)i); +#ifdef __APPLE__ + //while ( 1 ) + { + //sleep(60); + printf("calc_nxt64bits: illegal char.(%c %d) in (%s).%d\n",c,c,NXTaddr,(int32_t)i); + } +#endif + return(0); + } + nxt64bits += mult * (c - '0'); + if ( nxt64bits < lastval ) + printf("calc_nxt64bits: warning: 64bit overflow %llx < %llx\n",(long long)nxt64bits,(long long)lastval); + lastval = nxt64bits; + } + while ( *NXTaddr == '0' && *NXTaddr != 0 ) + NXTaddr++; + if ( cmp_nxt64bits(NXTaddr,nxt64bits) != 0 ) + printf("error calculating nxt64bits: %s -> %llx -> %s\n",NXTaddr,(long long)nxt64bits,nxt64str(nxt64bits)); + if ( polarity < 0 ) + return(-(int64_t)nxt64bits); + return(nxt64bits); +} + +cJSON *addrs_jsonarray(uint64_t *addrs,int32_t num) +{ + int32_t j; cJSON *array; + array = cJSON_CreateArray(); + for (j=0; j +#include +#include +#include +#include +#include +#include + +//#include "../crypto777/OS_portable.h" + +#define MAX_JSON_FIELD 4096 // on the big side + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* cJSON Types: */ +#define cJSON_False 0 +#define cJSON_True 1 +#define cJSON_NULL 2 +#define cJSON_Number 3 +#define cJSON_String 4 +#define cJSON_Array 5 +#define cJSON_Object 6 + +#define is_cJSON_Null(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_NULL) +#define is_cJSON_Array(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Array) +#define is_cJSON_String(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_String) +#define is_cJSON_Number(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Number) +#define is_cJSON_Object(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Object) +#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True) +#define is_cJSON_False(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_False) + +#define cJSON_IsReference 256 + + /* The cJSON structure: */ + typedef struct cJSON { + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + + int32_t type; /* The type of the item, as above. */ + + char *valuestring; /* The item's string, if type==cJSON_String */ + int64_t valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ + + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + } cJSON; + + typedef struct cJSON_Hooks { + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); + } cJSON_Hooks; + + /* Supply malloc, realloc and free functions to cJSON */ + extern void cJSON_InitHooks(cJSON_Hooks* hooks); + + + /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ + extern cJSON *cJSON_Parse(const char *value); + /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ + extern char *cJSON_Print(cJSON *item); + /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ + extern char *cJSON_PrintUnformatted(cJSON *item); + /* Delete a cJSON entity and all subentities. */ + extern void cJSON_Delete(cJSON *c); + + /* Returns the number of items in an array (or object). */ + extern int cJSON_GetArraySize(cJSON *array); + /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ + extern cJSON *cJSON_GetArrayItem(cJSON *array,int32_t item); + /* Get item "string" from object. Case insensitive. */ + extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); + + /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ + extern const char *cJSON_GetErrorPtr(void); + + /* These calls create a cJSON item of the appropriate type. */ + extern cJSON *cJSON_CreateNull(void); + extern cJSON *cJSON_CreateTrue(void); + extern cJSON *cJSON_CreateFalse(void); + extern cJSON *cJSON_CreateBool(int32_t b); + extern cJSON *cJSON_CreateNumber(double num); + extern cJSON *cJSON_CreateString(const char *string); + extern cJSON *cJSON_CreateArray(void); + extern cJSON *cJSON_CreateObject(void); + + /* These utilities create an Array of count items. */ + extern cJSON *cJSON_CreateIntArray(int64_t *numbers,int32_t count); + extern cJSON *cJSON_CreateFloatArray(float *numbers,int32_t count); + extern cJSON *cJSON_CreateDoubleArray(double *numbers,int32_t count); + extern cJSON *cJSON_CreateStringArray(char **strings,int32_t count); + + /* Append item to the specified array/object. */ + extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); + extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); + /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ + extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); + extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); + + /* Remove/Detatch items from Arrays/Objects. */ + extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int32_t which); + extern void cJSON_DeleteItemFromArray(cJSON *array,int32_t which); + extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); + extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); + + /* Update array items. */ + extern void cJSON_ReplaceItemInArray(cJSON *array,int32_t which,cJSON *newitem); + extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); + + /* Duplicate a cJSON item */ + extern cJSON *cJSON_Duplicate(cJSON *item,int32_t recurse); + /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + need to be released. With recurse!=0, it will duplicate any children connected to the item. + The item->next and ->prev pointers are always zero on return from Duplicate. */ + + /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ + extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int32_t require_null_terminated); + + extern void cJSON_Minify(char *json); + + /* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + + struct destbuf { char buf[MAX_JSON_FIELD]; }; + + /* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) +#define jfieldstr get_cJSON_fieldname + + char *cJSON_str(cJSON *json); + char *jstr(cJSON *json,char *field); + char *jprint(cJSON *json,int32_t freeflag); + int32_t jint(cJSON *json,char *field); + uint32_t juint(cJSON *json,char *field); + char *jstri(cJSON *json,int32_t i); + int32_t jinti(cJSON *json,int32_t i); + uint32_t juinti(cJSON *json,int32_t i); + uint64_t j64bitsi(cJSON *json,int32_t i); + double jdoublei(cJSON *json,int32_t i); + double jdouble(cJSON *json,char *field); + cJSON *jobj(cJSON *json,char *field); + cJSON *jarray(int32_t *nump,cJSON *json,char *field); + cJSON *jitem(cJSON *array,int32_t i); + uint64_t j64bits(cJSON *json,char *field); + void jadd(cJSON *json,char *field,cJSON *item); + void jaddstr(cJSON *json,char *field,char *str); + void jaddnum(cJSON *json,char *field,double num); + void jadd64bits(cJSON *json,char *field,uint64_t nxt64bits); + void jaddi(cJSON *json,cJSON *item); + void jaddistr(cJSON *json,char *str); + void jaddinum(cJSON *json,double num); + void jaddi64bits(cJSON *json,uint64_t nxt64bits); + void jdelete(cJSON *object,char *string); + cJSON *jduplicate(cJSON *json); + int32_t jnum(cJSON *obj,char *field); + + bits256 jbits256(cJSON *json,char *field); + bits256 jbits256i(cJSON *json,int32_t i); + void jaddbits256(cJSON *json,char *field,bits256 hash); + void jaddibits256(cJSON *json,bits256 hash); + void copy_cJSON(struct destbuf *dest,cJSON *obj); + void copy_cJSON2(char *dest,int32_t maxlen,cJSON *obj); + cJSON *gen_list_json(char **list); + int32_t extract_cJSON_str(char *dest,int32_t max,cJSON *json,char *field); + + void free_json(cJSON *json); + int64_t _conv_cJSON_float(cJSON *json); + int64_t conv_cJSON_float(cJSON *json,char *field); + int64_t get_cJSON_int(cJSON *json,char *field); + void add_satoshis_json(cJSON *json,char *field,uint64_t satoshis); + uint64_t get_satoshi_obj(cJSON *json,char *field); + + int32_t get_API_int(cJSON *obj,int32_t val); + uint32_t get_API_uint(cJSON *obj,uint32_t val); + uint64_t get_API_nxt64bits(cJSON *obj); + double get_API_float(cJSON *obj); + char *get_cJSON_fieldname(cJSON *obj); + void ensure_jsonitem(cJSON *json,char *field,char *value); + int32_t in_jsonarray(cJSON *array,char *value); + char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params); + uint64_t calc_nxt64bits(const char *str); + int32_t expand_nxt64bits(char *str,uint64_t nxt64bits); + char *nxt64str(uint64_t nxt64bits); + char *nxt64str2(uint64_t nxt64bits); + cJSON *addrs_jsonarray(uint64_t *addrs,int32_t num); + int32_t myatoi(char *str,int32_t range); + + char *stringifyM(char *str); +#define replace_backslashquotes unstringify + char *unstringify(char *str); +#define jtrue cJSON_CreateTrue +#define jfalse cJSON_CreateFalse + +#define jfieldname get_cJSON_fieldname + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/komodo.h b/src/komodo.h index f7dc35ea1..b348f70e0 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -22,26 +22,33 @@ #include #include #include -#include "komodo_utils.h" -int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals); +void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t kheight,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout); void komodo_init(); int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp); +char *komodo_issuemethod(char *method,char *params,uint16_t port); -int32_t NOTARIZED_HEIGHT,Num_nutxos; +int32_t ASSETCHAINS_SHORTFLAG,NOTARIZED_HEIGHT,Num_nutxos,KMDHEIGHT = 43000; uint256 NOTARIZED_HASH,NOTARIZED_DESTTXID; pthread_mutex_t komodo_mutex; +uint32_t KOMODO_INITDONE; +char KMDUSERPASS[1024]; uint16_t BITCOIND_PORT = 7771; +uint64_t KOMODO_DEPOSIT,PENDING_KOMODO_TX; +#include "komodo_utils.h" +queue_t DepositsQ,PendingsQ; + +#include "cJSON.c" #include "komodo_bitcoind.h" #include "komodo_interest.h" -#ifdef KOMODO_PAX #include "komodo_pax.h" -#endif #include "komodo_notary.h" +#include "komodo_gateway.h" -int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals) + +void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t KMDheight,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout) { - static FILE *fp; static int32_t errs,didinit; char fname[512]; int32_t ht,k,i,func; uint8_t num,pubkeys[64][33]; + static FILE *fp; static int32_t errs; char fname[512]; int32_t ht,func; uint8_t num,pubkeys[64][33]; #ifdef WIN32 sprintf(fname,"%s\\%s",GetDataDir(false).string().c_str(),(char *)"komodostate"); #else @@ -55,7 +62,7 @@ int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numno { if ( fread(&ht,1,sizeof(ht),fp) != sizeof(ht) ) errs++; - //printf("func.(%d %c) ht.%d\n",func,func,ht); + //printf("fpos.%ld func.(%d %c) ht.%d ",ftell(fp),func,func,ht); if ( func == 'P' ) { if ( (num= fgetc(fp)) < 64 ) @@ -93,11 +100,40 @@ int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numno errs++; komodo_nutxoadd(ht,nid,hash,mask,n); } + else if ( func == 'K' ) + { + int32_t kheight; + if ( fread(&kheight,1,sizeof(kheight),fp) != sizeof(kheight) ) + errs++; + if ( kheight > KMDHEIGHT ) + { + KMDHEIGHT = kheight; + } + //printf("ht.%d KMDHEIGHT <- %d\n",ht,kheight); + } + else if ( func == 'R' ) + { + uint16_t olen,v; uint64_t ovalue; uint256 txid; uint8_t opret[10000]; + if ( fread(&txid,1,sizeof(txid),fp) != sizeof(txid) ) + errs++; + if ( fread(&v,1,sizeof(v),fp) != sizeof(v) ) + errs++; + if ( fread(&ovalue,1,sizeof(ovalue),fp) != sizeof(ovalue) ) + errs++; + if ( fread(&olen,1,sizeof(olen),fp) != sizeof(olen) ) + errs++; + if ( olen < sizeof(opret) ) + { + if ( fread(opret,1,olen,fp) != olen ) + errs++; + komodo_opreturn(ht,ovalue,opret,olen,txid,v); + } else printf("illegal olen.%u\n",olen); + } else if ( func == 'D' ) { //printf("D[%d]\n",ht); } -#ifdef KOMODO_PAX +//#ifdef KOMODO_PAX else if ( func == 'V' ) { int32_t numpvals; uint32_t pvals[128]; @@ -108,14 +144,21 @@ int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numno //printf("load pvals ht.%d numpvals.%d\n",ht,numpvals); } else printf("error loading pvals[%d]\n",numpvals); } -#endif +//#endif else printf("illegal func.(%d %c)\n",func,func); } } else fp = fopen(fname,"wb+"); printf("fname.(%s) fpos.%ld\n",fname,ftell(fp)); + KOMODO_INITDONE = (uint32_t)time(NULL); + } + if ( height <= 0 ) + { + printf("early return: stateupdate height.%d\n",height); + return; } if ( fp != 0 ) // write out funcid, height, other fields, call side effect function { + //printf("fpos.%ld ",ftell(fp)); if ( height < 0 ) { height = -height; @@ -124,9 +167,37 @@ int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numno if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) ) errs++; } + else if ( KMDheight > 0 ) + { + fputc('K',fp); + if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) ) + errs++; + if ( fwrite(&KMDheight,1,sizeof(KMDheight),fp) != sizeof(KMDheight) ) + errs++; + //printf("ht.%d K %d\n",height,KMDheight); + } + else if ( opretbuf != 0 && opretlen > 0 ) + { + uint16_t olen = opretlen; + fputc('R',fp); + if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) ) + errs++; + if ( fwrite(&txhash,1,sizeof(txhash),fp) != sizeof(txhash) ) + errs++; + if ( fwrite(&vout,1,sizeof(vout),fp) != sizeof(vout) ) + errs++; + if ( fwrite(&opretvalue,1,sizeof(opretvalue),fp) != sizeof(opretvalue) ) + errs++; + if ( fwrite(&olen,1,sizeof(olen),fp) != olen ) + errs++; + if ( fwrite(opretbuf,1,olen,fp) != olen ) + errs++; + //printf("ht.%d R opret[%d]\n",height,olen); + komodo_opreturn(height,opretvalue,opretbuf,olen,txhash,vout); + } else if ( notarypubs != 0 && numnotaries > 0 ) { - //printf("func P[%d] errs.%d\n",numnotaries,errs); + //printf("ht.%d func P[%d] errs.%d\n",height,numnotaries,errs); fputc('P',fp); if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) ) errs++; @@ -137,7 +208,7 @@ int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numno } else if ( voutmask != 0 && numvouts > 0 ) { - //printf("func U %d %d errs.%d hashsize.%ld\n",numvouts,notaryid,errs,sizeof(txhash)); + //printf("ht.%d func U %d %d errs.%d hashsize.%ld\n",height,numvouts,notaryid,errs,sizeof(txhash)); fputc('U',fp); if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) ) errs++; @@ -149,22 +220,30 @@ int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numno errs++; komodo_nutxoadd(height,notaryid,txhash,voutmask,numvouts); } -#ifdef KOMODO_PAX +//#ifdef KOMODO_PAX else if ( pvals != 0 && numpvals > 0 ) { - fputc('V',fp); - if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) ) - errs++; - fputc(numpvals,fp); - if ( fwrite(pvals,sizeof(uint32_t),numpvals,fp) != numpvals ) - errs++; - komodo_pvals(height,pvals,numpvals); + int32_t i,nonz = 0; + for (i=0; i<32; i++) + if ( pvals[i] != 0 ) + nonz++; + if ( nonz >= 32 ) + { + fputc('V',fp); + if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) ) + errs++; + fputc(numpvals,fp); + if ( fwrite(pvals,sizeof(uint32_t),numpvals,fp) != numpvals ) + errs++; + komodo_pvals(height,pvals,numpvals); + //printf("ht.%d V numpvals[%d]\n",height,numpvals); + } //printf("save pvals height.%d numpvals.%d\n",height,numpvals); } -#endif +//#endif else if ( height != 0 ) { - //printf("func N ht.%d errs.%d\n",NOTARIZED_HEIGHT,errs); + //printf("ht.%d func N ht.%d errs.%d\n",height,NOTARIZED_HEIGHT,errs); fputc('N',fp); if ( fwrite(&height,1,sizeof(height),fp) != sizeof(height) ) errs++; @@ -180,9 +259,9 @@ int32_t komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numno } } -int32_t komodo_voutupdate(int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen,int32_t height,uint256 txhash,int32_t i,int32_t j,uint64_t *voutmaskp,int32_t *specialtxp,int32_t *notarizedheightp) +int32_t komodo_voutupdate(int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen,int32_t height,uint256 txhash,int32_t i,int32_t j,uint64_t *voutmaskp,int32_t *specialtxp,int32_t *notarizedheightp,uint64_t value) { - static uint256 zero; int32_t k,opretlen,nid,len = 0; uint256 kmdtxid,desttxid; uint8_t crypto777[33]; + static uint256 zero; int32_t opretlen,nid,len = 0; uint256 kmdtxid,desttxid; uint8_t crypto777[33]; if ( scriptlen == 35 && scriptbuf[0] == 33 && scriptbuf[34] == 0xac ) { decode_hex(crypto777,33,(char *)CRYPTO777_PUBSECPSTR); @@ -217,7 +296,7 @@ int32_t komodo_voutupdate(int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen, } } } - if ( j == 1 && scriptbuf[len++] == 0x6a ) + if ( scriptbuf[len++] == 0x6a ) { if ( (opretlen= scriptbuf[len++]) == 0x4c ) opretlen = scriptbuf[len++]; @@ -226,43 +305,55 @@ int32_t komodo_voutupdate(int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen, opretlen = scriptbuf[len++]; opretlen = (opretlen << 8) + scriptbuf[len++]; } - if ( opretlen >= 32*2+4 && strcmp(KOMODO_SOURCE,(char *)&scriptbuf[len+32*2+4]) == 0 ) + //for (k=0; k= 32*2+4 && strcmp(KOMODO_SOURCE,(char *)&scriptbuf[len+32*2+4]) == 0 ) { len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&kmdtxid); len += iguana_rwnum(0,&scriptbuf[len],4,(uint8_t *)notarizedheightp); len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&desttxid); - //for (k=0; k NOTARIZED_HEIGHT && *notarizedheightp < height ) { printf("ht.%d NOTARIZED.%d KMD.%s BTCTXID.%s (%s)\n",height,*notarizedheightp,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len]); NOTARIZED_HEIGHT = *notarizedheightp; NOTARIZED_HASH = kmdtxid; NOTARIZED_DESTTXID = desttxid; - komodo_stateupdate(height,0,0,0,zero,0,0,0,0); + komodo_stateupdate(height,0,0,0,zero,0,0,0,0,0,0,0,0,0); } else printf("reject ht.%d NOTARIZED.%d %s.%s DESTTXID.%s (%s)\n",height,*notarizedheightp,KOMODO_SOURCE,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len]); } -#ifdef KOMODO_PAX - else if ( i == 0 && scriptbuf[len] == 'P' ) - { - double KMDBTC,BTCUSD,CNYUSD; uint32_t numpvals,timestamp,pvals[128]; - numpvals = dpow_readprices(&scriptbuf[++len],×tamp,&KMDBTC,&BTCUSD,&CNYUSD,pvals); - komodo_stateupdate(height,0,0,0,zero,0,0,pvals,numpvals); - //printf("vout OP_RETURN.%d prices numpvals.%d opretlen.%d\n",height,numpvals,opretlen); - } -#endif + else if ( i == 0 && j == 1 && opretlen == 149 ) + komodo_paxpricefeed(height,&scriptbuf[len],opretlen); + else komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,value,&scriptbuf[len],opretlen,j); } return(notaryid); } +int32_t komodo_isratify(int32_t isspecial,int32_t numvalid) +{ + if ( isspecial != 0 && numvalid > 13 ) + return(1); + else return(0); +} + +// Special tx have vout[0] -> CRYPTO777 +// with more than 13 pay2pubkey outputs -> ratify +// if all outputs to notary -> notary utxo +// if txi == 0 && 2 outputs and 2nd OP_RETURN, len == 32*2+4 -> notarized, 1st byte 'P' -> pricefeed +// OP_RETURN: 'D' -> deposit, 'W' -> withdraw + void komodo_connectblock(CBlockIndex *pindex,CBlock& block) { - static int32_t didinit; - char *scriptstr,*opreturnstr; uint64_t signedmask,voutmask; + uint64_t signedmask,voutmask; uint8_t scriptbuf[4096],pubkeys[64][33]; uint256 kmdtxid,btctxid,txhash; - int32_t i,j,k,numvalid,specialtx,notarizedheight,notaryid,len,numvouts,numvins,height,txn_count,flag; + int32_t i,j,k,numvalid,specialtx,notarizedheight,notaryid,len,numvouts,numvins,height,txn_count; komodo_init(); + KOMODO_INITDONE = (uint32_t)time(NULL); +#ifdef KOMODO_ISSUER + komodo_gateway_issuer(); +#else + komodo_gateway_redeemer(); +#endif if ( pindex != 0 ) { height = pindex->nHeight; @@ -278,8 +369,13 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) len = block.vtx[i].vout[j].scriptPubKey.size(); if ( len <= sizeof(scriptbuf) ) { +#ifdef KOMODO_ZCASH memcpy(scriptbuf,block.vtx[i].vout[j].scriptPubKey.data(),len); - notaryid = komodo_voutupdate(notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,¬arizedheight); +#else + memcpy(scriptbuf,(uint8_t *)&block.vtx[i].vout[j].scriptPubKey[0],len); +#endif + // signedmask is needed here! + notaryid = komodo_voutupdate(notaryid,scriptbuf,len,height,txhash,i,j,&voutmask,&specialtx,¬arizedheight,(uint64_t)block.vtx[i].vout[j].nValue); if ( 0 && i > 0 ) { for (k=0; k= 0 && notaryid < 64 && voutmask != 0 ) { - komodo_stateupdate(height,0,0,notaryid,txhash,voutmask,numvouts,0,0); + komodo_stateupdate(height,0,0,notaryid,txhash,voutmask,numvouts,0,0,0,0,0,0,0); //komodo_nutxoadd(height,notaryid,txhash,voutmask,numvouts); } signedmask = 0; @@ -314,7 +410,11 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) len = block.vtx[i].vout[j].scriptPubKey.size(); if ( len <= sizeof(scriptbuf) ) { +#ifdef KOMODO_ZCASH memcpy(scriptbuf,block.vtx[i].vout[j].scriptPubKey.data(),len); +#else + memcpy(scriptbuf,(uint8_t *)&block.vtx[i].vout[j].scriptPubKey[0],len); +#endif if ( len == 35 && scriptbuf[0] == 33 && scriptbuf[34] == 0xac ) { memcpy(pubkeys[numvalid++],scriptbuf+1,33); @@ -324,16 +424,17 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) } } } - if ( numvalid > 13 ) + if ( komodo_isratify(1,numvalid) > 13 ) { memset(&txhash,0,sizeof(txhash)); - komodo_stateupdate(height,pubkeys,numvalid,0,txhash,0,0,0,0); + komodo_stateupdate(height,pubkeys,numvalid,0,txhash,0,0,0,0,0,0,0,0,0); } printf("new notaries.%d newheight.%d from height.%d\n",numvouts-1,KOMODO_PUBKEYS_HEIGHT(height),height); } } } } else printf("komodo_connectblock: unexpected null pindex\n"); + KOMODO_INITDONE = (uint32_t)time(NULL); } diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index e566ce84a..d46c4eca0 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -15,11 +15,345 @@ // komodo functions that interact with bitcoind C++ +#ifdef _WIN32 +#include +#include +#else +#include +#include +#endif + +struct MemoryStruct { char *memory; size_t size; }; +struct return_string { char *ptr; size_t len; }; + +// return data from the server +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) + + +/************************************************************************ + * + * Initialize the string handler so that it is thread safe + * + ************************************************************************/ + +void init_string(struct return_string *s) +{ + s->len = 0; + s->ptr = (char *)calloc(1,s->len+1); + if ( s->ptr == NULL ) + { + fprintf(stderr,"init_string malloc() failed\n"); + exit(-1); + } + s->ptr[0] = '\0'; +} + +/************************************************************************ + * + * Use the "writer" to accumulate text until done + * + ************************************************************************/ + +size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s) +{ + size_t new_len = s->len + size*nmemb; + s->ptr = (char *)realloc(s->ptr,new_len+1); + if ( s->ptr == NULL ) + { + fprintf(stderr, "accumulate realloc() failed\n"); + exit(-1); + } + memcpy(s->ptr+s->len,ptr,size*nmemb); + s->ptr[new_len] = '\0'; + s->len = new_len; + return(size * nmemb); +} + +/************************************************************************ + * + * return the current system time in milliseconds + * + ************************************************************************/ + +#define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field +#ifdef EXTRACT_BITCOIND_RESULT + +/************************************************************************ + * + * perform post processing of the results + * + ************************************************************************/ + +char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params) +{ + long i,j,len; char *retstr = 0; cJSON *json,*result,*error; + //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); + if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) + { + if ( strcmp(command,"signrawtransaction") != 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); + return(rpcstr); + } + json = cJSON_Parse(rpcstr); + if ( json == 0 ) + { + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params); + free(rpcstr); + return(0); + } + result = cJSON_GetObjectItem(json,"result"); + error = cJSON_GetObjectItem(json,"error"); + if ( error != 0 && result != 0 ) + { + if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL ) + { + retstr = cJSON_Print(result); + len = strlen(retstr); + if ( retstr[0] == '"' && retstr[len-1] == '"' ) + { + for (i=1,j=0; itype&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) + { + if ( strcmp(command,"signrawtransaction") != 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr); + } + free(rpcstr); + } else retstr = rpcstr; + free_json(json); + //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr); + return(retstr); +} +#endif + +/************************************************************************ + * + * perform the query + * + ************************************************************************/ + + +char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params) +{ + static int didinit,count,count2; static double elapsedsum,elapsedsum2; + struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle; + char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime; + if ( didinit == 0 ) + { + didinit = 1; + curl_global_init(CURL_GLOBAL_ALL); //init the curl session + } + numretries = 0; + if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) + specialcase = 1; + else specialcase = 0; + if ( url[0] == 0 ) + strcpy(url,"http://127.0.0.1:7876/nxt"); + if ( specialcase != 0 && 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params); +try_again: + if ( retstrp != 0 ) + *retstrp = 0; + starttime = OS_milliseconds(); + curl_handle = curl_easy_init(); + init_string(&s); + headers = curl_slist_append(0,"Expect:"); + + curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl_handle,CURLOPT_URL, url); + curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function + curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback + curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash + curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback + if ( strncmp(url,"https",5) == 0 ) + { + curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); + curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); + } + if ( userpass != 0 ) + curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); + databuf = 0; + if ( params != 0 ) + { + if ( command != 0 && specialcase == 0 ) + { + len = strlen(params); + if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) { + bracket0 = bracket1 = (char *)""; + } + else + { + bracket0 = (char *)"["; + bracket1 = (char *)"]"; + } + + databuf = (char *)malloc(256 + strlen(command) + strlen(params)); + sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1); + //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); + // + } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params); + curl_easy_setopt(curl_handle,CURLOPT_POST,1L); + if ( databuf != 0 ) + curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf); + else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params); + } + //laststart = milliseconds(); + res = curl_easy_perform(curl_handle); + curl_slist_free_all(headers); + curl_easy_cleanup(curl_handle); + if ( databuf != 0 ) // clean up temporary buffer + { + free(databuf); + databuf = 0; + } + if ( res != CURLE_OK ) + { + numretries++; + if ( specialcase != 0 ) + { + printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); + free(s.ptr); + return(0); + } + else if ( numretries >= 1 ) + { + //printf("Maximum number of retries exceeded!\n"); + free(s.ptr); + return(0); + } + printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); + free(s.ptr); + sleep((1< (%s)\n",params,s.ptr); + count2++; + elapsedsum2 += (OS_milliseconds() - starttime); + if ( (count2 % 10000) == 0) + printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command); + return(s.ptr); + } + } + printf("bitcoind_RPC: impossible case\n"); + free(s.ptr); + return(0); +} + +static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data) +{ + size_t realsize = (size * nmemb); + struct MemoryStruct *mem = (struct MemoryStruct *)data; + mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1)); + if ( mem->memory != 0 ) + { + if ( ptr != 0 ) + memcpy(&(mem->memory[mem->size]),ptr,realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + } + //printf("got %d bytes\n",(int32_t)(size*nmemb)); + return(realsize); +} + +char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) +{ + struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0; + if ( (cHandle= *cHandlep) == NULL ) + *cHandlep = cHandle = curl_easy_init(); + else curl_easy_reset(cHandle); + //#ifdef DEBUG + //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1); + //#endif + curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0); + //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1); + curl_easy_setopt(cHandle,CURLOPT_URL,url); + curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10); + if ( userpass != 0 && userpass[0] != 0 ) + curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass); + if ( postfields != 0 && postfields[0] != 0 ) + { + curl_easy_setopt(cHandle,CURLOPT_POST,1); + curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields); + } + if ( hdr0 != NULL && hdr0[0] != 0 ) + { + //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:""); + headers = curl_slist_append(headers,hdr0); + if ( hdr1 != 0 && hdr1[0] != 0 ) + headers = curl_slist_append(headers,hdr1); + if ( hdr2 != 0 && hdr2[0] != 0 ) + headers = curl_slist_append(headers,hdr2); + if ( hdr3 != 0 && hdr3[0] != 0 ) + headers = curl_slist_append(headers,hdr3); + } //headers = curl_slist_append(0,"Expect:"); + if ( headers != 0 ) + curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers); + //res = curl_easy_perform(cHandle); + memset(&chunk,0,sizeof(chunk)); + curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback); + curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk); + curl_easy_perform(cHandle); + curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code); + if ( headers != 0 ) + curl_slist_free_all(headers); + if ( code != 200 ) + printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory); + return(chunk.memory); +} + +char *komodo_issuemethod(char *method,char *params,uint16_t port) +{ + //static void *cHandle; + char url[512],*retstr=0,*retstr2=0,postdata[8192]; + if ( params == 0 || params[0] == 0 ) + params = (char *)"[]"; + if ( strlen(params) < sizeof(postdata)-128 ) + { + sprintf(url,(char *)"http://127.0.0.1:%u",port); + sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); + //printf("postdata.(%s) USERPASS.(%s)\n",postdata,KMDUSERPASS); + retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,KMDUSERPASS,method,params); + //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); + } + return(retstr2); +} +//curl --url "http://127.0.0.1:13033" --user "user1557335368:pass111720054" --data "{\"method\":\"getinfo\",\"params\":[]}" + uint32_t komodo_txtime(uint256 hash) { CTransaction tx; uint256 hashBlock; - if (!GetTransaction(hash, tx, hashBlock, true)) + if (!GetTransaction(hash, tx, +#ifndef KOMODO_ZCASH + Params().GetConsensus(), +#endif + hashBlock, true)) { //printf("null GetTransaction\n"); return(tx.nLockTime); @@ -33,13 +367,18 @@ void komodo_disconnect(CBlockIndex *pindex,CBlock& block) //uint256 zero; //printf("disconnect ht.%d\n",pindex->nHeight); //memset(&zero,0,sizeof(zero)); - //komodo_stateupdate(-pindex->nHeight,0,0,0,zero,0,0,0,0); + //komodo_stateupdate(-pindex->nHeight,0,0,0,zero,0,0,0,0,0,0,0); } int32_t komodo_block2height(CBlock *block) { - int32_t i,n,height = 0; uint8_t *ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data(); + int32_t i,n,height = 0; uint8_t *ptr; komodo_init(); +#ifdef KOMODO_ZCASH + ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data(); +#else + ptr = (uint8_t *)&block->vtx[0].vin[0].scriptSig[0]; +#endif if ( block->vtx[0].vin[0].scriptSig.size() > 5 ) { //for (i=0; i<6; i++) @@ -58,7 +397,11 @@ int32_t komodo_block2height(CBlock *block) void komodo_block2pubkey33(uint8_t *pubkey33,CBlock& block) { +#ifdef KOMODO_ZCASH uint8_t *ptr = (uint8_t *)block.vtx[0].vout[0].scriptPubKey.data(); +#else + uint8_t *ptr = (uint8_t *)&block.vtx[0].vout[0].scriptPubKey[0]; +#endif komodo_init(); memcpy(pubkey33,ptr+1,33); } @@ -70,7 +413,11 @@ void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height) memset(pubkey33,0,33); if ( pindex != 0 ) { - if ( ReadBlockFromDisk(block,(const CBlockIndex *)pindex) != 0 ) + if ( ReadBlockFromDisk(block,(const CBlockIndex *)pindex +#ifndef KOMODO_ZCASH + ,Params().GetConsensus() +#endif + ) != 0 ) { komodo_block2pubkey33(pubkey33,block); } diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h new file mode 100644 index 000000000..43b1c4bbe --- /dev/null +++ b/src/komodo_gateway.h @@ -0,0 +1,339 @@ +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ + +// paxdeposit equivalent in reverse makes opreturn and KMD does the same in reverse + +struct pax_transaction +{ + struct queueitem DL; + uint256 txid; + uint64_t komodoshis,fiatoshis; + uint16_t vout; + char symbol[4]; uint8_t rmd160[20],shortflag; +}; + +void komodo_gateway_deposits(CMutableTransaction& txNew) +{ + struct pax_transaction *ptr; uint8_t *script,opret[10000],data[10000]; int32_t i,len=0,opretlen=0,numvouts=1; + PENDING_KOMODO_TX = 0; + while ( (ptr= (struct pax_transaction *)queue_dequeue(&DepositsQ)) != 0 ) + { + txNew.vout.resize(numvouts+1); + txNew.vout[numvouts].nValue = ptr->fiatoshis; + txNew.vout[numvouts].scriptPubKey.resize(25); + script = (uint8_t *)&txNew.vout[numvouts].scriptPubKey[0]; + *script++ = 0x76; + *script++ = 0xa9; + *script++ = 20; + memcpy(script,ptr->rmd160,20), script += 20; + *script++ = 0x88; + *script++ = 0xac; + for (i=0; i<32; i++) + { + printf("%02x",((uint8_t *)&ptr->txid)[i]); + data[len++] = ((uint8_t *)&ptr->txid)[i]; + } + data[len++] = ptr->vout & 0xff; + data[len++] = (ptr->vout >> 8) & 0xff; + printf(" vout.%u DEPOSIT %.8f\n",ptr->vout,(double)KOMODO_DEPOSIT/COIN); + PENDING_KOMODO_TX += ptr->fiatoshis; + numvouts++; + queue_enqueue((char *)"PENDINGS",&PendingsQ,&ptr->DL); + } + if ( numvouts > 1 ) + { + opretlen = komodo_opreturnscript(opret,'I',data,len); + txNew.vout.resize(numvouts+1); + txNew.vout[numvouts].nValue = 0; + txNew.vout[numvouts].scriptPubKey.resize(opretlen); + script = (uint8_t *)&txNew.vout[numvouts].scriptPubKey[0]; + memcpy(script,opret,opretlen); + } + printf("total numvouts.%d %.8f\n",numvouts,dstr(PENDING_KOMODO_TX)); +} + +int32_t komodo_check_deposit(CBlock& block) +{ + return(0); +} + +void komodo_gateway_deposit(uint64_t value,int32_t shortflag,char *symbol,uint64_t fiatoshis,uint8_t *rmd160,uint256 txid,uint16_t vout) // assetchain context +{ + struct pax_transaction *ptr; + ptr = (struct pax_transaction *)calloc(1,sizeof(*ptr)); + ptr->komodoshis = value; + ptr->fiatoshis = fiatoshis; + memcpy(ptr->symbol,symbol,3); + memcpy(ptr->rmd160,rmd160,20); + ptr->shortflag = shortflag; + ptr->txid = txid; + ptr->vout = vout; + KOMODO_DEPOSIT += fiatoshis; + queue_enqueue((char *)"DEPOSITS",&DepositsQ,&ptr->DL); +} + +int32_t komodo_gateway_depositremove(uint256 txid,uint16_t vout) // assetchain context +{ + int32_t iter,n=0; queue_t *Q; struct pax_transaction *ptr; struct queueitem *item; + for (iter=0; iter<2; iter++) + { + Q = (iter == 0) ? &DepositsQ : &PendingsQ; + portable_mutex_lock(&Q->mutex); + if ( Q->list != 0 ) + { + item = &ptr->DL; + DL_FOREACH(Q->list,item) + { + ptr = (struct pax_transaction *)item; + if ( memcmp(&ptr->txid,&txid,sizeof(txid)) == 0 && ptr->vout == vout ) + { + if ( KOMODO_DEPOSIT >= ptr->fiatoshis ) + KOMODO_DEPOSIT -= ptr->fiatoshis; + else KOMODO_DEPOSIT = 0; + printf("DELETE %.8f DEPOSIT %s %.8f\n",dstr(ptr->komodoshis),ptr->symbol,dstr(ptr->fiatoshis)); + DL_DELETE(Q->list,&ptr->DL); + n++; + free(ptr); + break; + } + } + } + portable_mutex_unlock(&Q->mutex); + } + if ( queue_size(&DepositsQ) == 0 && queue_size(&PendingsQ) == 0 ) + KOMODO_DEPOSIT = PENDING_KOMODO_TX = 0; + return(n); +} + +const char *komodo_opreturn(int32_t height,uint64_t value,uint8_t *opretbuf,int32_t opretlen,uint256 txid,uint16_t vout) +{ + uint8_t rmd160[20],addrtype,shortflag,pubkey33[33]; int32_t i,j,len,tokomodo=0; char base[4],coinaddr[64],destaddr[64]; int64_t fiatoshis,checktoshis; const char *typestr = "unknown"; +#ifdef KOMODO_ISSUER + tokomodo = 1; +#endif + if ( opretbuf[0] == ((tokomodo != 0) ? 'D' : 'W') ) + { + if ( opretlen == 34 ) + { + memset(base,0,sizeof(base)); + PAX_pubkey(0,&opretbuf[1],&addrtype,rmd160,base,&shortflag,&fiatoshis); + if ( fiatoshis < 0 ) + fiatoshis = -fiatoshis; + bitcoin_address(coinaddr,addrtype,rmd160,20); + checktoshis = PAX_fiatdest(tokomodo,destaddr,pubkey33,coinaddr,height,base,fiatoshis); + for (i=0; i %s ",dstr(fiatoshis),shortflag!=0?'-':'+',base,coinaddr); + for (i=0; i<32; i++) + printf("%02x",((uint8_t *)&txid)[i]); + printf(" <- txid.v%u ",vout); + for (i=0; i<33; i++) + printf("%02x",pubkey33[i]); + printf(" checkpubkey check %.8f v %.8f dest.(%s)\n",dstr(checktoshis),dstr(value),destaddr); + typestr = "deposit"; +#ifdef KOMODO_ISSUER + if ( strncmp(KOMODO_SOURCE,base,strlen(base)) == 0 && value >= (9999*checktoshis)/10000 && shortflag == ASSETCHAINS_SHORTFLAG ) + { + komodo_gateway_deposit(value,shortflag,base,fiatoshis,rmd160,txid,vout); + } +#else + if ( tokomodo != 0 && value <= (10000*checktoshis)/9999 ) + { + + } +#endif + } + } + else + { + for (i=0; i= offset+32*2+4 && strcmp((char *)&script[offset+32*2+4],"KMD") == 0 ) + typestr = "notarized"; + else if ( txi == 0 && vout == 1 && opretlen == 149 ) + { + typestr = "pricefeed"; + komodo_paxpricefeed(height,&script[offset],opretlen); + //printf("height.%d pricefeed len.%d\n",height,opretlen); + } + else komodo_stateupdate(height,0,0,0,utxid,0,0,0,0,0,value,&script[offset],opretlen,vout); + } + else if ( numvouts > 13 ) + typestr = "ratify"; +} + +int32_t komodo_gateway_tx(char *symbol,int32_t height,int32_t txi,char *txidstr,uint32_t port) +{ + char *retstr,params[256],*hexstr; uint8_t script[10000]; cJSON *json,*result,*vouts,*item,*sobj; int32_t vout,n,len,isspecial,retval = -1; uint64_t value; bits256 txid; + sprintf(params,"[\"%s\", 1]",txidstr); + if ( (retstr= komodo_issuemethod((char *)"getrawtransaction",params,port)) != 0 ) + { + if ( (json= cJSON_Parse(retstr)) != 0 ) + { + if ( (result= jobj(json,(char *)"result")) != 0 && (vouts= jarray(&n,result,(char *)"vout")) != 0 ) + { + retval = 0; + isspecial = 0; + txid = jbits256(result,(char *)"txid"); + for (vout=0; vout> 1; + if ( vout == 0 && ((memcmp(&hexstr[2],CRYPTO777_PUBSECPSTR,66) == 0 && len == 35) || (memcmp(&hexstr[6],CRYPTO777_RMD160STR,40) == 0 && len == 25)) ) + isspecial = 1; + else if ( len <= sizeof(script) ) + { + decode_hex(script,len,hexstr); + komodo_gateway_voutupdate(symbol,isspecial,height,txi,txid,vout,n,value,script,len); + } + } + } + } + } + free_json(json); + } + free(retstr); + } + return(retval); +} + +int32_t komodo_gateway_block(char *symbol,int32_t height,uint16_t port) +{ + char *retstr,*retstr2,params[128],*txidstr; int32_t i,n,retval = -1; cJSON *json,*tx,*result,*result2; + sprintf(params,"[%d]",height); + if ( (retstr= komodo_issuemethod((char *)"getblockhash",params,port)) != 0 ) + { + if ( (result= cJSON_Parse(retstr)) != 0 ) + { + if ( (txidstr= jstr(result,(char *)"result")) != 0 && strlen(txidstr) == 64 ) + { + sprintf(params,"[\"%s\"]",txidstr); + if ( (retstr2= komodo_issuemethod((char *)"getblock",params,port)) != 0 ) + { + //printf("getblock.(%s)\n",retstr2); + if ( (json= cJSON_Parse(retstr2)) != 0 ) + { + if ( (result2= jobj(json,(char *)"result")) != 0 && (tx= jarray(&n,result2,(char *)"tx")) != 0 ) + { + for (i=0; inotaryid = notaryid; HASH_ADD_KEYPTR(hh,NUTXOS,&np->txhash,sizeof(np->txhash),np); printf("Add NUTXO[%d] <- %s notaryid.%d t%u %s %llx\n",Num_nutxos,Notaries[notaryid][0],notaryid,komodo_txtime(txhash),txhash.ToString().c_str(),(long long)voutmask); - //if ( addflag != 0 ) - // komodo_stateupdate(height,0,0,notaryid,txhash,voutmask,numvouts,0,0); Num_nutxos++; pthread_mutex_unlock(&komodo_mutex); } @@ -135,6 +133,8 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33) // -1 if not notary, 0 if notary, 1 if special notary struct knotary_entry *kp; int32_t numnotaries,modval = -1; *notaryidp = -1; + if ( height < 0 || height/KOMODO_ELECTION_GAP >= sizeof(Pubkeys)/sizeof(*Pubkeys) ) + return(-1); pthread_mutex_lock(&komodo_mutex); HASH_FIND(hh,Pubkeys[height/KOMODO_ELECTION_GAP].Notaries,pubkey33,33,kp); pthread_mutex_unlock(&komodo_mutex); @@ -198,6 +198,8 @@ void komodo_init() if ( didinit == 0 ) { didinit = 1; + iguana_initQ(&DepositsQ,(char *)"Deposits"); + iguana_initQ(&PendingsQ,(char *)"Pendings"); pthread_mutex_init(&komodo_mutex,NULL); decode_hex(NOTARY_PUBKEY33,33,(char *)NOTARY_PUBKEY.c_str()); n = (int32_t)(sizeof(Notaries)/sizeof(*Notaries)); @@ -209,6 +211,6 @@ void komodo_init() } komodo_notarysinit(0,pubkeys,k); memset(&zero,0,sizeof(zero)); - komodo_stateupdate(0,0,0,0,zero,0,0,0,0); + komodo_stateupdate(0,0,0,0,zero,0,0,0,0,0,0,0,0,0); } } diff --git a/src/komodo_pax.h b/src/komodo_pax.h index 5c8cdf88d..71d9178d8 100644 --- a/src/komodo_pax.h +++ b/src/komodo_pax.h @@ -71,20 +71,36 @@ void pax_rank(uint64_t *ranked,uint32_t *pvals) int32_t dpow_readprices(uint8_t *data,uint32_t *timestampp,double *KMDBTCp,double *BTCUSDp,double *CNYUSDp,uint32_t *pvals) { - uint32_t kmdbtc,btcusd,cnyusd; int32_t i,n,len = 0; + uint32_t kmdbtc,btcusd,cnyusd; int32_t i,n,nonz,len = 0; + if ( data[0] == 'P' && data[5] == 35 ) + data++; len += iguana_rwnum(0,&data[len],sizeof(uint32_t),(void *)timestampp); len += iguana_rwnum(0,&data[len],sizeof(uint32_t),(void *)&n); + if ( n != 35 ) + { + printf("dpow_readprices illegal n.%d\n",n); + return(-1); + } len += iguana_rwnum(0,&data[len],sizeof(uint32_t),(void *)&kmdbtc); // /= 1000 len += iguana_rwnum(0,&data[len],sizeof(uint32_t),(void *)&btcusd); // *= 1000 len += iguana_rwnum(0,&data[len],sizeof(uint32_t),(void *)&cnyusd); *KMDBTCp = ((double)kmdbtc / (1000000000. * 1000.)); *BTCUSDp = ((double)btcusd / (1000000000. / 1000.)); *CNYUSDp = ((double)cnyusd / 1000000000.); - for (i=0; i 0 ) { - for (i=0; i<32; i++) - printf("%u ",pvals[i]); - printf("t%u n.%d KMD %f BTC %f CNY %f (%f)\n",timestamp,n,KMDBTC,BTCUSD,CNYUSD,CNYUSD!=0?1./CNYUSD:0); - } - if ( timestamp > time(NULL)-600 ) - { - n = komodo_opreturnscript(opret,'P',data+sizeof(crc32),(int32_t)(fsize-sizeof(crc32))); if ( 0 && lastcrc != crc32 ) { - for (i=0; i time(NULL)-600 ) + { + n = komodo_opreturnscript(opret,'P',data+sizeof(crc32),(int32_t)(fsize-sizeof(crc32))); + if ( 0 && lastcrc != crc32 ) + { + for (i=0; i maxsize.%d or data[%d]\n",fsize,maxsize,(int32_t)sizeof(data)); @@ -153,14 +171,29 @@ int32_t komodo_pax_opreturn(uint8_t *opret,int32_t maxsize) return(val32); }*/ -int32_t PAX_pubkey(uint8_t *pubkey33,uint8_t addrtype,uint8_t rmd160[20],char fiat[4],uint8_t shortflag,int32_t fiatoshis) +int32_t PAX_pubkey(int32_t rwflag,uint8_t *pubkey33,uint8_t *addrtypep,uint8_t rmd160[20],char fiat[4],uint8_t *shortflagp,int64_t *fiatoshisp) { - memset(pubkey33,0,33); - pubkey33[0] = 0x02 | (shortflag != 0); - memcpy(&pubkey33[1],fiat,3); - iguana_rwnum(1,&pubkey33[4],sizeof(fiatoshis),(void *)&fiatoshis); - pubkey33[12] = addrtype; - memcpy(&pubkey33[13],rmd160,20); + if ( rwflag != 0 ) + { + memset(pubkey33,0,33); + pubkey33[0] = 0x02 | (*shortflagp != 0); + memcpy(&pubkey33[1],fiat,3); + iguana_rwnum(rwflag,&pubkey33[4],sizeof(*fiatoshisp),(void *)fiatoshisp); + pubkey33[12] = *addrtypep; + memcpy(&pubkey33[13],rmd160,20); + } + else + { + *shortflagp = (pubkey33[0] == 0x03); + memcpy(fiat,&pubkey33[1],3); + fiat[3] = 0; + iguana_rwnum(rwflag,&pubkey33[4],sizeof(*fiatoshisp),(void *)fiatoshisp); + if ( *shortflagp != 0 ) + *fiatoshisp = -(*fiatoshisp); + *addrtypep = pubkey33[12]; + memcpy(rmd160,&pubkey33[13],20); + } + return(33); } double PAX_val(uint32_t pval,int32_t baseid) @@ -173,7 +206,7 @@ double PAX_val(uint32_t pval,int32_t baseid) void komodo_pvals(int32_t height,uint32_t *pvals,uint8_t numpvals) { - int32_t i,nonz; double KMDBTC,BTCUSD,CNYUSD; uint32_t kmdbtc,btcusd,cnyusd; + int32_t i,nonz; uint32_t kmdbtc,btcusd,cnyusd; double KMDBTC,BTCUSD,CNYUSD; if ( numpvals >= 35 ) { for (nonz=i=0; i<32; i++) @@ -194,7 +227,8 @@ void komodo_pvals(int32_t height,uint32_t *pvals,uint8_t numpvals) PVALS[36 * NUM_PRICES] = height; memcpy(&PVALS[36 * NUM_PRICES + 1],pvals,sizeof(*pvals) * 35); NUM_PRICES++; - //printf("OP_RETURN.%d KMD %.8f BTC %.6f CNY %.6f NUM_PRICES.%d\n",height,KMDBTC,BTCUSD,CNYUSD,NUM_PRICES); + if ( 0 ) + printf("OP_RETURN.%d KMD %.8f BTC %.6f CNY %.6f NUM_PRICES.%d (%llu %llu %llu)\n",height,KMDBTC,BTCUSD,CNYUSD,NUM_PRICES,(long long)kmdbtc,(long long)btcusd,(long long)cnyusd); } } } @@ -214,7 +248,7 @@ int32_t komodo_baseid(char *origbase) uint64_t komodo_paxcalc(uint32_t *pvals,int32_t baseid,int32_t relid,uint64_t basevolume) { - uint32_t pvalb,pvalr,kmdbtc,btcusd; uint64_t usdvol,baseusd,usdkmd,baserel,sum,ranked[32]; int32_t i; + uint32_t pvalb,pvalr,kmdbtc,btcusd; uint64_t usdvol,baseusd,usdkmd,baserel,ranked[32]; if ( basevolume > 1000000*COIN ) return(0); if ( (pvalb= pvals[baseid]) != 0 ) @@ -252,7 +286,7 @@ uint64_t komodo_paxcalc(uint32_t *pvals,int32_t baseid,int32_t relid,uint64_t ba uint64_t komodo_paxprice(int32_t height,char *base,char *rel,uint64_t basevolume) { - int32_t baseid=-1,relid=-1,i,ht; uint32_t *ptr; + int32_t baseid=-1,relid=-1,i; uint32_t *ptr; if ( (baseid= komodo_baseid(base)) >= 0 && (relid= komodo_baseid(rel)) >= 0 ) { for (i=NUM_PRICES-1; i>=0; i--) @@ -267,7 +301,7 @@ uint64_t komodo_paxprice(int32_t height,char *base,char *rel,uint64_t basevolume int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel) { - int32_t baseid=-1,relid=-1,i,ht,num = 0; uint32_t *ptr; + int32_t baseid=-1,relid=-1,i,num = 0; uint32_t *ptr; if ( (baseid= komodo_baseid(base)) >= 0 && (relid= komodo_baseid(rel)) >= 0 ) { for (i=NUM_PRICES-1; i>=0; i--) @@ -283,11 +317,19 @@ int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *bas return(num); } -uint64_t PAX_fiatdest(char *fiatbuf,char *destaddr,uint8_t pubkey33[33],char *coinaddr,int32_t height,char *origbase,int64_t fiatoshis) +void komodo_paxpricefeed(int32_t height,uint8_t *pricefeed,int32_t opretlen) { - uint8_t shortflag = 0; char base[4]; int32_t i,baseid,relid; uint8_t addrtype,rmd160[20]; uint64_t komodoshis = 0; - fiatbuf[0] = 0; - if ( strcmp(base,(char *)"KMD") == 0 || strcmp(base,(char *)"kmd") == 0 ) + double KMDBTC,BTCUSD,CNYUSD; uint32_t numpvals,timestamp,pvals[128]; uint256 zero; + numpvals = dpow_readprices(pricefeed,×tamp,&KMDBTC,&BTCUSD,&CNYUSD,pvals); + memset(&zero,0,sizeof(zero)); + komodo_stateupdate(height,0,0,0,zero,0,0,pvals,numpvals,0,0,0,0,0); + //printf("komodo_paxpricefeed vout OP_RETURN.%d prices numpvals.%d opretlen.%d\n",height,numpvals,opretlen); +} + +uint64_t PAX_fiatdest(int32_t tokomodo,char *destaddr,uint8_t pubkey33[33],char *coinaddr,int32_t height,char *origbase,int64_t fiatoshis) +{ + uint8_t shortflag = 0; char base[4]; int32_t i,baseid; uint8_t addrtype,rmd160[20]; int64_t komodoshis = 0; + if ( (baseid= komodo_baseid(origbase)) < 0 || baseid == MAX_CURRENCIES ) return(0); for (i=0; i<3; i++) base[i] = toupper(origbase[i]); @@ -297,8 +339,7 @@ uint64_t PAX_fiatdest(char *fiatbuf,char *destaddr,uint8_t pubkey33[33],char *co komodoshis = komodo_paxprice(height,base,(char *)"KMD",(uint64_t)fiatoshis); if ( bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr) == 20 ) { - // put JSON into fiatbuf enough to replicate/validate - PAX_pubkey(pubkey33,addrtype,rmd160,base,shortflag,fiatoshis); + PAX_pubkey(1,pubkey33,&addrtype,rmd160,base,&shortflag,tokomodo != 0 ? &komodoshis : &fiatoshis); bitcoin_address(destaddr,KOMODO_PUBTYPE,pubkey33,33); } return(komodoshis); diff --git a/src/komodo_utils.h b/src/komodo_utils.h index ad935a691..d1b27a160 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -13,14 +13,33 @@ * * ******************************************************************************/ +#define SATOSHIDEN ((uint64_t)100000000L) +#define dstr(x) ((double)(x) / SATOSHIDEN) +#define portable_mutex_t pthread_mutex_t +#define portable_mutex_init(ptr) pthread_mutex_init(ptr,NULL) +#define portable_mutex_lock pthread_mutex_lock +#define portable_mutex_unlock pthread_mutex_unlock + +struct allocitem { uint32_t allocsize,type; }; +struct queueitem { struct queueitem *next,*prev; uint32_t allocsize,type; }; + +typedef struct queue +{ + struct queueitem *list; + pthread_mutex_t mutex; + char name[64],initflag; +} queue_t; + union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; typedef union _bits256 bits256; #include "mini-gmp.c" #include "uthash.h" +#include "utlist.h" #define CRYPTO777_PUBSECPSTR "020e46e79a2a8d12b9b5d12c7a91adb4e454edfae43c0a0cb805427d2ac7613fd9" #define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA" +#define CRYPTO777_RMD160STR "f1dce4182fce875748c4986b240ff7d7bc3fffb0" #define KOMODO_PUBTYPE 60 @@ -736,7 +755,7 @@ int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr } for (i=0; i>4) & 0xf); + hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf); + //printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]); + } + hexbytes[len*2] = 0; + //printf("len.%ld\n",len*2+1); + return((int32_t)len*2+1); +} + +char *bits256_str(char hexstr[65],bits256 x) +{ + init_hexbytes_noT(hexstr,x.bytes,sizeof(x)); + return(hexstr); +} + int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp) { int32_t i; uint64_t x; @@ -883,6 +937,23 @@ int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t * return(len); } +int32_t komodo_scriptitemlen(int32_t *opretlenp,uint8_t *script) +{ + int32_t opretlen,len = 0; + if ( (opretlen= script[len++]) >= 0x4c ) + { + if ( opretlen == 0x4c ) + opretlen = script[len++]; + else if ( opretlen == 0x4d ) + { + opretlen = script[len++]; + opretlen = (opretlen << 8) | script[len++]; + } + } + *opretlenp = opretlen; + return(len); +} + int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen) { int32_t offset = 0; @@ -902,7 +973,260 @@ int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_ script[offset++] = opretlen; } } else script[offset++] = opretlen; - script[offset] = type; // covered by opretlen - memcpy(&script[offset],opret,opretlen); - return(opretlen + offset); + script[offset++] = type; // covered by opretlen + memcpy(&script[offset],opret,opretlen-1); + return(offset + opretlen - 1); +} + +long _stripwhite(char *buf,int accept) +{ + int32_t i,j,c; + if ( buf == 0 || buf[0] == 0 ) + return(0); + for (i=j=0; buf[i]!=0; i++) + { + buf[j] = c = buf[i]; + if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') ) + j++; + } + buf[j] = 0; + return(j); +} + +char *clonestr(char *str) +{ + char *clone; + if ( str == 0 || str[0] == 0 ) + { + printf("warning cloning nullstr.%p\n",str); +#ifdef __APPLE__ + while ( 1 ) sleep(1); +#endif + str = (char *)""; + } + clone = (char *)malloc(strlen(str)+16); + strcpy(clone,str); + return(clone); +} + +int32_t safecopy(char *dest,char *src,long len) +{ + int32_t i = -1; + if ( src != 0 && dest != 0 && src != dest ) + { + if ( dest != 0 ) + memset(dest,0,len); + for (i=0; iinitflag == 0 ) + { + portable_mutex_init(&queue->mutex); + queue->initflag = 1; + } + portable_mutex_lock(&queue->mutex); +} + +void queue_enqueue(char *name,queue_t *queue,struct queueitem *item) +{ + if ( queue->name[0] == 0 && name != 0 && name[0] != 0 ) + strcpy(queue->name,name); + if ( item == 0 ) + { + printf("FATAL type error: queueing empty value\n"); + return; + } + lock_queue(queue); + DL_APPEND(queue->list,item); + portable_mutex_unlock(&queue->mutex); +} + +struct queueitem *queue_dequeue(queue_t *queue) +{ + struct queueitem *item = 0; + lock_queue(queue); + if ( queue->list != 0 ) + { + item = queue->list; + DL_DELETE(queue->list,item); + } + portable_mutex_unlock(&queue->mutex); + return(item); +} + +void *queue_delete(queue_t *queue,struct queueitem *copy,int32_t copysize) +{ + struct queueitem *item = 0; + lock_queue(queue); + if ( queue->list != 0 ) + { + DL_FOREACH(queue->list,item) + { + if ( item == copy || (item->allocsize == copysize && memcmp((void *)((long)item + sizeof(struct queueitem)),(void *)((long)copy + sizeof(struct queueitem)),copysize) == 0) ) + { + DL_DELETE(queue->list,item); + portable_mutex_unlock(&queue->mutex); + printf("name.(%s) deleted item.%p list.%p\n",queue->name,item,queue->list); + return(item); + } + } + } + portable_mutex_unlock(&queue->mutex); + return(0); +} + +void *queue_free(queue_t *queue) +{ + struct queueitem *item = 0; + lock_queue(queue); + if ( queue->list != 0 ) + { + DL_FOREACH(queue->list,item) + { + DL_DELETE(queue->list,item); + free(item); + } + //printf("name.(%s) dequeue.%p list.%p\n",queue->name,item,queue->list); + } + portable_mutex_unlock(&queue->mutex); + return(0); +} + +void *queue_clone(queue_t *clone,queue_t *queue,int32_t size) +{ + struct queueitem *ptr,*item = 0; + lock_queue(queue); + if ( queue->list != 0 ) + { + DL_FOREACH(queue->list,item) + { + ptr = (struct queueitem *)calloc(1,sizeof(*ptr)); + memcpy(ptr,item,size); + queue_enqueue(queue->name,clone,ptr); + } + //printf("name.(%s) dequeue.%p list.%p\n",queue->name,item,queue->list); + } + portable_mutex_unlock(&queue->mutex); + return(0); +} + +int32_t queue_size(queue_t *queue) +{ + int32_t count = 0; + struct queueitem *tmp; + lock_queue(queue); + DL_COUNT(queue->list,tmp,count); + portable_mutex_unlock(&queue->mutex); + return count; +} + +void iguana_initQ(queue_t *Q,char *name) +{ + struct queueitem *item,*I; + memset(Q,0,sizeof(*Q)); + I = (struct queueitem *)calloc(1,sizeof(*I)); + strcpy(Q->name,name); + queue_enqueue(name,Q,I); + if ( (item= queue_dequeue(Q)) != 0 ) + free(item); } diff --git a/src/main.cpp b/src/main.cpp index df7a7c3f0..e5fcc4736 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -556,6 +556,7 @@ uint8_t NOTARY_PUBKEY33[33]; //#define KOMODO_ENABLE_INTEREST enabling this is a hardfork #define KOMODO_SOURCE "KMD" #define KOMODO_PAX +#define KOMODO_ZCASH #include "komodo.h" ////////////////////////////////////////////////////////////////////////////// @@ -719,13 +720,13 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) } BOOST_FOREACH(const CTxIn& txin, tx.vin) { - if ( txin.nSequence == 0xfffffffe && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD && (int64_t)tx.nLockTime > nBlockTime ) + if ( txin.nSequence == 0xfffffffe && (((int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD && (int64_t)tx.nLockTime > nBlockTime) || ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD && (int64_t)tx.nLockTime > nBlockHeight)) ) { } else if (!txin.IsFinal()) { - printf("non-final txin seq.%x\n",txin.nSequence); + printf("non-final txin seq.%x locktime.%u vs nTime.%u\n",txin.nSequence,(uint32_t)tx.nLockTime,(uint32_t)nBlockTime); return false; } } @@ -1151,7 +1152,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (!view.HaveCoins(txin.prevout.hash)) { if (pfMissingInputs) *pfMissingInputs = true; - fprintf(stderr,"missing inputs\n"); + //fprintf(stderr,"missing inputs\n"); return false; } } diff --git a/src/miner.cpp b/src/miner.cpp index 6afed045d..41a4f9f84 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -335,7 +335,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) //txNew.nLockTime = (uint32_t)time(NULL) - 60; txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); - int32_t i,opretlen; uint8_t opret[8192],*ptr; + int32_t i,opretlen; uint8_t opret[256],*ptr; if ( (opretlen= komodo_pax_opreturn(opret,sizeof(opret))) > 0 ) { txNew.vout.resize(2); diff --git a/src/mini-gmp.c b/src/mini-gmp.c index 54497ca72..4cc08c27c 100644 --- a/src/mini-gmp.c +++ b/src/mini-gmp.c @@ -70,8 +70,7 @@ see https://www.gnu.org/licenses/. */ #define GMP_MAX(a, b) ((a) > (b) ? (a) : (b)) #define gmp_assert_nocarry(x) do { \ - mp_limb_t __cy = x; if ( __cy != 0 ) \ - ; \ + mp_limb_t __cy = x; if ( __cy != 0 ) {} \ assert (__cy == 0); \ } while (0) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 46340b5a4..c27f8213c 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -131,7 +131,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) if ( pindex != 0 && tx.nLockTime != 0 ) { interest = komodo_interest(pindex->nHeight,txout.nValue,tx.nLockTime,pindex->nTime); - fprintf(stderr,"TxtoJSON interest %llu %.8f\n",(long long)interest,(double)interest/COIN); + //fprintf(stderr,"TxtoJSON interest %llu %.8f\n",(long long)interest,(double)interest/COIN); out.push_back(Pair("interest", ValueFromAmount(interest))); } out.push_back(Pair("n", (int64_t)i)); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 100f33a65..8b72e6986 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -753,7 +753,8 @@ void StartRPCThreads() g_rpcSignals.Started(); // Launch one async rpc worker. The ability to launch multiple workers is not recommended at present and thus the option is disabled. - getAsyncRPCQueue()->addWorker(); + //for (int i=0; i<32; i++) + getAsyncRPCQueue()->addWorker(); /* int n = GetArg("-rpcasyncthreads", 1); if (n<1) { diff --git a/src/tinyformat.h b/src/tinyformat.h index 73d49a1fe..7d3de1de2 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -469,7 +469,7 @@ class FormatIterator void finish() { // It would be nice if we could do this from the destructor, but we - // can't if TINFORMAT_ERROR is used to throw an exception! + // can't if TINYFORMAT_ERROR is used to throw an exception! m_fmt = printFormatStringLiteral(m_out, m_fmt); if(*m_fmt != '\0') TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string"); diff --git a/src/utlist.h b/src/utlist.h new file mode 100755 index 000000000..93c7ceef0 --- /dev/null +++ b/src/utlist.h @@ -0,0 +1,753 @@ +/* + Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UTLIST_H +#define UTLIST_H + +#define UTLIST_VERSION 1.9.9 + +#include + +/* + * This file contains macros to manipulate singly and doubly-linked lists. + * + * 1. LL_ macros: singly-linked lists. + * 2. DL_ macros: doubly-linked lists. + * 3. CDL_ macros: circular doubly-linked lists. + * + * To use singly-linked lists, your structure must have a "next" pointer. + * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * Either way, the pointer to the head of the list must be initialized to NULL. + * + * ----------------.EXAMPLE ------------------------- + * struct item { + * int id; + * struct item *prev, *next; + * } + * + * struct item *list = NULL: + * + * int main() { + * struct item *item; + * ... allocate and populate item ... + * DL_APPEND(list, item); + * } + * -------------------------------------------------- + * + * For doubly-linked lists, the append and delete macros are O(1) + * For singly-linked lists, append and delete are O(n) but prepend is O(1) + * The sort macro is O(n log(n)) for all types of single/double/circular lists. + */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ code), this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define LDECLTYPE(x) decltype(x) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define LDECLTYPE(x) char* +#endif +#elif defined(__ICCARM__) +#define NO_DECLTYPE +#define LDECLTYPE(x) char* +#else /* GNU, Sun and other compilers */ +#define LDECLTYPE(x) __typeof(x) +#endif + +/* for VS2008 we use some workarounds to get around the lack of decltype, + * namely, we always reassign our tmp variable to the list head if we need + * to dereference its prev/next pointers, and save/restore the real head.*/ +#ifdef NO_DECLTYPE +#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define _NEXT(elt,list,next) ((char*)((list)->next)) +#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define _SV(elt,list) +#define _NEXT(elt,list,next) ((elt)->next) +#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define _PREV(elt,list,prev) ((elt)->prev) */ +#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define _RS(list) +#define _CASTASGN(a,b) (a)=(b) +#endif + +/****************************************************************************** + * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * + * Unwieldy variable names used here to avoid shadowing passed-in variables. * + *****************************************************************************/ +#define LL_SORT(list, cmp) \ +LL_SORT2(list, cmp, next) + +#define LL_SORT2(list, cmp, next) \ +do { \ +LDECLTYPE(list) _ls_p; \ +LDECLTYPE(list) _ls_q; \ +LDECLTYPE(list) _ls_e; \ +LDECLTYPE(list) _ls_tail; \ +int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ +if (list) { \ +_ls_insize = 1; \ +_ls_looping = 1; \ +while (_ls_looping) { \ +_CASTASGN(_ls_p,list); \ +list = NULL; \ +_ls_tail = NULL; \ +_ls_nmerges = 0; \ +while (_ls_p) { \ +_ls_nmerges++; \ +_ls_q = _ls_p; \ +_ls_psize = 0; \ +for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ +_ls_psize++; \ +_SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ +if (!_ls_q) break; \ +} \ +_ls_qsize = _ls_insize; \ +while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ +if (_ls_psize == 0) { \ +_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ +_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ +} else if (_ls_qsize == 0 || !_ls_q) { \ +_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ +_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ +} else if (cmp(_ls_p,_ls_q) <= 0) { \ +_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ +_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ +} else { \ +_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ +_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ +} \ +if (_ls_tail) { \ +_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ +} else { \ +_CASTASGN(list,_ls_e); \ +} \ +_ls_tail = _ls_e; \ +} \ +_ls_p = _ls_q; \ +} \ +if (_ls_tail) { \ +_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ +} \ +if (_ls_nmerges <= 1) { \ +_ls_looping=0; \ +} \ +_ls_insize *= 2; \ +} \ +} \ +} while (0) + + +#define DL_SORT(list, cmp) \ +DL_SORT2(list, cmp, prev, next) + +#define DL_SORT2(list, cmp, prev, next) \ +do { \ +LDECLTYPE(list) _ls_p; \ +LDECLTYPE(list) _ls_q; \ +LDECLTYPE(list) _ls_e; \ +LDECLTYPE(list) _ls_tail; \ +int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ +if (list) { \ +_ls_insize = 1; \ +_ls_looping = 1; \ +while (_ls_looping) { \ +_CASTASGN(_ls_p,list); \ +list = NULL; \ +_ls_tail = NULL; \ +_ls_nmerges = 0; \ +while (_ls_p) { \ +_ls_nmerges++; \ +_ls_q = _ls_p; \ +_ls_psize = 0; \ +for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ +_ls_psize++; \ +_SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ +if (!_ls_q) break; \ +} \ +_ls_qsize = _ls_insize; \ +while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ +if (_ls_psize == 0) { \ +_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ +_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ +} else if (_ls_qsize == 0 || !_ls_q) { \ +_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ +_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ +} else if (cmp(_ls_p,_ls_q) <= 0) { \ +_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ +_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ +} else { \ +_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ +_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ +} \ +if (_ls_tail) { \ +_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ +} else { \ +_CASTASGN(list,_ls_e); \ +} \ +_SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ +_ls_tail = _ls_e; \ +} \ +_ls_p = _ls_q; \ +} \ +_CASTASGN(list->prev, _ls_tail); \ +_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ +if (_ls_nmerges <= 1) { \ +_ls_looping=0; \ +} \ +_ls_insize *= 2; \ +} \ +} \ +} while (0) + +#define CDL_SORT(list, cmp) \ +CDL_SORT2(list, cmp, prev, next) + +#define CDL_SORT2(list, cmp, prev, next) \ +do { \ +LDECLTYPE(list) _ls_p; \ +LDECLTYPE(list) _ls_q; \ +LDECLTYPE(list) _ls_e; \ +LDECLTYPE(list) _ls_tail; \ +LDECLTYPE(list) _ls_oldhead; \ +LDECLTYPE(list) _tmp; \ +int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ +if (list) { \ +_ls_insize = 1; \ +_ls_looping = 1; \ +while (_ls_looping) { \ +_CASTASGN(_ls_p,list); \ +_CASTASGN(_ls_oldhead,list); \ +list = NULL; \ +_ls_tail = NULL; \ +_ls_nmerges = 0; \ +while (_ls_p) { \ +_ls_nmerges++; \ +_ls_q = _ls_p; \ +_ls_psize = 0; \ +for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ +_ls_psize++; \ +_SV(_ls_q,list); \ +if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ +_ls_q = NULL; \ +} else { \ +_ls_q = _NEXT(_ls_q,list,next); \ +} \ +_RS(list); \ +if (!_ls_q) break; \ +} \ +_ls_qsize = _ls_insize; \ +while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ +if (_ls_psize == 0) { \ +_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ +_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ +if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ +} else if (_ls_qsize == 0 || !_ls_q) { \ +_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ +_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ +if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ +} else if (cmp(_ls_p,_ls_q) <= 0) { \ +_ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ +_NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ +if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ +} else { \ +_ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ +_NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ +if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ +} \ +if (_ls_tail) { \ +_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ +} else { \ +_CASTASGN(list,_ls_e); \ +} \ +_SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ +_ls_tail = _ls_e; \ +} \ +_ls_p = _ls_q; \ +} \ +_CASTASGN(list->prev,_ls_tail); \ +_CASTASGN(_tmp,list); \ +_SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ +if (_ls_nmerges <= 1) { \ +_ls_looping=0; \ +} \ +_ls_insize *= 2; \ +} \ +} \ +} while (0) + +/****************************************************************************** + * singly linked list macros (non-circular) * + *****************************************************************************/ +#define LL_PREPEND(head,add) \ +LL_PREPEND2(head,add,next) + +#define LL_PREPEND2(head,add,next) \ +do { \ +(add)->next = head; \ +head = add; \ +} while (0) + +#define LL_CONCAT(head1,head2) \ +LL_CONCAT2(head1,head2,next) + +#define LL_CONCAT2(head1,head2,next) \ +do { \ +LDECLTYPE(head1) _tmp; \ +if (head1) { \ +_tmp = head1; \ +while (_tmp->next) { _tmp = _tmp->next; } \ +_tmp->next=(head2); \ +} else { \ +(head1)=(head2); \ +} \ +} while (0) + +#define LL_APPEND(head,add) \ +LL_APPEND2(head,add,next) + +#define LL_APPEND2(head,add,next) \ +do { \ +LDECLTYPE(head) _tmp; \ +(add)->next=NULL; \ +if (head) { \ +_tmp = head; \ +while (_tmp->next) { _tmp = _tmp->next; } \ +_tmp->next=(add); \ +} else { \ +(head)=(add); \ +} \ +} while (0) + +#define LL_DELETE(head,del) \ +LL_DELETE2(head,del,next) + +#define LL_DELETE2(head,del,next) \ +do { \ +LDECLTYPE(head) _tmp; \ +if ((head) == (del)) { \ +(head)=(head)->next; \ +} else { \ +_tmp = head; \ +while (_tmp->next && (_tmp->next != (del))) { \ +_tmp = _tmp->next; \ +} \ +if (_tmp->next) { \ +_tmp->next = ((del)->next); \ +} \ +} \ +} while (0) + +/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ +#define LL_APPEND_VS2008(head,add) \ +LL_APPEND2_VS2008(head,add,next) + +#define LL_APPEND2_VS2008(head,add,next) \ +do { \ +if (head) { \ +(add)->next = head; /* use add->next as a temp variable */ \ +while ((add)->next->next) { (add)->next = (add)->next->next; } \ +(add)->next->next=(add); \ +} else { \ +(head)=(add); \ +} \ +(add)->next=NULL; \ +} while (0) + +#define LL_DELETE_VS2008(head,del) \ +LL_DELETE2_VS2008(head,del,next) + +#define LL_DELETE2_VS2008(head,del,next) \ +do { \ +if ((head) == (del)) { \ +(head)=(head)->next; \ +} else { \ +char *_tmp = (char*)(head); \ +while ((head)->next && ((head)->next != (del))) { \ +head = (head)->next; \ +} \ +if ((head)->next) { \ +(head)->next = ((del)->next); \ +} \ +{ \ +char **_head_alias = (char**)&(head); \ +*_head_alias = _tmp; \ +} \ +} \ +} while (0) +#ifdef NO_DECLTYPE +#undef LL_APPEND +#define LL_APPEND LL_APPEND_VS2008 +#undef LL_DELETE +#define LL_DELETE LL_DELETE_VS2008 +#undef LL_DELETE2 +#define LL_DELETE2 LL_DELETE2_VS2008 +#undef LL_APPEND2 +#define LL_APPEND2 LL_APPEND2_VS2008 +#undef LL_CONCAT /* no LL_CONCAT_VS2008 */ +#undef DL_CONCAT /* no DL_CONCAT_VS2008 */ +#endif +/* end VS2008 replacements */ + +#define LL_COUNT(head,el,counter) \ +LL_COUNT2(head,el,counter,next) \ + +#define LL_COUNT2(head,el,counter,next) \ +{ \ +counter = 0; \ +LL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define LL_FOREACH(head,el) \ +LL_FOREACH2(head,el,next) + +#define LL_FOREACH2(head,el,next) \ +for(el=head;el;el=(el)->next) + +#define LL_FOREACH_SAFE(head,el,tmp) \ +LL_FOREACH_SAFE2(head,el,tmp,next) + +#define LL_FOREACH_SAFE2(head,el,tmp,next) \ +for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + +#define LL_SEARCH_SCALAR(head,out,field,val) \ +LL_SEARCH_SCALAR2(head,out,field,val,next) + +#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ +LL_FOREACH2(head,out,next) { \ +if ((out)->field == (val)) break; \ +} \ +} while(0) + +#define LL_SEARCH(head,out,elt,cmp) \ +LL_SEARCH2(head,out,elt,cmp,next) + +#define LL_SEARCH2(head,out,elt,cmp,next) \ +do { \ +LL_FOREACH2(head,out,next) { \ +if ((cmp(out,elt))==0) break; \ +} \ +} while(0) + +#define LL_REPLACE_ELEM(head, el, add) \ +do { \ +LDECLTYPE(head) _tmp; \ +assert(head != NULL); \ +assert(el != NULL); \ +assert(add != NULL); \ +(add)->next = (el)->next; \ +if ((head) == (el)) { \ +(head) = (add); \ +} else { \ +_tmp = head; \ +while (_tmp->next && (_tmp->next != (el))) { \ +_tmp = _tmp->next; \ +} \ +if (_tmp->next) { \ +_tmp->next = (add); \ +} \ +} \ +} while (0) + +#define LL_PREPEND_ELEM(head, el, add) \ +do { \ +LDECLTYPE(head) _tmp; \ +assert(head != NULL); \ +assert(el != NULL); \ +assert(add != NULL); \ +(add)->next = (el); \ +if ((head) == (el)) { \ +(head) = (add); \ +} else { \ +_tmp = head; \ +while (_tmp->next && (_tmp->next != (el))) { \ +_tmp = _tmp->next; \ +} \ +if (_tmp->next) { \ +_tmp->next = (add); \ +} \ +} \ +} while (0) \ + + +/****************************************************************************** + * doubly linked list macros (non-circular) * + *****************************************************************************/ +#define DL_PREPEND(head,add) \ +DL_PREPEND2(head,add,prev,next) + +#define DL_PREPEND2(head,add,prev,next) \ +do { \ +(add)->next = head; \ +if (head) { \ +(add)->prev = (head)->prev; \ +(head)->prev = (add); \ +} else { \ +(add)->prev = (add); \ +} \ +(head) = (add); \ +} while (0) + +#define DL_APPEND(head,add) \ +DL_APPEND2(head,add,prev,next) + +#define DL_APPEND2(head,add,prev,next) \ +do { \ +if (head) { \ +(add)->prev = (head)->prev; \ +(head)->prev->next = (add); \ +(head)->prev = (add); \ +(add)->next = NULL; \ +} else { \ +(head)=(add); \ +(head)->prev = (head); \ +(head)->next = NULL; \ +} \ +} while (0) + +#define DL_CONCAT(head1,head2) \ +DL_CONCAT2(head1,head2,prev,next) + +#define DL_CONCAT2(head1,head2,prev,next) \ +do { \ +LDECLTYPE(head1) _tmp; \ +if (head2) { \ +if (head1) { \ +_tmp = (head2)->prev; \ +(head2)->prev = (head1)->prev; \ +(head1)->prev->next = (head2); \ +(head1)->prev = _tmp; \ +} else { \ +(head1)=(head2); \ +} \ +} \ +} while (0) + +#define DL_DELETE(head,del) \ +DL_DELETE2(head,del,prev,next) + +#define DL_DELETE2(head,del,prev,next) \ +do { \ +assert((del)->prev != NULL); \ +if ((del)->prev == (del)) { \ +(head)=NULL; \ +} else if ((del)==(head)) { \ +(del)->next->prev = (del)->prev; \ +(head) = (del)->next; \ +} else { \ +(del)->prev->next = (del)->next; \ +if ((del)->next) { \ +(del)->next->prev = (del)->prev; \ +} else { \ +(head)->prev = (del)->prev; \ +} \ +} \ +} while (0) + +#define DL_COUNT(head,el,counter) \ +DL_COUNT2(head,el,counter,next) \ + +#define DL_COUNT2(head,el,counter,next) \ +{ \ +counter = 0; \ +DL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define DL_FOREACH(head,el) \ +DL_FOREACH2(head,el,next) + +#define DL_FOREACH2(head,el,next) \ +for(el=head;el;el=(el)->next) + +/* this version is safe for deleting the elements during iteration */ +#define DL_FOREACH_SAFE(head,el,tmp) \ +DL_FOREACH_SAFE2(head,el,tmp,next) + +#define DL_FOREACH_SAFE2(head,el,tmp,next) \ +for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + +/* these are identical to their singly-linked list counterparts */ +#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR +#define DL_SEARCH LL_SEARCH +#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 +#define DL_SEARCH2 LL_SEARCH2 + +#define DL_REPLACE_ELEM(head, el, add) \ +do { \ +assert(head != NULL); \ +assert(el != NULL); \ +assert(add != NULL); \ +if ((head) == (el)) { \ +(head) = (add); \ +(add)->next = (el)->next; \ +if ((el)->next == NULL) { \ +(add)->prev = (add); \ +} else { \ +(add)->prev = (el)->prev; \ +(add)->next->prev = (add); \ +} \ +} else { \ +(add)->next = (el)->next; \ +(add)->prev = (el)->prev; \ +(add)->prev->next = (add); \ +if ((el)->next == NULL) { \ +(head)->prev = (add); \ +} else { \ +(add)->next->prev = (add); \ +} \ +} \ +} while (0) + +#define DL_PREPEND_ELEM(head, el, add) \ +do { \ +assert(head != NULL); \ +assert(el != NULL); \ +assert(add != NULL); \ +(add)->next = (el); \ +(add)->prev = (el)->prev; \ +(el)->prev = (add); \ +if ((head) == (el)) { \ +(head) = (add); \ +} else { \ +(add)->prev->next = (add); \ +} \ +} while (0) \ + + +/****************************************************************************** + * circular doubly linked list macros * + *****************************************************************************/ +#define CDL_PREPEND(head,add) \ +CDL_PREPEND2(head,add,prev,next) + +#define CDL_PREPEND2(head,add,prev,next) \ +do { \ +if (head) { \ +(add)->prev = (head)->prev; \ +(add)->next = (head); \ +(head)->prev = (add); \ +(add)->prev->next = (add); \ +} else { \ +(add)->prev = (add); \ +(add)->next = (add); \ +} \ +(head)=(add); \ +} while (0) + +#define CDL_DELETE(head,del) \ +CDL_DELETE2(head,del,prev,next) + +#define CDL_DELETE2(head,del,prev,next) \ +do { \ +if ( ((head)==(del)) && ((head)->next == (head))) { \ +(head) = 0L; \ +} else { \ +(del)->next->prev = (del)->prev; \ +(del)->prev->next = (del)->next; \ +if ((del) == (head)) (head)=(del)->next; \ +} \ +} while (0) + +#define CDL_COUNT(head,el,counter) \ +CDL_COUNT2(head,el,counter,next) \ + +#define CDL_COUNT2(head, el, counter,next) \ +{ \ +counter = 0; \ +CDL_FOREACH2(head,el,next){ ++counter; } \ +} + +#define CDL_FOREACH(head,el) \ +CDL_FOREACH2(head,el,next) + +#define CDL_FOREACH2(head,el,next) \ +for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) + +#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ +CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) + +#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ +for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ +(el) && ((tmp2)=(el)->next, 1); \ +((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) + +#define CDL_SEARCH_SCALAR(head,out,field,val) \ +CDL_SEARCH_SCALAR2(head,out,field,val,next) + +#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ +CDL_FOREACH2(head,out,next) { \ +if ((out)->field == (val)) break; \ +} \ +} while(0) + +#define CDL_SEARCH(head,out,elt,cmp) \ +CDL_SEARCH2(head,out,elt,cmp,next) + +#define CDL_SEARCH2(head,out,elt,cmp,next) \ +do { \ +CDL_FOREACH2(head,out,next) { \ +if ((cmp(out,elt))==0) break; \ +} \ +} while(0) + +#define CDL_REPLACE_ELEM(head, el, add) \ +do { \ +assert(head != NULL); \ +assert(el != NULL); \ +assert(add != NULL); \ +if ((el)->next == (el)) { \ +(add)->next = (add); \ +(add)->prev = (add); \ +(head) = (add); \ +} else { \ +(add)->next = (el)->next; \ +(add)->prev = (el)->prev; \ +(add)->next->prev = (add); \ +(add)->prev->next = (add); \ +if ((head) == (el)) { \ +(head) = (add); \ +} \ +} \ +} while (0) + +#define CDL_PREPEND_ELEM(head, el, add) \ +do { \ +assert(head != NULL); \ +assert(el != NULL); \ +assert(add != NULL); \ +(add)->next = (el); \ +(add)->prev = (el)->prev; \ +(el)->prev = (add); \ +(add)->prev->next = (add); \ +if ((head) == (el)) { \ +(head) = (add); \ +} \ +} while (0) \ + +#endif /* UTLIST_H */ diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7f4a2e003..e934bfa66 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -466,7 +466,7 @@ Value sendtoaddress(const Array& params, bool fHelp) return wtx.GetHash().GetHex(); } -uint64_t PAX_fiatdest(char *fiatbuf,char *destaddr,uint8_t pubkey33[33],char *coinaddr,int32_t height,char *base,int64_t fiatoshis); +uint64_t PAX_fiatdest(int32_t tokomodo,char *destaddr,uint8_t pubkey33[33],char *coinaddr,int32_t height,char *base,int64_t fiatoshis); int32_t komodo_opreturnscript(uint8_t *script,uint8_t type,uint8_t *opret,int32_t opretlen); #define CRYPTO777_KMDADDR "RXL3YXG2ceaB6C5hfJcN4fvmLH2C34knhA" @@ -484,8 +484,8 @@ Value paxdeposit(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); int64_t fiatoshis = atof(params[1].get_str().c_str()) * COIN; std::string base = params[2].get_str(); - std::string dest; char fiatbuf[1024]; - komodoshis = PAX_fiatdest(fiatbuf,destaddr,pubkey33,(char *)params[0].get_str().c_str(),chainActive.Tip()->nHeight,(char *)base.c_str(),fiatoshis); + std::string dest; + komodoshis = PAX_fiatdest(0,destaddr,pubkey33,(char *)params[0].get_str().c_str(),chainActive.Tip()->nHeight,(char *)base.c_str(),fiatoshis); dest.append(destaddr); CBitcoinAddress destaddress(CRYPTO777_KMDADDR); if (!destaddress.IsValid()) @@ -496,17 +496,11 @@ Value paxdeposit(const Array& params, bool fHelp) printf(" ht.%d srcaddr.(%s) %s fiatoshis.%lld -> dest.(%s) komodoshis.%llu\n",chainActive.Tip()->nHeight,(char *)params[0].get_str().c_str(),(char *)base.c_str(),(long long)fiatoshis,destaddr,(long long)komodoshis); EnsureWalletIsUnlocked(); CWalletTx wtx; - /*std::string account,paxstr,tmp; - account.append((char *)"account"); - paxstr.append(fiatbuf); - tmp.append("PAX"); - wtx.mapValue["PAX"] = paxstr; - pwalletMain->SetAddressBook(destaddress.Get(),account,tmp);*/ uint8_t opretbuf[64]; int32_t opretlen; uint64_t fee = komodoshis / 1000; if ( fee < 10000 ) fee = 10000; opretlen = komodo_opreturnscript(opretbuf,'D',pubkey33,33); - SendMoney(destaddress.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis); + SendMoney(address.Get(),fee,fSubtractFeeFromAmount,wtx,opretbuf,opretlen,komodoshis); return wtx.GetHash().GetHex(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 3a25d8363..ee58ed703 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2592,14 +2592,11 @@ bool CWallet::CreateTransaction(const vector& vecSend, } else { - // Insert change txn at random position: - nChangePosRet = GetRandInt(txNew.vout.size()+1); + nChangePosRet = txNew.vout.size() - 1; // dont change first or last vector::iterator position = txNew.vout.begin()+nChangePosRet; txNew.vout.insert(position, newTxOut); } - } - else - reservekey.ReturnKey(); + } else reservekey.ReturnKey(); // Fill vin // @@ -2935,7 +2932,7 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool) if (!HaveKey(keypool.vchPubKey.GetID())) throw runtime_error("ReserveKeyFromKeyPool(): unknown key in key pool"); assert(keypool.vchPubKey.IsValid()); - LogPrintf("keypool reserve %d\n", nIndex); + //LogPrintf("keypool reserve %d\n", nIndex); } } @@ -2957,7 +2954,7 @@ void CWallet::ReturnKey(int64_t nIndex) LOCK(cs_wallet); setKeyPool.insert(nIndex); } - LogPrintf("keypool return %d\n", nIndex); + //LogPrintf("keypool return %d\n", nIndex); } bool CWallet::GetKeyFromPool(CPubKey& result)