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