]> Git Repo - VerusCoin.git/blobdiff - src/cc/rewards.cpp
Merge pull request #234 from Asherda/dev
[VerusCoin.git] / src / cc / rewards.cpp
index efb47fdb3b84fb4a42e3c1a9c6054ce2165b15a2..0f524756d2de7cb0bb2fb1f7203c1a19a109901b 100644 (file)
@@ -66,8 +66,6 @@
  
  */
 
-extern std::string CCerror;
-
 int64_t RewardsCalc(int64_t amount,uint256 txid,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit)
 {
     int32_t numblocks; uint64_t duration,reward = 0;
@@ -194,9 +192,9 @@ bool RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransactio
     else return(true);
 }
 
-bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
+bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
 {
-    uint256 txid,fundingtxid,hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx;
+    uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx;
     numvins = tx.vin.size();
     numvouts = tx.vout.size();
     preventCCvins = preventCCvouts = -1;
@@ -244,14 +242,20 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
                     //vout.0: funding CC change or recover normal payout
                     //vout.1: normal output to unlock address
                     //vout.n-1: opreturn 'U' sbits fundingtxid
-                    if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
+                    if ( fundingtxid == tx.vin[0].prevout.hash )
+                        return eval->Invalid("cant unlock fundingtxid");
+                    else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
                         return eval->Invalid("always should find vin.0, but didnt");
+                    else if ( DecodeRewardsOpRet(tx.vin[0].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid) != 'L' )
+                        return eval->Invalid("can only unlock locktxid");
+                    else if ( fundingtxid != vinfundingtxid )
+                        return eval->Invalid("mismatched vinfundingtxid");
                     for (i=0; i<numvins; i++)
                     {
                         if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
                             return eval->Invalid("unexpected normal vin for unlock");
                     }
-                    if ( numvouts == 1 && numvins == 1 )
+                    if ( numvouts == 2 && numvins == 1 )
                     {
                         if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 )
                             return eval->Invalid("unlock recover tx vout.0 is not normal output");
@@ -259,12 +263,14 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
                             return eval->Invalid("unlock recover tx vout.0 mismatched scriptPubKey");
                         else if ( tx.vout[0].nValue > vinTx.vout[0].nValue )
                             return eval->Invalid("unlock recover tx vout.0 mismatched amounts");
+                        else if ( tx.vout[1].nValue > 0 )
+                            return eval->Invalid("unlock recover tx vout.1 nonz amount");
                         else return(true);
                     }
                     if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
-                        return eval->Invalid("lock tx vout.0 is normal output");
-                    else if ( tx.vout.size() < 3 )
-                        return eval->Invalid("unlock tx not enough vouts");
+                        return eval->Invalid("unlock tx vout.0 is normal output");
+                    else if ( numvouts != 3 )
+                        return eval->Invalid("unlock tx wrong number of vouts");
                     else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
                         return eval->Invalid("unlock tx vout.0 is normal output");
                     else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 )
@@ -277,6 +283,8 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
                         return false;
                     else if ( tx.vout[1].nValue > amount+reward )
                         return eval->Invalid("unlock tx vout.1 isnt amount+reward");
+                    else if ( tx.vout[2].nValue > 0 )
+                        return eval->Invalid("unlock tx vout.2 isnt 0");
                     preventCCvouts = 1;
                     break;
             }
@@ -286,7 +294,7 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
     return(true);
 }
 
-uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t refsbits,uint256 reffundingtxid,uint64_t needed)
+static uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t refsbits,uint256 reffundingtxid,uint64_t needed)
 {
     uint8_t funcid; uint64_t sbits,nValue; uint256 fundingtxid; char str[65];
     memset(&txid,0,sizeof(txid));
@@ -535,7 +543,8 @@ std::string RewardsAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,i
     sbits = stringbits(planstr);
     if ( RewardsPlanExists(cp,sbits,rewardspk,a,b,c,d) == 0 )
     {
-        fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
+        CCerror = strprintf("Rewards plan %s doesnt exist\n",planstr);
+        fprintf(stderr,"%s\n",CCerror.c_str());
         return("");
     }
     sbits = stringbits(planstr);
@@ -543,8 +552,12 @@ std::string RewardsAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,i
     {
         mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,rewardspk));
         return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeRewardsOpRet('A',sbits,fundingtxid)));
-    } else fprintf(stderr,"cant find enough inputs\n");
-    fprintf(stderr,"cant find fundingtxid\n");
+    } else {
+        CCerror = "cant find enough inputs";
+        fprintf(stderr,"%s\n", CCerror.c_str());
+    }
+    CCerror = "cant find fundingtxid";
+    fprintf(stderr,"%s\n", CCerror.c_str());
     return("");
 }
 
