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 ) {