From 463caf96ec1251afdee1939dc5359ba96e3e6bd5 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Mon, 28 Jan 2019 13:54:21 +0100 Subject: [PATCH] Gateways with new TokensCC (#15) - Adapting Gateways to new Tokens - Making withdraws serialized until solution for parallel is made --- src/cc/CCGateways.h | 3 +- src/cc/CCtx.cpp | 10 +- src/cc/dapps/oraclefeed.c | 184 +++----- src/cc/gateways.cpp | 970 ++++++++++++++++++++++++-------------- src/rpc/server.cpp | 4 +- src/rpc/server.h | 4 +- src/wallet/rpcwallet.cpp | 29 +- 7 files changed, 700 insertions(+), 504 deletions(-) diff --git a/src/cc/CCGateways.h b/src/cc/CCGateways.h index b629ade1f..7ecae2228 100644 --- a/src/cc/CCGateways.h +++ b/src/cc/CCGateways.h @@ -28,10 +28,9 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex); std::string GatewaysCompleteSigning(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex); std::string GatewaysMarkDone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin); +UniValue GatewaysPendingDeposits(uint256 bindtxid,std::string refcoin); UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin); UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin); -UniValue GatewaysMultisig(char *txidaddr); - // CCcustom UniValue GatewaysInfo(uint256 bindtxid); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 630a00d8f..a8d832661 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -390,9 +390,9 @@ int64_t CCfullsupply(uint256 tokenid) return(0); } -int64_t CCtoken_balance(char *coinaddr,uint256 tokenid) +int64_t CCtoken_balance(char *coinaddr,uint256 reftokenid) { - int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; + int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 tokenid,txid,hashBlock; std::vector vopretExtra; std::vector > unspentOutputs; uint8_t evalCode; @@ -401,11 +401,11 @@ int64_t CCtoken_balance(char *coinaddr,uint256 tokenid) for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; - if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 ) { - char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN); + char str[65]; std::vector voutTokenPubkeys; - if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, voutTokenPubkeys, vopretExtra) != 0 && assetid == tokenid ) + if ( reftokenid==txid || (DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, tokenid, voutTokenPubkeys, vopretExtra) != 0 && reftokenid == tokenid)) { sum += it->second.satoshis; } diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index 8a819a147..8f7ccb197 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -475,7 +475,7 @@ int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *m cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr) { cJSON *retjson; char *retstr; - if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspending",bindtxidstr,refcoin,"","")) != 0 ) + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspendingwithdraws",bindtxidstr,refcoin,"","")) != 0 ) { //printf("pending.(%s)\n",jprint(retjson,0)); return(retjson); @@ -588,13 +588,12 @@ void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int } } -void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys,char *bindtxidstr) +void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys) { cJSON *retjson; char *retstr,Mstr[10],tmp[128]; sprintf(Mstr,"%d",M); - sprintf(tmp,"\"%s\"",bindtxidstr); - if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,tmp,"")) != 0 ) + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,"","")) != 0 ) { fprintf(stderr,"unexpected addmultisigaddress json.(%s)\n",jprint(retjson,0)); free(retstr); @@ -644,7 +643,6 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd printf("createrawtx satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN); return(0); } - satoshis -= txfee; sprintf(array,"\'[\"%s\"]\'",depositaddr); if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 ) { @@ -699,7 +697,7 @@ cJSON *addsignature(char *refcoin,char *acname,char *rawtx) { if ( is_cJSON_True(jobj(retjson,"complete")) != 0 ) return(retjson); - else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) ) + else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) + 2 ) { jaddnum(retjson,"partialtx",1); return(retjson); @@ -714,32 +712,14 @@ cJSON *addsignature(char *refcoin,char *acname,char *rawtx) return(0); } -char *get_gatewaysmultisig(char *refcoin,char *acname,char *txidaddr,int32_t *K) -{ - char *retstr,*hexstr,*hex=0; cJSON *retjson; - if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",txidaddr,"","","")) != 0 ) - { - if ((hexstr=jstr(retjson,"hex")) != 0 ) - { - if (strlen(hexstr)>0) hex = clonestr(hexstr); - } - *K=jint(retjson,"number_of_signs"); - free_json(retjson); - } - else if ( retstr != 0 ) - { - printf("error parsing gatewaysmultisig.(%s)\n",retstr); - free(retstr); - } - return(hex); -} - -bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex) +bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *coin,char *hex) { char str[65],*retstr; cJSON *retjson; - if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 ) + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),coin,hex,"")) != 0 ) { - return(komodobroadcast(refcoin,acname,retjson)); + txid=komodobroadcast(refcoin,acname,retjson); + free(retjson); + return (txid); } else if ( retstr != 0 ) { @@ -749,36 +729,38 @@ bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex) return (zeroid); } -void gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *coin,char *hex) +bits256 gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *coin,char *hex) { - char str[65],str2[65],*retstr; cJSON *retjson; - printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid)); + char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid; if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayscompletesigning",bits256_str(str,withtxid),coin,hex,"")) != 0 ) { - komodobroadcast(refcoin,acname,retjson); - free_json(retjson); + txid=komodobroadcast(refcoin,acname,retjson); + free(retjson); + return (txid); } else if ( retstr != 0 ) { printf("error parsing gatewayscompletesigning.(%s)\n",retstr); free(retstr); } + return (zeroid); } -void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin) +bits256 gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin) { - char str[65],str2[65],*retstr; cJSON *retjson; - printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid)); + char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid; if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,"","")) != 0 ) { - komodobroadcast(refcoin,acname,retjson); - free_json(retjson); + txid=komodobroadcast(refcoin,acname,retjson); + free(retjson); + return (txid); } else if ( retstr != 0 ) { printf("error parsing gatewaysmarkdone.(%s)\n",retstr); free(retstr); } + return (zeroid); } int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys) @@ -882,55 +864,9 @@ int32_t markerexists(char *refcoin,char *acname,char *coinaddr) free_json(array); } } - fprintf(stderr,"Num=%d\n",num); return(num); } -int32_t markerfromthisnodeorunconfirmed(char *refcoin,char *acname,char *coinaddr) -{ - cJSON *array,*item,*rawtx,*vins,*vin; bits256 txid,tmptxid; int32_t i,n,m,num=0; char *retstr; - if ( (array= get_addressutxos(refcoin,acname,coinaddr)) != 0 ) - { - n=cJSON_GetArraySize(array); - for (i=0; i 0 ) - { - num = 1; - break; - } - } - } - free_json(array); - } else return(-1); - } - return(num); -} void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N) { @@ -941,7 +877,9 @@ 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],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,origtxid; int64_t satoshis; + cJSON *retjson,*pending,*item,*clijson; char str[65],str1[65],str2[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; + int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,withdrawtxid,lasttxid,completetxid; int64_t satoshis; + memset(&zeroid,0,sizeof(zeroid)); if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 ) { @@ -954,52 +892,55 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t if ( processed != 0 ) // avoid out of utxo conditions break; item = jitem(pending,i); - origtxid = jbits256(item,"txid"); + withdrawtxid = jbits256(item,"withdrawtxid"); //process item.0 {"txid":"10ec8f4dad6903df6b249b361b879ac77b0617caad7629b97e10f29fa7e99a9b","txidaddr":"RMbite4TGugVmkGmu76ytPHDEQZQGSUjxz","withdrawaddr":"RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc","amount":"1.00000000","depositaddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","signeraddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj"} - if ( (txidaddr= jstr(item,"txidaddr")) != 0 && (withdrawaddr= jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 ) + if ( (txidaddr=jstr(item,"withdrawtxidaddr"))!= 0 && (withdrawaddr=jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 ) { - if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0) + if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0) { if ( strcmp(depositaddr,signeraddr) == 0 ) { rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis); if ( rawtx != 0 ) { - if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0) + if ( (clijson=addsignature(refcoin,"",rawtx)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0) { - gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex")); - fprintf(stderr,"withdraw %.8f %s to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr); + txid=gatewayscompletesigning("KMD",acname,withdrawtxid,refcoin,jstr(clijson,"hex")); + if (txid.txid!=zeroid.txid) fprintf(stderr,"#WITHDRAW (%s) complete signing tx sent - %s\n",bits256_str(str,withdrawtxid),bits256_str(str1,txid)); + else fprintf(stderr,"error broadcasting tx on %s",acname); free_json(clijson); - } - processed++; + processed++; + } free(rawtx); } else fprintf(stderr,"couldnt create rawtx\n"); } else { - if ( (rawtx= get_gatewaysmultisig(refcoin,acname,txidaddr,&K)) == 0) + lasttxid = jbits256(item,"last_txid"); + if ( lasttxid.txid==withdrawtxid.txid) { rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis); } - if ( rawtx != 0 ) + else rawtx=jstr(item,"hex"); + K=jint(item,"number_of_signs"); + if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 ) { - if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 ) - { - if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) - { - gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex")); - fprintf(stderr,"withdraw %.8f %s M.%d N.%d to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,M,N,withdrawaddr); - } - else if ( jint(clijson,"partialtx") != 0 ) - { - txid=gatewayspartialsign(refcoin,acname,origtxid,jstr(clijson,"hex")); - fprintf(stderr,"%d sign(s) %dof%d partialtx %s sent\n",K+1,M,N,bits256_str(str,txid)); - } - free_json(clijson); + if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) + { + txid=gatewayscompletesigning("KMD",acname,lasttxid,refcoin,jstr(clijson,"hex")); + if (txid.txid!=zeroid.txid) fprintf(stderr,"#WITHDRAW (%s) complete signing tx (%dof%d) sent - %s\n",bits256_str(str,withdrawtxid),M,N,bits256_str(str1,txid)); + else fprintf(stderr,"error broadcasting tx on %s",acname); } + else if ( jint(clijson,"partialtx") != 0 ) + { + txid=gatewayspartialsign("KMD",acname,lasttxid,refcoin,jstr(clijson,"hex")); + if (txid.txid!=zeroid.txid) fprintf(stderr,"#WITHDRAW (%s) partial tx (%d/%dof%d) sent - %s\n",bits256_str(str,withdrawtxid),K+1,M,N,bits256_str(str1,txid)); + else fprintf(stderr,"error broadcasting tx on %s",acname); + } + free_json(clijson); processed++; - free(rawtx); - } else fprintf(stderr,"couldnt create msig rawtx\n"); + } + free(rawtx); } } } @@ -1012,24 +953,27 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t { if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 ) { - if ( (pending=jarray(&n,retjson,"processed")) != 0 ) + if ((pending=jarray(&n,retjson,"processed")) != 0) { for (i=0; i pubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2) +CScript EncodeGatewaysBindOpRet(uint8_t funcid,uint256 tokenid,std::string coin,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector gatewaypubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2) { - CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << prefix << prefix2 << taddr << tokenid << totalsupply << M << N << pubkeys << oracletxid); - return(opret); + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; + std::vector pubkeys; + + cp = CCinit(&C,EVAL_GATEWAYS); + gatewayspk = GetUnspendable(cp,0); + pubkeys.push_back(gatewayspk); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << totalsupply << oracletxid << M << N << gatewaypubkeys << taddr << prefix << prefix2); + return(EncodeTokenOpRet(tokenid,pubkeys,opret)); } -uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,std::string &coin,uint256 &tokenid,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2) +uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,uint256 &tokenid,std::string &coin,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2) { - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector vOpretExtra; std::vector pubkeys; + + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + { + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); depositaddr[0] = 0; - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> prefix; ss >> prefix2; ss >> taddr; ss >> tokenid; ss >> totalsupply; ss >> M; ss >> N; ss >> pubkeys; ss >> oracletxid) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> totalsupply; ss >> oracletxid; ss >> M; ss >> N; ss >> gatewaypubkeys; ss >> taddr; ss >> prefix; ss >> prefix2;) != 0 ) { if ( prefix == 60 ) { if ( N > 1 ) { - strcpy(depositaddr,CBitcoinAddress(CScriptID(GetScriptForMultisig(M,pubkeys))).ToString().c_str()); - //Getscriptaddress(depositaddr,GetScriptForMultisig(M,pubkeys)); - fprintf(stderr,"f.%c M.%d of N.%d size.%d -> %s\n",f,M,N,(int32_t)pubkeys.size(),depositaddr); - } else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(pubkeys[0])) << OP_CHECKSIG); + strcpy(depositaddr,CBitcoinAddress(CScriptID(GetScriptForMultisig(M,gatewaypubkeys))).ToString().c_str()); + //fprintf(stderr,"f.%c M.%d of N.%d size.%d -> %s\n",f,M,N,(int32_t)gatewaypubkeys.size(),depositaddr); + } else Getscriptaddress(depositaddr,CScript() << ParseHex(HexStr(gatewaypubkeys[0])) << OP_CHECKSIG); } else { @@ -189,118 +190,134 @@ uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,st return(0); } -CScript EncodeGatewaysDepositOpRet(uint8_t funcid,std::string coin,uint256 bindtxid,std::vector publishers,std::vectortxids,int32_t height,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) +CScript EncodeGatewaysDepositOpRet(uint8_t funcid,uint256 bindtxid,std::string refcoin,std::vector publishers,std::vectortxids,int32_t height,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << deposithex << proof << destpub << amount); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << bindtxid << publishers << txids << height << cointxid << claimvout << deposithex << proof << destpub << amount); return(opret); } -uint8_t DecodeGatewaysDepositOpRet(const CScript &scriptPubKey,std::string &coin,uint256 &bindtxid,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &cointxid, int32_t &claimvout,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) +uint8_t DecodeGatewaysDepositOpRet(const CScript &scriptPubKey,uint256 &bindtxid,std::string &refcoin,std::vector&publishers,std::vector&txids,int32_t &height,uint256 &cointxid, int32_t &claimvout,std::string &deposithex,std::vector &proof,CPubKey &destpub,int64_t &amount) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> coin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> claimvout; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> bindtxid; ss >> publishers; ss >> txids; ss >> height; ss >> cointxid; ss >> claimvout; ss >> deposithex; ss >> proof; ss >> destpub; ss >> amount) != 0 ) { return(f); } return(0); } -// encodes payload for the token opret (needs to be added to the tail of it) -CScript EncodeGatewaysClaimOpRet(uint8_t funcid, std::string refcoin, uint256 bindtxid, uint256 deposittxid, CPubKey destpub, int64_t amount) +CScript EncodeGatewaysClaimOpRet(uint8_t funcid,uint256 tokenid,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount) { - CScript opret; + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; + std::vector pubkeys; - opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << bindtxid << deposittxid << destpub << amount); - return(opret); + pubkeys.push_back(destpub); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << deposittxid << destpub << amount); + return(EncodeTokenOpRet(tokenid,pubkeys,opret)); } -uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &tokenid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) +uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &tokenid,uint256 &bindtxid,std::string &refcoin,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) { - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector pubkeys; std::vector vOpretExtra; + + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + { + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> bindtxid; ss >> refcoin; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid, std::string refcoin, CPubKey withdrawpub, int64_t amount) +CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid,uint256 tokenid,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) { - CScript opret; - opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << withdrawpub << amount); - return(opret); + CScript opret; uint8_t evalcode = EVAL_GATEWAYS; struct CCcontract_info *cp,C; CPubKey gatewayspk; + std::vector pubkeys; + + cp = CCinit(&C,EVAL_GATEWAYS); + gatewayspk = GetUnspendable(cp,0); + pubkeys.push_back(gatewayspk); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << bindtxid << refcoin << withdrawpub << amount); + return(EncodeTokenOpRet(tokenid,pubkeys,opret)); } -uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &tokenid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) +uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256& tokenid, uint256 &bindtxid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) { - std::vector vopret; uint8_t *script,e,f; + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector pubkeys; std::vector vOpretExtra; - - GetOpReturnData(scriptPubKey, vopret); + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + { + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> bindtxid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysPartialOpRet(uint8_t funcid,int32_t K, CPubKey signerpk, std::string refcoin,std::string hex) +CScript EncodeGatewaysPartialOpRet(uint8_t funcid, uint256 withdrawtxid,std::string refcoin,int32_t K, CPubKey signerpk,std::string hex) { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << K << signerpk << refcoin << hex); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << K << signerpk << hex); return(opret); } -uint8_t DecodeGatewaysPartialOpRet(const CScript &scriptPubKey,int32_t &K, CPubKey &signerpk, std::string &refcoin,std::string &hex) +uint8_t DecodeGatewaysPartialOpRet(const CScript &scriptPubKey,uint256 &withdrawtxid,std::string &refcoin,int32_t &K, CPubKey &signerpk,std::string &hex) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> K; ss >> signerpk; ss >> refcoin; ss >> hex) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> withdrawtxid; ss >> refcoin; ss >> K; ss >> signerpk; ss >> hex) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysCompleteSigningOpRet(uint8_t funcid,std::string refcoin,uint256 withdrawtxid,std::string hex) +CScript EncodeGatewaysCompleteSigningOpRet(uint8_t funcid,uint256 withdrawtxid,std::string refcoin,std::string hex) { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << withdrawtxid << hex); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << withdrawtxid << refcoin << hex); return(opret); } -uint8_t DecodeGatewaysCompleteSigningOpRet(const CScript &scriptPubKey, std::string &refcoin, uint256 &withdrawtxid,std::string &hex) +uint8_t DecodeGatewaysCompleteSigningOpRet(const CScript &scriptPubKey,uint256 &withdrawtxid,std::string &refcoin,std::string &hex) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> withdrawtxid; ss >> hex) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> withdrawtxid; ss >> refcoin; ss >> hex) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysMarkDoneOpRet(uint8_t funcid,std::string refcoin,uint256 withdrawtxid) +CScript EncodeGatewaysMarkDoneOpRet(uint8_t funcid,std::string refcoin,uint256 completetxid,uint256 withdrawtxid) { CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << withdrawtxid); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << refcoin << completetxid < vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> withdrawtxid;) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> refcoin; ss >> completetxid; ss >> withdrawtxid;) != 0 ) { return(f); } @@ -309,12 +326,19 @@ uint8_t DecodeGatewaysMarkDoneOpRet(const CScript &scriptPubKey, std::string &re uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey) { - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && (script[0] == EVAL_GATEWAYS || script[0] == EVAL_TOKENS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 ) + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector pubkeys; std::vector vOpretExtra; uint256 tokenid; + + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) { - if (f == 'B' && f == 'D' && f == 't' && f == 'W' && f == 'P' && f == 'M') + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && script[0] == EVAL_GATEWAYS) + { + f=script[1]; + if (f == 'B' || f == 'D' || f == 'C' || f == 'W' || f == 'P' || f == 'S' || f == 'M') return(f); } return(0); @@ -429,7 +453,7 @@ uint256 GatewaysReverseScan(uint256 &txid,int32_t height,uint256 reforacletxid,u return(zeroid); } -int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) // dont forget to check mempool! +int32_t GatewaysCointxidExists(struct CCcontract_info *cp,uint256 cointxid) { char txidaddr[64]; std::string coin; int32_t numvouts; uint256 hashBlock; std::vector > addressIndex; @@ -457,7 +481,9 @@ uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::ve int64_t GatewaysVerify(char *refdepositaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 cointxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub) { - std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0; + std::vector txids; uint256 proofroot,hashBlock,txid = zeroid; CTransaction tx; std::string name,description,format; + char destaddr[64],destpubaddr[64],claimaddr[64],str[65],str2[65]; int32_t i,numvouts; int64_t nValue = 0; + if ( myGetTransaction(oracletxid,tx,hashBlock) == 0 || (numvouts= tx.vout.size()) <= 0 ) { fprintf(stderr,"GatewaysVerify cant find oracletxid %s\n",uint256_str(str,oracletxid)); @@ -505,7 +531,7 @@ int64_t GatewaysDepositval(CTransaction tx,CPubKey mypk) int32_t numvouts,claimvout,height; int64_t amount; std::string coin,deposithex; std::vector publishers; std::vectortxids; uint256 bindtxid,cointxid; std::vector proof; CPubKey claimpubkey; if ( (numvouts= tx.vout.size()) > 0 ) { - if ( DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,coin,bindtxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk ) + if ( DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,bindtxid,coin,publishers,txids,height,cointxid,claimvout,deposithex,proof,claimpubkey,amount) == 'D' && claimpubkey == mypk ) { // coin, bindtxid, publishers fprintf(stderr,"need to validate deposittxid more\n"); @@ -574,74 +600,74 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & //vout.0: CC vout of total tokens from deposit amount to asset eval code //(vout.1): CC vout if there is change of unused tokens back to owner of tokens (deposit amount less than available tokens) //vout.n-1: opreturn - 't' tokenid zeroid 0 mypubkey (NOTE: opreturn is with asset eval code) - if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,tokenidClaim,refcoin,bindtxid,deposittxid,destpub,amount)==0) - return eval->Invalid("invalid gatewaysclaim OP_RETURN data!"); - else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) - return eval->Invalid("vin.0 is normal for gatewaysClaim!"); - else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for gatewaysClaim!"); - else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) - return eval->Invalid("vin.2 is CC for gatewaysClaim!"); - else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.0 is CC for gatewaysClaim!"); - else if ( numvouts > 2 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.1 is CC for gatewaysClaim!"); - else if (myGetTransaction(bindtxid,bindtx,hashblock) == 0) - return eval->Invalid("invalid gatewaysbind txid!"); - else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenidBind,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B') - return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different in bind tx"); - else if (tokenidClaim!=tokenidBind) - return eval->Invalid("tokenid does not match tokenid from gatewaysbind"); - else if (komodo_txnotarizedconfirmed(bindtxid) == false) - return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); - else if (myGetTransaction(deposittxid,deposittx,hashblock) == 0) - return eval->Invalid("invalid gatewaysdeposittxid!"); - else if ((numvouts=deposittx.vout.size()) > 0 && DecodeGatewaysDepositOpRet(deposittx.vout[numvouts-1].scriptPubKey,tmprefcoin,tmptxid,tmppublishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D') - return eval->Invalid("invalid gatewaysdeposit OP_RETURN data!"); - else if (tmprefcoin!=refcoin) - return eval->Invalid("refcoin different in deposit tx"); - else if (bindtxid!=tmptxid) - return eval->Invalid("bindtxid does not match to bindtxid from gatewaysdeposit"); - else if (tmpamount>totalsupply) - return eval->Invalid("deposit amount greater then bind total supply"); - else if (komodo_txnotarizedconfirmed(deposittxid) == false) - return eval->Invalid("gatewaysdeposit tx is not yet confirmed(notarised)!"); - else if (amount>tmpamount) - return eval->Invalid("claimed amount greater then deposit amount"); - else if (destpub!=tmpdestpub) - return eval->Invalid("destination pubkey different than in deposit tx"); - else - { - int32_t m; - merkleroot = zeroid; - for (i=m=0; iInvalid(validationError); - } - if ( GatewaysCointxidExists(cp,cointxid) != 0 ) - { - sprintf(validationError,"cointxid.%s already exists\n",uint256_str(str,cointxid)); - return eval->Invalid(validationError); - } - if (GatewaysVerify(depositaddr,oracletxid,claimvout,tmprefcoin,cointxid,deposithex,proof,merkleroot,destpub)!=amount) - return eval->Invalid("deposittxid didnt validate\n"); - } + // if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,tokenidClaim,refcoin,bindtxid,deposittxid,destpub,amount)==0) + // return eval->Invalid("invalid gatewaysclaim OP_RETURN data!"); + // else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + // return eval->Invalid("vin.0 is normal for gatewaysClaim!"); + // else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) + // return eval->Invalid("vin.1 is CC for gatewaysClaim!"); + // else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) + // return eval->Invalid("vin.2 is CC for gatewaysClaim!"); + // else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + // return eval->Invalid("vout.0 is CC for gatewaysClaim!"); + // else if ( numvouts > 2 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + // return eval->Invalid("vout.1 is CC for gatewaysClaim!"); + // else if (myGetTransaction(bindtxid,bindtx,hashblock) == 0) + // return eval->Invalid("invalid gatewaysbind txid!"); + // else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenidBind,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B') + // return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); + // else if (tmprefcoin!=refcoin) + // return eval->Invalid("refcoin different in bind tx"); + // else if (tokenidClaim!=tokenidBind) + // return eval->Invalid("tokenid does not match tokenid from gatewaysbind"); + // else if (komodo_txnotarizedconfirmed(bindtxid) == false) + // return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); + // else if (myGetTransaction(deposittxid,deposittx,hashblock) == 0) + // return eval->Invalid("invalid gatewaysdeposittxid!"); + // else if ((numvouts=deposittx.vout.size()) > 0 && DecodeGatewaysDepositOpRet(deposittx.vout[numvouts-1].scriptPubKey,tmprefcoin,tmptxid,tmppublishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D') + // return eval->Invalid("invalid gatewaysdeposit OP_RETURN data!"); + // else if (tmprefcoin!=refcoin) + // return eval->Invalid("refcoin different in deposit tx"); + // else if (bindtxid!=tmptxid) + // return eval->Invalid("bindtxid does not match to bindtxid from gatewaysdeposit"); + // else if (tmpamount>totalsupply) + // return eval->Invalid("deposit amount greater then bind total supply"); + // else if (komodo_txnotarizedconfirmed(deposittxid) == false) + // return eval->Invalid("gatewaysdeposit tx is not yet confirmed(notarised)!"); + // else if (amount>tmpamount) + // return eval->Invalid("claimed amount greater then deposit amount"); + // else if (destpub!=tmpdestpub) + // return eval->Invalid("destination pubkey different than in deposit tx"); + // else + // { + // int32_t m; + // merkleroot = zeroid; + // for (i=m=0; iInvalid(validationError); + // } + // if ( GatewaysCointxidExists(cp,cointxid) != 0 ) + // { + // sprintf(validationError,"cointxid.%s already exists\n",uint256_str(str,cointxid)); + // return eval->Invalid(validationError); + // } + // if (GatewaysVerify(depositaddr,oracletxid,claimvout,tmprefcoin,cointxid,deposithex,proof,merkleroot,destpub)!=amount) + // return eval->Invalid("deposittxid didnt validate\n"); + // } break; case 'W': //vin.0: normal input @@ -669,8 +695,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & break; } } - - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) fprintf(stderr,"Gatewaysget validated\n"); @@ -683,65 +707,81 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & // helper functions for rpc calls in rpcwallet.cpp -int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 reftokenid,int64_t total,int32_t maxinputs) +int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 bindtxid,int64_t total,int32_t maxinputs) { - char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 tokenid,txid,hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid; - std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr); - threshold = total/(maxinputs+1); - //fprintf(stderr,"check %s for gateway inputs\n",coinaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + char coinaddr[64],depositaddr[64]; int64_t threshold,nValue,price,totalinputs = 0,totalsupply,amount; + CTransaction vintx,bindtx; int32_t vout,numvouts,n = 0; uint8_t M,N,evalcode,funcid,taddr,prefix,prefix2; std::vector pubkeys; + std::vector > unspentOutputs; std::string refcoin,tmprefcoin; CPubKey withdrawpub,destpub; + uint256 tokenid,txid,oracletxid,tmpbindtxid,tmptokenid,deposittxid,hashBlock; + + if ( GetTransaction(bindtxid,bindtx,hashBlock,false) != 0 ) { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - if ( it->second.satoshis < threshold ) - continue; - for (j=0; jsecond.satoshis/COIN); - if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 ) - continue; - GetOpReturnData(vintx.vout[vintx.vout.size()-1].scriptPubKey, vopret); - if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> tokenid) != 0 ) + GetTokensCCaddress(cp,coinaddr,pk); + SetCCunspents(unspentOutputs,coinaddr); + threshold = total/(maxinputs+1); + fprintf(stderr,"check %s for gateway inputs\n",coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - tokenid = revuint256(tokenid); - char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for reftokenid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,reftokenid),uint256_str(str2,tokenid),(double)vintx.vout[vout].nValue/COIN); - if ( tokenid == reftokenid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) + txid = it->first.txhash; + vout = (int32_t)it->first.index; + if ( it->second.satoshis < threshold ) + continue; + // for (j=0; jsecond.satoshis/COIN); - if ( total != 0 && maxinputs != 0 ) + funcid=DecodeGatewaysOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey); + if (vout==0 && funcid=='B' && bindtxid==txid && total != 0 && maxinputs != 0) + { mtx.vin.push_back(CTxIn(txid,vout,CScript())); - //nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; + totalinputs += it->second.satoshis; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) break; + } + else if (vout==1 && funcid=='W' && DecodeGatewaysWithdrawOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,tmptokenid,tmpbindtxid,tmprefcoin,withdrawpub,amount) == 'W' && + tmpbindtxid==bindtxid && tmprefcoin==refcoin && tmptokenid==tokenid && total != 0 && maxinputs != 0) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + totalinputs += it->second.satoshis; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) break; + } + else if (vout==1 && funcid=='C' && DecodeGatewaysClaimOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,tmptokenid,tmpbindtxid,tmprefcoin,deposittxid,destpub,amount) == 'C' && + tmpbindtxid==bindtxid && tmprefcoin==refcoin && tmptokenid==tokenid && total != 0 && maxinputs != 0) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + totalinputs += it->second.satoshis; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) break; + } } } + return(totalinputs); } + else fprintf(stderr,"invalid GatewaysBind\n"); } - return(totalinputs); + else fprintf(stderr,"can't find GatewaysBind txid\n"); + return(0); } -int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) // dont forget to check mempool! +int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 reftokenid) { - char markeraddr[64],depositaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; CTransaction tx; + char markeraddr[64],depositaddr[64]; std::string coin; int32_t numvouts; int64_t totalsupply; uint256 tokenid,oracletxid,hashBlock; + uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; CTransaction tx; std::vector > addressIndex; + _GetCCaddress(markeraddr,EVAL_GATEWAYS,gatewayspk); - fprintf(stderr,"bind markeraddr.(%s) need to scan mempool also\n",markeraddr); SetCCtxids(addressIndex,markeraddr); for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { if ( GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' ) { if ( tokenid == reftokenid ) { @@ -751,15 +791,29 @@ int32_t GatewaysBindExists(struct CCcontract_info *cp,CPubKey gatewayspk,uint256 } } } + BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) + { + const CTransaction &txmempool = e.GetTx(); + const uint256 &hash = txmempool.GetHash(); + + if ((numvouts=txmempool.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) == 'B' && + tokenid == reftokenid) + return(1); + } + return(0); } std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; struct CCcontract_info *cp,C; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; char destaddr[64],coinaddr[64],str[65],*fstr; + CTransaction oracletx; uint8_t taddr,prefix,prefix2; CPubKey mypk,gatewayspk; CScript opret; uint256 hashBlock; + struct CCcontract_info *cp,*cpTokens,C,CTokens; std::string name,description,format; int32_t i,numvouts; int64_t fullsupply; + char destaddr[64],coinaddr[64],myTokenCCaddr[64],str[65],*fstr; + cp = CCinit(&C,EVAL_GATEWAYS); - if ( strcmp((char *)"KMD",coin.c_str()) == 0 ) + cpTokens = CCinit(&CTokens,EVAL_TOKENS); + if (coin=="KMD") { taddr = 0; prefix = 60; @@ -794,20 +848,21 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); + _GetCCaddress(myTokenCCaddr,EVAL_TOKENS,mypk); gatewayspk = GetUnspendable(cp,0); if ( _GetCCaddress(destaddr,EVAL_GATEWAYS,gatewayspk) == 0 ) { fprintf(stderr,"Gateway bind.%s (%s) cant create globaladdr\n",coin.c_str(),uint256_str(str,tokenid)); return(""); } - if ( (fullsupply= CCfullsupply(tokenid)) != totalsupply ) + if ( (fullsupply=CCfullsupply(tokenid)) != totalsupply ) { fprintf(stderr,"Gateway bind.%s (%s) globaladdr.%s totalsupply %.8f != fullsupply %.8f\n",coin.c_str(),uint256_str(str,tokenid),cp->unspendableCCaddr,(double)totalsupply/COIN,(double)fullsupply/COIN); return(""); } - if ( CCtoken_balance(destaddr,tokenid) != totalsupply ) + if ( CCtoken_balance(myTokenCCaddr,tokenid) != totalsupply ) { - fprintf(stderr,"Gateway bind.%s (%s) destaddr.%s globaladdr.%s token balance %.8f != %.8f\n",coin.c_str(),uint256_str(str,tokenid),destaddr,cp->unspendableCCaddr,(double)CCtoken_balance(destaddr,tokenid)/COIN,(double)totalsupply/COIN); + fprintf(stderr,"token balance on %s %.8f != %.8f\n",myTokenCCaddr,(double)CCtoken_balance(myTokenCCaddr,tokenid)/COIN,(double)totalsupply/COIN); return(""); } if ( GetTransaction(oracletxid,oracletx,hashBlock,false) == 0 || (numvouts= oracletx.vout.size()) <= 0 ) @@ -820,20 +875,24 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t fprintf(stderr,"mismatched oracle name %s != %s\n",name.c_str(),coin.c_str()); return(""); } - if ( (fstr= (char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 ) + if ( (fstr=(char *)format.c_str()) == 0 || strncmp(fstr,"Ihh",3) != 0 ) { fprintf(stderr,"illegal format (%s) != (%s)\n",fstr,(char *)"Ihh"); return(""); } - if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) // dont forget to check mempool! + if ( GatewaysBindExists(cp,gatewayspk,tokenid) != 0 ) { fprintf(stderr,"Gateway bind.%s (%s) already exists\n",coin.c_str(),uint256_str(str,tokenid)); return(""); } if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2))); + if (AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, totalsupply, 64)>0) + { + mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,totalsupply,gatewayspk)); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,gatewayspk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysBindOpRet('B',tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2))); + } } CCerror = strprintf("cant find enough inputs"); fprintf(stderr,"%s\n", CCerror.c_str() ); @@ -843,7 +902,7 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction bindtx; CPubKey mypk,gatewayspk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; + CTransaction bindtx; CPubKey mypk; uint256 oracletxid,merkleroot,mhash,hashBlock,tokenid,txid; int64_t totalsupply; int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2; std::string coin; struct CCcontract_info *cp,C; std::vector pubkeys,publishers; std::vectortxids; char str[67],depositaddr[64],txidaddr[64]; @@ -851,14 +910,13 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - gatewayspk = GetUnspendable(cp,0); //fprintf(stderr,"GatewaysDeposit ht.%d %s %.8f numpks.%d\n",height,refcoin.c_str(),(double)amount/COIN,(int32_t)pubkeys.size()); if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 ) { fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin ) + if ( DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin ) { fprintf(stderr,"invalid coin - bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); @@ -901,7 +959,7 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: { mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,destpub)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysDepositOpRet('D',coin,bindtxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,destpub,amount))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysDepositOpRet('D',bindtxid,coin,publishers,txids,height,cointxid,claimvout,deposithex,proof,destpub,amount))); } fprintf(stderr,"cant find enough inputs\n"); return(""); @@ -925,7 +983,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) { fprintf(stderr,"invalid coin - bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); @@ -935,7 +993,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui fprintf(stderr,"cant find deposittxid %s\n",uint256_str(str,bindtxid)); return(""); } - if (DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,coin,tmptxid,publishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D' || coin != refcoin) + if (DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,tmptxid,coin,publishers,txids,height,cointxid,claimvout,deposithex,proof,tmpdestpub,tmpamount) != 'D' || coin != refcoin) { fprintf(stderr,"invalid coin - deposittxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); @@ -945,32 +1003,20 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui fprintf(stderr,"different destination pubkey from desdeposittxid\n"); return(""); } - if ( (depositamount= GatewaysDepositval(tx,mypk)) != amount ) + if ( (depositamount=GatewaysDepositval(tx,mypk)) != amount ) { fprintf(stderr,"invalid Gateways deposittxid %s %.8f != %.8f\n",uint256_str(str,deposittxid),(double)depositamount/COIN,(double)amount/COIN); return(""); } - //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2); if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { - ///////// if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,tokenid,amount,60)) > 0 ) - if ((inputs = AddTokenCCInputs(cp, mtx, gatewayspk, tokenid, amount, 60)) > 0) + if ((inputs=AddGatewaysInputs(cp, mtx, gatewayspk, bindtxid, amount, 60)) > 0) { - if ( inputs > amount ) - CCchange = (inputs - amount); - _GetCCaddress(destaddr,EVAL_GATEWAYS,mypk); - //printf("expecting deposittxid/v0 to be to %s\n",destaddr); - mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); // triggers EVAL_GATEWAYS validation - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,amount,mypk)); // transfer back to normal token - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk)); - - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(mypk); // the pubkey where tokens are going (vout[0]) - - return(FinalizeCCTx(0,cp,mtx,mypk,txfee, - EncodeTokenOpRet('t', EVAL_GATEWAYS, tokenid, voutTokenPubkeys, - EncodeGatewaysClaimOpRet('t', refcoin, bindtxid, deposittxid, destpub, amount)))); // yes, 't' is passed twice + if ( inputs > amount ) CCchange = (inputs - amount); + mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,amount,destpub)); + if ( CCchange != 0 ) mtx.vout.push_back(MakeTokensCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysClaimOpRet('C',tokenid,bindtxid,refcoin,deposittxid,destpub,amount))); } } CCerror = strprintf("cant find enough inputs or mismatched total"); @@ -981,159 +1027,377 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction tx; - CPubKey mypk, gatewayspk; - uint256 tokenid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; - std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; - struct CCcontract_info *cpGateways, gatewaysC; - struct CCcontract_info *cpTokens, tokensC; - - cpGateways = CCinit(&gatewaysC, EVAL_GATEWAYS); - cpTokens = CCinit(&tokensC, EVAL_TOKENS); + CTransaction tx; CPubKey mypk,gatewayspk,signerpk; uint256 txid,tokenid,hashBlock,oracletxid,tmptokenid,tmpbindtxid,withdrawtxid; int32_t K,vout,numvouts; + int64_t nValue,totalsupply,inputs,CCchange=0; uint8_t funcid,M,N,taddr,prefix,prefix2; std::string coin,hex; + std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; struct CCcontract_info *cp,C,*cpTokens,CTokens; + std::vector > unspentOutputs; + cp = CCinit(&C,EVAL_GATEWAYS); + cpTokens = CCinit(&CTokens,EVAL_TOKENS); if ( txfee == 0 ) txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - gatewayspk = GetUnspendable(cpGateways, 0); + gatewayspk = GetUnspendable(cp, 0); if( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(""); } - if( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) { fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); } + _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second.satoshis; + K=0; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && + (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))!=0 && (funcid=='W' || funcid=='P')) + { + if (funcid=='W' && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,tmpbindtxid,coin,withdrawpub,amount)=='W' + && refcoin==coin && tmptokenid==tokenid && tmpbindtxid==bindtxid) + { + CCerror = strprintf("unable to create withdraw, another withdraw pending\n"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + + else if (funcid=='P' && DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,hex)=='P' && + GetTransaction(withdrawtxid,tx,hashBlock,false)!=0 && (numvouts=tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,tmpbindtxid,coin,withdrawpub,amount)=='W' + && refcoin==coin && tmptokenid==tokenid && tmpbindtxid==bindtxid) + { + CCerror = strprintf("unable to create withdraw, another withdraw pending\n"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } + } if( AddNormalinputs(mtx, mypk, 3*txfee, 4) > 0 ) { - /////if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,tokenid,amount,60)) > 0 ) if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, amount, 60)) > 0) { - if ( inputs > amount ) - CCchange = (inputs - amount); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, amount, gatewayspk)); - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS, txfee, gatewayspk)); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); - - char unspendableGatewaysAddr[64]; - GetCCaddress(cpGateways, unspendableGatewaysAddr, gatewayspk); - - uint8_t unspendableGatewaysPrivkey[32]; - GetUnspendable(cpGateways, unspendableGatewaysPrivkey); - - // add additional unspendable addr from Gateways: - CCaddr2set(cpTokens, EVAL_GATEWAYS, gatewayspk, unspendableGatewaysPrivkey, unspendableGatewaysAddr); - - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(gatewayspk); // the pubkey where tokens are going vout[0] (and for checking the 'change' the Tokens contract will find pubkeys itself) - - return(FinalizeCCTx(0, cpTokens, mtx, mypk, txfee, - EncodeTokenOpRet('t', EVAL_GATEWAYS, tokenid, voutTokenPubkeys, - EncodeGatewaysWithdrawOpRet('W', refcoin, withdrawpub, amount)))); + if ( inputs > amount ) CCchange = (inputs - amount); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); + mtx.vout.push_back(MakeTokensCC1vout(EVAL_GATEWAYS,amount,gatewayspk)); + //mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG)); + if ( CCchange != 0 ) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); + return(FinalizeCCTx(0, cpTokens, mtx, mypk, txfee,EncodeGatewaysWithdrawOpRet('W',tokenid,bindtxid,refcoin,withdrawpub,amount))); + } + else + { + CCerror = strprintf("not enough balance of tokens for withdraw"); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - CCerror = strprintf("cant find enough token inputs or mismatched total"); - fprintf(stderr, "%s\n", CCerror.c_str()); - return(""); - } - CCerror = strprintf("cant find enough normal inputs or mismatched total"); + CCerror = strprintf("cant find enough normal inputs"); fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } -std::string GatewaysPartialSign(uint64_t txfee,uint256 txid,std::string refcoin, std::string hex) +std::string GatewaysPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,txidaddrpk,signerpk; struct CCcontract_info *cp,C; CTransaction tx; - std::vector > unspentOutputs; char txidaddr[65]; - int32_t maxK,K=0; uint256 tmptxid,parttxid,hashBlock; + CPubKey mypk,withdrawpub,signerpk,gatewayspk; struct CCcontract_info *cp,C; CTransaction tx,bindtx; + std::vector > unspentOutputs; char funcid,str[65],depositaddr[64]; + int32_t numvouts,K=0; uint256 withdrawtxid,hashBlock,bindtxid,tokenid,oracletxid,tmptokenid; std::string coin,tmphex; int64_t amount,totalsupply; + uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; + cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) - txfee = 5000; + txfee = 10000; mypk = pubkey2pk(Mypubkey()); - txidaddrpk=CCtxidaddr(txidaddr,txid); - SetCCunspents(unspentOutputs,txidaddr); - maxK=0; - if (unspentOutputs.size()==0) + gatewayspk = GetUnspendable(cp,0); + if (GetTransaction(lasttxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0 + || (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) { - if (AddNormalinputs(mtx,mypk,2*txfee,3)==0) fprintf(stderr,"error adding funds for partialsign\n"); + CCerror = strprintf("can't find last tx %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - else + if (funcid=='W') { - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + withdrawtxid=lasttxid; + if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) { - tmptxid = it->first.txhash; - if (GetTransaction(tmptxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK ) - { - maxK=K; - parttxid=tmptxid; - } + CCerror = strprintf("invalid withdraw tx %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - if (maxK>0) + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=bindtx.vout.size())<=0) { - if (AddNormalinputs(mtx,mypk,txfee,3)==0) fprintf(stderr,"error adding funds for partialsign\n"); - mtx.vin.push_back(CTxIn(parttxid,0,CScript())); + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - else fprintf(stderr,"Error finding previous partial tx\n"); } - - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,5000,txidaddrpk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysPartialOpRet('P',maxK+1,mypk,refcoin,hex))); + else if (funcid=='P') + { + if (DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) + { + CCerror = strprintf("cannot decode partialsign tx opret %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(withdrawtxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0) + { + CCerror = strprintf("can't find withdraw tx %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' + || refcoin!=coin) + { + CCerror = strprintf("invalid withdraw tx %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=bindtx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } + if (AddNormalinputs(mtx,mypk,txfee,3)==0) fprintf(stderr,"error adding funds for partialsign\n"); + mtx.vin.push_back(CTxIn(tx.GetHash(),0,CScript())); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysPartialOpRet('P',withdrawtxid,refcoin,K+1,mypk,hex))); } -std::string GatewaysCompleteSigning(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,std::string hex) +std::string GatewaysCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; char txidaddr[65]; + CPubKey mypk,gatewayspk,signerpk,withdrawpub; struct CCcontract_info *cp,C; char funcid,str[65],depositaddr[64]; int64_t amount,totalsupply; + std::string coin,tmphex; CTransaction tx,bindtx; uint256 withdrawtxid,hashBlock,tokenid,tmptokenid,bindtxid,oracletxid; int32_t K=0,numvouts; + uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; + cp = CCinit(&C,EVAL_GATEWAYS); mypk = pubkey2pk(Mypubkey()); gatewayspk = GetUnspendable(cp,0); if ( txfee == 0 ) - txfee = 10000; - - mtx.vin.push_back(CTxIn(withdrawtxid,2,CScript())); + txfee = 10000; + if (GetTransaction(lasttxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0 + || (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))==0 || (funcid!='W' && funcid!='P')) + { + CCerror = strprintf("invalid last txid %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + if (funcid=='W') + { + withdrawtxid=lasttxid; + if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=tx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } + else if (funcid=='P') + { + if (DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,tmphex)!='P' || refcoin!=coin) + { + CCerror = strprintf("cannot decode partialsign tx opret %s\n",uint256_str(str,lasttxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(withdrawtxid,tx,hashBlock,false)==0 || (numvouts=tx.vout.size())==0) + { + CCerror = strprintf("invalid withdraw txid %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + printf("aaaaaaaaaaa\n"); + CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=bindtx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + } + if (AddNormalinputs(mtx,mypk,txfee,3)==0) fprintf(stderr,"error adding funds for completesigning\n"); + mtx.vin.push_back(CTxIn(lasttxid,0,CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysCompleteSigningOpRet('C',refcoin,withdrawtxid,hex))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysCompleteSigningOpRet('S',withdrawtxid,refcoin,hex))); } std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string refcoin) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; char txidaddr[65]; + CPubKey mypk; struct CCcontract_info *cp,C; char str[65],depositaddr[64]; CTransaction tx,bindtx; int32_t numvouts; + uint256 withdrawtxid,bindtxid,oracletxid,tokenid,tmptokenid,hashBlock; std::string coin,hex; + uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; int64_t amount,totalsupply; CPubKey withdrawpub; + cp = CCinit(&C,EVAL_GATEWAYS); mypk = pubkey2pk(Mypubkey()); if ( txfee == 0 ) txfee = 10000; + if (GetTransaction(completetxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())<=0) + { + CCerror = strprintf("invalid completesigning txid %s\n",uint256_str(str,completetxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,hex)!='S' || refcoin!=coin) + { + CCerror = strprintf("cannot decode completesigning tx opret %s\n",uint256_str(str,completetxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(withdrawtxid,tx,hashBlock,false)==0 || (numvouts= tx.vout.size())==0) + { + CCerror = strprintf("invalid withdraw txid %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount)!='W' || refcoin!=coin) + { + CCerror = strprintf("cannot decode withdraw tx opret %s\n",uint256_str(str,withdrawtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (GetTransaction(bindtxid,bindtx,hashBlock,false)==0 || (numvouts=bindtx.vout.size())<=0) + { + CCerror = strprintf("can't find bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + else if (DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' + || refcoin!=coin || tokenid!=tmptokenid) + { + CCerror = strprintf("invalid bind tx %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } mtx.vin.push_back(CTxIn(completetxid,0,CScript())); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysMarkDoneOpRet('M',refcoin,completetxid))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysMarkDoneOpRet('M',refcoin,completetxid,withdrawtxid))); +} + +UniValue GatewaysPendingDeposits(uint256 bindtxid,std::string refcoin) +{ + UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,hex,pub; + CPubKey mypk,gatewayspk,destpub; std::vector pubkeys,publishers; std::vector txids; + uint256 tmpbindtxid,hashBlock,txid,tokenid,oracletxid,cointxid; uint8_t M,N,taddr,prefix,prefix2; + char depositaddr[65],coinaddr[65],str[65],destaddr[65],txidaddr[65]; std::vector proof; + int32_t numvouts,vout,claimvout,height; int64_t totalsupply,nValue,amount; struct CCcontract_info *cp,C; + std::vector > unspentOutputs; + + cp = CCinit(&C,EVAL_GATEWAYS); + mypk = pubkey2pk(Mypubkey()); + gatewayspk = GetUnspendable(cp,0); + _GetCCaddress(coinaddr,EVAL_GATEWAYS,mypk); + if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + { + CCerror = strprintf("cant find bindtxid %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin) + { + CCerror = strprintf("invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second.satoshis; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size())>0 && + DecodeGatewaysDepositOpRet(tx.vout[numvouts-1].scriptPubKey,tmpbindtxid,coin,publishers,txids,height,cointxid,claimvout,hex,proof,destpub,amount) == 'D' + && tmpbindtxid==bindtxid && refcoin == coin && myIsutxo_spentinmempool(txid,vout) == 0) + { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("cointxid",uint256_str(str,cointxid))); + obj.push_back(Pair("deposittxid",uint256_str(str,txid))); + CCtxidaddr(txidaddr,txid); + obj.push_back(Pair("deposittxidaddr",txidaddr)); + _GetCCaddress(destaddr,EVAL_TOKENS,destpub); + obj.push_back(Pair("tokens_destination_address",destaddr)); + pub=HexStr(destpub); + obj.push_back(Pair("claim_pubkey",pub)); + obj.push_back(Pair("amount",(double)amount/COIN)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + pending.push_back(obj); + } + } + result.push_back(Pair("coin",refcoin)); + result.push_back(Pair("pending",pending)); + return(result); } UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) { - UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string tmprefcoin; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; - uint256 hashBlock,tokenid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; - char depositaddr[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],cctxidaddr[64],signeraddr[64]; - int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C; + UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,hex; CPubKey mypk,gatewayspk,withdrawpub,signerpk; + std::vector msigpubkeys; uint256 hashBlock,tokenid,txid,tmpbindtxid,tmptokenid,oracletxid,withdrawtxid; uint8_t M,N,taddr,prefix,prefix2; + char funcid,depositaddr[65],coinaddr[65],tokensaddr[65],destaddr[65],str[65],withaddr[65],numstr[32],signeraddr[65],txidaddr[65]; + int32_t i,n,numvouts,vout,queueflag,K; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C; std::vector > unspentOutputs; cp = CCinit(&C,EVAL_GATEWAYS); mypk = pubkey2pk(Mypubkey()); gatewayspk = GetUnspendable(cp,0); _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); + GetTokensCCaddress(cp,tokensaddr,gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { - fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); - return(result); + CCerror = strprintf("cant find bindtxid %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin ) { - fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); - return(result); + CCerror = strprintf("invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } n = msigpubkeys.size(); queueflag = 0; @@ -1149,28 +1413,45 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) txid = it->first.txhash; vout = (int32_t)it->first.index; nValue = (int64_t)it->second.satoshis; - fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue); - if ( vout == 2 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && - DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0) + K=0; + if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && + (funcid=DecodeGatewaysOpRet(tx.vout[numvouts-1].scriptPubKey))!=0 && (funcid=='W' || funcid=='P') && myIsutxo_spentinmempool(txid,vout) == 0) { - Getscriptaddress(destaddr,tx.vout[0].scriptPubKey); - Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); - if ( strcmp(destaddr,coinaddr) == 0 ) + if (funcid=='W') + { + if (DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,tmpbindtxid,coin,withdrawpub,amount)==0 || refcoin!=coin || tmptokenid!=tokenid || tmpbindtxid!=bindtxid) continue; + } + else if (funcid=='P') + { + if (DecodeGatewaysPartialOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,K,signerpk,hex)!='P' || GetTransaction(withdrawtxid,tx,hashBlock,false)==0 + || (numvouts=tx.vout.size())<=0 || DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,tmpbindtxid,coin,withdrawpub,amount)!='W' + || refcoin!=coin || tmptokenid!=tokenid || tmpbindtxid!=bindtxid) + continue; + } + Getscriptaddress(destaddr,tx.vout[1].scriptPubKey); + Getscriptaddress(withaddr,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG); + if ( strcmp(destaddr,tokensaddr) == 0 ) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("txid",uint256_str(str,txid))); - _GetCCaddress(cctxidaddr,EVAL_GATEWAYS,CCtxidaddr(txidaddr,txid)); - obj.push_back(Pair("txidaddr",cctxidaddr)); + obj.push_back(Pair("withdrawtxid",uint256_str(str,tx.GetHash()))); + CCtxidaddr(txidaddr,tx.GetHash()); + obj.push_back(Pair("withdrawtxidaddr",txidaddr)); obj.push_back(Pair("withdrawaddr",withaddr)); - sprintf(numstr,"%.8f",(double)tx.vout[0].nValue/COIN); - obj.push_back(Pair("amount",numstr)); - obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + sprintf(numstr,"%.8f",(double)tx.vout[1].nValue/COIN); + obj.push_back(Pair("amount",numstr)); + obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(tx.GetHash()))); if ( queueflag != 0 ) { obj.push_back(Pair("depositaddr",depositaddr)); Getscriptaddress(signeraddr,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG); obj.push_back(Pair("signeraddr",signeraddr)); } + if (N>1) + { + obj.push_back(Pair("number_of_signs",K)); + obj.push_back(Pair("last_txid",uint256_str(str,txid))); + if (K>0) obj.push_back(Pair("hex",hex)); + } pending.push_back(obj); } } @@ -1183,9 +1464,10 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) { - UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string tmprefcoin,hex; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; - uint256 withdrawtxid,hashBlock,txid,tokenid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; - char depositaddr[64],coinaddr[64],str[65],numstr[32],txidaddr[64],cctxidaddr[64],withaddr[64]; + UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string coin,hex; + CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; + uint256 withdrawtxid,hashBlock,txid,tokenid,tmptokenid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + char depositaddr[65],coinaddr[65],str[65],numstr[32],withaddr[65],txidaddr[65]; int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,nValue,amount; struct CCcontract_info *cp,C; std::vector > unspentOutputs; @@ -1194,14 +1476,16 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) gatewayspk = GetUnspendable(cp,0); _GetCCaddress(coinaddr,EVAL_GATEWAYS,gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) - { - fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); - return(result); + { + CCerror = strprintf("cant find bindtxid %s\n",uint256_str(str,bindtxid)); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || refcoin != coin) { - fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); - return(result); + CCerror = strprintf("invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); } n = msigpubkeys.size(); queueflag = 0; @@ -1217,20 +1501,21 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) txid = it->first.txhash; vout = (int32_t)it->first.index; nValue = (int64_t)it->second.satoshis; - //fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue); if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && - DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,tmprefcoin,withdrawtxid,hex) == 'C' && myIsutxo_spentinmempool(txid,vout) == 0) + DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,withdrawtxid,coin,hex) == 'S' && refcoin == coin && myIsutxo_spentinmempool(txid,vout) == 0) { - if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W') + if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 + && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tmptokenid,bindtxid,coin,withdrawpub,amount) == 'W' || refcoin!=coin || tmptokenid!=tokenid) { UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("txid",uint256_str(str,txid))); - obj.push_back(Pair("withdrawtxid",uint256_str(str,withdrawtxid))); - _GetCCaddress(cctxidaddr,EVAL_GATEWAYS,CCtxidaddr(txidaddr,withdrawtxid)); - obj.push_back(Pair("withdrawtxidaddr",cctxidaddr)); - Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); + obj.push_back(Pair("completesigningtxid",uint256_str(str,txid))); + obj.push_back(Pair("withdrawtxid",uint256_str(str,withdrawtxid))); + CCtxidaddr(txidaddr,withdrawtxid); + obj.push_back(Pair("withdrawtxidaddr",txidaddr)); + Getscriptaddress(withaddr,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG); obj.push_back(Pair("withdrawaddr",withaddr)); - obj.push_back(Pair("confirmed_or_notarized",komodo_txnotarizedconfirmed(txid))); + sprintf(numstr,"%.8f",(double)tx.vout[1].nValue/COIN); + obj.push_back(Pair("amount",numstr)); obj.push_back(Pair("hex",hex)); processed.push_back(obj); } @@ -1242,40 +1527,6 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) return(result); } -UniValue GatewaysMultisig(char *cctxidaddr) -{ - std::string parthex,hex,refcoin; uint256 txid,hashBlock; CTransaction tx; int32_t i,maxK,K,numvouts; CPubKey signerpk; - std::vector > unspentOutputs; UniValue result(UniValue::VOBJ); - - SetCCunspents(unspentOutputs,cctxidaddr); - maxK=0; - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - if (GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK ) - { - maxK=K; - parthex=hex; - } - } - - BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) - { - const CTransaction &txmempool = e.GetTx(); - const uint256 &hash = txmempool.GetHash(); - - if ((numvouts=txmempool.vout.size()) > 0 && DecodeGatewaysPartialOpRet(txmempool.vout[numvouts-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK) - { - maxK=K; - parthex=hex; - } - } - - result.push_back(Pair("hex",parthex)); - result.push_back(Pair("number_of_signs",maxK)); - return (result); -} - UniValue GatewaysList() { UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock,oracletxid,tokenid; CTransaction vintx; std::string coin; int64_t totalsupply; char str[65],depositaddr[64]; uint8_t M,N,taddr,prefix,prefix2; std::vector pubkeys; @@ -1286,7 +1537,7 @@ UniValue GatewaysList() txid = it->first.txhash; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 ) + if ( vintx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,vintx.vout[vintx.vout.size()-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 ) { result.push_back(uint256_str(str,txid)); } @@ -1298,16 +1549,19 @@ UniValue GatewaysList() UniValue GatewaysInfo(uint256 bindtxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; 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; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining; + UniValue result(UniValue::VOBJ),a(UniValue::VARR); std::string coin; char str[67],numstr[65],depositaddr[64],gatewaystokens[64]; + uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; + CPubKey Gatewayspk; struct CCcontract_info *cp,C; int32_t i; int64_t totalsupply,remaining; + result.push_back(Pair("result","success")); result.push_back(Pair("name","Gateways")); cp = CCinit(&C,EVAL_GATEWAYS); Gatewayspk = GetUnspendable(cp,0); - _GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk); + GetTokensCCaddress(cp,gatewaystokens,Gatewayspk); if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) { 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 > 0 ) + if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,tokenid,coin,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 0 ) { if ( N > 1 ) { @@ -1326,7 +1580,7 @@ UniValue GatewaysInfo(uint256 bindtxid) result.push_back(Pair("tokenid",uint256_str(str,tokenid))); sprintf(numstr,"%.8f",(double)totalsupply/COIN); result.push_back(Pair("totalsupply",numstr)); - remaining = CCtoken_balance(gatewaysassets,tokenid); + remaining = CCtoken_balance(gatewaystokens,tokenid); sprintf(numstr,"%.8f",(double)remaining/COIN); result.push_back(Pair("remaining",numstr)); sprintf(numstr,"%.8f",(double)(totalsupply - remaining)/COIN); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 82a400e71..208b3cf02 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -478,9 +478,9 @@ static const CRPCCommand vRPCCommands[] = { "gateways", "gatewayspartialsign", &gatewayspartialsign, true }, { "gateways", "gatewayscompletesigning", &gatewayscompletesigning, true }, { "gateways", "gatewaysmarkdone", &gatewaysmarkdone, true }, - { "gateways", "gatewayspending", &gatewayspending, true }, + { "gateways", "gatewayspendingdeposits", &gatewayspendingdeposits, true }, + { "gateways", "gatewayspendingwithdraws", &gatewayspendingwithdraws, true }, { "gateways", "gatewaysprocessed", &gatewaysprocessed, true }, - { "gateways", "gatewaysmultisig", &gatewaysmultisig, true }, // dice { "dice", "dicelist", &dicelist, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 3edc85ebf..b812ccc9d 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -300,9 +300,9 @@ extern UniValue gatewayswithdraw(const UniValue& params, bool fHelp); extern UniValue gatewayspartialsign(const UniValue& params, bool fHelp); extern UniValue gatewayscompletesigning(const UniValue& params, bool fHelp); extern UniValue gatewaysmarkdone(const UniValue& params, bool fHelp); -extern UniValue gatewayspending(const UniValue& params, bool fHelp); +extern UniValue gatewayspendingdeposits(const UniValue& params, bool fHelp); +extern UniValue gatewayspendingwithdraws(const UniValue& params, bool fHelp); extern UniValue gatewaysprocessed(const UniValue& params, bool fHelp); -extern UniValue gatewaysmultisig(const UniValue& params, bool fHelp); extern UniValue channelslist(const UniValue& params, bool fHelp); extern UniValue channelsinfo(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 e111ad98a..0ffc370e2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6263,11 +6263,23 @@ UniValue gatewaysmarkdone(const UniValue& params, bool fHelp) return(result); } -UniValue gatewayspending(const UniValue& params, bool fHelp) +UniValue gatewayspendingdeposits(const UniValue& params, bool fHelp) { uint256 bindtxid; std::string coin; if ( fHelp || params.size() != 2 ) - throw runtime_error("gatewayspending bindtxid coin\n"); + throw runtime_error("gatewayspendingdeposits bindtxid coin\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(); + return(GatewaysPendingDeposits(bindtxid,coin)); +} + +UniValue gatewayspendingwithdraws(const UniValue& params, bool fHelp) +{ + uint256 bindtxid; std::string coin; + if ( fHelp || params.size() != 2 ) + throw runtime_error("gatewayspendingwithdraws bindtxid coin\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()); @@ -6287,19 +6299,6 @@ UniValue gatewaysprocessed(const UniValue& params, bool fHelp) return(GatewaysProcessedWithdraws(bindtxid,coin)); } -UniValue gatewaysmultisig(const UniValue& params, bool fHelp) -{ - UniValue result(UniValue::VOBJ); std::string hex; char *txidaddr; - if ( fHelp || params.size() != 1 ) - throw runtime_error("gatewaysmultisig 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"); - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - txidaddr = (char *)params[0].get_str().c_str(); - return(GatewaysMultisig(txidaddr)); -} - UniValue oracleslist(const UniValue& params, bool fHelp) { if ( fHelp || params.size() > 0 )