@@ -553,7 +566,8 @@ std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t
     CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t lockedfunds,sbits,funding,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C;
     if ( deposit < txfee )
     {
-        fprintf(stderr,"deposit amount less than txfee\n");
+        CCerror = "deposit amount less than txfee";
+        fprintf(stderr,"%s\n",CCerror.c_str());
         return("");
     }
     cp = CCinit(&C,EVAL_REWARDS);
@@ -564,12 +578,14 @@ std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t
     sbits = stringbits(planstr);
     if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
     {
-        fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
+        CCerror = strprintf("Rewards plan %s doesnt exist\n",planstr);
+        fprintf(stderr,"%s\n",CCerror.c_str());
         return("");
     }
     if ( deposit < mindeposit )
     {
-        fprintf(stderr,"Rewards plan %s deposit %.8f < mindeposit %.8f\n",planstr,(double)deposit/COIN,(double)mindeposit/COIN);
+        CCerror = strprintf("Rewards plan %s deposit %.8f < mindeposit %.8f\n",planstr,(double)deposit/COIN,(double)mindeposit/COIN);
+        fprintf(stderr,"%s\n",CCerror.c_str());
         return("");
     }
     if ( (funding= RewardsPlanFunds(lockedfunds,sbits,cp,rewardspk,fundingtxid)) >= deposit ) // arbitrary cmpval
@@ -579,7 +595,10 @@ std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t
             mtx.vout.push_back(MakeCC1vout(cp->evalcode,deposit,rewardspk));
             mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
             return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeRewardsOpRet('L',sbits,fundingtxid)));
-        } else fprintf(stderr,"cant find enough inputs %.8f not enough for %.8f, make sure you imported privkey for the -pubkey address\n",(double)funding/COIN,(double)deposit/COIN);
+        } else {
+            CCerror = strprintf("cant find enough inputs %.8f not enough for %.8f, make sure you imported privkey for the -pubkey address\n",(double)funding/COIN,(double)deposit/COIN);
+            fprintf(stderr,"%s\n",CCerror.c_str());
+        }
     }
     fprintf(stderr,"cant find rewards inputs funding %.8f locked %.8f vs deposit %.8f\n",(double)funding/COIN,(double)lockedfunds/COIN,(double)deposit/COIN);
     return("");
@@ -587,13 +606,19 @@ std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t
 
 std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid)
 {
-    CMutableTransaction mtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,rewardspk; CScript opret,scriptPubKey,ignore; uint256 hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; int64_t funding,reward=0,amount=0,inputs,CCchange=0; struct CCcontract_info *cp,C;
+    CMutableTransaction mtx,firstmtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,rewardspk; CScript scriptPubKey,ignore; uint256 hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; int64_t funding,reward=0,amount=0,inputs,CCchange=0; struct CCcontract_info *cp,C;
     cp = CCinit(&C,EVAL_REWARDS);
     if ( txfee == 0 )
         txfee = 10000;
     rewardspk = GetUnspendable(cp,0);
     mypk = pubkey2pk(Mypubkey());
     sbits = stringbits(planstr);
+    if ( locktxid == fundingtxid )
+    {
+        fprintf(stderr,"Rewards plan cant unlock fundingtxid\n");
+        CCerror = "Rewards plan cant unlock fundingtxid";
+        return("");
+    }
     if ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
     {
         fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
@@ -631,7 +656,8 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2
         {
             if ( reward > txfee )
             {
-                if ( (inputs= AddRewardsInputs(ignore,0,cp,mtx,rewardspk,reward+txfee,30,sbits,fundingtxid)) > 0 )
+                firstmtx = mtx;
+                if ( (inputs= AddRewardsInputs(ignore,0,cp,mtx,rewardspk,reward+txfee,30,sbits,fundingtxid)) >= reward+txfee )
                 {
                     if ( inputs >= (reward + 2*txfee) )
                         CCchange = (inputs - (reward + txfee));
@@ -642,10 +668,10 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2
                 }
                 else
                 {
-                    mtx.vout.push_back(CTxOut(amount-txfee,scriptPubKey));
+                    firstmtx.vout.push_back(CTxOut(amount-txfee,scriptPubKey));
                     //CCerror = "cant find enough rewards inputs";
                     fprintf(stderr,"not enough rewards funds to payout %.8f, recover mode tx\n",(double)(reward+txfee)/COIN);
-                    return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret));
+                    return(FinalizeCCTx(-1LL,cp,firstmtx,mypk,txfee,EncodeRewardsOpRet('U',sbits,fundingtxid)));
                 }
             }
             else
This page took 0.02781 seconds and 4 git commands to generate.