*/
-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;
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;
//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");
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 )
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;
}
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));
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);
{
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("");
}
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);
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
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("");
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);
{
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));
}
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