From 989313c931275c8e988a95e93cd55e7e7cd02503 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 28 Apr 2016 22:19:20 -0500 Subject: [PATCH] createmultisig and addmultisigaddress --- crypto777/iguana_secp.c | 2 +- crypto777/inet.c | 16 +- iguana/SuperNET_keys.c | 2 +- iguana/iguana777.c | 4 +- iguana/iguana777.h | 9 +- iguana/iguana_json.c | 4 +- iguana/iguana_rpc.c | 3 +- iguana/iguana_unspents.c | 39 +++-- iguana/iguana_wallet.c | 298 +++++++++++++++++++++++++++------- iguana/tests/addmultisig | 2 + iguana/tests/createmultisig | 2 + iguana/tests/walletpassphrase | 4 +- includes/iguana_apideclares.h | 5 +- 13 files changed, 294 insertions(+), 96 deletions(-) create mode 100755 iguana/tests/addmultisig create mode 100755 iguana/tests/createmultisig diff --git a/crypto777/iguana_secp.c b/crypto777/iguana_secp.c index 97236497c..780e8656c 100755 --- a/crypto777/iguana_secp.c +++ b/crypto777/iguana_secp.c @@ -178,7 +178,7 @@ bits256 bitcoin_pubkey33(uint8_t *data,bits256 privkey) data[0] = oddeven; memcpy(data+1,pubkey.bytes,sizeof(pubkey)); EC_KEY_free(KEY); - } + } else memset(pubkey.bytes,0,sizeof(pubkey)); return(pubkey); } diff --git a/crypto777/inet.c b/crypto777/inet.c index d9f216a9b..4ca687a67 100755 --- a/crypto777/inet.c +++ b/crypto777/inet.c @@ -389,13 +389,25 @@ void expand_ipbits(char *ipaddr,uint64_t ipbits) uint64_t calc_ipbits(char *ip_port) { - uint64_t ipbits = 0; char ipaddr[64]; + uint64_t ipbits = 0; char ipaddr[64],ipaddr2[64]; int32_t i; if ( ip_port != 0 ) { ipbits = _calc_ipbits(ip_port); expand_ipbits(ipaddr,ipbits); if ( ipbits != 0 && strcmp(ipaddr,ip_port) != 0 ) - printf("calc_ipbits error: (%s) -> %llx -> (%s)\n",ip_port,(long long)ipbits,ipaddr);//, getchar(); + { + for (i=0; i<63; i++) + if ( (ipaddr[i]= ip_port[i]) == ':' || ipaddr[i] == 0 ) + break; + ipaddr[i] = 0; + ipbits = _calc_ipbits(ipaddr); + expand_ipbits(ipaddr2,ipbits); + if ( ipbits != 0 && strcmp(ipaddr,ipaddr2) != 0 ) + { + printf("calc_ipbits error: (%s) -> %llx -> (%s)\n",ip_port,(long long)ipbits,ipaddr);//, getchar(); + ipbits = 0; + } + } } return(ipbits); } diff --git a/iguana/SuperNET_keys.c b/iguana/SuperNET_keys.c index 48a7b984e..c91b64eb5 100755 --- a/iguana/SuperNET_keys.c +++ b/iguana/SuperNET_keys.c @@ -151,7 +151,7 @@ int32_t SuperNET_savejsonfile(char *finalfname,bits256 privkey,bits256 destpubke else { //sprintf(fname,"confs/iguana.conf"); - printf("save (%s) <- (%s)\n",destfname,confstr); + //printf("save (%s) <- (%s)\n",destfname,confstr); if ( (fp= fopen(destfname,"wb")) != 0 ) { if ( fwrite(confstr,1,strlen(confstr)+1,fp) == strlen(confstr)+1 ) diff --git a/iguana/iguana777.c b/iguana/iguana777.c index 5f6408a98..c3fd3cea7 100755 --- a/iguana/iguana777.c +++ b/iguana/iguana777.c @@ -839,7 +839,7 @@ struct iguana_info *iguana_setcoin(char *symbol,void *launched,int32_t maxpeers, return(coin); } -int32_t iguana_launchcoin(char *symbol,cJSON *json) +int32_t iguana_launchcoin(struct supernet_info *myinfo,char *symbol,cJSON *json) { int32_t maxpeers,maphash,initialheight,minconfirms,maxrequests,maxbundles; int64_t maxrecvcache; uint64_t services; struct iguana_info **coins,*coin; @@ -848,6 +848,8 @@ int32_t iguana_launchcoin(char *symbol,cJSON *json) printf("launchcoin.%s\n",symbol); if ( (coin= iguana_coinadd(symbol,json)) == 0 ) return(-1); + if ( myinfo->rpcsymbol[0] == 0 || iguana_coinfind(myinfo->rpcsymbol) == 0 ) + strcpy(myinfo->rpcsymbol,symbol); if ( coin->launched == 0 ) { if ( juint(json,"GBavail") < 8 ) diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 3e8c97ae3..f42fd89d3 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -474,7 +474,7 @@ struct iguana_bundlereq struct iguana_bitmap { int32_t width,height,amplitude; char name[52]; uint8_t data[IGUANA_WIDTH*IGUANA_HEIGHT*3]; }; -struct iguana_waddress { UT_hash_handle hh; uint8_t rmd160[20],type,pubkey[33],wiftype; bits256 privkey; char symbol[8],coinaddr[36],wifstr[54]; }; +struct iguana_waddress { UT_hash_handle hh; uint16_t scriptlen; uint8_t rmd160[20],type,pubkey[33],wiftype; bits256 privkey; char symbol[8],coinaddr[36],wifstr[54]; uint8_t redeemScript[]; }; struct iguana_waccount { UT_hash_handle hh; char account[128]; struct iguana_waddress *waddr,*current; }; struct iguana_wallet { UT_hash_handle hh; struct iguana_waccount *wacct; }; @@ -511,7 +511,7 @@ struct iguana_info double bandwidth,maxbandwidth,backstopmillis; bits256 backstophash2; int64_t spaceused; int32_t initialheight,mapflags,minconfirms,numrecv,bindsock,isRT,backstop,blocksrecv,merging,polltimeout,numreqtxids,allhashes,balanceflush; bits256 reqtxids[64]; void *launched,*started,*rpcloop; - uint64_t bloomsearches,bloomhits,bloomfalse,collisions; + uint64_t bloomsearches,bloomhits,bloomfalse,collisions,txfee_perkb; uint8_t blockspace[IGUANA_MAXPACKETSIZE + 8192]; struct OS_memspace blockMEM; struct iguana_blocks blocks; bits256 APIblockhash,APItxid; char *APIblockstr; struct iguana_hhutxo *utxotable; struct iguana_hhaccount *accountstable; char lastdispstr[2048]; @@ -771,14 +771,14 @@ int32_t iguana_send_supernet(struct iguana_info *coin,struct iguana_peer *addr,c struct iguana_waccount *iguana_waccountfind(struct supernet_info *myinfo,struct iguana_info *coin,char *account); struct iguana_waddress *iguana_waccountadd(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount **wacctp,char *walletaccount,char *coinaddr); -struct iguana_waddress *iguana_waccountswitch(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr); +struct iguana_waddress *iguana_waccountswitch(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr,char *redeemScript); struct iguana_waddress *iguana_waddresscalc(uint8_t pubval,uint8_t wiftype,struct iguana_waddress *addr,bits256 privkey); struct iguana_waddress *iguana_waddressfind(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,char *coinaddr); char *iguana_coinjson(struct iguana_info *coin,char *method,cJSON *json); cJSON *iguana_peersjson(struct iguana_info *coin,int32_t addronly); //int32_t btc_priv2wif(char *wifstr,uint8_t privkey[32],uint8_t addrtype); //int32_t btc_pub2rmd(uint8_t rmd160[20],uint8_t pubkey[33]); -int32_t iguana_launchcoin(char *symbol,cJSON *json); +int32_t iguana_launchcoin(struct supernet_info *myinfo,char *symbol,cJSON *json); int32_t iguana_bundleinitmap(struct iguana_info *coin,struct iguana_bundle *bp,int32_t height,bits256 hash2,bits256 hash1); int32_t iguana_jsonQ(); int32_t is_bitcoinrpc(struct supernet_info *myinfo,char *method,char *remoteaddr); @@ -927,6 +927,7 @@ struct iguana_waddress *iguana_waddresssearch(struct supernet_info *myinfo,struc int64_t iguana_addressreceived(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *json,char *remoteaddr,cJSON *txids,cJSON *vouts,char *coinaddr,int32_t minconf); cJSON *iguana_walletjson(struct supernet_info *myinfo); int32_t iguana_payloadupdate(struct supernet_info *myinfo,struct iguana_info *coin,char *retstr,struct iguana_waddress *waddr,char *account); +int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,const struct vin_info *vp); extern int32_t HDRnet,netBLOCKS; diff --git a/iguana/iguana_json.c b/iguana/iguana_json.c index aabfc106b..2b74906c8 100755 --- a/iguana/iguana_json.c +++ b/iguana/iguana_json.c @@ -613,7 +613,7 @@ STRING_ARG(iguana,addcoin,newcoin) // if ( strcmp(symbol,"BTC") == 0 ) // return(clonestr("{\"result\":\"BTC for chrome app is not yet\"}")); #endif - if ( (retval= iguana_launchcoin(symbol,json)) > 0 ) + if ( (retval= iguana_launchcoin(myinfo,symbol,json)) > 0 ) { if ( myinfo->rpcsymbol[0] == 0 ) safecopy(myinfo->rpcsymbol,symbol,sizeof(myinfo->rpcsymbol)); @@ -841,7 +841,7 @@ STRING_ARG(SuperNET,bitcoinrpc,setcoin) strcpy(myinfo->rpcsymbol,setcoin); touppercase(myinfo->rpcsymbol); printf("bitcoinrpc.%s\n",myinfo->rpcsymbol); - if ( iguana_launchcoin(myinfo->rpcsymbol,json) < 0 ) + if ( iguana_launchcoin(myinfo,myinfo->rpcsymbol,json) < 0 ) return(clonestr("{\"error\":\"error creating coin\"}")); else { diff --git a/iguana/iguana_rpc.c b/iguana/iguana_rpc.c index f98e85606..1f655e7cb 100755 --- a/iguana/iguana_rpc.c +++ b/iguana/iguana_rpc.c @@ -234,7 +234,7 @@ static char *createmultisig(RPCARGS) static char *addmultisigaddress(RPCARGS) { - return(sglue3(0,CALLGLUE,"bitcoinrpc","createmultisig","M",params[0],"pubkeys",params[1],"account",params[2])); + return(sglue3(0,CALLGLUE,"bitcoinrpc","addmultisigaddress","M",params[0],"pubkeys",params[1],"account",params[2])); } // blockchain @@ -553,6 +553,7 @@ struct RPC_info { char *name; char *(*rpcfunc)(RPCARGS); int32_t flag0,remotefla { "move", &movecmd, false, false }, { "sendfrom", &sendfrom, false, false }, { "sendmany", &sendmany, false, false }, + { "addmultisig", &addmultisigaddress, false, false }, { "addmultisigaddress", &addmultisigaddress, false, false }, { "getblock", &getblock, false, true }, { "gettransaction", &gettransaction, false, true }, diff --git a/iguana/iguana_unspents.c b/iguana/iguana_unspents.c index f576e4211..aa0d6d69f 100755 --- a/iguana/iguana_unspents.c +++ b/iguana/iguana_unspents.c @@ -2216,24 +2216,27 @@ int32_t iguana_convert(struct iguana_info *coin,int32_t helperid,struct iguana_b void iguana_RTramchainfree(struct iguana_info *coin,struct iguana_bundle *bp) { int32_t hdrsi; - printf("free RTramchain\n"); - iguana_utxoupdate(coin,-1,0,0,0,0,-1); // free hashtables - coin->RTheight = coin->balanceswritten * coin->chain->bundlesize; - coin->RTgenesis = 0; - iguana_ramchain_free(coin,&coin->RTramchain,1); - if ( bp != 0 ) - bp->ramchain = coin->RTramchain; - iguana_mempurge(&coin->RTmem); - iguana_mempurge(&coin->RThashmem); - coin->RTdatabad = 0; - for (hdrsi=coin->bundlescount-1; hdrsi>0; hdrsi--) - if ( (bp= coin->bundles[hdrsi]) == 0 && bp != coin->current ) - { - iguana_volatilespurge(coin,&bp->ramchain); - if ( iguana_volatilesmap(coin,&bp->ramchain) != 0 ) - printf("error mapping bundle.[%d]\n",hdrsi); - } - printf("done RTramchain\n"); + if ( coin->utxotable != 0 ) + { + printf("free RTramchain\n"); + iguana_utxoupdate(coin,-1,0,0,0,0,-1); // free hashtables + coin->RTheight = coin->balanceswritten * coin->chain->bundlesize; + coin->RTgenesis = 0; + iguana_ramchain_free(coin,&coin->RTramchain,1); + if ( bp != 0 ) + bp->ramchain = coin->RTramchain; + iguana_mempurge(&coin->RTmem); + iguana_mempurge(&coin->RThashmem); + coin->RTdatabad = 0; + for (hdrsi=coin->bundlescount-1; hdrsi>0; hdrsi--) + if ( (bp= coin->bundles[hdrsi]) == 0 && bp != coin->current ) + { + iguana_volatilespurge(coin,&bp->ramchain); + if ( iguana_volatilesmap(coin,&bp->ramchain) != 0 ) + printf("error mapping bundle.[%d]\n",hdrsi); + } + printf("done RTramchain\n"); + } } void *iguana_ramchainfile(struct iguana_info *coin,struct iguana_ramchain *dest,struct iguana_ramchain *R,struct iguana_bundle *bp,int32_t bundlei,struct iguana_block *block) diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index 1675a6cf4..778a64dd8 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -57,19 +57,23 @@ void iguana_walletdelete(struct supernet_info *myinfo,int32_t deleteflag) cJSON *iguana_walletjson(struct supernet_info *myinfo) { - struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; cJSON *wallet,*account; + struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; cJSON *wallet,*account; char scriptstr[4096]; HASH_ITER(hh,myinfo->wallet,wacct,tmp) { account = cJSON_CreateObject(); HASH_ITER(hh,wacct->waddr,waddr,tmp2) { - if ( bits256_nonz(waddr->privkey) == 0 ) + if ( bits256_nonz(waddr->privkey) == 0 && waddr->scriptlen == 0 ) { free_json(account); printf("found a null privkey in wallet, abort saving\n"); return(0); } - jaddbits256(account,waddr->coinaddr,waddr->privkey); + if ( waddr->scriptlen != 0 ) + { + init_hexbytes_noT(scriptstr,waddr->redeemScript,waddr->scriptlen); + jaddstr(account,waddr->coinaddr,scriptstr); + } else jaddbits256(account,waddr->coinaddr,waddr->privkey); } wallet = cJSON_CreateObject(); jadd(wallet,wacct->account,account); @@ -85,46 +89,72 @@ struct iguana_waddress *iguana_waddressfind(struct supernet_info *myinfo,struct return(waddr); } -struct iguana_waddress *iguana_waddresscreate(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,char *coinaddr) +struct iguana_waddress *iguana_waddressalloc(char *symbol,char *coinaddr,char *redeemScript) +{ + struct iguana_waddress *waddr; int32_t scriptlen; + scriptlen = (redeemScript != 0) ? ((int32_t)strlen(redeemScript) >> 1) : 0; + waddr = mycalloc('w',1,sizeof(*waddr) + scriptlen); + strcpy(waddr->coinaddr,coinaddr); + strcpy(waddr->symbol,symbol); + if ( (waddr->scriptlen= scriptlen) != 0 ) + decode_hex(waddr->redeemScript,scriptlen,redeemScript); + return(waddr); +} + +struct iguana_waddress *iguana_waddresscreate(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,char *coinaddr,char *redeemScript) { struct iguana_waddress *waddr,*ptr; int32_t len = (int32_t)strlen(coinaddr)+1; HASH_FIND(hh,wacct->waddr,coinaddr,len,waddr); if ( waddr == 0 ) { - waddr = mycalloc('w',1,sizeof(*waddr)); - strcpy(waddr->coinaddr,coinaddr); - strcpy(waddr->symbol,coin->symbol); - HASH_ADD_KEYPTR(hh,wacct->waddr,waddr->coinaddr,len,waddr); - myinfo->dirty = (uint32_t)time(NULL); - printf("create (%s).%d -> (%s)\n",coinaddr,len,wacct->account); + if ( (waddr= iguana_waddressalloc(coin->symbol,coinaddr,redeemScript)) != 0 ) + { + HASH_ADD_KEYPTR(hh,wacct->waddr,waddr->coinaddr,len,waddr); + myinfo->dirty = (uint32_t)time(NULL); + printf("create (%s).%d scriptlen.%d -> (%s)\n",coinaddr,len,waddr->scriptlen,wacct->account); + } else printf("error iguana_waddressalloc null waddr\n"); } //else printf("have (%s) in (%s)\n",coinaddr,wacct->account); if ( (ptr= iguana_waddressfind(myinfo,coin,wacct,coinaddr)) != waddr ) printf("iguana_waddresscreate verify error %p vs %p\n",ptr,waddr); return(waddr); } -struct iguana_waddress *iguana_waddressadd(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,struct iguana_waddress *addwaddr) +struct iguana_waddress *iguana_waddressadd(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,struct iguana_waddress *addwaddr,char *redeemScript) { struct iguana_waddress *waddr,*ptr; int32_t len = (int32_t)strlen(addwaddr->coinaddr)+1; HASH_FIND(hh,wacct->waddr,addwaddr->coinaddr,len,waddr); if ( waddr == 0 ) { - waddr = mycalloc('w',1,sizeof(*waddr)); - memcpy(waddr,addwaddr,sizeof(*waddr)); - addwaddr = waddr; - HASH_ADD_KEYPTR(hh,wacct->waddr,waddr->coinaddr,len,waddr); - myinfo->dirty = (uint32_t)time(NULL); - printf("add (%s).%d -> (%s)\n",waddr->coinaddr,len,wacct->account); + if ( (waddr= iguana_waddressalloc(coin->symbol,addwaddr->coinaddr,redeemScript)) != 0 ) + { + HASH_ADD_KEYPTR(hh,wacct->waddr,waddr->coinaddr,len,waddr); + myinfo->dirty = (uint32_t)time(NULL); + printf("add (%s).%d scriptlen.%d -> (%s)\n",waddr->coinaddr,len,waddr->scriptlen,wacct->account); + } else printf("error iguana_waddressalloc null waddr\n"); } //else printf("have (%s) in (%s)\n",waddr->coinaddr,wacct->account); if ( (ptr= iguana_waddressfind(myinfo,coin,wacct,waddr->coinaddr)) != waddr ) printf("iguana_waddressadd verify error %p vs %p\n",ptr,waddr); if ( waddr != 0 && waddr != addwaddr ) { - waddr->privkey = addwaddr->privkey; + if ( redeemScript != 0 && (addwaddr->scriptlen= (int32_t)strlen(redeemScript) >> 1) != 0 ) + { + if ( waddr->scriptlen != addwaddr->scriptlen ) + { + if ( waddr->scriptlen < addwaddr->scriptlen ) + { + printf("unexpected waddr->scriptlen mismatch\n"); + } + waddr->scriptlen = addwaddr->scriptlen; + decode_hex(waddr->redeemScript,waddr->scriptlen,redeemScript); + } + } + if ( bits256_nonz(waddr->privkey) == 0 ) + waddr->privkey = addwaddr->privkey; memcpy(waddr->pubkey,addwaddr->pubkey,sizeof(waddr->pubkey)); memcpy(waddr->rmd160,addwaddr->rmd160,sizeof(waddr->rmd160)); strcpy(waddr->coinaddr,addwaddr->coinaddr); - strcpy(waddr->wifstr,addwaddr->wifstr); + if ( waddr->wifstr[0] == 0 ) + strcpy(waddr->wifstr,addwaddr->wifstr); waddr->wiftype = addwaddr->wiftype; waddr->type = addwaddr->type; myinfo->dirty = (uint32_t)time(NULL); @@ -200,7 +230,7 @@ struct iguana_waddress *iguana_waddresscalc(uint8_t pubtype,uint8_t wiftype,stru return(0); } -struct iguana_waddress *iguana_waccountswitch(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr) +struct iguana_waddress *iguana_waccountswitch(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr,char *redeemScript) { struct iguana_waccount *wacct = 0; struct iguana_waddress addr,*waddr = 0; int32_t flag = 0; if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,coinaddr)) != 0 ) @@ -211,8 +241,8 @@ struct iguana_waddress *iguana_waccountswitch(struct supernet_info *myinfo,struc } if ( (wacct= iguana_waccountcreate(myinfo,coin,account)) != 0 ) { - waddr = iguana_waddresscreate(myinfo,coin,wacct,coinaddr); - if ( flag != 0 ) + waddr = iguana_waddresscreate(myinfo,coin,wacct,coinaddr,redeemScript); + if ( flag != 0 && redeemScript == 0 ) iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,waddr,addr.privkey); } return(waddr); @@ -263,15 +293,15 @@ cJSON *getaddressesbyaccount(struct supernet_info *myinfo,struct iguana_info *co return(array); } -struct iguana_waddress *iguana_waccountadd(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount **wacctp,char *walletaccount,char *coinaddr) +/*struct iguana_waddress *iguana_waccountadd(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount **wacctp,char *walletaccount,char *coinaddr,char *redeemScript) { struct iguana_waccount *wacct; struct iguana_waddress *waddr = 0; if ( (wacct= iguana_waccountfind(myinfo,coin,walletaccount)) == 0 ) wacct = iguana_waccountcreate(myinfo,coin,walletaccount); if ( wacct != 0 ) - waddr = iguana_waddresscreate(myinfo,coin,wacct,coinaddr); + waddr = iguana_waddresscreate(myinfo,coin,wacct,coinaddr,redeemScript); return(waddr); -} +}*/ void iguana_walletlock(struct supernet_info *myinfo) { @@ -328,7 +358,7 @@ int32_t iguana_addressvalidate(struct iguana_info *coin,uint8_t *addrtypep,uint8 cJSON *iguana_waddressjson(cJSON *item,struct iguana_waddress *waddr) { - char str[256]; + char str[256],redeemScript[4096]; if ( item == 0 ) item = cJSON_CreateObject(); jaddstr(item,"address",waddr->coinaddr); @@ -339,17 +369,22 @@ cJSON *iguana_waddressjson(cJSON *item,struct iguana_waddress *waddr) init_hexbytes_noT(str,waddr->rmd160,20); jaddstr(item,"rmd160",str); jaddstr(item,"coin",waddr->symbol); + if ( waddr->scriptlen > 0 ) + { + init_hexbytes_noT(redeemScript,waddr->redeemScript,waddr->scriptlen); + jaddstr(item,"redeemScript",redeemScript); + } return(item); } -char *setaccount(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr) +char *setaccount(struct supernet_info *myinfo,struct iguana_info *coin,char *account,char *coinaddr,char *redeemScript) { uint8_t addrtype,rmd160[20]; struct iguana_waddress *waddr=0; if ( coinaddr != 0 && coinaddr[0] != 0 && account != 0 && account[0] != 0 ) { if ( iguana_addressvalidate(coin,&addrtype,rmd160,coinaddr) < 0 ) return(clonestr("{\"error\":\"invalid coin address\"}")); - if ( (waddr= iguana_waccountswitch(myinfo,coin,account,coinaddr)) != 0 ) + if ( (waddr= iguana_waccountswitch(myinfo,coin,account,coinaddr,redeemScript)) != 0 ) return(clonestr("{\"result\":\"success\"}")); else return(clonestr("{\"error\":\"couldnt set account\"}")); } @@ -407,11 +442,31 @@ bits256 iguana_str2priv(struct supernet_info *myinfo,struct iguana_info *coin,ch { if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,str)) != 0 ) privkey = waddr->privkey; + else memset(privkey.bytes,0,sizeof(privkey)); } } return(privkey); } +int32_t iguana_pubkeyget(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *pubkey33,char *pkstr) +{ + bits256 privkey,pubkey; + decode_hex(pubkey33,(int32_t)strlen(pkstr) >> 1,pkstr); + if ( bitcoin_pubkeylen(pubkey33) <= 0 ) + { + privkey = iguana_str2priv(myinfo,coin,pkstr); + if ( bits256_nonz(privkey) == 0 ) + return(-1); + else + { + pubkey = bitcoin_pubkey33(pubkey33,privkey); + if ( bits256_nonz(pubkey) == 0 ) + return(-1); + } + } + return(0); +} + char *iguana_addressconv(struct iguana_info *coin,char *destaddr,struct iguana_info *other,int32_t isp2sh,uint8_t rmd160[20]) { if ( bitcoin_address(destaddr,isp2sh != 0 ? other->chain->pubtype : other->chain->p2shtype,rmd160,20) == destaddr ) @@ -469,7 +524,7 @@ int32_t iguana_payloadupdate(struct supernet_info *myinfo,struct iguana_info *co return(retval); } -cJSON *iguana_walletadd(struct supernet_info *myinfo,struct iguana_waddress **waddrp,struct iguana_info *coin,char *retstr,char *account,struct iguana_waddress *refwaddr,int32_t setcurrent) +cJSON *iguana_walletadd(struct supernet_info *myinfo,struct iguana_waddress **waddrp,struct iguana_info *coin,char *retstr,char *account,struct iguana_waddress *refwaddr,int32_t setcurrent,char *redeemScript) { cJSON *retjson=0; struct iguana_waccount *wacct; struct iguana_waddress *waddr; if ( (wacct= iguana_waccountfind(myinfo,coin,account)) == 0 ) @@ -477,7 +532,7 @@ cJSON *iguana_walletadd(struct supernet_info *myinfo,struct iguana_waddress **wa if ( wacct != 0 ) { //waddr = iguana_waddressfind(myinfo,coin,wacct,refwaddr->coinaddr); - waddr = iguana_waddressadd(myinfo,coin,wacct,refwaddr); + waddr = iguana_waddressadd(myinfo,coin,wacct,refwaddr,redeemScript); if ( setcurrent != 0 ) wacct->current = waddr; if ( iguana_payloadupdate(myinfo,coin,retstr,waddr,account) < 0 ) @@ -505,11 +560,12 @@ char *getnewaddress(struct supernet_info *myinfo,struct iguana_waddress **waddrp struct iguana_waddress addr; cJSON *retjson; if ( myinfo->expiration == 0 ) return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; if ( retstr != 0 ) { memset(&addr,0,sizeof(addr)); if ( iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&addr,rand256(1)) != 0 ) - retjson = iguana_walletadd(myinfo,waddrp,coin,retstr,account,&addr,1); + retjson = iguana_walletadd(myinfo,waddrp,coin,retstr,account,&addr,1,0); else return(clonestr("{\"error\":\"couldnt calculate waddr\"}")); } else return(clonestr("{\"error\":\"no wallet data\"}")); return(jprint(retjson,1)); @@ -555,6 +611,7 @@ ZERO_ARGS(bitcoinrpc,getinfo) { jaddstr(retjson,"result","success"); jaddnum(retjson,"protocolversion",PROTOCOL_VERSION); + jaddnum(retjson,"kbfee",dstr(coin->txfee_perkb)); jaddnum(retjson,"blocks",coin->blocks.hwmchain.height); jaddnum(retjson,"longestchain",coin->longestchain); jaddnum(retjson,"port",coin->chain->portp2p); @@ -570,7 +627,10 @@ TWO_STRINGS(bitcoinrpc,setaccount,address,account) { if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); - return(setaccount(myinfo,coin,account,address)); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + return(setaccount(myinfo,coin,account,address,0)); } STRING_ARG(bitcoinrpc,getaccount,address) @@ -587,6 +647,7 @@ STRING_ARG(bitcoinrpc,getnewaddress,account) return(clonestr("{\"error\":\"no remote\"}")); if ( myinfo->expiration == 0 ) return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; if ( (retstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,0)) != 0 ) { free(retstr); @@ -606,6 +667,7 @@ STRING_ARG(bitcoinrpc,getaccountaddress,account) return(clonestr("{\"error\":\"no remote\"}")); if ( myinfo->expiration == 0 ) return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; if ( account != 0 && account[0] != 0 ) { if ( (wacct= iguana_waccountfind(myinfo,coin,account)) == 0 ) @@ -647,7 +709,7 @@ ZERO_ARGS(bitcoinrpc,walletlock) void iguana_walletinitcheck(struct supernet_info *myinfo,struct iguana_info *coin) { // "wallet":{"test":{"R9S7zZzzvgb4CkiBH1i7gnFcwJuL1MYbxN":"18ab9c89ce83929db720cf26b663bf762532276146cd9d3e1f89086fcdf00053"}} - cJSON *payload,*item,*array,*child; char *account,*coinaddr,*privkeystr; int32_t i,j,n,len; struct iguana_waccount *wacct,*tmp; struct iguana_waddress waddr; bits256 privkey; + cJSON *payload,*item,*array,*child; char *account,*coinaddr,*privkeystr; int32_t i,j,n,len; struct iguana_waccount *wacct,*tmp; struct iguana_waddress waddr; bits256 privkey; uint8_t addrtype,rmd160[20]; if ( myinfo->wallet == 0 && myinfo->decryptstr != 0 && (payload= cJSON_Parse(myinfo->decryptstr)) != 0 ) { if ( (array= jobj(payload,"wallet")) != 0 ) @@ -670,21 +732,24 @@ void iguana_walletinitcheck(struct supernet_info *myinfo,struct iguana_info *coi { if ( iguana_waddresssearch(myinfo,coin,&tmp,coinaddr) == 0 ) { - privkey = bits256_conv(privkeystr); - if ( iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&waddr,privkey) != 0 ) + memset(&waddr,0,sizeof(waddr)); + strcpy(waddr.coinaddr,coinaddr); + if ( bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr) == sizeof(rmd160) && addrtype == coin->chain->p2shtype ) + iguana_waddressadd(myinfo,coin,wacct,&waddr,privkeystr); + else { - strcpy(waddr.coinaddr,coinaddr); - iguana_waddressadd(myinfo,coin,wacct,&waddr); - //iguana_waccountswitch(myinfo,coin,account,coinaddr); + privkey = bits256_conv(privkeystr); + if ( iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&waddr,privkey) != 0 ) + iguana_waddressadd(myinfo,coin,wacct,&waddr,0); } } else printf("dup.(%s) ",coinaddr); + len = (int32_t)strlen(privkeystr); + for (j=0; jnext; } @@ -702,7 +767,7 @@ void iguana_walletinitcheck(struct supernet_info *myinfo,struct iguana_info *coi int32_t iguana_walletemit(struct supernet_info *myinfo,char *fname,struct iguana_info *coin,cJSON *array) { - cJSON *item,*child; uint8_t addrtype,wiftype,rmd160[20]; char str[64],wifstr[128],*account,*coinaddr,*privkeystr; int32_t i,j,n; FILE *fp; bits256 privkey; + cJSON *item,*child; uint8_t addrtype,wiftype,rmd160[20]; char p2shaddr[128],str[64],wifstr[128],*account,*coinaddr,*privkeystr; int32_t i,j,n; FILE *fp; bits256 privkey; if ( (fp= fopen(fname,"wb")) == 0 ) return(-1); n = cJSON_GetArraySize(array); @@ -718,19 +783,28 @@ int32_t iguana_walletemit(struct supernet_info *myinfo,char *fname,struct iguana privkeystr = child->valuestring; if ( coinaddr != 0 && privkeystr != 0 ) { - // RZXuGgmzABFpXRmGJet8AbJoqVGEs27WgdvkSSXUMg7en8jjBW2m 2016-03-26T18:40:06Z reserve=1 # addr=GRVaqhY6XVWGeEabEEx5gE7mAQ7EYQi5JV - privkey = bits256_conv(privkeystr); bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); wiftype = 188; for (j=0; jchain != 0 && coin->chain->pubtype == addrtype ) + { + if ( (coin= Coins[j]) != 0 && coin->chain != 0 ) { - wiftype = coin->chain->wiftype; - break; + if ( addrtype == coin->chain->pubtype ) + { + wiftype = coin->chain->wiftype; + privkey = bits256_conv(privkeystr); + if ( bitcoin_priv2wif(wifstr,privkey,wiftype) > 0 ) + { + fprintf(fp,"%s %s %32s=%d # addr=%s\n",wifstr,utc_str(str,(uint32_t)time(NULL)),account,i+1,coinaddr); + } + break; + } + else if ( addrtype == coin->chain->p2shtype ) + { + fprintf(fp,"%s %s %32s=%d # addr=%s # p2sh\n",privkeystr,utc_str(str,(uint32_t)time(NULL)),account,i+1,p2shaddr); + break; + } } - if ( bitcoin_priv2wif(wifstr,privkey,wiftype) > 0 ) - { - fprintf(fp,"%s %s %32s=%d # addr=%s\n",wifstr,utc_str(str,(uint32_t)time(NULL)),account,i+1,coinaddr); } } child = child->next; @@ -808,6 +882,9 @@ TWOSTRINGS_AND_INT(bitcoinrpc,importprivkey,wif,account,rescan) bits256 privkey; char *retstr; cJSON *retjson; struct iguana_waddress addr,*waddr; struct iguana_waccount *wacct = 0; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; if ( account == 0 || account[0] == 0 ) account = "default"; privkey = iguana_str2priv(myinfo,coin,wif); @@ -818,11 +895,12 @@ TWOSTRINGS_AND_INT(bitcoinrpc,importprivkey,wif,account,rescan) { if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,addr.coinaddr)) != 0 ) { - waddr = iguana_waccountswitch(myinfo,coin,account,addr.coinaddr); + waddr = iguana_waccountswitch(myinfo,coin,account,addr.coinaddr,0); return(clonestr("{\"result\":\"privkey already in wallet\"}")); } if ( myinfo->expiration == 0 ) return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; if ( (retstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,0)) != 0 ) { free(retstr); @@ -830,7 +908,7 @@ TWOSTRINGS_AND_INT(bitcoinrpc,importprivkey,wif,account,rescan) if ( waddr == 0 ) waddr = &addr; iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,waddr,privkey); - retjson = iguana_walletadd(myinfo,0,coin,retstr,account,waddr,0); + retjson = iguana_walletadd(myinfo,0,coin,retstr,account,waddr,0,0); if ( retstr != 0 ) scrubfree(retstr); return(jprint(retjson,1)); @@ -844,6 +922,9 @@ STRING_ARG(bitcoinrpc,dumpprivkey,address) cJSON *retjson; struct iguana_waddress *waddr; struct iguana_waccount *wacct; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,address)) != 0 && waddr->wifstr[0] != 0 ) { retjson = cJSON_CreateObject(); @@ -857,6 +938,9 @@ ZERO_ARGS(bitcoinrpc,checkwallet) cJSON *retjson; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); return(jprint(retjson,1)); @@ -867,6 +951,9 @@ ZERO_ARGS(bitcoinrpc,repairwallet) cJSON *retjson; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); return(jprint(retjson,1)); @@ -879,6 +966,7 @@ STRING_ARG(bitcoinrpc,dumpwallet,filename) return(clonestr("{\"error\":\"no remote\"}")); if ( myinfo->expiration != 0 ) { + myinfo->expiration++; if ( (retstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,0)) != 0 ) { if ( (retjson= cJSON_Parse(retstr)) != 0 ) @@ -908,6 +996,7 @@ STRING_ARG(bitcoinrpc,backupwallet,filename) return(clonestr("{\"error\":\"no remote\"}")); if ( myinfo->expiration != 0 ) { + myinfo->expiration++; if ( (loginstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,0)) != 0 ) { retstr = clonestr("{\"error\":\"couldnt backup wallet\"}"); @@ -940,7 +1029,11 @@ cJSON *iguana_payloadmerge(cJSON *loginjson,cJSON *importjson) if ( (field= jfieldname(item)) != 0 ) { if ( (obj= jobj(retjson,field)) == 0 ) - jaddbits256(retjson,field,jbits256(item,0)); + { + if ( strlen(field) == 20*2 ) + jaddstr(retjson,field,jstr(item,0)); + else jaddbits256(retjson,field,jbits256(item,0)); + } } item = item->next; } @@ -954,6 +1047,7 @@ STRING_ARG(bitcoinrpc,importwallet,filename) return(clonestr("{\"error\":\"no remote\"}")); if ( myinfo->expiration != 0 ) { + myinfo->expiration++; if ( (importstr= OS_filestr(&filesize,filename)) != 0 ) { if ( (importjson= cJSON_Parse(importstr)) != 0 ) @@ -1175,22 +1269,85 @@ STRING_AND_INT(bitcoinrpc,getreceivedbyaddress,address,minconf) return(jprint(retjson,1)); } -INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,array,ignore) +INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,pubkeys,ignore) { - cJSON *retjson; + cJSON *retjson,*pkjson; uint8_t script[2048],p2sh_rmd160[20]; char msigaddr[64],*pkstr,scriptstr[sizeof(script)*2+1]; struct vin_info V; int32_t i,len,n = cJSON_GetArraySize(pubkeys); if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( n < 0 || n > 16 || M < 0 || M > n ) + return(clonestr("{\"error\":\"illegal number of pubkeys\"}")); + memset(&V,0,sizeof(V)); + V.M = M, V.N = n; + pkjson = cJSON_CreateArray(); + for (i=0; ichain->p2shtype,p2sh_rmd160,sizeof(p2sh_rmd160)); + jaddstr(retjson,"result","success"); + jaddstr(retjson,"address",msigaddr); + init_hexbytes_noT(scriptstr,script,len); + jaddstr(retjson,"redeemScript",scriptstr); + jaddnum(retjson,"M",M); + jaddnum(retjson,"N",n); + jadd(retjson,"pubkeys",pkjson); + } + else + { + jaddstr(retjson,"error","couldnt get all pubkeys"); + free_json(pkjson); + } return(jprint(retjson,1)); } -INT_ARRAY_STRING(bitcoinrpc,addmultisig,M,array,account) // +INT_ARRAY_STRING(bitcoinrpc,addmultisigaddress,M,pubkeys,account) // { - cJSON *retjson; + cJSON *retjson,*tmpjson,*setjson=0; char *retstr,*str=0,*msigaddr,*redeemScript; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); - retjson = cJSON_CreateObject(); - return(jprint(retjson,1)); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + if ( (retstr= bitcoinrpc_createmultisig(IGUANA_CALLARGS,M,pubkeys,account)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (msigaddr= jstr(retjson,"address")) != 0 ) + { + if ( (redeemScript= jstr(retjson,"redeemScript")) == 0 || (str= setaccount(myinfo,coin,account,msigaddr,redeemScript)) == 0 || (setjson= cJSON_Parse(str)) == 0 || jobj(setjson,"error") != 0 ) + { + if ( jobj(retjson,"result") != 0 ) + jdelete(retjson,"result"); + if ( jobj(retjson,"error") == 0 ) + jaddstr(retjson,"error","couldnt add multisig address to account"); + } + else + { + tmpjson = cJSON_CreateObject(); + jaddstr(tmpjson,"result",msigaddr); + free_json(retjson); + free(retstr); + retjson = tmpjson; + } + } + if ( setjson != 0 ) + free_json(setjson); + if ( str != 0 ) + free(str); + return(jprint(retjson,1)); + } else return(clonestr("{\"error\":\"couldnt parse retstr from createmultisig\"}")); + } else return(clonestr("{\"error\":\"no retstr from createmultisig\"}")); } STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees) @@ -1204,7 +1361,12 @@ DOUBLE_ARG(bitcoinrpc,settxfee,amount) cJSON *retjson; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + coin->txfee_perkb = amount * SATOSHIDEN; retjson = cJSON_CreateObject(); + jadd(retjson,"result",jtrue()); return(jprint(retjson,1)); } @@ -1213,6 +1375,9 @@ S_D_SS(bitcoinrpc,sendtoaddress,address,amount,comment,comment2) cJSON *retjson; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; retjson = cJSON_CreateObject(); return(jsuccess()); } @@ -1222,6 +1387,9 @@ SS_D_I_SS(bitcoinrpc,sendfrom,fromaccount,toaddress,amount,minconf,comment,comme cJSON *retjson; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; retjson = cJSON_CreateObject(); return(jsuccess()); } @@ -1231,6 +1399,9 @@ SS_D_I_S(bitcoinrpc,move,fromaccount,toaccount,amount,minconf,comment) cJSON *retjson; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } @@ -1240,6 +1411,9 @@ S_A_I_S(bitcoinrpc,sendmany,fromaccount,array,minconf,comment) cJSON *retjson; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } diff --git a/iguana/tests/addmultisig b/iguana/tests/addmultisig new file mode 100755 index 000000000..f1ed80c00 --- /dev/null +++ b/iguana/tests/addmultisig @@ -0,0 +1,2 @@ +curl --url "http://127.0.0.1:7778" --data "{\"method\":\"addmultisig\",\"params\":[2, [\"002629c77b81a4d338a339488aaff796a93aeec8c734b22dee865d0ff58ff64c\", \"d0296ed1364639c696c374730320480301f3194c86231f62f0409cd76467f87c\", \"d045925b3e6f648bca6ed0c65149ee445137f0ab14e88cf60013d88419bcdd60\"], \"msigs\"]}" + diff --git a/iguana/tests/createmultisig b/iguana/tests/createmultisig new file mode 100755 index 000000000..84f093b80 --- /dev/null +++ b/iguana/tests/createmultisig @@ -0,0 +1,2 @@ +curl --url "http://127.0.0.1:7778" --data "{\"method\":\"createmultisig\",\"params\":[2, [\"002629c77b81a4d338a339488aaff796a93aeec8c734b22dee865d0ff58ff64c\", \"d0296ed1364639c696c374730320480301f3194c86231f62f0409cd76467f87c\", \"d045925b3e6f648bca6ed0c65149ee445137f0ab14e88cf60013d88419bcdd60\"]]}" + diff --git a/iguana/tests/walletpassphrase b/iguana/tests/walletpassphrase index 347d3fd52..16c6669bf 100755 --- a/iguana/tests/walletpassphrase +++ b/iguana/tests/walletpassphrase @@ -1,2 +1,2 @@ -curl --url "http://127.0.0.1:7778" --data "{\"method\":\"walletpassphrase\",\"params\":[\"test\", 600]}" -#curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"bitcoinrpc\",\"method\":\"walletpassphrase\",\"password\":\"test\",\"timeout\":300}" +#curl --url "http://127.0.0.1:7778" --data "{\"method\":\"walletpassphrase\",\"params\":[\"test\", 600]}" +curl --url "http://127.0.0.1:7778" --data "{\"agent\":\"bitcoinrpc\",\"method\":\"walletpassphrase\",\"password\":\"test\",\"timeout\":300}" diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 7ba340aee..2dfbc2664 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -57,8 +57,9 @@ STRING_ARG(bitcoinrpc,getaccount,address); STRING_ARG(bitcoinrpc,getaccountaddress,account); TWO_STRINGS(bitcoinrpc,setaccount,address,account); -INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,array,ignore); // -INT_ARRAY_STRING(bitcoinrpc,addmultisig,M,array,account); // +INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,pubkeys,ignore); +INT_ARRAY_STRING(bitcoinrpc,addmultisigaddress,M,pubkeys,account); + STRING_ARRAY_OBJ_STRING(bitcoinrpc,signrawtransaction,rawtx,vins,privkeys,sighash); // STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees); //