From 1f6d62e7c84a43cbf58a70e82cb1dcd5ec1f196d Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 13:40:21 +0500 Subject: [PATCH] MakeTokensCC1of2vout MakeTokensCCcond1of2 test code added gateways partially adapted for tokens --- src/cc/CCinclude.h | 18 ++++-- src/cc/CCtokens.cpp | 10 ++- src/cc/CCtokens.h | 1 - src/cc/CCtx.cpp | 31 +++++---- src/cc/CCutils.cpp | 47 +++++++++++++- src/cc/gateways.cpp | 153 ++++++++++++++++++++++++++++---------------- src/cc/heir.cpp | 2 +- 7 files changed, 182 insertions(+), 80 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 1b6e804fc..3e70ba380 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -91,10 +91,14 @@ struct CCcontract_info char unspendableCCaddr[64], CChexstr[72], normaladdr[64]; uint8_t CCpriv[32]; - // this for 1of2 key spending condition (for this evalcode) + // this for 1of2 keys coins cryptocondition (for this evalcode) // NOTE: only one evalcode is allowed at this time - char unspendable1of2addr[64]; - CPubKey unspendable1of2pk[2]; + char coins1of2addr[64]; + CPubKey coins1of2pk[2]; + + // the same for tokens 1of2 keys cc + char tokens1of2addr[64]; + CPubKey tokens1of2pk[2]; // this is for spending from two additional 'unspendable' CC addresses of other eval codes // (that is, for spending from several cc contract 'unspendable' addresses): @@ -153,15 +157,15 @@ uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk); int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); - bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey); bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); + +CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopretExtra); -//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector &origpubkey); uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &data); int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen); @@ -182,6 +186,10 @@ CC* GetCryptoCondition(CScript const& scriptSig); void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr); void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr); void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr); + +CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2); +CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2); + bool IsCCInput(CScript const& scriptSig); int32_t unstringbits(char *buf,uint64_t bits); uint64_t stringbits(char *str); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 4a2c6031e..62fb1fa78 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -51,7 +51,7 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid,std::vector origpubkey,st } // this is for other contracts which use tokens and build customized extra payloads to token's opret: -CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys) +CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload) { CScript opret; uint8_t ccType = 0; @@ -63,10 +63,14 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t //uint8_t tokenFuncId = (isTransferrable) ? (uint8_t)'t' : (uint8_t)'l'; //opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); - opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; if (ccType >= 1) ss << voutPubkeys[0]; if (ccType == 2) ss << voutPubkeys[1];); + opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ + if(ccType >= 1) ss << voutPubkeys[0]; \ + if(ccType == 2) ss << voutPubkeys[1]; \ + if(payload.size() > 0) ss << payload); return(opret); } + uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description) { std::vector vopret; uint8_t dummyEvalcode, funcid, *script; @@ -578,7 +582,7 @@ std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector d std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(pubkey2pk(destpubkey)); // dest pubkey for validating vout - return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet('t', EVAL_TOKENS, assetid, voutTokenPubkeys))); // By setting EVAL_TOKENS we're getting out from assets validation code + return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet('t', EVAL_TOKENS, assetid, voutTokenPubkeys, CScript()))); // By setting EVAL_TOKENS we're getting out from assets validation code } else { fprintf(stderr, "not enough CC token inputs for %.8f\n", (double)total / COIN); diff --git a/src/cc/CCtokens.h b/src/cc/CCtokens.h index f65a56b41..34223bc0b 100644 --- a/src/cc/CCtokens.h +++ b/src/cc/CCtokens.h @@ -31,7 +31,6 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t //int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description); std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total); -CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys); //this is in CCinclude.h int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 79473b87a..ec0a24b3f 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -45,7 +45,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; - CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *cond; + CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond; CPubKey unspendablepk; n = mtx.vout.size(); @@ -130,7 +130,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran else { Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey); - //fprintf(stderr,"vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr); + //fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr); if ( strcmp(destaddr,myaddr) == 0 ) { privkey = myprivkey; @@ -140,37 +140,44 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { privkey = unspendablepriv; cond = othercond; - //fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable); + //fprintf(stderr,"FinalizeCCTx() unspendable CC addr.(%s)\n",unspendable); } // check if this is the 2nd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr2) == 0) { - //fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2); + //fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2); privkey = cp->unspendablepriv2; - if ( othercond2 == 0 ) //&& cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR && cp->evalcode != EVAL_ASSETS && cp->evalcode != EVAL_TOKENS) + if ( othercond2 == 0 ) othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2); - //else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR || cp->evalcode == EVAL_ASSETS || cp->evalcode == EVAL_TOKENS) ) - // othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3); cond = othercond2; } // check if this is 3rd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 ) { - //fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3); + //fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3); privkey = cp->unspendablepriv3; if ( othercond3 == 0 ) othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3); cond = othercond3; } - // check if this is spending from 1of2 cc addr: - else if (strcmp(cp->unspendable1of2addr, destaddr) == 0) + // check if this is spending from 1of2 cc coins addr: + else if (strcmp(cp->coins1of2addr, destaddr) == 0) { - //fprintf(stderr,"matched %s unspendable1of2!\n",cp->unspendable1of2addr); + fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr); privkey = myprivkey; if (othercond1of2 == 0) - othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->unspendable1of2pk[0], cp->unspendable1of2pk[1]); + othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->coins1of2pk[0], cp->coins1of2pk[1]); cond = othercond1of2; } + // check if this is spending from 1of2 cc tokens addr: + else if (strcmp(cp->tokens1of2addr, destaddr) == 0) + { + fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr); + privkey = myprivkey; + if (othercond1of2tokens == 0) + othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->tokens1of2pk[0], cp->tokens1of2pk[1]); + cond = othercond1of2tokens; + } else { fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index eef21c72a..c07755c2a 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -76,6 +76,39 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2) return(vout); } +CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) +{ + // make 1of2 sigs cond + std::vector pks; + pks.push_back(CCNewSecp256k1(pk1)); + pks.push_back(CCNewSecp256k1(pk2)); + CC *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode)); // this is eval cc + CC *cond1of2Sig = CCNewThreshold(1, pks); // this is 1 of 2 sigs cc + CC *cond1of2Threshold = CCNewThreshold(2, { condEvalCC, cond1of2Sig }); + + // make token cond + struct CCcontract_info *cpTokens, tokensC; + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); + + std::vector pksTokens; + pks.push_back(CCNewSecp256k1(unspendableTokensPk)); + CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // this is eval cc + CC *condUnspendableSig = CCNewThreshold(1, pksTokens); // this is 1 of 2 sigs cc + CC *condTopThreshold = CCNewThreshold(2, { condEvalTokensCC, condUnspendableSig }); + + return CCNewThreshold(2, { cond1of2Threshold, condTopThreshold }); +} + +CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) +{ + CTxOut vout; + CC *payoutCond = MakeTokensCCcond1of2(evalcode, pk1, pk2); + vout = CTxOut(nValue, CCPubKey(payoutCond)); + cc_free(payoutCond); + return(vout); +} + CC* GetCryptoCondition(CScript const& scriptSig) { auto pc = scriptSig.begin(); @@ -198,9 +231,17 @@ void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t * // set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 cryptocondition vout: void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr) { - cp->unspendable1of2pk[0] = pk1; - cp->unspendable1of2pk[1] = pk2; - strcpy(cp->unspendable1of2addr, coinaddr); + cp->coins1of2pk[0] = pk1; + cp->coins1of2pk[1] = pk2; + strcpy(cp->coins1of2addr, coinaddr); +} + +// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 tokens cryptocondition vout: +void CCaddr1of2setTokens(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr) +{ + cp->tokens1of2pk[0] = pk1; + cp->tokens1of2pk[1] = pk2; + strcpy(cp->tokens1of2addr, coinaddr); } bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index 2768e9fbd..c64d56b80 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -132,14 +132,18 @@ Implementation Issues: - When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking. This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly. + -- When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking. + -- This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly. + ++ The use of tokenconvert has been changed to the use of the new Tokens contract which can enforce other contracts validation by forwarding eval->validate call to GatewaysValidate + ++ So all tokens remain within that Tokens contract eval code. - Care must be taken so that tokens are not lost and can be converted back. - - This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241 - - The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS. + -- Care must be taken so that tokens are not lost and can be converted back. + -- This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241 + ++ tokenconvert now returns 'not implemented', no need to use it at all. + -- The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS. + ++ The gatewaysclaim automatically transfers the deposit amount of tokens to depositor's address (within EVAL_TOKENS). + */ @@ -204,38 +208,42 @@ uint8_t DecodeGatewaysDepositOpRet(const CScript &scriptPubKey,std::string &coin return(0); } -CScript EncodeGatewaysClaimOpRet(uint8_t funcid,uint256 assetid,std::string refcoin,uint256 bindtxid,uint256 deposittxid,CPubKey destpub,int64_t amount) +// 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 opret; uint8_t evalcode = EVAL_ASSETS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << refcoin << bindtxid << deposittxid << destpub << amount); + CScript opret; + + opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << bindtxid << deposittxid << destpub << amount); return(opret); } -uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &assetid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) +uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &tokenid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,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 >> assetid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid,uint256 assetid, std::string refcoin, CPubKey withdrawpub, int64_t amount) +CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid, std::string refcoin, CPubKey withdrawpub, int64_t amount) { - CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << refcoin << withdrawpub << amount); + CScript opret; + opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << withdrawpub << amount); return(opret); } -uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &assetid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) +uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &tokenid, std::string &refcoin, CPubKey &withdrawpub, 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 >> assetid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) { return(f); } @@ -304,7 +312,7 @@ 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_ASSETS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 ) + if ( vopret.size() > 2 && (script[0] == EVAL_GATEWAYS || script[0] == EVAL_TOKENS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 ) { if (f == 'B' && f == 'D' && f == 't' && f == 'W' && f == 'P' && f == 'M') return(f); @@ -512,7 +520,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks,height,claimvout; bool retval; uint8_t funcid,hash[32],M,N,taddr,prefix,prefix2; char str[65],destaddr[64],depositaddr[65],validationError[512]; std::vector txids; std::vector pubkeys,publishers,tmppublishers; std::vector proof; int64_t totalsupply,amount,tmpamount; - uint256 hashblock,txid,bindtxid,deposittxid,assetid,oracletxid,tokenid,cointxid,tmptxid,tmpxtxid2,merkleroot,mhash; CTransaction bindtx,deposittx,oracletx; + uint256 hashblock,txid,bindtxid,deposittxid,tokenidClaim,oracletxid,tokenidBind,cointxid,tmptxid,tmpxtxid2,merkleroot,mhash; CTransaction bindtx,deposittx,oracletx; std::string refcoin,tmprefcoin,deposithex; CPubKey destpub,tmpdestpub; fprintf(stderr,"return true without gateways validation\n"); @@ -565,8 +573,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & //vin.2: CC input of marker from gatewaysdeposit tx //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' assetid zeroid 0 mypubkey (NOTE: opreturn is with asset eval code) - if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,refcoin,bindtxid,deposittxid,destpub,amount)==0) + //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!"); @@ -580,12 +588,12 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & 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,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B') + 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 (tokenid!=assetid) - return eval->Invalid("assetid does not match tokenid from gatewaysbind"); + 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) @@ -642,7 +650,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & //vout.1: normal vout txfee marker to withdraw destination pubkey //vout.2: CC vout txfee marker to gateways CC address //vout.n-2: CC vout if there is change of unused tokens back to owner of tokens (withdraw amount less than owner available tokens) - //vout.n-1: opreturn - 'W' assetid refcoin withdrawpub amount + //vout.n-1: opreturn - 'W' tokenid refcoin withdrawpub amount break; case 'P': //vin.0: normal input @@ -675,9 +683,9 @@ 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 refassetid,int64_t total,int32_t maxinputs) +int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 reftokenid,int64_t total,int32_t maxinputs) { - char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 assetid,txid,hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid; + 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); @@ -701,11 +709,11 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP 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 >> assetid) != 0 ) + if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> tokenid) != 0 ) { - assetid = revuint256(assetid); - char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for refassetid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,refassetid),uint256_str(str2,assetid),(double)vintx.vout[vout].nValue/COIN); - if ( assetid == refassetid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) + 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 ) { //fprintf(stderr,"total %llu maxinputs.%d %.8f\n",(long long)total,maxinputs,(double)it->second.satoshis/COIN); if ( total != 0 && maxinputs != 0 ) @@ -905,7 +913,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui CTransaction tx; CPubKey mypk,gatewayspk,tmpdestpub; struct CCcontract_info *cp,C; uint8_t M,N,taddr,prefix,prefix2; std::string coin, deposithex; std::vector msigpubkeys,publishers; int64_t totalsupply,depositamount,tmpamount,inputs,CCchange=0; int32_t numvouts,claimvout,height; std::vector proof; - uint256 hashBlock,assetid,oracletxid,tmptxid,cointxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64]; std::vector txids; + uint256 hashBlock,tokenid,oracletxid,tmptxid,cointxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64]; std::vector txids; cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) @@ -917,7 +925,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,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,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(""); @@ -945,17 +953,24 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2); if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { - if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,assetid,amount,60)) > 0 ) + ///////// if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,tokenid,amount,60)) > 0 ) + if ((inputs = AddTokenCCInputs(cp, mtx, gatewayspk, tokenid, 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_ASSETS,amount,mypk)); // transfer back to normal token + 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)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysClaimOpRet('t',assetid,refcoin,bindtxid,deposittxid,destpub,amount))); + 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 } } CCerror = strprintf("cant find enough inputs or mismatched total"); @@ -966,39 +981,67 @@ 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; struct CCcontract_info *cp,C; - uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; + 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]; - cp = CCinit(&C,EVAL_GATEWAYS); + struct CCcontract_info *cpGateways, gatewaysC; + struct CCcontract_info *cpTokens, tokensC; + + cpGateways = CCinit(&gatewaysC, EVAL_GATEWAYS); + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + if ( txfee == 0 ) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - gatewayspk = GetUnspendable(cp,0); - if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + gatewayspk = GetUnspendable(cpGateways, 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,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,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(""); } - if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 ) + if( AddNormalinputs(mtx, mypk, 3*txfee, 4) > 0 ) { - if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,assetid,amount,60)) > 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_GATEWAYS,amount,gatewayspk)); + 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)); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS, txfee, gatewayspk)); if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysWithdrawOpRet('W',assetid,refcoin,withdrawpub,amount))); + 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)))); } + CCerror = strprintf("cant find enough token inputs or mismatched total"); + fprintf(stderr, "%s\n", CCerror.c_str()); + return(""); + } - CCerror = strprintf("cant find enough inputs or mismatched total"); + CCerror = strprintf("cant find enough normal inputs or mismatched total"); fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } @@ -1073,7 +1116,7 @@ std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string ref 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,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + 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; std::vector > unspentOutputs; @@ -1087,7 +1130,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(result); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) { fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); return(result); @@ -1108,7 +1151,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) 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,assetid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0) + DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0) { Getscriptaddress(destaddr,tx.vout[0].scriptPubKey); Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); @@ -1141,7 +1184,7 @@ 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,assetid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + 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]; int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,nValue,amount; struct CCcontract_info *cp,C; std::vector > unspentOutputs; @@ -1155,7 +1198,7 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(result); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) { fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); return(result); @@ -1178,7 +1221,7 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) 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) { - if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W') + if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W') { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid",uint256_str(str,txid))); diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 7d5ea7cfe..fe93e7a5a 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -690,7 +690,7 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, if ((inputs=Helper::addOwnerInputs(cp, tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) { // 2 x txfee: 1st for marker vout, 2nd to miners //mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,amount,HeirCCpk)); - mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk + mtx.vout.push_back(MakeTokensCC1of2vout(/*Helper::getMyEval()*/EVAL_HEIR, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk // add a marker for finding all plans in HeirList() CPubKey HeirContractPubKey = GetUnspendable(cp, 0);