From 7fccea1dab7299ea0c715d8a8be01c393300558d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 17 Sep 2018 03:08:28 -1100 Subject: [PATCH] Msig suppport --- src/cc/CCGateways.h | 2 +- src/cc/dapps/oraclefeed.c | 155 ++++++++++++++++++++++++++++++++------ src/cc/gateways.cpp | 30 +------- src/rpcserver.cpp | 1 + src/rpcserver.h | 1 + src/wallet/rpcwallet.cpp | 20 +++++ 6 files changed, 159 insertions(+), 50 deletions(-) diff --git a/src/cc/CCGateways.h b/src/cc/CCGateways.h index cfb3bd482..5d8e98228 100644 --- a/src/cc/CCGateways.h +++ b/src/cc/CCGateways.h @@ -27,7 +27,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector withdrawpub,int64_t amount); UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin); std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid); -UniValue GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *unspentstr); +UniValue GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *txidaddr); // CCcustom UniValue GatewaysInfo(uint256 bindtxid); diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index 40db2882b..be7b14b81 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -546,6 +546,109 @@ void importaddress(char *refcoin,char *acname,char *depositaddr) return(0); } +cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) +{ + cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid; + *totalp = 0; + if ( (n= cJSON_GetArraySize(unspents)) > 0 ) + { + for (i=0; i= required ) + break; + } + } + } + return(vins); +} + +char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signeraddr,char *withdrawaddr,int64_t satoshis) +{ + char *retstr,*retstr2,array[128],*txstr = 0; cJSON *retjson2,*retjson,*vins,*vouts; int64_t txfee,total,change = 0; + if ( strcmp(refcoin,"BTC") == 0 ) + txfee = 20000; + else txfee = 10000; + if ( satoshis < txfee ) + { + printf("createmultisig satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIS); + return(0); + } + satoshis -= txfee; + sprintf(array,"[\"%s\"]",depositaddr); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent",1,99999999,array,"")) != 0 ) + { + //createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...} + if ( (vins= getinputarray(&total,retjson,satoshis)) != 0 ) + { + if ( total >= satoshis ) + { + vouts = cJSON_CreatObject(); + jaddstr(vouts,withdrawaddr,(double)satoshis/SATOSHIDEN); + if ( total > satoshis+txfee ) + { + change = (total - satoshis); + jaddstr(vouts,depositaddr,(double)change/SATOSHIDEN); + } + if ( (retjson2= get_komodocli(refcoin,&txstr,acname,"createrawtransaction",jprint(vins,0),jprint(vouts,0),"","")) != 0 ) + { + printf("createmultisig: unexpected JSON2.(%s)\n",jprint(retjson2,0)); + free_json(retjson2); + } + else if ( txstr == 0 ) + printf("createmultisig: null txstr and JSON2\n"); + free_json(vins); + free_json(vouts); + } + } + } + else if ( retstr != 0 ) + { + printf("createmultisig: unexpected null JSON, retstr.(%s)\n",retstr); + free(retstr); + } + else printf("createmultisig: null retstr and JSON\n"); + return(txstr); +} + +cJSON *addmultisignature(char *refcoin,char *acname,char *signeraddr,char *rawtx) +{ + char *retstr,*hexstr; cJSON *retjson; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 ) + { + if ( jint(retjson,"complete") != 0 ) + return(retjson); + else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) ) + { + jadd(retjson,"partialtx",1)' + return(retjson); + } + free_json(retjson); + } + return(0); +} + +char *get_gatewaysmultisig(char *refcoin,char *acname,char *bindtxidstr,char *withtxidstr,char *txidaddr) +{ + char *retstr,*hexstr,*hex=0; cJSON *retjson; + if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",bindtxidstr,refcoin,withtxidstr,txidstr)) != 0 ) + { + if ( (hexstr= jstr(retjson,"hex")) != 0 ) + hex = clonestr(hexstr); + free_json(retjson); + } + return(hex); +} void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin,bits256 cointxid) { @@ -661,7 +764,7 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t /// if enough sigs, sendrawtransaction and when it confirms spend marker (txid.2) /// if not enough sigs, post partially signed to acname with marker2 // monitor marker2, for the partially signed withdraws - cJSON *retjson,*pending,*item,*clijson; char str[65],*unspentstr,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,retval,processed = 0; bits256 txid,cointxid,origtxid,zeroid; int64_t satoshis; + cJSON *retjson,*pending,*item,*clijson; char str[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,retval,processed = 0; bits256 txid,cointxid,origtxid,zeroid; int64_t satoshis; memset(&zeroid,0,sizeof(zeroid)); if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 ) { @@ -699,32 +802,38 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t fprintf(stderr,"ERROR withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); } } - else if ( (unspentstr= get_listunspent(refcoin,"",depositaddr)) != 0 ) + else { - if ( (clijson= get_komodocli("KMD",&retstr2,acname,"gatewaysmultisig",bindtxidstr,bits256_str(str,origtxid),unspentstr)) != 0 ) + if ( (rawtx= get_gatewaysmultisig(refcoin,acname,bindtxidstr,bits256_str(str,origtxid),txidaddr)) == 0 ) { - if ( jint(clijson,"complete") != 0 ) - { - cointxid = komodobroadcast(refcoin,"",clijson2); - if ( bits256_nonz(cointxid) != 0 ) - { - fprintf(stderr,"withdraw %s M.%d N.%d %s %s %.8f processed\n",refcoin,M,N,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); - gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); - processed++; - } - } - else if ( jint(clijson,"partialtx") != 0 ) - { - // 10000 + ith -> txidaddr - txid = komodobroadcast("KMD",acname,clijson2); - fprintf(stderr,"%s M.%d of N.%d partialtx %s sent\n",refcoin,M,N,bits256_str(str,txid)); - processed++; - } - free_json(clijson); + rawtx = createmultisig(refcoin,"",depositaddr,signeraddr,withdrawaddr,satoshis); } - free(unspentstr); + if ( rawtx != 0 ) + { + if ( (clijson= addmultisignature(refcoin,"",signeraddr,rawtx)) != 0 ) + { + if ( jint(clijson,"complete") != 0 ) + { + cointxid = komodobroadcast(refcoin,"",clijson); + if ( bits256_nonz(cointxid) != 0 ) + { + fprintf(stderr,"withdraw %s M.%d N.%d %s %s %.8f processed\n",refcoin,M,N,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); + gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); + } + } + else if ( jint(clijson,"partialtx") != 0 ) + { + // 10000 + ith -> txidaddr + txid = komodobroadcast("KMD",acname,clijson); + fprintf(stderr,"%s M.%d of N.%d partialtx %s sent\n",refcoin,M,N,bits256_str(str,txid)); + } + free_json(clijson); + } + processed++; + free(rawtx); + } else fprintf(stderr,"couldnt create msig rawtx\n"); } - } else fprintf(stderr,"error sending %s txidaddr.%s -> %s exists.%d\n",acname,txidaddr,bits256_str(str,txid),coinaddrexists(refcoin,acname,txidaddr)); + } } else if ( retval > 0 ) { diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index df5c24e7c..6a4f60413 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -837,23 +837,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) return(result); } -std::string GatewaysMultisigUpdate(struct CCcontract_info *cp,int32_t &complete,int32_t &partialtx,CPubKey mypk,int32_t ith,uint256 withdrawtxid,uint8_t M,uint8_t N,char *unspentstr) -{ - CMutableTransaction mtx; cJSON *unspents; std::string hex,rawtx; CScript opret; uint64_t txfee = 10000; - complete = partialtx = 0; - { - // iterate txidaddr, extract signatures! - // iterate for sigs depth and find the deepest - // if not already a signer, add signature and post to next - // if first one, then create a rawtx and sign it, ie. depth 1 - // if fully signed, broadcast - - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); - } - return(hex); -} - -UniValue GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *unspentstr) +std::string GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *txidaddr) { UniValue result(UniValue::VOBJ); std::string coin,hex; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CPubKey Gatewayspk,mypk; struct CCcontract_info *cp,C; int32_t i,n,complete,partialtx; int64_t totalsupply; cp = CCinit(&C,EVAL_GATEWAYS); @@ -868,22 +852,16 @@ UniValue GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,ui depositaddr[0] = 0; if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 1 && coin == refcoin ) { + // need a decentralized way to add signatures to msig tx n = pubkeys.size(); for (i=0; i send tx to refcoin withdraw complete - // partialtx:1 -> send partialsig to txidaddr, satoshis 10000 + ith pubkey + 1 - result.push_back(Pair("result","success")); - result.push_back(Pair("coin",refcoin)); - result.push_back(Pair("complete",complete)); - result.push_back(Pair("partialtx",partialtx)); - result.push_back(Pair("hex",hex)); - return(result); + return(hex); } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c4c8d378b..d268ed7fa 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -418,6 +418,7 @@ static const CRPCCommand vRPCCommands[] = { "gateways", "gatewaysclaim", &gatewaysclaim, true }, { "gateways", "gatewayswithdraw", &gatewayswithdraw, true }, { "gateways", "gatewayspending", &gatewayspending, true }, + { "gateways", "gatewaysmultisig", &gatewaysmultisig, true }, { "gateways", "gatewaysmarkdone", &gatewaysmarkdone, true }, /* dice */ diff --git a/src/rpcserver.h b/src/rpcserver.h index a697ee4ee..1ebff82ef 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -244,6 +244,7 @@ extern UniValue gatewaysclaim(const UniValue& params, bool fHelp); extern UniValue gatewayswithdraw(const UniValue& params, bool fHelp); extern UniValue gatewayspending(const UniValue& params, bool fHelp); extern UniValue gatewaysmarkdone(const UniValue& params, bool fHelp); +extern UniValue gatewaysmultisig(const UniValue& params, bool fHelp); extern UniValue channelsinfo(const UniValue& params, bool fHelp); extern UniValue channelsbind(const UniValue& params, bool fHelp); extern UniValue channelsopen(const UniValue& params, bool fHelp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ef5b33ab5..e0afbb982 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5543,6 +5543,26 @@ UniValue gatewayspending(const UniValue& params, bool fHelp) return(GatewaysPendingWithdraws(bindtxid,coin)); } +UniValue gatewaysmultisig(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 bindtxid,withtxid; std::string coin,hex; char *txidaddr; + if ( fHelp || params.size() != 2 ) + throw runtime_error("gatewaysmultisig bindtxid coin withtxid txidaddr\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + coin = params[1].get_str(); + withtxid = Parseuint256((char *)params[2].get_str().c_str()); + txidaddr = params[3].get_str().c_str(); + hex = GatewaysMultisig(0,coin,bindtxid,withdrawtxid,txidaddr); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex",hex)); + } else ERR_RESULT("couldnt gatewaysmultisig"); + return(result); +} + UniValue oracleslist(const UniValue& params, bool fHelp) { if ( fHelp || params.size() > 0 )