From 93cfcaa7efeb6251cddda6afe3f01fe747ce97eb Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 14 Sep 2018 15:03:44 +0200 Subject: [PATCH 01/25] - Modified AddChannelsInputs to uses inputs from CC channel for payment - Inital validate skeleton - Defined OP_RETURN format --- src/cc/channels.cpp | 326 ++++++++++++++++++++++++++++++++------------ 1 file changed, 239 insertions(+), 87 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index dc1a3f291..0ecd6a1be 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -111,11 +111,101 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti else return(true); } +CScript EncodeChannelsOpRet(uint8_t funcid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) +{ + CScript opret; uint8_t evalcode = EVAL_CHANNELS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << opentxid << srcpub << destpub << numpayments << payment << hashchain); + return(opret); +} + +uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) +{ + std::vector vopret; uint8_t *script,e,f,funcid; + GetOpReturnData(scriptPubKey, vopret); + if ( vopret.size() > 2 ) + { + script = (uint8_t *)vopret.data(); + if ( script[0] == EVAL_CHANNELS ) + { + funcid = script[1]; + //fprintf(stderr,"decode.[%c]\n",funcid); + switch ( funcid ) + { + case 'c': + return(funcid); + break; + default: + if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> opentxid; ss >> srcpub; ss >> destpub; ss >> numpayments; ss >> payment; ss >> hashchain) != 0 ) + { + return(f); + } + break; + } + } else fprintf(stderr,"script[0] %02x != EVAL_CHANNELS\n",script[0]); + } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size()); + return(0); +} + +CScript EncodeChannelsPaymentOpRet(uint8_t funcid,uint256 opentxid,uint256 prevtxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) +{ + CScript opret; uint8_t evalcode = EVAL_CHANNELS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << opentxid << prevtxid << srcpub << destpub << numpayments << payment << hashchain); + return(opret); +} + +uint8_t DecodeChannelsPaymentOpRet(const CScript &scriptPubKey,uint256 &opentxid,uint256 &prevtxid,CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) +{ + std::vector vopret; uint8_t *script,e,f,funcid; + GetOpReturnData(scriptPubKey, vopret); + if ( vopret.size() > 2 ) + { + script = (uint8_t *)vopret.data(); + if ( script[0] == EVAL_CHANNELS ) + { + if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> opentxid; ss >> srcpub; ss >> destpub; ss >> numpayments; ss >> payment; ss >> hashchain) != 0 ) + { + return(f); + } + } else fprintf(stderr,"script[0] %02x != EVAL_CHANNELS\n",script[0]); + } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size()); + return(0); +} + +//bool GetChannelOpenTx(struct CCcontract_info *cp, CTransaction &channelOpenTx, CPubKey srcpub, CPubKey destpub, int32_t &numpayments, int64_t &payment, uint256 &hashchain) +//{ +// uint256 txid, hashBlock, origtxid; +// char CCaddr[64]; +// std::vector > txids; +// uint8_t funcid; +// CPubKey opensrcpub, opendestpub; +// int32_t numvouts; +// +// GetCCaddress1of2(cp,CCaddr,srcpub,destpub); +// SetCCtxids(txids,CCaddr); +// +// for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) +// { +// txid=it->first.txhash; +// if (GetTransaction(txid,channelOpenTx,hashBlock,false) != 0 && (numvouts= channelOpenTx.vout.size()) > 0) +// { +// if (((funcid = DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,origtxid,opensrcpub,opendestpub,numpayments,payment,hashchain)) != 0) && (funcid == 'O') && (srcpub==opensrcpub && (destpub==opendestpub))) +// { +// return true; +// } +// } +// } +// +// return false; +//} + bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; - return(false); + int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,param1,numpayments; bool retval; uint256 txid,hashblock,param3,hashchain,opentxid,prevtxid; uint8_t funcid, hash[32]; char str[65],destaddr[64]; + int64_t param2,payment; + CPubKey srcpub, destpub; std::vector > txids; + CTransaction channelOpenTx; + numvins = tx.vin.size(); numvouts = tx.vout.size(); preventCCvins = preventCCvouts = -1; @@ -140,6 +230,43 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { txid = tx.GetHash(); memcpy(hash,&txid,sizeof(hash)); + + if ( (funcid = DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, opentxid, srcpub, destpub, param1, param2, param3)) != 0) + { + switch ( funcid ) + { + case 'O': + if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) + return eval->Invalid("vin.0 is normal for channelOpen"); + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.0 is CC for channelOpen"); + else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.1 is CC for channelOpen"); + else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.2 is CC for channelOpen"); + else if ( numpayments > 1000) + return eval->Invalid("too many payment increments"); + else if ( tx.vout[0].nValue != param1 * param2) + return eval->Invalid("tx funds do not match sum of payments"); + break; + case 'C': + break; + case 'P': + DecodeChannelsPaymentOpRet(tx.vout[numvouts-1].scriptPubKey, opentxid, prevtxid, srcpub, destpub, param1, param2, param3); + if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) + return eval->Invalid("vin.0 is normal for channelOpen"); + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.0 is CC for channelOpen"); + + if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) + { + return (false); + } + break; + case 'R': + break; + } + } retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) fprintf(stderr,"Channelsget validated\n"); @@ -152,57 +279,57 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & // helper functions for rpc calls in rpcwallet.cpp -CScript EncodeChannelsOpRet(uint8_t funcid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) +int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, uint256 prevtxid) { - CScript opret; uint8_t evalcode = EVAL_CHANNELS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << srcpub << destpub << numpayments << payment << hashchain); - return(opret); -} - -uint8_t DecodeChannelsOpRet(uint256 txid,const CScript &scriptPubKey,CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) -{ - std::vector vopret; uint8_t *script,e,f,funcid; - GetOpReturnData(scriptPubKey, vopret); - if ( vopret.size() > 2 ) - { - script = (uint8_t *)vopret.data(); - if ( script[0] == EVAL_CHANNELS ) - { - if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> srcpub; ss >> destpub; ss >> numpayments; ss >> payment; ss >> hashchain) != 0 ) - { - return(f); - } - } else fprintf(stderr,"script[0] %02x != EVAL_CHANNELS\n",script[0]); - } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size()); - return(0); -} - -int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) -{ - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; + char coinaddr[64]; int64_t param2,totalinputs = 0; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t funcid,param1,numvouts,vout; std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); + CPubKey srcpub,destpub; + + GetCCaddress1of2(cp,coinaddr,srcpub,destpub); 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; - // no need to prevent dup - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0) { - if ( (nValue= IsChannelsvout(cp,vintx,vout)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) - { - if ( 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) ) + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) != 0 && prevtxid==tmp_txid) + if ( (totalinputs=IsChannelsvout(cp,tx,vout)) > 0) + { + txid = it->first.txhash; + vout = 0; break; + } + } + } + + if (myIsutxo_spentinmempool(txid,vout) != 0) + { + txid=zeroid; + int32_t mindepth=1000; + + BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) + { + const CTransaction &txmempool = e.GetTx(); + const uint256 &hash = tx.GetHash(); + if ((numvouts=txmempool.vout.size()) > 0 && + (funcid=DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)) != 0 && + funcid=='P' && param1 < mindepth) + { + txid=hash; + vout=0; + totalinputs=txmempool.vout[vout].nValue; + mindepth=param1; + } } } - return(totalinputs); + + if (txid != zeroid) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + return totalinputs; + } + else return 0; } std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment) @@ -232,12 +359,74 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',mypk,destpub,numpayments,payment,hashchain))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',zeroid,mypk,destpub,numpayments,payment,hashchain))); } return(""); } -std::string ChannelStop(uint64_t txfee,CPubKey destpub,uint256 origtxid) +std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 opentxid,int32_t numpayments) +{ + CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,secret,hashblock,entropy,hentropy,param3; + struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,param1; + int64_t param2,payment,change,funds; + uint8_t hash[32],hashdest[32]; + CTransaction channelOpenTx,prevTx; + + if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) + { + if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsPaymentOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, txid, srcpub, destpub, param1, param2, param3)) != 0) && (funcid == 'O' || funcid == 'P')) + { + if (mypk != srcpub || mypk != destpub) + { + fprintf(stderr,"this is not our channel\n"); + return(""); + } + + prevdepth=param1; + payment=param2; + } + else + { + fprintf(stderr,"invalid previous txid\n"); + return(""); + } + + if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) + { + hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < prevdepth-numpayments; i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & secret, hashdest, 32); + } + else + { + fprintf(stderr,"invalid channel open txid\n"); + return(""); + } + } + // verify lasttxid and origtxid match and src is me + // also verify hashchain depth and amount, set prevdepth + cp = CCinit(&C,EVAL_CHANNELS); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) + { + if ((funds=AddChannelsInputs(cp,mtx,prevtxid)) != 0 && (change=funds-numpayments*payment)>=0) { + mtx.vout.push_back(CTxOut(numpayments * payment, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS, txfee, mypk)); + mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub)); + return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsPaymentOpRet('P', opentxid, prevtxid, mypk, destpub, prevdepth - numpayments, payment, secret))); + } + } + return(""); +} + +std::string ChannelClose(uint64_t txfee,uint256 prevtxid,uint256 opentxid,CPubKey destpub) { CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; // verify this is one of our outbound channels @@ -248,49 +437,12 @@ std::string ChannelStop(uint64_t txfee,CPubKey destpub,uint256 origtxid) if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) { mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('S',mypk,destpub,0,0,zeroid))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('S',opentxid,mypk,destpub,0,0,zeroid))); } return(""); } -std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 origtxid,int32_t n,int64_t amount) -{ - CMutableTransaction mtx; CPubKey mypk,destpub; uint256 secret; struct CCcontract_info *cp,C; int32_t prevdepth; - // verify lasttxid and origtxid match and src is me - // also verify hashchain depth and amount, set prevdepth - cp = CCinit(&C,EVAL_CHANNELS); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) - { - // add locked funds inputs - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('P',mypk,destpub,prevdepth-n,amount,secret))); - } - return(""); -} - -std::string ChannelCollect(uint64_t txfee,uint256 paytxid,uint256 origtxid,int32_t n,int64_t amount) -{ - CMutableTransaction mtx; CPubKey mypk,senderpub; struct CCcontract_info *cp,C; int32_t prevdepth; - // verify paytxid and origtxid match and dest is me - // also verify hashchain depth and amount - cp = CCinit(&C,EVAL_CHANNELS); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) - { - // add locked funds inputs - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); - mtx.vout.push_back(CTxOut(amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',senderpub,mypk,prevdepth-n,amount,paytxid))); - } - return(""); -} - -std::string ChannelRefund(uint64_t txfee,uint256 stoptxid,uint256 origtxid) +std::string ChannelRefund(uint64_t txfee,uint256 closetxid,uint256 opentxid) { CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t amount; // verify stoptxid and origtxid match and are mine @@ -302,14 +454,14 @@ std::string ChannelRefund(uint64_t txfee,uint256 stoptxid,uint256 origtxid) { mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(CTxOut(amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',mypk,mypk,0,0,stoptxid))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,mypk,0,0,closetxid))); } return(""); } UniValue ChannelsInfo() { - UniValue result(UniValue::VOBJ); CTransaction tx; uint256 txid,hashBlock,hashchain; struct CCcontract_info *cp,C; uint8_t funcid; char myCCaddr[64]; int32_t vout,numvouts,numpayments; int64_t nValue,payment; CPubKey srcpub,destpub,mypk; + UniValue result(UniValue::VOBJ); CTransaction tx; uint256 txid,hashBlock,hashchain,opentxid; struct CCcontract_info *cp,C; uint8_t funcid; char myCCaddr[64]; int32_t vout,numvouts,numpayments; int64_t nValue,payment; CPubKey srcpub,destpub,mypk; std::vector > txids; result.push_back(Pair("result","success")); result.push_back(Pair("name","Channels")); @@ -325,7 +477,7 @@ UniValue ChannelsInfo() nValue = (int64_t)it->second; if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - if ( DecodeChannelsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,srcpub,destpub,numpayments,payment,hashchain) == 'O' || funcid == 'P' ) + if ( DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'O' || funcid == 'P' ) { char str[67],str2[67]; fprintf(stderr,"%s func.%c %s -> %s %.8f num.%d of %.8f\n",mypk == srcpub ? "send" : "recv",funcid,pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),(double)tx.vout[0].nValue/COIN,numpayments,(double)payment/COIN); From c2fa2759d61cc39a7e55b3365eed7a7b7cc20642 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 14 Sep 2018 22:36:10 +0200 Subject: [PATCH 02/25] Small fixes --- src/cc/CCchannels.h | 7 ++-- src/cc/channels.cpp | 78 +++++++++++++++++++++++++++++----------- src/rpcserver.cpp | 3 +- src/rpcserver.h | 4 +-- src/wallet/rpcwallet.cpp | 58 +++++++++--------------------- 5 files changed, 80 insertions(+), 70 deletions(-) diff --git a/src/cc/CCchannels.h b/src/cc/CCchannels.h index 26057457f..ba31883a2 100644 --- a/src/cc/CCchannels.h +++ b/src/cc/CCchannels.h @@ -22,10 +22,9 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment); -std::string ChannelStop(uint64_t txfee,CPubKey destpub,uint256 origtxid); -std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 origtxid,int32_t n,int64_t amount); -std::string ChannelCollect(uint64_t txfee,uint256 paytxid,uint256 origtxid,int32_t n,int64_t amount); -std::string ChannelRefund(uint64_t txfee,uint256 stoptxid,uint256 origtxid); +std::string ChannelPayment(uint64_t txfee,uint256 opentxid,uint256 prevtxid,int64_t amount); +std::string ChannelClose(uint64_t txfee,uint256 opentxid); +std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid); // CCcustom UniValue ChannelsInfo(); diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 0ecd6a1be..01a422715 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -244,7 +244,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vout.1 is CC for channelOpen"); else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("vout.2 is CC for channelOpen"); - else if ( numpayments > 1000) + else if ( numpayments > CHANNELS_MAXPAYMENTS) return eval->Invalid("too many payment increments"); else if ( tx.vout[0].nValue != param1 * param2) return eval->Invalid("tx funds do not match sum of payments"); @@ -287,7 +287,6 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, u GetCCaddress1of2(cp,coinaddr,srcpub,destpub); SetCCunspents(unspentOutputs,coinaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0) @@ -301,12 +300,10 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, u } } } - if (myIsutxo_spentinmempool(txid,vout) != 0) { txid=zeroid; int32_t mindepth=1000; - BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) { const CTransaction &txmempool = e.GetTx(); @@ -323,7 +320,6 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, u } } } - if (txid != zeroid) { mtx.vin.push_back(CTxIn(txid,vout,CScript())); @@ -344,6 +340,8 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 cp = CCinit(&C,EVAL_CHANNELS); if ( txfee == 0 ) txfee = 10000; + if (numpayments>CHANNELS_MAXPAYMENTS) + return (""); mypk = pubkey2pk(Mypubkey()); funds = numpayments * payment; if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 ) @@ -364,38 +362,78 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 return(""); } -std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 opentxid,int32_t numpayments) +std::string ChannelPayment(uint64_t txfee,uint256 opentxid,uint256 prevtxid,int64_t amount) { CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,secret,hashblock,entropy,hentropy,param3; - struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,param1; + struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments,param1; int64_t param2,payment,change,funds; uint8_t hash[32],hashdest[32]; CTransaction channelOpenTx,prevTx; - if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) + if (opentxid==prevtxid) { - if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsPaymentOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, txid, srcpub, destpub, param1, param2, param3)) != 0) && (funcid == 'O' || funcid == 'P')) + if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) { - if (mypk != srcpub || mypk != destpub) + if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)) != 0) && funcid == 'O') + { + if (mypk == srcpub || mypk == destpub) + { + prevdepth=param1; + payment=param2; + } + else + { + fprintf(stderr,"this is not our channel\n"); + return(""); + } + } + else + { + fprintf(stderr,"invalid previous txid\n"); + return(""); + } + if (amount % payment != 0) + return (""); + numpayments=amount/payment; + hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < numpayments; i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & secret, hashdest, 32); + + } + } + else if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) + { + if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsPaymentOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, txid, srcpub, destpub, param1, param2, param3)) != 0) && funcid == 'P') + { + if (mypk == srcpub || mypk == destpub) + { + prevdepth=param1; + payment=param2; + } + else { fprintf(stderr,"this is not our channel\n"); return(""); } - - prevdepth=param1; - payment=param2; } else { fprintf(stderr,"invalid previous txid\n"); return(""); } - + if ((numpayments=amount % payment) != 0) + return (""); + numpayments=amount/payment; if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) { hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < prevdepth-numpayments; i++) + for (i = 0; i < numpayments; i++) { vcalc_sha256(0, hashdest, hash, 32); memcpy(hash, hashdest, 32); @@ -416,8 +454,8 @@ std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 opentxid,int3 mypk = pubkey2pk(Mypubkey()); if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) { - if ((funds=AddChannelsInputs(cp,mtx,prevtxid)) != 0 && (change=funds-numpayments*payment)>=0) { - mtx.vout.push_back(CTxOut(numpayments * payment, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); + if ((funds=AddChannelsInputs(cp,mtx,prevtxid)) != 0 && (change=funds-amount)>=0) { + mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS, txfee, mypk)); mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub)); return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsPaymentOpRet('P', opentxid, prevtxid, mypk, destpub, prevdepth - numpayments, payment, secret))); @@ -426,7 +464,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 prevtxid,uint256 opentxid,int3 return(""); } -std::string ChannelClose(uint64_t txfee,uint256 prevtxid,uint256 opentxid,CPubKey destpub) +std::string ChannelClose(uint64_t txfee,uint256 opentxid) { CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; // verify this is one of our outbound channels @@ -437,12 +475,12 @@ std::string ChannelClose(uint64_t txfee,uint256 prevtxid,uint256 opentxid,CPubKe if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) { mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('S',opentxid,mypk,destpub,0,0,zeroid))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('S',opentxid,mypk,mypk,0,0,zeroid))); } return(""); } -std::string ChannelRefund(uint64_t txfee,uint256 closetxid,uint256 opentxid) +std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) { CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t amount; // verify stoptxid and origtxid match and are mine diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 8934ae717..7d2eab1e3 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -383,8 +383,7 @@ static const CRPCCommand vRPCCommands[] = { "channels", "channelsinfo", &channelsinfo, true }, { "channels", "channelsopen", &channelsopen, true }, { "channels", "channelspayment", &channelspayment, true }, - { "channels", "channelscollect", &channelscollect, true }, - { "channels", "channelsstop", &channelsstop, true }, + { "channels", "channelsclose", &channelsclose, true }, { "channels", "channelsrefund", &channelsrefund, true }, /* Oracles */ diff --git a/src/rpcserver.h b/src/rpcserver.h index f4c502d63..a78f1b6fc 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -254,11 +254,9 @@ extern UniValue gatewayspending(const UniValue& params, bool fHelp); extern UniValue gatewaysmarkdone(const UniValue& params, bool fHelp); extern UniValue gatewaysmultisig(const UniValue& params, bool fHelp); extern UniValue channelsinfo(const UniValue& params, bool fHelp); -extern UniValue channelsbind(const UniValue& params, bool fHelp); extern UniValue channelsopen(const UniValue& params, bool fHelp); extern UniValue channelspayment(const UniValue& params, bool fHelp); -extern UniValue channelscollect(const UniValue& params, bool fHelp); -extern UniValue channelsstop(const UniValue& params, bool fHelp); +extern UniValue channelsclose(const UniValue& params, bool fHelp); extern UniValue channelsrefund(const UniValue& params, bool fHelp); //extern UniValue tokenswapask(const UniValue& params, bool fHelp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8f64d093d..c105b4872 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5153,42 +5153,21 @@ UniValue channelsopen(const UniValue& params, bool fHelp) return(result); } -UniValue channelsstop(const UniValue& params, bool fHelp) -{ - UniValue result(UniValue::VOBJ); std::vector destpub; struct CCcontract_info *cp,C; std::string hex; uint256 origtxid; - cp = CCinit(&C,EVAL_CHANNELS); - if ( fHelp || params.size() != 2 ) - throw runtime_error("channelsstop destpubkey origtxid\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); - destpub = ParseHex(params[0].get_str().c_str()); - origtxid = Parseuint256((char *)params[1].get_str().c_str()); - hex = ChannelStop(0,pubkey2pk(destpub),origtxid); - if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt create channelsstop transaction"); - return(result); -} - UniValue channelspayment(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,prevtxid; int32_t n; int64_t amount; + UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,prevtxid; int32_t n; int64_t amount; cp = CCinit(&C,EVAL_CHANNELS); if ( fHelp || params.size() != 4 ) - throw runtime_error("channelspayment prevtxid origtxid n amount\n"); + throw runtime_error("channelspayment opentxid prevtxid amount\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); - prevtxid = Parseuint256((char *)params[0].get_str().c_str()); - origtxid = Parseuint256((char *)params[1].get_str().c_str()); + opentxid = Parseuint256((char *)params[0].get_str().c_str()); + prevtxid = Parseuint256((char *)params[1].get_str().c_str()); n = atoi((char *)params[2].get_str().c_str()); amount = atoi((char *)params[3].get_str().c_str()); - hex = ChannelPayment(0,prevtxid,origtxid,n,amount); + hex = ChannelPayment(0,opentxid,prevtxid,amount); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); @@ -5197,42 +5176,39 @@ UniValue channelspayment(const UniValue& params, bool fHelp) return(result); } -UniValue channelscollect(const UniValue& params, bool fHelp) +UniValue channelsclose(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,paytxid; int32_t n; int64_t amount; + UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid; cp = CCinit(&C,EVAL_CHANNELS); - if ( fHelp || params.size() != 4 ) - throw runtime_error("channelscollect paytxid origtxid n amount\n"); + if ( fHelp || params.size() != 2 ) + throw runtime_error("channelsclose opentxid\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); - paytxid = Parseuint256((char *)params[0].get_str().c_str()); - origtxid = Parseuint256((char *)params[1].get_str().c_str()); - n = atoi((char *)params[2].get_str().c_str()); - amount = atoi((char *)params[3].get_str().c_str()); - hex = ChannelCollect(0,paytxid,origtxid,n,amount); + opentxid = Parseuint256((char *)params[1].get_str().c_str()); + hex = ChannelClose(0,opentxid); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt create channelscollect transaction"); + } else ERR_RESULT("couldnt create channelsstop transaction"); return(result); } UniValue channelsrefund(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 origtxid,stoptxid; + UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,closetxid; cp = CCinit(&C,EVAL_CHANNELS); if ( fHelp || params.size() != 2 ) - throw runtime_error("channelsrefund stoptxid origtxid\n"); + throw runtime_error("channelsrefund opentxid closetxid\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); - stoptxid = Parseuint256((char *)params[0].get_str().c_str()); - origtxid = Parseuint256((char *)params[1].get_str().c_str()); - hex = ChannelRefund(0,stoptxid,origtxid); + opentxid = Parseuint256((char *)params[0].get_str().c_str()); + closetxid = Parseuint256((char *)params[1].get_str().c_str()); + hex = ChannelRefund(0,opentxid,closetxid); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); From 5aa6428feba6f92cf4fa204e5ed476d88f5c0390 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sat, 15 Sep 2018 11:22:48 +0200 Subject: [PATCH 03/25] - Fixes --- src/cc/channels.cpp | 150 ++++++++++++++++++++++----------------- src/wallet/rpcwallet.cpp | 4 +- 2 files changed, 85 insertions(+), 69 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 01a422715..744c223d1 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -128,10 +128,9 @@ uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubK if ( script[0] == EVAL_CHANNELS ) { funcid = script[1]; - //fprintf(stderr,"decode.[%c]\n",funcid); switch ( funcid ) { - case 'c': + case 'O': return(funcid); break; default: @@ -171,37 +170,12 @@ uint8_t DecodeChannelsPaymentOpRet(const CScript &scriptPubKey,uint256 &opentxid return(0); } -//bool GetChannelOpenTx(struct CCcontract_info *cp, CTransaction &channelOpenTx, CPubKey srcpub, CPubKey destpub, int32_t &numpayments, int64_t &payment, uint256 &hashchain) -//{ -// uint256 txid, hashBlock, origtxid; -// char CCaddr[64]; -// std::vector > txids; -// uint8_t funcid; -// CPubKey opensrcpub, opendestpub; -// int32_t numvouts; -// -// GetCCaddress1of2(cp,CCaddr,srcpub,destpub); -// SetCCtxids(txids,CCaddr); -// -// for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) -// { -// txid=it->first.txhash; -// if (GetTransaction(txid,channelOpenTx,hashBlock,false) != 0 && (numvouts= channelOpenTx.vout.size()) > 0) -// { -// if (((funcid = DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,origtxid,opensrcpub,opendestpub,numpayments,payment,hashchain)) != 0) && (funcid == 'O') && (srcpub==opensrcpub && (destpub==opendestpub))) -// { -// return true; -// } -// } -// } -// -// return false; -//} - bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,param1,numpayments; bool retval; uint256 txid,hashblock,param3,hashchain,opentxid,prevtxid; uint8_t funcid, hash[32]; char str[65],destaddr[64]; - int64_t param2,payment; + int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,param1,depth; bool retval; + uint256 txid,hashblock,param3,opentxid,prevtxid,entropy,hentropy,secret,gensecret,genhashchain; + uint8_t funcid,hash[32],hashdest[32]; + int64_t param2,numpayments; CPubKey srcpub, destpub; std::vector > txids; CTransaction channelOpenTx; @@ -236,34 +210,72 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & switch ( funcid ) { case 'O': - if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) - return eval->Invalid("vin.0 is normal for channelOpen"); - else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.0 is CC for channelOpen"); - else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.1 is CC for channelOpen"); - else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.2 is CC for channelOpen"); - else if ( numpayments > CHANNELS_MAXPAYMENTS) - return eval->Invalid("too many payment increments"); - else if ( tx.vout[0].nValue != param1 * param2) - return eval->Invalid("tx funds do not match sum of payments"); - break; - case 'C': + //vin.0: normal input + //vout.0: CC vout for channel funding on CC1of2 pubkey + //vout.1: CC vout marker to senders pubKey + //vout.2: CC vout marker to receiver pubkey + //vout.3: opreturn - 'O' zerotxid senderspubkey receiverspubkey totalnumberofpayments paymentamount hashchain + return eval->Invalid("unexpected ChannelsValidate for channelopen"); break; case 'P': - DecodeChannelsPaymentOpRet(tx.vout[numvouts-1].scriptPubKey, opentxid, prevtxid, srcpub, destpub, param1, param2, param3); - if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) - return eval->Invalid("vin.0 is normal for channelOpen"); - else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.0 is CC for channelOpen"); - - if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) + //vin.0: normal input + //vin.1: CC input from channel funding + //vout.0: normal output of payment amount to receiver pubkey + //vout.1: CC vout change to CC1of2 pubkey + //vout.n-2: CC vout marker to payment issuer + //vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret + if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for channelPayment"); + else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) + return eval->Invalid("vin.1 is CC for channelPayment"); + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 ) + return eval->Invalid("vout.0 is normal for channelPayment"); + else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.1 is CC for channelPayment"); + else if ( tx.vout.size() == 4 && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.2 is CC for channelPayment"); + else if (DecodeChannelsPaymentOpRet(tx.vout[numvouts-1].scriptPubKey, opentxid, prevtxid, srcpub, destpub, depth, numpayments, secret) != 'P') + return eval->Invalid("invalid OP_RETURN data"); + else if ( tx.vout[0].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG) + return eval->Invalid("payment funds do not go to receiver"); + else if ( param2 > CHANNELS_MAXPAYMENTS) + return eval->Invalid("too many payment increments"); + else { - return (false); + if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) + { + if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, opentxid, srcpub, destpub, param1, param2, param3)) != 0 && funcid!='O') + return eval->Invalid("invalid channelopen OP_RETURN data"); + hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < param1; i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + if (i==depth) endiancpy((uint8_t * ) & gensecret, hashdest, 32); + } + endiancpy((uint8_t * ) & genhashchain, hashdest, 32); + + if (secret!=gensecret) + return eval->Invalid("invalid secret for payment"); + else if (param3!=genhashchain) + return eval->Invalid("invalid secret for payment, does not reach final hashchain"); + else if (tx.vout[0].nValue != numpayments*param2) + return eval->Invalid("vout amount does not match numberofpayments*payment"); + } } break; + case 'C': + //vin.0: normal input for 2*txfee (normal fee and marker) + //vout.0: CC vout marker to senders pubKey + //vout.1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0 + return eval->Invalid("unexpected ChannelsValidate for channelclose"); case 'R': + //vin.0: normal input + //vin.1: CC input from channel funding + //vout.0: normal output of CC input to senders pubkey + //vout.1: CC vout marker to senders pubKey + //vout.2: opreturn - 'R' opentxid senderspubkey receiverspubkey 0 0 closetxid break; } } @@ -333,18 +345,16 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 CMutableTransaction mtx; uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; CPubKey mypk; struct CCcontract_info *cp,C; if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS ) { - CCerror = strprintf("invalid ChannelsFund param numpayments.%d max.%d payment.%lld\n",numpayments,CHANNELS_MAXPAYMENTS,(long long)payment); + CCerror = strprintf("invalid ChannelOpen param numpayments.%d max.%d payment.%lld\n",numpayments,CHANNELS_MAXPAYMENTS,(long long)payment); fprintf(stderr,"%s\n",CCerror.c_str()); return(""); } cp = CCinit(&C,EVAL_CHANNELS); if ( txfee == 0 ) txfee = 10000; - if (numpayments>CHANNELS_MAXPAYMENTS) - return (""); mypk = pubkey2pk(Mypubkey()); funds = numpayments * payment; - if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 ) + if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 ) { hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash); endiancpy(hash,(uint8_t *)&hentropy,32); @@ -355,8 +365,6 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 } endiancpy((uint8_t *)&hashchain,hashdest,32); mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub)); - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',zeroid,mypk,destpub,numpayments,payment,hashchain))); } return(""); @@ -393,7 +401,10 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,uint256 prevtxid,int6 return(""); } if (amount % payment != 0) + { + fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); return (""); + } numpayments=amount/payment; hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); endiancpy(hash, (uint8_t * ) & hentropy, 32); @@ -426,14 +437,17 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,uint256 prevtxid,int6 fprintf(stderr,"invalid previous txid\n"); return(""); } - if ((numpayments=amount % payment) != 0) + if (amount % payment != 0) + { + fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); return (""); + } numpayments=amount/payment; if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) { hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < numpayments; i++) + for (i = 0; i < prevdepth-numpayments; i++) { vcalc_sha256(0, hashdest, hash, 32); memcpy(hash, hashdest, 32); @@ -452,15 +466,19 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,uint256 prevtxid,int6 if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) { if ((funds=AddChannelsInputs(cp,mtx,prevtxid)) != 0 && (change=funds-amount)>=0) { mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS, txfee, mypk)); mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub)); return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsPaymentOpRet('P', opentxid, prevtxid, mypk, destpub, prevdepth - numpayments, payment, secret))); + } else + { + fprintf(stderr,"error adding CC inputs\n"); + return(""); } } + fprintf(stderr,"error adding normal inputs\n"); return(""); } @@ -472,9 +490,8 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) { - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('S',opentxid,mypk,mypk,0,0,zeroid))); } return(""); @@ -488,9 +505,8 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) { - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(CTxOut(amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,mypk,0,0,closetxid))); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c105b4872..3aa736a16 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5157,7 +5157,7 @@ UniValue channelspayment(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,prevtxid; int32_t n; int64_t amount; cp = CCinit(&C,EVAL_CHANNELS); - if ( fHelp || params.size() != 4 ) + if ( fHelp || params.size() != 3 ) throw runtime_error("channelspayment opentxid prevtxid amount\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"); @@ -5180,7 +5180,7 @@ UniValue channelsclose(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid; cp = CCinit(&C,EVAL_CHANNELS); - if ( fHelp || params.size() != 2 ) + if ( fHelp || params.size() != 1 ) throw runtime_error("channelsclose opentxid\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"); From f2cf63f98b238ca8c20d66c019ea608bdb9c02a1 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sat, 15 Sep 2018 11:42:21 +0200 Subject: [PATCH 04/25] fix --- src/wallet/rpcwallet.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3aa736a16..a126c780e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5165,8 +5165,7 @@ UniValue channelspayment(const UniValue& params, bool fHelp) LOCK2(cs_main, pwalletMain->cs_wallet); opentxid = Parseuint256((char *)params[0].get_str().c_str()); prevtxid = Parseuint256((char *)params[1].get_str().c_str()); - n = atoi((char *)params[2].get_str().c_str()); - amount = atoi((char *)params[3].get_str().c_str()); + amount = atoi((char *)params[2].get_str().c_str()); hex = ChannelPayment(0,opentxid,prevtxid,amount); if ( hex.size() > 0 ) { From 93346f25d9341f83af6e41c86a786d363b5b0d9e Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sun, 16 Sep 2018 22:44:08 +0200 Subject: [PATCH 05/25] - Fixing payment, open, validate .... --- src/cc/CCchannels.h | 2 +- src/cc/CCinclude.h | 1 + src/cc/CCtx.cpp | 6 +- src/cc/channels.cpp | 409 ++++++++++++++++++--------------------- src/wallet/rpcwallet.cpp | 9 +- 5 files changed, 200 insertions(+), 227 deletions(-) diff --git a/src/cc/CCchannels.h b/src/cc/CCchannels.h index ba31883a2..6988b5913 100644 --- a/src/cc/CCchannels.h +++ b/src/cc/CCchannels.h @@ -22,7 +22,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment); -std::string ChannelPayment(uint64_t txfee,uint256 opentxid,uint256 prevtxid,int64_t amount); +std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount); std::string ChannelClose(uint64_t txfee,uint256 opentxid); std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 7ac0bfb98..2c3c6f5e6 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -125,6 +125,7 @@ uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv); CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk); CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2); CC *MakeCCcond1(uint8_t evalcode,CPubKey pk); +CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2); 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); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index a9d3f68e7..f1ee0b309 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -119,12 +119,14 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran cond = othercond; //fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable); } - else if ( strcmp(destaddr,cp->unspendableaddr2) == 0 ) + else if ( strcmp(destaddr,cp->unspendableaddr2) == 0) { //fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2); privkey = cp->unspendablepriv2; - if ( othercond2 == 0 ) + if ( othercond2 == 0 && cp->evalcode != EVAL_CHANNELS) othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2); + else if ( othercond2 == 0 && cp->evalcode == EVAL_CHANNELS) + othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3); cond = othercond2; } else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 ) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 744c223d1..21249a7e9 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -62,55 +62,19 @@ Possible third iteration: // start of consensus code -int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) +int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub, CPubKey destpub,int32_t v) { - char destaddr[64]; + char destaddr[64],channeladdr[64]; + + GetCCaddress1of2(cp,channeladdr,srcpub,destpub); if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) + if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,channeladdr) == 0 ) return(tx.vout[v].nValue); } return(0); } -bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) -{ - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - //fprintf(stderr,"vini.%d check mempool\n",i); - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant Channels from mempool"); - if ( (assetoshis= IsChannelsvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - inputs += assetoshis; - } - } - } - for (i=0; iInvalid("mismatched inputs != outputs + txfee"); - } - else return(true); -} - CScript EncodeChannelsOpRet(uint8_t funcid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) { CScript opret; uint8_t evalcode = EVAL_CHANNELS; @@ -119,40 +83,6 @@ CScript EncodeChannelsOpRet(uint8_t funcid,uint256 opentxid,CPubKey srcpub,CPubK } uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) -{ - std::vector vopret; uint8_t *script,e,f,funcid; - GetOpReturnData(scriptPubKey, vopret); - if ( vopret.size() > 2 ) - { - script = (uint8_t *)vopret.data(); - if ( script[0] == EVAL_CHANNELS ) - { - funcid = script[1]; - switch ( funcid ) - { - case 'O': - return(funcid); - break; - default: - if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> opentxid; ss >> srcpub; ss >> destpub; ss >> numpayments; ss >> payment; ss >> hashchain) != 0 ) - { - return(f); - } - break; - } - } else fprintf(stderr,"script[0] %02x != EVAL_CHANNELS\n",script[0]); - } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size()); - return(0); -} - -CScript EncodeChannelsPaymentOpRet(uint8_t funcid,uint256 opentxid,uint256 prevtxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) -{ - CScript opret; uint8_t evalcode = EVAL_CHANNELS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << opentxid << prevtxid << srcpub << destpub << numpayments << payment << hashchain); - return(opret); -} - -uint8_t DecodeChannelsPaymentOpRet(const CScript &scriptPubKey,uint256 &opentxid,uint256 &prevtxid,CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) { std::vector vopret; uint8_t *script,e,f,funcid; GetOpReturnData(scriptPubKey, vopret); @@ -170,12 +100,61 @@ uint8_t DecodeChannelsPaymentOpRet(const CScript &scriptPubKey,uint256 &opentxid return(0); } +bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) +{ + static uint256 zerohash; + uint256 txid,param3; + CPubKey srcpub,destpub; + int32_t param1; int64_t param2; uint8_t funcid; + CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; + numvins = tx.vin.size(); + numvouts = tx.vout.size(); + + if ((numvouts=tx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)) !=0) + { + for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) + { + //fprintf(stderr,"vini.%d check mempool\n",i); + if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("cant find vinTx"); + else + { + //fprintf(stderr,"vini.%d check hash and vout\n",i); + if ( hashBlock == zerohash ) + return eval->Invalid("cant Channels from mempool"); + if ( (assetoshis= IsChannelsvout(cp,vinTx,srcpub,destpub,tx.vin[i].prevout.n)) != 0 ) + inputs += assetoshis; + } + } + } + } + else + { + return eval->Invalid("invalid op_return data"); + } + for (i=0; iInvalid("mismatched inputs != outputs + txfee"); + } + else return(true); +} + bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,param1,depth; bool retval; - uint256 txid,hashblock,param3,opentxid,prevtxid,entropy,hentropy,secret,gensecret,genhashchain; + int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,param1; bool retval; + uint256 txid,hashblock,param3,opentxid,tmp_txid,entropy,hentropy,gensecret,genhashchain,hashchain; uint8_t funcid,hash[32],hashdest[32]; - int64_t param2,numpayments; + int64_t param2,payment; CPubKey srcpub, destpub; std::vector > txids; CTransaction channelOpenTx; @@ -183,17 +162,11 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & numvins = tx.vin.size(); numvouts = tx.vout.size(); preventCCvins = preventCCvouts = -1; + fprintf(stderr,"validateCC\n"); if ( numvouts < 1 ) return eval->Invalid("no vouts"); else { - for (i=0; iInvalid("illegal normal vini"); - } - } //fprintf(stderr,"check amounts\n"); if ( ChannelsExactAmounts(cp,eval,tx,1,10000) == false ) { @@ -214,7 +187,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.0: CC vout for channel funding on CC1of2 pubkey //vout.1: CC vout marker to senders pubKey //vout.2: CC vout marker to receiver pubkey - //vout.3: opreturn - 'O' zerotxid senderspubkey receiverspubkey totalnumberofpayments paymentamount hashchain + //vout.n-2: normal change + //vout.n-1: opreturn - 'O' zerotxid senderspubkey receiverspubkey totalnumberofpayments paymentamount hashchain return eval->Invalid("unexpected ChannelsValidate for channelopen"); break; case 'P': @@ -222,45 +196,48 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vin.1: CC input from channel funding //vout.0: normal output of payment amount to receiver pubkey //vout.1: CC vout change to CC1of2 pubkey - //vout.n-2: CC vout marker to payment issuer + //vout.2: CC vout marker to payment issuer + //vout.n-2: normal change //vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelPayment"); else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) return eval->Invalid("vin.1 is CC for channelPayment"); - else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 ) - return eval->Invalid("vout.0 is normal for channelPayment"); - else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.1 is CC for channelPayment"); - else if ( tx.vout.size() == 4 && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.2 is CC for channelPayment"); - else if (DecodeChannelsPaymentOpRet(tx.vout[numvouts-1].scriptPubKey, opentxid, prevtxid, srcpub, destpub, depth, numpayments, secret) != 'P') - return eval->Invalid("invalid OP_RETURN data"); - else if ( tx.vout[0].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG) - return eval->Invalid("payment funds do not go to receiver"); - else if ( param2 > CHANNELS_MAXPAYMENTS) + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.0 is CC for channelPayment"); + else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) + return eval->Invalid("vout.1 is normal for channelPayment"); +// else if ( tx.vout.size() == 4 && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) +// return eval->Invalid("vout.2 is CC for channelPayment"); + else if ( tx.vout[1].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG) + return eval->Invalid("payment funds do not go to receiver -"); + else if ( param1 > CHANNELS_MAXPAYMENTS) return eval->Invalid("too many payment increments"); else { if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) { - if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, opentxid, srcpub, destpub, param1, param2, param3)) != 0 && funcid!='O') + if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O') return eval->Invalid("invalid channelopen OP_RETURN data"); hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < param1; i++) + for (i = 0; i < numpayments; i++) { vcalc_sha256(0, hashdest, hash, 32); memcpy(hash, hashdest, 32); - if (i==depth) endiancpy((uint8_t * ) & gensecret, hashdest, 32); + if (i==param1-1) + { + endiancpy((uint8_t*)&gensecret,hashdest,32); + } } - endiancpy((uint8_t * ) & genhashchain, hashdest, 32); + endiancpy((uint8_t*)&genhashchain,hashdest,32); - if (secret!=gensecret) + fprintf(stderr,"gensecret=%s secret=%s genhashchain=%s hashchain=%s\n",gensecret.ToString().c_str(),param3.ToString().c_str(),genhashchain.ToString().c_str(),hashchain.ToString().c_str()); + if (param3!=gensecret) return eval->Invalid("invalid secret for payment"); - else if (param3!=genhashchain) + else if (hashchain!=genhashchain) return eval->Invalid("invalid secret for payment, does not reach final hashchain"); - else if (tx.vout[0].nValue != numpayments*param2) + else if (tx.vout[0].nValue != param1*payment) return eval->Invalid("vout amount does not match numberofpayments*payment"); } } @@ -291,31 +268,58 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & // helper functions for rpc calls in rpcwallet.cpp -int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, uint256 prevtxid) +int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, CTransaction openTx, uint256 &prevtxid) { - char coinaddr[64]; int64_t param2,totalinputs = 0; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t funcid,param1,numvouts,vout; + char coinaddr[64]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t funcid,param1; std::vector > unspentOutputs; CPubKey srcpub,destpub; + uint8_t myprivkey[32]; + + //fprintf(stderr,"numvouts=%d decode=%c\n",numvouts=openTx.vout.size(),DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)); + + if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)=='O') + { + GetCCaddress1of2(cp,coinaddr,srcpub,destpub); + SetCCunspents(unspentOutputs,coinaddr); + Myprivkey(myprivkey); + CCaddr2set(cp,EVAL_CHANNELS,srcpub,myprivkey,coinaddr); + CCaddr3set(cp,EVAL_CHANNELS,destpub,myprivkey,coinaddr); + } + else + { + fprintf(stderr,"invalid open tx id\n"); + return 0; + } - GetCCaddress1of2(cp,coinaddr,srcpub,destpub); - SetCCunspents(unspentOutputs,coinaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0) + fprintf(stderr,"txhash: %d\n",it->first.txhash); + if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) != 0 && prevtxid==tmp_txid) - if ( (totalinputs=IsChannelsvout(cp,tx,vout)) > 0) - { - txid = it->first.txhash; - vout = 0; - break; - } + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0))>0) + { + txid = it->first.txhash; + break; + } } } - if (myIsutxo_spentinmempool(txid,vout) != 0) + +// fprintf(stderr,"prevtxid=%s , GetTX=%d\n",prevtxid.ToString().c_str(),GetTransaction(prevtxid,tx,hashBlock,false)); +// if (GetTransaction(prevtxid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0) +// { +// fprintf(stderr,"prevtxid=%s decode=%c total=%d\n",prevtxid.ToString().c_str(),DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3),IsChannelsvout(cp,tx,srcpub,destpub,0)); +// if ((funcid=DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)) != 0 && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0)) > 0) +// { +// //if (funcid='P') DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,tmp_txid,srcpub,destpub,param1,param2,param3) +// txid=prevtxid; +// fprintf(stderr,"found utxo, txid=%d, funds=%d\n",txid,totalinputs); +// } +// } + if (myIsutxo_spentinmempool(txid,0) != 0) { + fprintf(stderr,"spent in mempool\n"); txid=zeroid; - int32_t mindepth=1000; + int32_t mindepth=CHANNELS_MAXPAYMENTS; BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) { const CTransaction &txmempool = e.GetTx(); @@ -325,24 +329,25 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, u funcid=='P' && param1 < mindepth) { txid=hash; - vout=0; - totalinputs=txmempool.vout[vout].nValue; + totalinputs=txmempool.vout[0].nValue; mindepth=param1; } } } + else fprintf(stderr,"not spent in mempool\n"); if (txid != zeroid) { - mtx.vin.push_back(CTxIn(txid,vout,CScript())); - return totalinputs; + prevtxid=txid; + mtx.vin.push_back(CTxIn(txid,0,CScript())); + return totalinputs; } else return 0; } std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment) { - CMutableTransaction mtx; uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; CPubKey mypk; struct CCcontract_info *cp,C; + CMutableTransaction mtx; uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; CPubKey mypk,channelspk; struct CCcontract_info *cp,C; if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS ) { CCerror = strprintf("invalid ChannelOpen param numpayments.%d max.%d payment.%lld\n",numpayments,CHANNELS_MAXPAYMENTS,(long long)payment); @@ -370,111 +375,77 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 return(""); } -std::string ChannelPayment(uint64_t txfee,uint256 opentxid,uint256 prevtxid,int64_t amount) +std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) { - CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,secret,hashblock,entropy,hentropy,param3; - struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments,param1; - int64_t param2,payment,change,funds; + CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,secret,hashblock,entropy,hentropy,prevtxid; + struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments; + int64_t payment,change,funds; uint8_t hash[32],hashdest[32]; CTransaction channelOpenTx,prevTx; - if (opentxid==prevtxid) - { - if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) - { - if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)) != 0) && funcid == 'O') - { - if (mypk == srcpub || mypk == destpub) - { - prevdepth=param1; - payment=param2; - } - else - { - fprintf(stderr,"this is not our channel\n"); - return(""); - } - } - else - { - fprintf(stderr,"invalid previous txid\n"); - return(""); - } - if (amount % payment != 0) - { - fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); - return (""); - } - numpayments=amount/payment; - hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); - endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < numpayments; i++) - { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); - } - endiancpy((uint8_t * ) & secret, hashdest, 32); - - } - } - else if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) - { - if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsPaymentOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, txid, srcpub, destpub, param1, param2, param3)) != 0) && funcid == 'P') - { - if (mypk == srcpub || mypk == destpub) - { - prevdepth=param1; - payment=param2; - } - else - { - fprintf(stderr,"this is not our channel\n"); - return(""); - } - } - else - { - fprintf(stderr,"invalid previous txid\n"); - return(""); - } - if (amount % payment != 0) - { - fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); - return (""); - } - numpayments=amount/payment; - if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) - { - hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); - endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < prevdepth-numpayments; i++) - { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); - } - endiancpy((uint8_t * ) & secret, hashdest, 32); - } - else - { - fprintf(stderr,"invalid channel open txid\n"); - return(""); - } - } - // verify lasttxid and origtxid match and src is me - // also verify hashchain depth and amount, set prevdepth cp = CCinit(&C,EVAL_CHANNELS); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + + if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) { - if ((funds=AddChannelsInputs(cp,mtx,prevtxid)) != 0 && (change=funds-amount)>=0) { - mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub)); - return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsPaymentOpRet('P', opentxid, prevtxid, mypk, destpub, prevdepth - numpayments, payment, secret))); - } else + fprintf(stderr, "invalid channel open txid\n"); + return (""); + } + + if (AddNormalinputs(mtx,mypk,txfee,1) > 0) + { + if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount)>=0) { - fprintf(stderr,"error adding CC inputs\n"); + fprintf(stderr,"prevtxid=%s\n",prevtxid.ToString().c_str()); + if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) + { + if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, payment, hashchain)) != 0) && (funcid == 'P' || funcid=='O')) + { + if (mypk != srcpub && mypk != destpub) + { + fprintf(stderr,"this is not our channel\n"); + return(""); + } + else if (amount % payment != 0) + { + fprintf(stderr,"invalid amount, not a magnitude of payment size - %d %d\n",amount,payment); + return (""); + } + } + else + { + fprintf(stderr,"invalid previous tx\n"); + return(""); + } + + numpayments=amount/payment; + + hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < prevdepth-numpayments; i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & secret, hashdest, 32); + } + else + { + fprintf(stderr, "cannot find previous tx (channel open or payment)\n"); + return (""); + } + // verify lasttxid and origtxid match and src is me + // also verify hashchain depth and amount, set prevdepth + + mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub)); + mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); + return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', opentxid, mypk, destpub, prevdepth - numpayments, payment, secret))); + } + else + { + fprintf(stderr,"error adding CC inputs: funds=%d change=%d\n",funds,change); return(""); } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a126c780e..1e342fc84 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5157,16 +5157,15 @@ UniValue channelspayment(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,prevtxid; int32_t n; int64_t amount; cp = CCinit(&C,EVAL_CHANNELS); - if ( fHelp || params.size() != 3 ) - throw runtime_error("channelspayment opentxid prevtxid amount\n"); + if ( fHelp || params.size() != 2 ) + throw runtime_error("channelspayment opentxid amount\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); opentxid = Parseuint256((char *)params[0].get_str().c_str()); - prevtxid = Parseuint256((char *)params[1].get_str().c_str()); - amount = atoi((char *)params[2].get_str().c_str()); - hex = ChannelPayment(0,opentxid,prevtxid,amount); + amount = atoi((char *)params[1].get_str().c_str()); + hex = ChannelPayment(0,opentxid,amount); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); From acd84a38985130811fb3e69a9c3799f56d693d5b Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sun, 16 Sep 2018 22:47:47 +0200 Subject: [PATCH 06/25] fix --- src/cc/channels.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 21249a7e9..a064cefa6 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -293,7 +293,6 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - fprintf(stderr,"txhash: %d\n",it->first.txhash); if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0) { if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0))>0) @@ -410,7 +409,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) } else if (amount % payment != 0) { - fprintf(stderr,"invalid amount, not a magnitude of payment size - %d %d\n",amount,payment); + fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); return (""); } } From 352856b87faca48ebe6c38202fdbc69dfabd5b69 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sun, 16 Sep 2018 22:50:54 +0200 Subject: [PATCH 07/25] fix --- src/cc/channels.cpp | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index a064cefa6..dcbeefc2a 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -232,7 +232,6 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & } endiancpy((uint8_t*)&genhashchain,hashdest,32); - fprintf(stderr,"gensecret=%s secret=%s genhashchain=%s hashchain=%s\n",gensecret.ToString().c_str(),param3.ToString().c_str(),genhashchain.ToString().c_str(),hashchain.ToString().c_str()); if (param3!=gensecret) return eval->Invalid("invalid secret for payment"); else if (hashchain!=genhashchain) @@ -275,8 +274,6 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C CPubKey srcpub,destpub; uint8_t myprivkey[32]; - //fprintf(stderr,"numvouts=%d decode=%c\n",numvouts=openTx.vout.size(),DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)); - if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)=='O') { GetCCaddress1of2(cp,coinaddr,srcpub,destpub); @@ -302,18 +299,6 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C } } } - -// fprintf(stderr,"prevtxid=%s , GetTX=%d\n",prevtxid.ToString().c_str(),GetTransaction(prevtxid,tx,hashBlock,false)); -// if (GetTransaction(prevtxid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0) -// { -// fprintf(stderr,"prevtxid=%s decode=%c total=%d\n",prevtxid.ToString().c_str(),DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3),IsChannelsvout(cp,tx,srcpub,destpub,0)); -// if ((funcid=DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)) != 0 && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0)) > 0) -// { -// //if (funcid='P') DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,tmp_txid,srcpub,destpub,param1,param2,param3) -// txid=prevtxid; -// fprintf(stderr,"found utxo, txid=%d, funds=%d\n",txid,totalinputs); -// } -// } if (myIsutxo_spentinmempool(txid,0) != 0) { fprintf(stderr,"spent in mempool\n"); @@ -397,7 +382,6 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount)>=0) { - fprintf(stderr,"prevtxid=%s\n",prevtxid.ToString().c_str()); if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) { if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, payment, hashchain)) != 0) && (funcid == 'P' || funcid=='O')) @@ -444,7 +428,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) } else { - fprintf(stderr,"error adding CC inputs: funds=%d change=%d\n",funds,change); + fprintf(stderr,"error adding CC inputs\n"); return(""); } } From 294b79f6bd66dcfd0d1b0f1fa8a820019d5f97b5 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sun, 16 Sep 2018 22:59:00 +0200 Subject: [PATCH 08/25] fix --- src/cc/channels.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index dcbeefc2a..396be12bc 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -220,21 +220,15 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O') return eval->Invalid("invalid channelopen OP_RETURN data"); hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); - endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < numpayments; i++) + endiancpy(hash, (uint8_t * ) & param3, 32); + for (i = 0; i < numpayments-param1; i++) { vcalc_sha256(0, hashdest, hash, 32); memcpy(hash, hashdest, 32); - if (i==param1-1) - { - endiancpy((uint8_t*)&gensecret,hashdest,32); - } } endiancpy((uint8_t*)&genhashchain,hashdest,32); - if (param3!=gensecret) - return eval->Invalid("invalid secret for payment"); - else if (hashchain!=genhashchain) + if (hashchain!=genhashchain) return eval->Invalid("invalid secret for payment, does not reach final hashchain"); else if (tx.vout[0].nValue != param1*payment) return eval->Invalid("vout amount does not match numberofpayments*payment"); From e741f587f5bfcc7691732d174649dfc7fa3a2f49 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sun, 16 Sep 2018 23:13:06 +0200 Subject: [PATCH 09/25] fix deadlock --- src/cc/channels.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 396be12bc..298430b1a 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -215,7 +215,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("too many payment increments"); else { - if (GetTransaction(opentxid,channelOpenTx,hashblock,false) != 0) + if (myGetTransaction(opentxid,channelOpenTx,hashblock) != 0) { if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O') return eval->Invalid("invalid channelopen OP_RETURN data"); From dd3bcadec44aae7f316c548084d1c359680a81ad Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 20 Sep 2018 17:42:24 +0200 Subject: [PATCH 10/25] - adding markers for transactions --- src/cc/channels.cpp | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 298430b1a..de2227c1b 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -189,14 +189,15 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.2: CC vout marker to receiver pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'O' zerotxid senderspubkey receiverspubkey totalnumberofpayments paymentamount hashchain - return eval->Invalid("unexpected ChannelsValidate for channelopen"); + return eval->Invalid("unexpected ChannelsValidate for channelsopen"); break; case 'P': //vin.0: normal input //vin.1: CC input from channel funding - //vout.0: normal output of payment amount to receiver pubkey - //vout.1: CC vout change to CC1of2 pubkey - //vout.2: CC vout marker to payment issuer + //vout.0: CC vout change to CC1of2 pubkey + //vout.1: CC vout marker to senders pubKey + //vout.2: CC vout marker to receiver pubkey + //vout.3: normal output of payment amount to receiver pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) @@ -205,11 +206,13 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vin.1 is CC for channelPayment"); else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("vout.0 is CC for channelPayment"); - else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) + else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.1 is CC for channelPayment (marker to srcPub)"); + else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.1 is CC for channelPayment (marker to dstPub)"); + else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) return eval->Invalid("vout.1 is normal for channelPayment"); -// else if ( tx.vout.size() == 4 && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) -// return eval->Invalid("vout.2 is CC for channelPayment"); - else if ( tx.vout[1].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG) + else if ( tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG) return eval->Invalid("payment funds do not go to receiver -"); else if ( param1 > CHANNELS_MAXPAYMENTS) return eval->Invalid("too many payment increments"); @@ -239,13 +242,14 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vin.0: normal input for 2*txfee (normal fee and marker) //vout.0: CC vout marker to senders pubKey //vout.1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0 - return eval->Invalid("unexpected ChannelsValidate for channelclose"); + return eval->Invalid("unexpected ChannelsValidate for channelsclose"); case 'R': //vin.0: normal input //vin.1: CC input from channel funding //vout.0: normal output of CC input to senders pubkey //vout.1: CC vout marker to senders pubKey //vout.2: opreturn - 'R' opentxid senderspubkey receiverspubkey 0 0 closetxid + return eval->Invalid("unexpected ChannelsValidate for channelsrefund"); break; } } @@ -337,7 +341,7 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 txfee = 10000; mypk = pubkey2pk(Mypubkey()); funds = numpayments * payment; - if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 ) + if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 ) { hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash); endiancpy(hash,(uint8_t *)&hentropy,32); @@ -348,6 +352,8 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 } endiancpy((uint8_t *)&hashchain,hashdest,32); mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',zeroid,mypk,destpub,numpayments,payment,hashchain))); } return(""); @@ -372,7 +378,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) return (""); } - if (AddNormalinputs(mtx,mypk,txfee,1) > 0) + if (AddNormalinputs(mtx,mypk,3*txfee,1) > 0) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount)>=0) { @@ -417,6 +423,8 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) // also verify hashchain depth and amount, set prevdepth mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', opentxid, mypk, destpub, prevdepth - numpayments, payment, secret))); } @@ -463,7 +471,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) UniValue ChannelsInfo() { - UniValue result(UniValue::VOBJ); CTransaction tx; uint256 txid,hashBlock,hashchain,opentxid; struct CCcontract_info *cp,C; uint8_t funcid; char myCCaddr[64]; int32_t vout,numvouts,numpayments; int64_t nValue,payment; CPubKey srcpub,destpub,mypk; + UniValue result(UniValue::VOBJ); CTransaction tx; uint256 txid,hashBlock,hashchain,opentxid; struct CCcontract_info *cp,C; char myCCaddr[64]; int32_t vout,numvouts,numpayments; int64_t nValue,payment; CPubKey srcpub,destpub,mypk; std::vector > txids; result.push_back(Pair("result","success")); result.push_back(Pair("name","Channels")); @@ -479,10 +487,15 @@ UniValue ChannelsInfo() nValue = (int64_t)it->second; if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - if ( DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'O' || funcid == 'P' ) + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'O') { char str[67],str2[67]; - fprintf(stderr,"%s func.%c %s -> %s %.8f num.%d of %.8f\n",mypk == srcpub ? "send" : "recv",funcid,pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),(double)tx.vout[0].nValue/COIN,numpayments,(double)payment/COIN); + fprintf(stderr,"%s %s -> %s %lldsat num.%d of %.8lldsat\n","ChannelOpen",pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),tx.vout[0].nValue,numpayments,payment); + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'P') + { + char str[67],str2[67]; + fprintf(stderr,"%s (%s) %s -> %s %lldsat num.%d of %.8lldsat\n","ChannelPayment",opentxid.ToString().c_str(),pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),tx.vout[0].nValue,numpayments,payment); } } } From 0e7a9780129b95f68aef42d0a436e4d430ef12f9 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 20 Sep 2018 17:45:28 +0200 Subject: [PATCH 11/25] - fix --- src/cc/channels.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index de2227c1b..1aaf2612f 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -490,12 +490,12 @@ UniValue ChannelsInfo() if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'O') { char str[67],str2[67]; - fprintf(stderr,"%s %s -> %s %lldsat num.%d of %.8lldsat\n","ChannelOpen",pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),tx.vout[0].nValue,numpayments,payment); + fprintf(stderr,"%s %s -> %s %\" PRId64 \"sat num.%d of %.8lldsat\n","ChannelOpen",pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),tx.vout[0].nValue,numpayments,payment); } else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'P') { char str[67],str2[67]; - fprintf(stderr,"%s (%s) %s -> %s %lldsat num.%d of %.8lldsat\n","ChannelPayment",opentxid.ToString().c_str(),pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),tx.vout[0].nValue,numpayments,payment); + fprintf(stderr,"%s (%s) %s -> %s %\" PRId64 \"sat num.%d of %.8lldsat\n","ChannelPayment",opentxid.ToString().c_str(),pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),tx.vout[0].nValue,numpayments,payment); } } } From 7394c6247432e62bc1a8c11828b3ee0185be768c Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 20 Sep 2018 17:47:47 +0200 Subject: [PATCH 12/25] - fix --- src/cc/channels.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 1aaf2612f..7086f9cf9 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -490,12 +490,12 @@ UniValue ChannelsInfo() if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'O') { char str[67],str2[67]; - fprintf(stderr,"%s %s -> %s %\" PRId64 \"sat num.%d of %.8lldsat\n","ChannelOpen",pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),tx.vout[0].nValue,numpayments,payment); + fprintf(stderr,"%s %s -> %s %lldsat num.%d of %.8lldsat\n","ChannelOpen",pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),(long long)tx.vout[0].nValue,numpayments,(long long)payment); } else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'P') { char str[67],str2[67]; - fprintf(stderr,"%s (%s) %s -> %s %\" PRId64 \"sat num.%d of %.8lldsat\n","ChannelPayment",opentxid.ToString().c_str(),pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),tx.vout[0].nValue,numpayments,payment); + fprintf(stderr,"%s (%s) %s -> %s %lldsat num.%d of %.8lldsat\n","ChannelPayment",opentxid.ToString().c_str(),pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),(long long)tx.vout[0].nValue,numpayments,(long long)payment); } } } From 7340ace3b15f9bf87bb371ee639653f15ad3436f Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 20 Sep 2018 22:14:10 +0200 Subject: [PATCH 13/25] test --- src/cc/channels.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 7086f9cf9..a30b04a30 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -168,7 +168,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & else { //fprintf(stderr,"check amounts\n"); - if ( ChannelsExactAmounts(cp,eval,tx,1,10000) == false ) + if ( 0) //ChannelsExactAmounts(cp,eval,tx,1,10000) == false ) { fprintf(stderr,"Channelsget invalid amount\n"); return false; @@ -274,15 +274,13 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)=='O') { + GetCCaddress1of2(cp,coinaddr,srcpub,destpub); SetCCunspents(unspentOutputs,coinaddr); - Myprivkey(myprivkey); - CCaddr2set(cp,EVAL_CHANNELS,srcpub,myprivkey,coinaddr); - CCaddr3set(cp,EVAL_CHANNELS,destpub,myprivkey,coinaddr); } else { - fprintf(stderr,"invalid open tx id\n"); + fprintf(stderr,"invalid open txid\n"); return 0; } @@ -317,11 +315,13 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C } } } - else fprintf(stderr,"not spent in mempool\n"); if (txid != zeroid) { prevtxid=txid; mtx.vin.push_back(CTxIn(txid,0,CScript())); + Myprivkey(myprivkey); + CCaddr2set(cp,EVAL_CHANNELS,srcpub,myprivkey,coinaddr); + CCaddr3set(cp,EVAL_CHANNELS,destpub,myprivkey,coinaddr); return totalinputs; } else return 0; @@ -329,7 +329,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment) { - CMutableTransaction mtx; uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; CPubKey mypk,channelspk; struct CCcontract_info *cp,C; + CMutableTransaction mtx; uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; CPubKey mypk; struct CCcontract_info *cp,C; if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS ) { CCerror = strprintf("invalid ChannelOpen param numpayments.%d max.%d payment.%lld\n",numpayments,CHANNELS_MAXPAYMENTS,(long long)payment); From 5628e37d9eea1efe3f480e35b4f705a8571d7b6f Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 21 Sep 2018 21:01:00 +0200 Subject: [PATCH 14/25] -fix --- src/cc/channels.cpp | 140 ++++++++++++++++++++++++++++++--------- src/wallet/rpcwallet.cpp | 2 +- 2 files changed, 109 insertions(+), 33 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index a30b04a30..62b3612d4 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -233,7 +233,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if (hashchain!=genhashchain) return eval->Invalid("invalid secret for payment, does not reach final hashchain"); - else if (tx.vout[0].nValue != param1*payment) + else if (tx.vout[0].nValue != param2*payment) return eval->Invalid("vout amount does not match numberofpayments*payment"); } } @@ -241,15 +241,16 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & case 'C': //vin.0: normal input for 2*txfee (normal fee and marker) //vout.0: CC vout marker to senders pubKey - //vout.1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0 + //vout.1: CC vout marker to receiver pubkey + //vout.2: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0 return eval->Invalid("unexpected ChannelsValidate for channelsclose"); case 'R': //vin.0: normal input //vin.1: CC input from channel funding - //vout.0: normal output of CC input to senders pubkey + //vout.0: CC vout marker to senders pubKey //vout.1: CC vout marker to senders pubKey - //vout.2: opreturn - 'R' opentxid senderspubkey receiverspubkey 0 0 closetxid - return eval->Invalid("unexpected ChannelsValidate for channelsrefund"); + //vout.2: normal output of CC input to senders pubkey + //vout.3: opreturn - 'R' opentxid senderspubkey receiverspubkey 0 0 closetxid break; } } @@ -269,12 +270,13 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { char coinaddr[64]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t funcid,param1; std::vector > unspentOutputs; - CPubKey srcpub,destpub; + CPubKey srcpub,destpub,mypk; uint8_t myprivkey[32]; + mypk = pubkey2pk(Mypubkey()); + if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)=='O') { - GetCCaddress1of2(cp,coinaddr,srcpub,destpub); SetCCunspents(unspentOutputs,coinaddr); } @@ -288,7 +290,9 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0))>0) + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && + tmp_txid==openTx.GetHash() && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0))>0) + { txid = it->first.txhash; break; @@ -306,12 +310,11 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C const uint256 &hash = tx.GetHash(); if ((numvouts=txmempool.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)) != 0 && - funcid=='P' && param1 < mindepth) + funcid=='P' && tmp_txid==openTx.GetHash() && param1 < mindepth) { txid=hash; totalinputs=txmempool.vout[0].nValue; mindepth=param1; - } } } @@ -371,13 +374,11 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) { fprintf(stderr, "invalid channel open txid\n"); return (""); } - if (AddNormalinputs(mtx,mypk,3*txfee,1) > 0) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount)>=0) @@ -402,9 +403,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) fprintf(stderr,"invalid previous tx\n"); return(""); } - numpayments=amount/payment; - hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); endiancpy(hash, (uint8_t * ) & hentropy, 32); for (i = 0; i < prevdepth-numpayments; i++) @@ -421,12 +420,11 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) } // verify lasttxid and origtxid match and src is me // also verify hashchain depth and amount, set prevdepth - mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); - return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', opentxid, mypk, destpub, prevdepth - numpayments, payment, secret))); + return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', opentxid, mypk, destpub, prevdepth-numpayments, numpayments, secret))); } else { @@ -440,41 +438,103 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) std::string ChannelClose(uint64_t txfee,uint256 opentxid) { - CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; + CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; struct CCcontract_info *cp,C; + CTransaction channelOpenTx; + uint256 hashblock,tmp_txid,param3; + int32_t numvouts,param1; + int64_t param2,funds; + // verify this is one of our outbound channels cp = CCinit(&C,EVAL_CHANNELS); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) { - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('S',opentxid,mypk,mypk,0,0,zeroid))); + fprintf(stderr, "invalid channel open tx\n"); + return (""); + } + if ((numvouts=channelOpenTx.vout.size()) < 1 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!='O') + { + fprintf(stderr, "invalid channel open tx\n"); + return (""); + } + if ( AddNormalinputs(mtx,mypk,3*txfee,1) > 0 ) + { + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,0,0,zeroid))); } return(""); } std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) { - CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t amount; + CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t funds,change,payment,param2; + int32_t i,numpayments,numvouts,param1; + uint256 hashchain,hashblock,txid,prevtxid,param3,entropy,hentropy,secret; + CTransaction channelOpenTx,prevTx; + CPubKey srcpub,destpub; + uint8_t funcid,hash[32],hashdest[32];; + // verify stoptxid and origtxid match and are mine cp = CCinit(&C,EVAL_CHANNELS); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) + if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) { - mtx.vout.push_back(CTxOut(amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,mypk,0,0,closetxid))); + fprintf(stderr, "invalid channel open tx\n"); + return (""); + } + if ((numvouts=channelOpenTx.vout.size()) < 1 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,numpayments,payment,hashchain)!='O') + { + fprintf(stderr, "invalid channel open tx\n"); + return (""); + } + if ( AddNormalinputs(mtx,mypk,3*txfee,1) > 0 ) + { + if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0) + { + if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) + { + if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)) != 0) && (funcid == 'P' || funcid=='O')) + { + if (mypk != srcpub) + { + fprintf(stderr,"this channel is not in our ownership\n"); + return(""); + } + } + hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < param1; i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & secret, hashdest, 32); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); + mtx.vout.push_back(CTxOut(funds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,destpub,numpayments-param1,payment,secret))); + } + } + else + { + fprintf(stderr,"error adding CC inputs\n"); + return(""); + } } return(""); } UniValue ChannelsInfo() { - UniValue result(UniValue::VOBJ); CTransaction tx; uint256 txid,hashBlock,hashchain,opentxid; struct CCcontract_info *cp,C; char myCCaddr[64]; int32_t vout,numvouts,numpayments; int64_t nValue,payment; CPubKey srcpub,destpub,mypk; + UniValue result(UniValue::VOBJ); CTransaction tx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain; struct CCcontract_info *cp,C; char myCCaddr[64],addr[64],str1[100],str2[100]; int32_t vout,numvouts,param1,numpayments; int64_t nValue,param2,payment; CPubKey srcpub,destpub,mypk; std::vector > txids; result.push_back(Pair("result","success")); - result.push_back(Pair("name","Channels")); + result.push_back(Pair("name","Channel Info")); cp = CCinit(&C,EVAL_CHANNELS); mypk = pubkey2pk(Mypubkey()); GetCCaddress(cp,myCCaddr,mypk); @@ -485,17 +545,33 @@ UniValue ChannelsInfo() txid = it->first.txhash; vout = (int32_t)it->first.index; nValue = (int64_t)it->second; - if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) + if ( (vout==0 || vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'O') + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O') { - char str[67],str2[67]; - fprintf(stderr,"%s %s -> %s %lldsat num.%d of %.8lldsat\n","ChannelOpen",pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),(long long)tx.vout[0].nValue,numpayments,(long long)payment); + GetCCaddress1of2(cp,addr,srcpub,destpub); + sprintf(str1,"Channel - %s",addr); + result.push_back(Pair(str1,"Open")); } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,numpayments,payment,hashchain) == 'P') + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'P') { - char str[67],str2[67]; - fprintf(stderr,"%s (%s) %s -> %s %lldsat num.%d of %.8lldsat\n","ChannelPayment",opentxid.ToString().c_str(),pubkey33_str(str,(uint8_t *)&srcpub),pubkey33_str(str2,(uint8_t *)&destpub),(long long)tx.vout[0].nValue,numpayments,(long long)payment); + if (GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O') + sprintf(str1,"Channel - %s",addr); + sprintf(str2,"Payment -> %s %lld payments of %lld",destpub.GetHash().ToString().c_str(),param2,payment); + result.push_back(Pair(str1,str2)); + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C') + { + GetCCaddress1of2(cp,addr,srcpub,destpub); + sprintf(str1,"Channel - %s",addr); + result.push_back(Pair(str1,"Close")); + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C') + { + GetCCaddress1of2(cp,addr,srcpub,destpub); + sprintf(str1,"Channel - %s",addr); + sprintf(str2,"Refund -> %s %lld payments of %lld",srcpub.GetHash().ToString().c_str(),param1,param2); + result.push_back(Pair(str1,"Refund")); } } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1e342fc84..83a65f0f0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5184,7 +5184,7 @@ UniValue channelsclose(const UniValue& params, bool fHelp) 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); - opentxid = Parseuint256((char *)params[1].get_str().c_str()); + opentxid = Parseuint256((char *)params[0].get_str().c_str()); hex = ChannelClose(0,opentxid); if ( hex.size() > 0 ) { From e5e3d065f3e0b0b370249b8539cb128feb28f79f Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 21 Sep 2018 21:03:49 +0200 Subject: [PATCH 15/25] -fix --- src/cc/channels.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 62b3612d4..ff94b77e0 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -557,7 +557,7 @@ UniValue ChannelsInfo() { if (GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O') sprintf(str1,"Channel - %s",addr); - sprintf(str2,"Payment -> %s %lld payments of %lld",destpub.GetHash().ToString().c_str(),param2,payment); + sprintf(str2,"Payment -> %s %lld payments of %lld",destpub.GetHash().ToString().c_str(),(long long)param2,(long long)payment); result.push_back(Pair(str1,str2)); } else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C') @@ -570,7 +570,7 @@ UniValue ChannelsInfo() { GetCCaddress1of2(cp,addr,srcpub,destpub); sprintf(str1,"Channel - %s",addr); - sprintf(str2,"Refund -> %s %lld payments of %lld",srcpub.GetHash().ToString().c_str(),param1,param2); + sprintf(str2,"Refund -> %s %lld payments of %lld",srcpub.GetHash().ToString().c_str(),(long long)param1,(long long)param2); result.push_back(Pair(str1,"Refund")); } } From 21eb7fa7d283e6e4c996d2d9c7aad9eaf2479d91 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 21 Sep 2018 21:32:15 +0200 Subject: [PATCH 16/25] -fix --- src/cc/channels.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index ff94b77e0..550a4cbd3 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -233,8 +233,11 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if (hashchain!=genhashchain) return eval->Invalid("invalid secret for payment, does not reach final hashchain"); - else if (tx.vout[0].nValue != param2*payment) + else if (tx.vout[3].nValue != param2*payment) + { + fprintf(stderr,"%lld=%lld*%lld\n",(long long)tx.vout[3].nValue,(long long)param2,(long long)payment); return eval->Invalid("vout amount does not match numberofpayments*payment"); + } } } break; @@ -290,8 +293,8 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && - tmp_txid==openTx.GetHash() && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0))>0) + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && fprintf(stderr,"%s - %s\n",tmp_txid.ToString().c_str(),openTx.GetHash().ToString().c_str()) && + (tmp_txid==openTx.GetHash() || tx.GetHash()==openTx.GetHash()) && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0))>0) { txid = it->first.txhash; @@ -308,9 +311,10 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { const CTransaction &txmempool = e.GetTx(); const uint256 &hash = tx.GetHash(); + if ((numvouts=txmempool.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)) != 0 && - funcid=='P' && tmp_txid==openTx.GetHash() && param1 < mindepth) + funcid=='P' && (tmp_txid==openTx.GetHash() || txmempool.GetHash()==openTx.GetHash()) && param1 < mindepth) { txid=hash; totalinputs=txmempool.vout[0].nValue; From fea4c38edddae6e00d85e909a222429baffb1520 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sat, 22 Sep 2018 11:53:31 +0200 Subject: [PATCH 17/25] -fix --- src/cc/channels.cpp | 70 ++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 550a4cbd3..16460e8c0 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -223,21 +223,17 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O') return eval->Invalid("invalid channelopen OP_RETURN data"); hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); - endiancpy(hash, (uint8_t * ) & param3, 32); + endiancpy(hash, (uint8_t * ) & hentropy, 32); for (i = 0; i < numpayments-param1; i++) { vcalc_sha256(0, hashdest, hash, 32); memcpy(hash, hashdest, 32); } endiancpy((uint8_t*)&genhashchain,hashdest,32); - if (hashchain!=genhashchain) - return eval->Invalid("invalid secret for payment, does not reach final hashchain"); + return eval->Invalid("invalid secret for payment, does not reach final hashchain!"); else if (tx.vout[3].nValue != param2*payment) - { - fprintf(stderr,"%lld=%lld*%lld\n",(long long)tx.vout[3].nValue,(long long)param2,(long long)payment); - return eval->Invalid("vout amount does not match numberofpayments*payment"); - } + return eval->Invalid("vout amount does not match number_of_payments*payment"); } } break; @@ -368,9 +364,9 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) { - CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,secret,hashblock,entropy,hentropy,prevtxid; + CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,secret,hashblock,entropy,hentropy,prevtxid,param3; struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments; - int64_t payment,change,funds; + int64_t payment,change,funds,param2; uint8_t hash[32],hashdest[32]; CTransaction channelOpenTx,prevTx; @@ -387,43 +383,46 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount)>=0) { - if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) + if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, numpayments, payment, hashchain)=='O') { - if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, payment, hashchain)) != 0) && (funcid == 'P' || funcid=='O')) + + if (mypk != srcpub && mypk != destpub) { - if (mypk != srcpub && mypk != destpub) + fprintf(stderr,"this is not our channel\n"); + return(""); + } + else if (amount % payment != 0) + { + fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); + return (""); + } + + numpayments=amount/payment; + + if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0 && (numvouts=prevTx.vout.size()) > 0 && + ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) && + (funcid == 'P' || funcid=='O')) + { + hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < prevdepth-numpayments; i++) { - fprintf(stderr,"this is not our channel\n"); - return(""); - } - else if (amount % payment != 0) - { - fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); - return (""); + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); } + endiancpy((uint8_t * ) & secret, hashdest, 32); } else { fprintf(stderr,"invalid previous tx\n"); return(""); } - numpayments=amount/payment; - hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); - endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < prevdepth-numpayments; i++) - { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); - } - endiancpy((uint8_t * ) & secret, hashdest, 32); } else { - fprintf(stderr, "cannot find previous tx (channel open or payment)\n"); + fprintf(stderr, "invalid channel open tx\n"); return (""); } - // verify lasttxid and origtxid match and src is me - // also verify hashchain depth and amount, set prevdepth mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, mypk, destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); @@ -455,7 +454,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) mypk = pubkey2pk(Mypubkey()); if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) { - fprintf(stderr, "invalid channel open tx\n"); + fprintf(stderr, "invalid channel open txid\n"); return (""); } if ((numvouts=channelOpenTx.vout.size()) < 1 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!='O') @@ -463,6 +462,11 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) fprintf(stderr, "invalid channel open tx\n"); return (""); } + if (mypk != srcpub) + { + fprintf(stderr,"this channel is not in our ownership\n"); + return(""); + } if ( AddNormalinputs(mtx,mypk,3*txfee,1) > 0 ) { mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); @@ -488,7 +492,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) mypk = pubkey2pk(Mypubkey()); if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) { - fprintf(stderr, "invalid channel open tx\n"); + fprintf(stderr, "invalid channel open txid\n"); return (""); } if ((numvouts=channelOpenTx.vout.size()) < 1 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,numpayments,payment,hashchain)!='O') From b32b682ae969366dade85d7aaa919aae85ffa001 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Sat, 22 Sep 2018 12:18:41 +0200 Subject: [PATCH 18/25] -fix --- src/cc/channels.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 16460e8c0..7bc1d8d5a 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -152,7 +152,7 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,param1; bool retval; - uint256 txid,hashblock,param3,opentxid,tmp_txid,entropy,hentropy,gensecret,genhashchain,hashchain; + uint256 txid,hashblock,param3,opentxid,tmp_txid,genhashchain,hashchain; uint8_t funcid,hash[32],hashdest[32]; int64_t param2,payment; CPubKey srcpub, destpub; @@ -222,8 +222,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O') return eval->Invalid("invalid channelopen OP_RETURN data"); - hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); - endiancpy(hash, (uint8_t * ) & hentropy, 32); + endiancpy(hash, (uint8_t * ) & param3, 32); for (i = 0; i < numpayments-param1; i++) { vcalc_sha256(0, hashdest, hash, 32); From d68350535dc3ed7b9abc1d803ac3070c600e8977 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 27 Sep 2018 10:46:45 +0200 Subject: [PATCH 19/25] - updated validation - added secret parameter to payment - reused marker for sender to validate creator of tx --- src/cc/CCchannels.h | 2 +- src/cc/channels.cpp | 217 +++++++++++++++++++++++++++------------ src/wallet/rpcwallet.cpp | 12 ++- 3 files changed, 163 insertions(+), 68 deletions(-) diff --git a/src/cc/CCchannels.h b/src/cc/CCchannels.h index 6988b5913..4754ae44e 100644 --- a/src/cc/CCchannels.h +++ b/src/cc/CCchannels.h @@ -22,7 +22,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment); -std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount); +std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret); std::string ChannelClose(uint64_t txfee,uint256 opentxid); std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid); diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 7bc1d8d5a..4d5d8934a 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -152,12 +152,12 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,param1; bool retval; - uint256 txid,hashblock,param3,opentxid,tmp_txid,genhashchain,hashchain; + uint256 txid,hashblock,param3,opentxid,closetxid,tmp_txid,genhashchain,hashchain; uint8_t funcid,hash[32],hashdest[32]; int64_t param2,payment; CPubKey srcpub, destpub; std::vector > txids; - CTransaction channelOpenTx; + CTransaction channelOpenTx,channelCloseTx; numvins = tx.vin.size(); numvouts = tx.vout.size(); @@ -189,11 +189,10 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.2: CC vout marker to receiver pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'O' zerotxid senderspubkey receiverspubkey totalnumberofpayments paymentamount hashchain - return eval->Invalid("unexpected ChannelsValidate for channelsopen"); - break; + return eval->Invalid("unexpected ChannelsValidate for channelsopen!"); case 'P': //vin.0: normal input - //vin.1: CC input from channel funding + //vin.1: CC input from channel funding and src marker //vout.0: CC vout change to CC1of2 pubkey //vout.1: CC vout marker to senders pubKey //vout.2: CC vout marker to receiver pubkey @@ -201,21 +200,21 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.n-2: normal change //vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) - return eval->Invalid("vin.0 is normal for channelPayment"); + return eval->Invalid("vin.0 is normal for channelPayment!"); else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for channelPayment"); + return eval->Invalid("vin.1 is CC for channelPayment!"); else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.0 is CC for channelPayment"); + return eval->Invalid("vout.0 is CC for channelPayment!"); else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.1 is CC for channelPayment (marker to srcPub)"); + return eval->Invalid("vout.1 is CC for channelPayment (marker to srcPub)!"); else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("vout.1 is CC for channelPayment (marker to dstPub)"); + return eval->Invalid("vout.1 is CC for channelPayment (marker to dstPub)!"); else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) - return eval->Invalid("vout.1 is normal for channelPayment"); + return eval->Invalid("vout.1 is normal for channelPayment!"); else if ( tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG) - return eval->Invalid("payment funds do not go to receiver -"); + return eval->Invalid("payment funds do not go to receiver!"); else if ( param1 > CHANNELS_MAXPAYMENTS) - return eval->Invalid("too many payment increments"); + return eval->Invalid("too many payment increments!"); else { if (myGetTransaction(opentxid,channelOpenTx,hashblock) != 0) @@ -232,23 +231,71 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if (hashchain!=genhashchain) return eval->Invalid("invalid secret for payment, does not reach final hashchain!"); else if (tx.vout[3].nValue != param2*payment) - return eval->Invalid("vout amount does not match number_of_payments*payment"); + return eval->Invalid("invalid amount, does not match number_of_payments*payment!"); } } break; case 'C': - //vin.0: normal input for 2*txfee (normal fee and marker) - //vout.0: CC vout marker to senders pubKey - //vout.1: CC vout marker to receiver pubkey - //vout.2: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0 - return eval->Invalid("unexpected ChannelsValidate for channelsclose"); + //vin.0: normal input + //vin.1: CC input from channel funding and src marker + //vout.0: CC vout for channel funding + //vout.1: CC vout marker to senders pubKey + //vout.2: CC vout marker to receiver pubkey + //vout.n-2: normal change + //vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0 + if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for channelClose!"); + else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) + return eval->Invalid("vin.1 is CC for channelClose!"); + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.0 is CC for channelClose!"); + else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.1 is CC for channelClose (marker to srcPub)!"); + else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.2 is CC for channelClose (marker to dstPub)!"); + else if ( param1 > CHANNELS_MAXPAYMENTS) + return eval->Invalid("too many payment increments!"); + else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0) + return eval->Invalid("invalid open txid!"); + else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) == 'O') + return eval->Invalid("invalid channelopen OP_RETURN data"); + else if (tx.vout[0].nValue != param2*payment) + return eval->Invalid("vout amount does not match number_of_payments*payment!"); + break; case 'R': //vin.0: normal input //vin.1: CC input from channel funding //vout.0: CC vout marker to senders pubKey - //vout.1: CC vout marker to senders pubKey + //vout.1: CC vout marker to receiver pubKey //vout.2: normal output of CC input to senders pubkey - //vout.3: opreturn - 'R' opentxid senderspubkey receiverspubkey 0 0 closetxid + //vout.n-2: normal change + //vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpaymewnts payment closetxid + if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + return eval->Invalid("vin.0 is normal for channelRefund!"); + else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) + return eval->Invalid("vin.1 is CC for channelRefund!"); + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.0 is CC for channelRefund (marker to srcPub)!"); + else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.1 is CC for channelRefund (marker to dstPub)!"); + else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) + return eval->Invalid("vout.2 is normal for channelRefund!"); + else if ( tx.vout[2].scriptPubKey!=CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG) + return eval->Invalid("payment funds do not go to sender!"); + else if ( param1 > CHANNELS_MAXPAYMENTS) + return eval->Invalid("too many payment increments!"); + else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0) + return eval->Invalid("invalid open txid!"); + else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) == 'O') + return eval->Invalid("invalid channelopen OP_RETURN data"); + else if (tx.vout[2].nValue != param2*payment) + return eval->Invalid("vout amount does not match number_of_payments*payment!"); + else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0) + return eval->Invalid("invalid close txid!"); + else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, param1, param2, param3) == 'C') + return eval->Invalid("invalid channelclose OP_RETURN data"); + else if (tmp_txid!=opentxid) + return eval->Invalid("invalid close tx, opentxid do not match on close and refund!"); break; } } @@ -268,11 +315,9 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { char coinaddr[64]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t funcid,param1; std::vector > unspentOutputs; - CPubKey srcpub,destpub,mypk; + CPubKey srcpub,destpub; uint8_t myprivkey[32]; - mypk = pubkey2pk(Mypubkey()); - if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)=='O') { GetCCaddress1of2(cp,coinaddr,srcpub,destpub); @@ -288,9 +333,9 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && fprintf(stderr,"%s - %s\n",tmp_txid.ToString().c_str(),openTx.GetHash().ToString().c_str()) && - (tmp_txid==openTx.GetHash() || tx.GetHash()==openTx.GetHash()) && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0))>0) - + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && + (tmp_txid==openTx.GetHash() || tx.GetHash()==openTx.GetHash()) && + (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0)+IsChannelsvout(cp,tx,srcpub,destpub,1))>0) { txid = it->first.txhash; break; @@ -309,10 +354,10 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C if ((numvouts=txmempool.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)) != 0 && - funcid=='P' && (tmp_txid==openTx.GetHash() || txmempool.GetHash()==openTx.GetHash()) && param1 < mindepth) + (tmp_txid==openTx.GetHash() || txmempool.GetHash()==openTx.GetHash()) && param1 < mindepth) { txid=hash; - totalinputs=txmempool.vout[0].nValue; + totalinputs=txmempool.vout[0].nValue+txmempool.vout[1].nValue; mindepth=param1; } } @@ -361,10 +406,10 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 return(""); } -std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) +std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret) { - CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,secret,hashblock,entropy,hentropy,prevtxid,param3; - struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments; + CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,gensecret,hashblock,entropy,hentropy,prevtxid,param3; + struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments,totalnumpayments; int64_t payment,change,funds,param2; uint8_t hash[32],hashdest[32]; CTransaction channelOpenTx,prevTx; @@ -378,11 +423,11 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) fprintf(stderr, "invalid channel open txid\n"); return (""); } - if (AddNormalinputs(mtx,mypk,3*txfee,1) > 0) + if (AddNormalinputs(mtx,mypk,2*txfee,1) > 0) { - if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount)>=0) + if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount-2*txfee)>=0) { - if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, numpayments, payment, hashchain)=='O') + if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O') { if (mypk != srcpub && mypk != destpub) @@ -399,17 +444,35 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount) numpayments=amount/payment; if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0 && (numvouts=prevTx.vout.size()) > 0 && - ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) && - (funcid == 'P' || funcid=='O')) + ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) && + (funcid == 'P' || funcid=='O')) { - hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); - endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < prevdepth-numpayments; i++) + if (secret!=zeroid) { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); + hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < prevdepth-numpayments; i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & secret, hashdest, 32); + } + else + { + endiancpy(hash, (uint8_t * ) & secret, 32); + for (i = 0; i < totalnumpayments-(prevdepth-numpayments); i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & gensecret, hashdest, 32); + if (gensecret!=hashchain) + { + fprintf(stderr,"invalid secret supplied\n"); + return(""); + } } - endiancpy((uint8_t * ) & secret, hashdest, 32); } else { @@ -442,7 +505,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) { CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; struct CCcontract_info *cp,C; CTransaction channelOpenTx; - uint256 hashblock,tmp_txid,param3; + uint256 hashblock,tmp_txid,prevtxid,param3; int32_t numvouts,param1; int64_t param2,funds; @@ -456,7 +519,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) fprintf(stderr, "invalid channel open txid\n"); return (""); } - if ((numvouts=channelOpenTx.vout.size()) < 1 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!='O') + if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!='O') { fprintf(stderr, "invalid channel open tx\n"); return (""); @@ -466,21 +529,31 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) fprintf(stderr,"this channel is not in our ownership\n"); return(""); } - if ( AddNormalinputs(mtx,mypk,3*txfee,1) > 0 ) + if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) { - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); - mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,0,0,zeroid))); + if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0) + { + mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds, mypk, destpub)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,0,0,zeroid))); + } + else + { + fprintf(stderr,"error adding CC inputs\n"); + return(""); + } } + fprintf(stderr,"error adding normal inputs\n"); return(""); } std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) { - CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t funds,change,payment,param2; + CMutableTransaction mtx; CPubKey mypk; struct CCcontract_info *cp,C; int64_t funds,payment,param2; int32_t i,numpayments,numvouts,param1; uint256 hashchain,hashblock,txid,prevtxid,param3,entropy,hentropy,secret; - CTransaction channelOpenTx,prevTx; + CTransaction channelOpenTx,channelCloseTx,prevTx; CPubKey srcpub,destpub; uint8_t funcid,hash[32],hashdest[32];; @@ -489,30 +562,43 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); + if (GetTransaction(closetxid,channelCloseTx,hashblock,false) == 0) + { + fprintf(stderr, "invalid channel close txid\n"); + return (""); + } + if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,param1,param2,param3)!='C') + { + fprintf(stderr, "invalid channel close tx\n"); + return (""); + } + if (txid!=opentxid) + { + fprintf(stderr,"%s - %s\n",txid.ToString().c_str(),opentxid.ToString().c_str()); + fprintf(stderr, "open and close txid are not from same channel\n"); + return (""); + } if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) { fprintf(stderr, "invalid channel open txid\n"); return (""); } - if ((numvouts=channelOpenTx.vout.size()) < 1 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,numpayments,payment,hashchain)!='O') + if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,numpayments,payment,hashchain)!='O') { fprintf(stderr, "invalid channel open tx\n"); return (""); } - if ( AddNormalinputs(mtx,mypk,3*txfee,1) > 0 ) + if (mypk != srcpub) + { + fprintf(stderr,"this channel is not in our ownership\n"); + return(""); + } + if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0) { - if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0) + if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)) != 0) && (funcid == 'P' || funcid=='O')) { - if ((numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)) != 0) && (funcid == 'P' || funcid=='O')) - { - if (mypk != srcpub) - { - fprintf(stderr,"this channel is not in our ownership\n"); - return(""); - } - } hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); endiancpy(hash, (uint8_t * ) & hentropy, 32); for (i = 0; i < param1; i++) @@ -524,7 +610,12 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); mtx.vout.push_back(CTxOut(funds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,destpub,numpayments-param1,payment,secret))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,destpub,param1,payment,closetxid))); + } + else + { + fprintf(stderr,"previous tx is invalid\n"); + return(""); } } else diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 83a65f0f0..ff910f2c9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5155,17 +5155,21 @@ UniValue channelsopen(const UniValue& params, bool fHelp) UniValue channelspayment(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,prevtxid; int32_t n; int64_t amount; + UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,secret=zeroid; int32_t n; int64_t amount; cp = CCinit(&C,EVAL_CHANNELS); if ( fHelp || params.size() != 2 ) - throw runtime_error("channelspayment opentxid amount\n"); + throw runtime_error("channelspayment opentxid amount [secret]\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); opentxid = Parseuint256((char *)params[0].get_str().c_str()); amount = atoi((char *)params[1].get_str().c_str()); - hex = ChannelPayment(0,opentxid,amount); + if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty()) + { + secret = Parseuint256((char *)params[2].get_str().c_str()); + } + hex = ChannelPayment(0,opentxid,amount,secret); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); @@ -5190,7 +5194,7 @@ UniValue channelsclose(const UniValue& params, bool fHelp) { result.push_back(Pair("result", "success")); result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt create channelsstop transaction"); + } else ERR_RESULT("couldnt create channelsclose transaction"); return(result); } From 5e1984d0d219c65d78881f3469dbd2c80199edb7 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 27 Sep 2018 16:24:55 +0200 Subject: [PATCH 20/25] -fix --- src/cc/CCinclude.h | 3 ++- src/cc/CCtx.cpp | 2 +- src/cc/CCutils.cpp | 9 +++++++ src/cc/channels.cpp | 66 ++++++++++++++++++++++++++++++++++++--------- 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 2c3c6f5e6..8be4bce29 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -54,6 +54,7 @@ extern uint32_t ASSETCHAINS_CC; extern std::string CCerror; #define SMALLVAL 0.000000000000001 +#define MIN_NOTARIZATION_CONFIRMS 2 union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; typedef union _bits256 bits256; @@ -149,7 +150,7 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey); std::vector Mypubkey(); bool Myprivkey(uint8_t myprivkey[]); int64_t CCduration(int32_t &numblocks,uint256 txid); - +bool isCCTxNotarizedConfirmed(uint256 txid); // CCtx std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret); void SetCCunspents(std::vector > &unspentOutputs,char *coinaddr); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index f1ee0b309..4e8561b20 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -111,7 +111,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { privkey = myprivkey; cond = mycond; - //fprintf(stderr,"my CC addr.(%s)\n",myaddr); + fprintf(stderr,"my CC addr.(%s)\n",myaddr); } else if ( strcmp(destaddr,unspendable) == 0 ) { diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index e03564971..c149be03f 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -410,3 +410,12 @@ int64_t CCduration(int32_t &numblocks,uint256 txid) return(duration); } +bool isCCTxNotarizedConfirmed(uint256 txid) +{ + int32_t confirms; + + CCduration(confirms,txid); + if (confirms >= MIN_NOTARIZATION_CONFIRMS) + return (true); + return (false); +} diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 4d5d8934a..460f2b91d 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -84,7 +84,7 @@ CScript EncodeChannelsOpRet(uint8_t funcid,uint256 opentxid,CPubKey srcpub,CPubK uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) { - std::vector vopret; uint8_t *script,e,f,funcid; + std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); if ( vopret.size() > 2 ) { @@ -151,13 +151,13 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,param1; bool retval; - uint256 txid,hashblock,param3,opentxid,closetxid,tmp_txid,genhashchain,hashchain; + int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,p1,param1; bool retval; + uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain; uint8_t funcid,hash[32],hashdest[32]; - int64_t param2,payment; + int64_t p2,param2,payment; CPubKey srcpub, destpub; std::vector > txids; - CTransaction channelOpenTx,channelCloseTx; + CTransaction channelOpenTx,channelCloseTx,prevTx; numvins = tx.vin.size(); numvouts = tx.vout.size(); @@ -199,7 +199,9 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.3: normal output of payment amount to receiver pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret - if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + if (isCCTxNotarizedConfirmed(opentxid) == 0) + return eval->Invalid("channelOpen is not yet confirmed(notarised)!"); + else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelPayment!"); else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) return eval->Invalid("vin.1 is CC for channelPayment!"); @@ -220,7 +222,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if (myGetTransaction(opentxid,channelOpenTx,hashblock) != 0) { if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O') - return eval->Invalid("invalid channelopen OP_RETURN data"); + return eval->Invalid("invalid channelopen OP_RETURN data!"); endiancpy(hash, (uint8_t * ) & param3, 32); for (i = 0; i < numpayments-param1; i++) { @@ -233,6 +235,17 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & else if (tx.vout[3].nValue != param2*payment) return eval->Invalid("invalid amount, does not match number_of_payments*payment!"); } + if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) + { + if ((numvouts=prevTx.vout.size()) > 0 && (DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3)) != 0) + return eval->Invalid("invalid previous tx OP_RETURN data!"); + else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) + return eval->Invalid("invalid destination for sender marker!"); + else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey) + return eval->Invalid("invalid destination for receiver marker!"); + else if (param1!=p1-p2) + return eval->Invalid("invalid payment depth!"); + } } break; case 'C': @@ -243,7 +256,9 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.2: CC vout marker to receiver pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0 - if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + if (isCCTxNotarizedConfirmed(opentxid) == 0) + return eval->Invalid("channelOpen is not yet confirmed(notarised)!"); + else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelClose!"); else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) return eval->Invalid("vin.1 is CC for channelClose!"); @@ -258,9 +273,20 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0) return eval->Invalid("invalid open txid!"); else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) == 'O') - return eval->Invalid("invalid channelopen OP_RETURN data"); + return eval->Invalid("invalid channelopen OP_RETURN data!"); else if (tx.vout[0].nValue != param2*payment) return eval->Invalid("vout amount does not match number_of_payments*payment!"); + else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) + { + if ((numvouts=prevTx.vout.size()) > 0 && (DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3)) != 0) + return eval->Invalid("invalid previous tx OP_RETURN data!"); + else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) + return eval->Invalid("invalid destination for sender marker!"); + else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey) + return eval->Invalid("invalid destination for receiver marker!"); + else if (tx.vout[0].nValue != prevTx.vout[0].nValue) + return eval->Invalid("invalid CC amount, input!=output!"); + } break; case 'R': //vin.0: normal input @@ -270,7 +296,11 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.2: normal output of CC input to senders pubkey //vout.n-2: normal change //vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpaymewnts payment closetxid - if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + if (isCCTxNotarizedConfirmed(opentxid) == 0) + return eval->Invalid("channelOpen is not yet confirmed(notarised)!"); + else if (isCCTxNotarizedConfirmed(param3) == 0) + return eval->Invalid("channelClose is not yet confirmed(notarised)!"); + else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelRefund!"); else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) return eval->Invalid("vin.1 is CC for channelRefund!"); @@ -287,15 +317,26 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0) return eval->Invalid("invalid open txid!"); else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) == 'O') - return eval->Invalid("invalid channelopen OP_RETURN data"); + return eval->Invalid("invalid channelopen OP_RETURN data!"); else if (tx.vout[2].nValue != param2*payment) return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0) return eval->Invalid("invalid close txid!"); else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, param1, param2, param3) == 'C') - return eval->Invalid("invalid channelclose OP_RETURN data"); + return eval->Invalid("invalid channelclose OP_RETURN data!"); else if (tmp_txid!=opentxid) return eval->Invalid("invalid close tx, opentxid do not match on close and refund!"); + else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) + { + if ((numvouts=prevTx.vout.size()) > 0 && (DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3)) != 0) + return eval->Invalid("invalid previous tx OP_RETURN data!"); + else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) + return eval->Invalid("invalid destination for sender marker!"); + else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey) + return eval->Invalid("invalid destination for receiver marker!"); + else if (tx.vout[2].nValue != prevTx.vout[0].nValue) + return eval->Invalid("invalid refund amount, must transfer all funds!"); + } break; } } @@ -366,6 +407,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { prevtxid=txid; mtx.vin.push_back(CTxIn(txid,0,CScript())); + mtx.vin.push_back(CTxIn(txid,1,CScript())); Myprivkey(myprivkey); CCaddr2set(cp,EVAL_CHANNELS,srcpub,myprivkey,coinaddr); CCaddr3set(cp,EVAL_CHANNELS,destpub,myprivkey,coinaddr); From 001d7ea10188063f5372c24d95fd1b14d84266ee Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 27 Sep 2018 18:41:33 +0200 Subject: [PATCH 21/25] -fix --- src/cc/CCutils.cpp | 1 - src/cc/channels.cpp | 64 +++++++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index c149be03f..cbf574532 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -63,7 +63,6 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2) CTxOut vout; CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2); vout = CTxOut(nValue,CCPubKey(payoutCond)); - fprintf(stderr,"payoutCond: %s\n",cc_conditionToJSONString(payoutCond)); cc_free(payoutCond); return(vout); } diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 460f2b91d..2635fe494 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -156,7 +156,6 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & uint8_t funcid,hash[32],hashdest[32]; int64_t p2,param2,payment; CPubKey srcpub, destpub; - std::vector > txids; CTransaction channelOpenTx,channelCloseTx,prevTx; numvins = tx.vin.size(); @@ -192,7 +191,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("unexpected ChannelsValidate for channelsopen!"); case 'P': //vin.0: normal input - //vin.1: CC input from channel funding and src marker + //vin.1: CC input from channel funding + //vin.2: CC input from src marker //vout.0: CC vout change to CC1of2 pubkey //vout.1: CC vout marker to senders pubKey //vout.2: CC vout marker to receiver pubkey @@ -205,6 +205,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vin.0 is normal for channelPayment!"); else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) return eval->Invalid("vin.1 is CC for channelPayment!"); + else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) + return eval->Invalid("vin.1 is CC for channelPayment!"); else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("vout.0 is CC for channelPayment!"); else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) @@ -237,20 +239,21 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & } if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { - if ((numvouts=prevTx.vout.size()) > 0 && (DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3)) != 0) + if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) return eval->Invalid("invalid destination for sender marker!"); else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey) return eval->Invalid("invalid destination for receiver marker!"); - else if (param1!=p1-p2) + else if (param1+param2!=p1) return eval->Invalid("invalid payment depth!"); } } break; case 'C': //vin.0: normal input - //vin.1: CC input from channel funding and src marker + //vin.1: CC input from channel funding + //vin.2: CC input from src marker //vout.0: CC vout for channel funding //vout.1: CC vout marker to senders pubKey //vout.2: CC vout marker to receiver pubkey @@ -262,6 +265,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vin.0 is normal for channelClose!"); else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) return eval->Invalid("vin.1 is CC for channelClose!"); + else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) + return eval->Invalid("vin.2 is CC for channelClose!"); else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("vout.0 is CC for channelClose!"); else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) @@ -278,7 +283,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { - if ((numvouts=prevTx.vout.size()) > 0 && (DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3)) != 0) + if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) return eval->Invalid("invalid destination for sender marker!"); @@ -291,6 +296,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & case 'R': //vin.0: normal input //vin.1: CC input from channel funding + //vin.2: CC input from src marker //vout.0: CC vout marker to senders pubKey //vout.1: CC vout marker to receiver pubKey //vout.2: normal output of CC input to senders pubkey @@ -304,6 +310,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vin.0 is normal for channelRefund!"); else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) return eval->Invalid("vin.1 is CC for channelRefund!"); + else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) + return eval->Invalid("vin.2 is CC for channelRefund!"); else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("vout.0 is CC for channelRefund (marker to srcPub)!"); else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) @@ -328,7 +336,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("invalid close tx, opentxid do not match on close and refund!"); else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { - if ((numvouts=prevTx.vout.size()) > 0 && (DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3)) != 0) + if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) return eval->Invalid("invalid destination for sender marker!"); @@ -391,11 +399,10 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) { const CTransaction &txmempool = e.GetTx(); - const uint256 &hash = tx.GetHash(); + const uint256 &hash = txmempool.GetHash(); - if ((numvouts=txmempool.vout.size()) > 0 && - (funcid=DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)) != 0 && - (tmp_txid==openTx.GetHash() || txmempool.GetHash()==openTx.GetHash()) && param1 < mindepth) + if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) != 0 && + tmp_txid==openTx.GetHash() && param1 < mindepth) { txid=hash; totalinputs=txmempool.vout[0].nValue+txmempool.vout[1].nValue; @@ -467,7 +474,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 } if (AddNormalinputs(mtx,mypk,2*txfee,1) > 0) { - if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount-2*txfee)>=0) + if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount)>=0) { if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O') { @@ -482,14 +489,28 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); return (""); } - numpayments=amount/payment; - if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0 && (numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) && (funcid == 'P' || funcid=='O')) { if (secret!=zeroid) + { + endiancpy(hash, (uint8_t * ) & secret, 32); + for (i = 0; i < totalnumpayments-(prevdepth-numpayments); i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & gensecret, hashdest, 32); + fprintf(stderr, "%d %d %d %s %s\n",(int)(totalnumpayments-(prevdepth-numpayments)),(int)prevdepth,(int)numpayments,gensecret.ToString().c_str(),hashchain.ToString().c_str()); + if (gensecret!=hashchain) + { + fprintf(stderr,"invalid secret supplied\n"); + return(""); + } + } + else { hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); endiancpy(hash, (uint8_t * ) & hentropy, 32); @@ -500,21 +521,6 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 } endiancpy((uint8_t * ) & secret, hashdest, 32); } - else - { - endiancpy(hash, (uint8_t * ) & secret, 32); - for (i = 0; i < totalnumpayments-(prevdepth-numpayments); i++) - { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); - } - endiancpy((uint8_t * ) & gensecret, hashdest, 32); - if (gensecret!=hashchain) - { - fprintf(stderr,"invalid secret supplied\n"); - return(""); - } - } } else { From 2ca1bcbe215022b97557e99b5567c33f624fef8e Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 27 Sep 2018 18:52:03 +0200 Subject: [PATCH 22/25] -fix --- src/cc/channels.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 2635fe494..b525d557e 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -277,10 +277,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("too many payment increments!"); else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0) return eval->Invalid("invalid open txid!"); - else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) == 'O') + else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O') return eval->Invalid("invalid channelopen OP_RETURN data!"); - else if (tx.vout[0].nValue != param2*payment) - return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) @@ -324,13 +322,13 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("too many payment increments!"); else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0) return eval->Invalid("invalid open txid!"); - else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) == 'O') + else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O') return eval->Invalid("invalid channelopen OP_RETURN data!"); else if (tx.vout[2].nValue != param2*payment) return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0) return eval->Invalid("invalid close txid!"); - else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, param1, param2, param3) == 'C') + else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C') return eval->Invalid("invalid channelclose OP_RETURN data!"); else if (tmp_txid!=opentxid) return eval->Invalid("invalid close tx, opentxid do not match on close and refund!"); From bd632043f2b184bf287483c070629771b68dbf1d Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 27 Sep 2018 20:06:21 +0200 Subject: [PATCH 23/25] -fix --- src/cc/channels.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index b525d557e..72f995e55 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -235,7 +235,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if (hashchain!=genhashchain) return eval->Invalid("invalid secret for payment, does not reach final hashchain!"); else if (tx.vout[3].nValue != param2*payment) - return eval->Invalid("invalid amount, does not match number_of_payments*payment!"); + return eval->Invalid("vout amount does not match number_of_payments*payment!"); } if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { @@ -247,6 +247,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("invalid destination for receiver marker!"); else if (param1+param2!=p1) return eval->Invalid("invalid payment depth!"); + else if (tx.vout[3].nValue > prevTx.vout[0].nValue) + return eval->Invalid("not enough funds in channel for that amount!"); } } break; @@ -279,6 +281,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("invalid open txid!"); else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O') return eval->Invalid("invalid channelopen OP_RETURN data!"); + else if (tx.vout[0].nValue != param1*payment) + return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) @@ -288,7 +292,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey) return eval->Invalid("invalid destination for receiver marker!"); else if (tx.vout[0].nValue != prevTx.vout[0].nValue) - return eval->Invalid("invalid CC amount, input!=output!"); + return eval->Invalid("invalid CC amount, amount must match funds in channel"); } break; case 'R': @@ -299,7 +303,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //vout.1: CC vout marker to receiver pubKey //vout.2: normal output of CC input to senders pubkey //vout.n-2: normal change - //vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpaymewnts payment closetxid + //vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpayments payment closetxid if (isCCTxNotarizedConfirmed(opentxid) == 0) return eval->Invalid("channelOpen is not yet confirmed(notarised)!"); else if (isCCTxNotarizedConfirmed(param3) == 0) @@ -324,24 +328,24 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("invalid open txid!"); else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O') return eval->Invalid("invalid channelopen OP_RETURN data!"); - else if (tx.vout[2].nValue != param2*payment) - return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0) return eval->Invalid("invalid close txid!"); else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C') return eval->Invalid("invalid channelclose OP_RETURN data!"); else if (tmp_txid!=opentxid) return eval->Invalid("invalid close tx, opentxid do not match on close and refund!"); + else if (tx.vout[2].nValue != param1*payment) + return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); - else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) + else if (tx.vout[0].scriptPubKey != prevTx.vout[1].scriptPubKey) return eval->Invalid("invalid destination for sender marker!"); - else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey) + else if (tx.vout[1].scriptPubKey != prevTx.vout[2].scriptPubKey) return eval->Invalid("invalid destination for receiver marker!"); else if (tx.vout[2].nValue != prevTx.vout[0].nValue) - return eval->Invalid("invalid refund amount, must transfer all funds!"); + return eval->Invalid("invalid amount, refund amount and funds in channel must match!"); } break; } @@ -551,9 +555,9 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) { CMutableTransaction mtx; CPubKey mypk,srcpub,destpub; struct CCcontract_info *cp,C; CTransaction channelOpenTx; - uint256 hashblock,tmp_txid,prevtxid,param3; - int32_t numvouts,param1; - int64_t param2,funds; + uint256 hashblock,tmp_txid,prevtxid,hashchain; + int32_t numvouts,numpayments; + int64_t payment,funds; // verify this is one of our outbound channels cp = CCinit(&C,EVAL_CHANNELS); @@ -565,7 +569,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) fprintf(stderr, "invalid channel open txid\n"); return (""); } - if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!='O') + if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O') { fprintf(stderr, "invalid channel open tx\n"); return (""); @@ -582,7 +586,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds, mypk, destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,0,0,zeroid))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,funds/payment,payment,zeroid))); } else { @@ -643,7 +647,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0) { - if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 && ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)) != 0) && (funcid == 'P' || funcid=='O')) + if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3) != 0) { hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); endiancpy(hash, (uint8_t * ) & hentropy, 32); From 7f0ed443f1e051d98fbcfe444c0ce60cd5b8b1b9 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Mon, 1 Oct 2018 18:24:14 +0200 Subject: [PATCH 24/25] -modified ChannelsExactAmount -fixes --- src/cc/CCchannels.h | 2 +- src/cc/CCtx.cpp | 2 +- src/cc/channels.cpp | 171 +++++++++++++++++++++++---------------- src/wallet/rpcwallet.cpp | 8 +- 4 files changed, 109 insertions(+), 74 deletions(-) diff --git a/src/cc/CCchannels.h b/src/cc/CCchannels.h index 4754ae44e..29b35d0e6 100644 --- a/src/cc/CCchannels.h +++ b/src/cc/CCchannels.h @@ -27,6 +27,6 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid); std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid); // CCcustom -UniValue ChannelsInfo(); +UniValue ChannelsInfo(char *); #endif diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 4e8561b20..abe65199d 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -111,7 +111,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { privkey = myprivkey; cond = mycond; - fprintf(stderr,"my CC addr.(%s)\n",myaddr); + } else if ( strcmp(destaddr,unspendable) == 0 ) { diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 72f995e55..de2657dc4 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -75,6 +75,19 @@ int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey return(0); } +int64_t IsChannelsMarkervout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub,int32_t v) +{ + char destaddr[64],ccaddr[64]; + + GetCCaddress(cp,ccaddr,srcpub); + if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,ccaddr) == 0 ) + return(tx.vout[v].nValue); + } + return(0); +} + CScript EncodeChannelsOpRet(uint8_t funcid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) { CScript opret; uint8_t evalcode = EVAL_CHANNELS; @@ -110,24 +123,15 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti numvins = tx.vin.size(); numvouts = tx.vout.size(); - if ((numvouts=tx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)) !=0) + if ((numvouts=tx.vout.size()) > 0 && DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)!=0) { for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) + if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("cant find vinTx"); + else { - //fprintf(stderr,"vini.%d check mempool\n",i); - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant Channels from mempool"); - if ( (assetoshis= IsChannelsvout(cp,vinTx,srcpub,destpub,tx.vin[i].prevout.n)) != 0 ) - inputs += assetoshis; - } + inputs += vinTx.vout[tx.vin[i].prevout.n].nValue; } } } @@ -137,9 +141,7 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti } for (i=0; iInvalid("no vouts"); else { - //fprintf(stderr,"check amounts\n"); - if ( 0) //ChannelsExactAmounts(cp,eval,tx,1,10000) == false ) + if (ChannelsExactAmounts(cp,eval,tx,1,10000) == false ) { fprintf(stderr,"Channelsget invalid amount\n"); return false; @@ -364,7 +365,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, CTransaction openTx, uint256 &prevtxid) { - char coinaddr[64]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t funcid,param1; + char coinaddr[64]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t param1; std::vector > unspentOutputs; CPubKey srcpub,destpub; uint8_t myprivkey[32]; @@ -386,14 +387,14 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (tmp_txid==openTx.GetHash() || tx.GetHash()==openTx.GetHash()) && - (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0)+IsChannelsvout(cp,tx,srcpub,destpub,1))>0) + (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0)+IsChannelsMarkervout(cp,tx,srcpub,1))>0) { txid = it->first.txhash; break; } } } - if (myIsutxo_spentinmempool(txid,0) != 0) + if (txid!=zeroid && myIsutxo_spentinmempool(txid,0) != 0) { fprintf(stderr,"spent in mempool\n"); txid=zeroid; @@ -476,7 +477,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 } if (AddNormalinputs(mtx,mypk,2*txfee,1) > 0) { - if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount)>=0) + if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && (change=funds-amount-txfee)>=0) { if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O') { @@ -505,7 +506,6 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 memcpy(hash, hashdest, 32); } endiancpy((uint8_t * ) & gensecret, hashdest, 32); - fprintf(stderr, "%d %d %d %s %s\n",(int)(totalnumpayments-(prevdepth-numpayments)),(int)prevdepth,(int)numpayments,gensecret.ToString().c_str(),hashchain.ToString().c_str()); if (gensecret!=hashchain) { fprintf(stderr,"invalid secret supplied\n"); @@ -515,13 +515,17 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 else { hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); - endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < prevdepth-numpayments; i++) + if (prevdepth-numpayments) { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < prevdepth-numpayments; i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & secret, hashdest, 32); } - endiancpy((uint8_t * ) & secret, hashdest, 32); + else endiancpy((uint8_t * ) & secret, (uint8_t * ) & hentropy, 32); } } else @@ -581,9 +585,9 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) } if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) { - if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0) + if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && funds-txfee>0) { - mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds, mypk, destpub)); + mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,funds/payment,payment,zeroid))); @@ -645,7 +649,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) } if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) { - if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0) + if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid)) !=0 && funds-txfee>0) { if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3) != 0) { @@ -659,7 +663,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) endiancpy((uint8_t * ) & secret, hashdest, 32); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); - mtx.vout.push_back(CTxOut(funds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + mtx.vout.push_back(CTxOut(funds-txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,destpub,param1,payment,closetxid))); } else @@ -677,52 +681,79 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) return(""); } -UniValue ChannelsInfo() +UniValue ChannelsInfo(char *CCaddr) { - UniValue result(UniValue::VOBJ); CTransaction tx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain; struct CCcontract_info *cp,C; char myCCaddr[64],addr[64],str1[100],str2[100]; int32_t vout,numvouts,param1,numpayments; int64_t nValue,param2,payment; CPubKey srcpub,destpub,mypk; + UniValue result(UniValue::VOBJ); CTransaction tx,opentx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain,prevtxid; + struct CCcontract_info *cp,C; char myCCaddr[64],addr[64],str1[256],str2[64]; int32_t vout,numvouts,param1,numpayments; + int64_t nValue,param2,payment; CPubKey srcpub,destpub,mypk; std::vector > txids; + result.push_back(Pair("result","success")); - result.push_back(Pair("name","Channel Info")); cp = CCinit(&C,EVAL_CHANNELS); mypk = pubkey2pk(Mypubkey()); - GetCCaddress(cp,myCCaddr,mypk); - SetCCtxids(txids,myCCaddr); - for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) + if (strcmp(CCaddr,"")==0) { - //int height = it->first.blockHeight; - txid = it->first.txhash; - vout = (int32_t)it->first.index; - nValue = (int64_t)it->second; - if ( (vout==0 || vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) + result.push_back(Pair("name","Channels Info")); + GetCCaddress(cp,myCCaddr,mypk); + SetCCtxids(txids,myCCaddr); + for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O') + //int height = it->first.blockHeight; + txid = it->first.txhash; + vout = (int32_t)it->first.index; + nValue = (int64_t)it->second; + if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - GetCCaddress1of2(cp,addr,srcpub,destpub); - sprintf(str1,"Channel - %s",addr); - result.push_back(Pair(str1,"Open")); - } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'P') - { - if (GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O') - sprintf(str1,"Channel - %s",addr); - sprintf(str2,"Payment -> %s %lld payments of %lld",destpub.GetHash().ToString().c_str(),(long long)param2,(long long)payment); - result.push_back(Pair(str1,str2)); - } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C') - { - GetCCaddress1of2(cp,addr,srcpub,destpub); - sprintf(str1,"Channel - %s",addr); - result.push_back(Pair(str1,"Close")); - } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C') - { - GetCCaddress1of2(cp,addr,srcpub,destpub); - sprintf(str1,"Channel - %s",addr); - sprintf(str2,"Refund -> %s %lld payments of %lld",srcpub.GetHash().ToString().c_str(),(long long)param1,(long long)param2); - result.push_back(Pair(str1,"Refund")); + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O') + { + GetCCaddress1of2(cp,addr,srcpub,destpub); + sprintf(str1,"%s - %lld payments of %lld satoshi",addr,(long long)param1,(long long)param2); + result.push_back(Pair("Channel", str1)); + } } } } + else + { + sprintf(str1,"Channel %s",CCaddr); + result.push_back(Pair("name",str1)); + strcpy(myCCaddr,CCaddr); + SetCCtxids(txids,myCCaddr); + prevtxid=zeroid; + for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) + { + //int height = it->first.blockHeight; + txid = it->first.txhash; + nValue = (int64_t)it->second; + if (txid!=prevtxid && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) + { + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O') + { + sprintf(str1,"%lld payments of %lld satoshi",(long long)param1,(long long)param2); + result.push_back(Pair("Open", str1)); + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'P') + { + if (GetTransaction(opentxid,opentx,hashBlock,false) != 0 && (numvouts=opentx.vout.size()) > 0 && DecodeChannelsOpRet(opentx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O') + { + Getscriptaddress(str2,tx.vout[3].scriptPubKey); + sprintf(str1,"%lld satoshi to %s, %lld payments left",(long long)(param2*payment),str2,(long long)param1); + result.push_back(Pair("Payment",str1)); + } + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C') + { + result.push_back(Pair("Close","channel")); + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'R') + { + Getscriptaddress(str2,tx.vout[2].scriptPubKey); + sprintf(str1,"%lld satoshi back to %s",(long long)(param1*param2),str2); + result.push_back(Pair("Refund",str1)); + } + } + prevtxid=txid; + } + } return(result); -} - +} \ No newline at end of file diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ff910f2c9..d4a83d83a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5124,11 +5124,15 @@ UniValue tokenaddress(const UniValue& params, bool fHelp) UniValue channelsinfo(const UniValue& params, bool fHelp) { - if ( fHelp || params.size() != 0 ) + char addr[100]; + if ( fHelp || params.size() > 1 ) throw runtime_error("channelsinfo\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"); - return(ChannelsInfo()); + strcpy(addr,""); + if (params.size() > 0 && !params[0].isNull() && !params[0].get_str().empty()) + strcpy(addr,params[0].get_str().c_str()); + return(ChannelsInfo(addr)); } UniValue channelsopen(const UniValue& params, bool fHelp) From 78086bc3bf538f763caea411a7306616b348b645 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Mon, 1 Oct 2018 18:52:21 +0200 Subject: [PATCH 25/25] - fix --- src/cc/CCchannels.h | 2 +- src/cc/CCutils.cpp | 2 +- src/cc/channels.cpp | 74 +++++++++++++++++++++------------------- src/wallet/rpcwallet.cpp | 10 +++--- 4 files changed, 46 insertions(+), 42 deletions(-) diff --git a/src/cc/CCchannels.h b/src/cc/CCchannels.h index 29b35d0e6..f67ef9a6c 100644 --- a/src/cc/CCchannels.h +++ b/src/cc/CCchannels.h @@ -27,6 +27,6 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid); std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid); // CCcustom -UniValue ChannelsInfo(char *); +UniValue ChannelsInfo(uint256 opentxid); #endif diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index cbf574532..491798a98 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -405,7 +405,7 @@ int64_t CCduration(int32_t &numblocks,uint256 txid) } numblocks = (pindex->nHeight - txheight); duration = (pindex->nTime - txtime); - fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->nHeight,txheight); + //fprintf(stderr,"duration %d (%u - %u) numblocks %d (%d - %d)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime,numblocks,pindex->nHeight,txheight); return(duration); } diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index de2657dc4..236f28e03 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -681,7 +681,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) return(""); } -UniValue ChannelsInfo(char *CCaddr) +UniValue ChannelsInfo(uint256 channeltxid) { UniValue result(UniValue::VOBJ); CTransaction tx,opentx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain,prevtxid; struct CCcontract_info *cp,C; char myCCaddr[64],addr[64],str1[256],str2[64]; int32_t vout,numvouts,param1,numpayments; @@ -691,7 +691,7 @@ UniValue ChannelsInfo(char *CCaddr) result.push_back(Pair("result","success")); cp = CCinit(&C,EVAL_CHANNELS); mypk = pubkey2pk(Mypubkey()); - if (strcmp(CCaddr,"")==0) + if (channeltxid==zeroid) { result.push_back(Pair("name","Channels Info")); GetCCaddress(cp,myCCaddr,mypk); @@ -704,10 +704,10 @@ UniValue ChannelsInfo(char *CCaddr) nValue = (int64_t)it->second; if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O') + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O') { GetCCaddress1of2(cp,addr,srcpub,destpub); - sprintf(str1,"%s - %lld payments of %lld satoshi",addr,(long long)param1,(long long)param2); + sprintf(str1,"%s - %lld payments of %lld satoshi - %s",addr,(long long)param1,(long long)param2,tx.GetHash().ToString().c_str()); result.push_back(Pair("Channel", str1)); } } @@ -715,44 +715,48 @@ UniValue ChannelsInfo(char *CCaddr) } else { - sprintf(str1,"Channel %s",CCaddr); - result.push_back(Pair("name",str1)); - strcpy(myCCaddr,CCaddr); - SetCCtxids(txids,myCCaddr); - prevtxid=zeroid; - for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) + if (GetTransaction(channeltxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && + (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O')) { - //int height = it->first.blockHeight; - txid = it->first.txhash; - nValue = (int64_t)it->second; - if (txid!=prevtxid && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) + GetCCaddress1of2(cp,addr,srcpub,destpub); + sprintf(str1,"Channel %s",addr); + result.push_back(Pair("name",str1)); + SetCCtxids(txids,addr); + prevtxid=zeroid; + for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O') + + txid = it->first.txhash; + nValue = (int64_t)it->second; + if (txid!=prevtxid && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - sprintf(str1,"%lld payments of %lld satoshi",(long long)param1,(long long)param2); - result.push_back(Pair("Open", str1)); - } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'P') - { - if (GetTransaction(opentxid,opentx,hashBlock,false) != 0 && (numvouts=opentx.vout.size()) > 0 && DecodeChannelsOpRet(opentx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O') + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O' && tx.GetHash()==channeltxid) { - Getscriptaddress(str2,tx.vout[3].scriptPubKey); - sprintf(str1,"%lld satoshi to %s, %lld payments left",(long long)(param2*payment),str2,(long long)param1); - result.push_back(Pair("Payment",str1)); + sprintf(str1,"%lld payments of %lld satoshi",(long long)param1,(long long)param2); + result.push_back(Pair("Open", str1)); + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'P' && opentxid==channeltxid) + { + if (GetTransaction(opentxid,opentx,hashBlock,false) != 0 && (numvouts=opentx.vout.size()) > 0 && DecodeChannelsOpRet(opentx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O') + { + Getscriptaddress(str2,tx.vout[3].scriptPubKey); + sprintf(str1,"%lld satoshi to %s, %lld payments left",(long long)(param2*payment),str2,(long long)param1); + result.push_back(Pair("Payment",str1)); + } + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C' && opentxid==channeltxid) + { + result.push_back(Pair("Close","channel")); + } + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'R' && opentxid==channeltxid) + { + Getscriptaddress(str2,tx.vout[2].scriptPubKey); + sprintf(str1,"%lld satoshi back to %s",(long long)(param1*param2),str2); + result.push_back(Pair("Refund",str1)); } } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C') - { - result.push_back(Pair("Close","channel")); - } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'R') - { - Getscriptaddress(str2,tx.vout[2].scriptPubKey); - sprintf(str1,"%lld satoshi back to %s",(long long)(param1*param2),str2); - result.push_back(Pair("Refund",str1)); - } + prevtxid=txid; } - prevtxid=txid; } } return(result); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d4a83d83a..d97df5b3a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5124,15 +5124,15 @@ UniValue tokenaddress(const UniValue& params, bool fHelp) UniValue channelsinfo(const UniValue& params, bool fHelp) { - char addr[100]; + uint256 opentxid; if ( fHelp || params.size() > 1 ) - throw runtime_error("channelsinfo\n"); + throw runtime_error("channelsinfo [opentxid]\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"); - strcpy(addr,""); + opentxid=zeroid; if (params.size() > 0 && !params[0].isNull() && !params[0].get_str().empty()) - strcpy(addr,params[0].get_str().c_str()); - return(ChannelsInfo(addr)); + opentxid = Parseuint256((char *)params[0].get_str().c_str()); + return(ChannelsInfo(opentxid)); } UniValue channelsopen(const UniValue& params, bool fHelp)