|
|
@ -157,23 +157,42 @@ uint8_t DecodePaymentsOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t & |
|
|
|
return(0); |
|
|
|
} |
|
|
|
|
|
|
|
CScript EncodePaymentsSnapsShotOpRet(int32_t lockedblocks,int32_t minrelease,int32_t top,int32_t bottom,int8_t fixedAmount,std::vector<std::vector<uint8_t>> excludeScriptPubKeys) |
|
|
|
CScript EncodePaymentsSnapsShotOpRet(int32_t lockedblocks,int32_t minrelease,int32_t minimum,int32_t top,int32_t bottom,int8_t fixedAmount,std::vector<std::vector<uint8_t>> excludeScriptPubKeys) |
|
|
|
{ |
|
|
|
CScript opret; uint8_t evalcode = EVAL_PAYMENTS; |
|
|
|
if ( (strcmp(ASSETCHAINS_SYMBOL, "CFEKPAY") == 0) ) // exempt for now, remove this after game completed.
|
|
|
|
{ |
|
|
|
minimum = 10000; |
|
|
|
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << top << bottom << fixedAmount << excludeScriptPubKeys); |
|
|
|
} |
|
|
|
else |
|
|
|
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << minimum << top << bottom << fixedAmount << excludeScriptPubKeys); |
|
|
|
return(opret); |
|
|
|
} |
|
|
|
|
|
|
|
uint8_t DecodePaymentsSnapsShotOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &top,int32_t &bottom,int8_t &fixedAmount,std::vector<std::vector<uint8_t>> &excludeScriptPubKeys) |
|
|
|
uint8_t DecodePaymentsSnapsShotOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &minimum,int32_t &top,int32_t &bottom,int8_t &fixedAmount,std::vector<std::vector<uint8_t>> &excludeScriptPubKeys) |
|
|
|
{ |
|
|
|
std::vector<uint8_t> vopret; uint8_t *script,e,f; |
|
|
|
GetOpReturnData(scriptPubKey, vopret); |
|
|
|
script = (uint8_t *)vopret.data(); |
|
|
|
if ( (strcmp(ASSETCHAINS_SYMBOL, "CFEKPAY") == 0) ) // exempt for now, remove this after game completed.
|
|
|
|
{ |
|
|
|
minimum = 10000; |
|
|
|
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> top; ; ss >> bottom; ss >> fixedAmount; ss >> excludeScriptPubKeys) != 0 ) |
|
|
|
{ |
|
|
|
if ( e == EVAL_PAYMENTS && f == 'S' ) |
|
|
|
return(f); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
|
|
|
|
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> minimum; ss >> top; ; ss >> bottom; ss >> fixedAmount; ss >> excludeScriptPubKeys) != 0 ) |
|
|
|
{ |
|
|
|
if ( e == EVAL_PAYMENTS && f == 'S' ) |
|
|
|
return(f); |
|
|
|
} |
|
|
|
} |
|
|
|
return(0); |
|
|
|
} |
|
|
|
|
|
|
@ -197,10 +216,11 @@ uint8_t DecodePaymentsTokensOpRet(CScript scriptPubKey,int32_t &lockedblocks,int |
|
|
|
return(0); |
|
|
|
} |
|
|
|
|
|
|
|
int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr) |
|
|
|
int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr, CScript &ccopret) |
|
|
|
{ |
|
|
|
char destaddr[64]; |
|
|
|
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) |
|
|
|
//if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
|
|
|
if ( getCCopret(tx.vout[v].scriptPubKey, ccopret) ) |
|
|
|
{ |
|
|
|
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && (cmpaddr[0] == 0 || strcmp(destaddr,cmpaddr) == 0) ) |
|
|
|
return(tx.vout[v].nValue); |
|
|
@ -259,36 +279,53 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & |
|
|
|
// change is/must be in vout[0]
|
|
|
|
// only 'F' or 1of2 txidaddr can be spent
|
|
|
|
// all vouts must match exactly
|
|
|
|
char temp[128], coinaddr[64], txidaddr[64]; std::string scriptpubkey; uint256 createtxid, blockhash, tokenid; CTransaction plantx; int8_t funcid=0, fixedAmount=0; |
|
|
|
int32_t i,lockedblocks,minrelease; int64_t change,totalallocations; std::vector<uint256> txidoprets; bool fHasOpret = false; CPubKey txidpk,Paymentspk; |
|
|
|
int32_t top,bottom=0; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; bool fFixedAmount = false; |
|
|
|
char temp[128], coinaddr[64]={0}, txidaddr[64]; std::string scriptpubkey; uint256 createtxid, blockhash, tokenid; CTransaction plantx; int8_t funcid=0, fixedAmount=0; |
|
|
|
int32_t i,lockedblocks,minrelease; int64_t change,totalallocations; std::vector<uint256> txidoprets; bool fHasOpret = false,fIsMerge = false; CPubKey txidpk,Paymentspk; |
|
|
|
int32_t top,bottom=0,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; bool fFixedAmount = false; CScript ccopret; |
|
|
|
mpz_t mpzTotalAllocations, mpzAllocation;; mpz_init(mpzTotalAllocations); |
|
|
|
// user marker vout to get the createtxid
|
|
|
|
if ( tx.vout.size() < 2 ) |
|
|
|
return(eval->Invalid("not enough vouts")); |
|
|
|
if ( tx.vout.back().scriptPubKey[0] == OP_RETURN ) |
|
|
|
if ( tx.vout.size() == 1 ) |
|
|
|
{ |
|
|
|
if ( IsPaymentsvout(cp,tx,0,coinaddr,ccopret) != 0 && ccopret.size() > 2 && DecodePaymentsMergeOpRet(ccopret,createtxid) ) |
|
|
|
{ |
|
|
|
fIsMerge = true; |
|
|
|
} else return(eval->Invalid("not enough vouts")); |
|
|
|
} |
|
|
|
else if ( tx.vout.back().scriptPubKey[0] == OP_RETURN ) |
|
|
|
{ |
|
|
|
scriptpubkey = HexStr(tx.vout[tx.vout.size()-2].scriptPubKey.begin()+2, tx.vout[tx.vout.size()-2].scriptPubKey.end()-1); |
|
|
|
fHasOpret = true; |
|
|
|
} else scriptpubkey = HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin()+2,tx.vout[tx.vout.size()-1].scriptPubKey.end()-1); |
|
|
|
} |
|
|
|
else scriptpubkey = HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin()+2,tx.vout[tx.vout.size()-1].scriptPubKey.end()-1); |
|
|
|
if ( !fIsMerge ) |
|
|
|
{ |
|
|
|
strcpy(temp, scriptpubkey.c_str()); |
|
|
|
pub2createtxid(temp); |
|
|
|
createtxid = Parseuint256(temp); |
|
|
|
} |
|
|
|
//printf("createtxid.%s\n",createtxid.ToString().c_str());
|
|
|
|
|
|
|
|
// use the createtxid to fetch the tx and all of the plans info.
|
|
|
|
if ( myGetTransaction(createtxid,plantx,blockhash) != 0 && plantx.vout.size() > 0 ) |
|
|
|
{ |
|
|
|
if ( ((funcid= DecodePaymentsOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets)) == 'C' || (funcid= DecodePaymentsSnapsShotOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid)) == 'O') ) |
|
|
|
if ( ((funcid= DecodePaymentsOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets)) == 'C' || (funcid= DecodePaymentsSnapsShotOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid)) == 'O') ) |
|
|
|
{ |
|
|
|
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) ) |
|
|
|
return(eval->Invalid("negative values")); |
|
|
|
if ( minimum < 10000 ) |
|
|
|
return(eval->Invalid("minimum must be over 10000")); |
|
|
|
Paymentspk = GetUnspendable(cp,0); |
|
|
|
txidpk = CCtxidaddr(txidaddr,createtxid); |
|
|
|
GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk); |
|
|
|
//fprintf(stderr, "lockedblocks.%i minrelease.%i totalallocations.%i txidopret1.%s txidopret2.%s\n",lockedblocks, minrelease, totalallocations, txidoprets[0].ToString().c_str(), txidoprets[1].ToString().c_str() );
|
|
|
|
if ( !CheckTxFee(tx, PAYMENTS_TXFEE+1, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) |
|
|
|
return eval->Invalid("txfee is too high"); |
|
|
|
// make sure change is in vout 0 and is paying to the contract address.
|
|
|
|
if ( (change= IsPaymentsvout(cp,tx,0,coinaddr,ccopret)) == 0 ) |
|
|
|
return(eval->Invalid("change is in wrong vout or is wrong tx type")); |
|
|
|
|
|
|
|
if ( !fIsMerge ) |
|
|
|
{ |
|
|
|
// Get all the script pubkeys and allocations
|
|
|
|
std::vector<int64_t> allocations; |
|
|
|
std::vector<CScript> scriptPubKeys; |
|
|
@ -331,7 +368,6 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & |
|
|
|
return(eval->Invalid("snapshots not activated on this chain")); |
|
|
|
if ( vAddressSnapshot.size() == 0 ) |
|
|
|
return(eval->Invalid("need first snapshot")); |
|
|
|
// need time for TX to me mined before the next snapshot.
|
|
|
|
if ( top > 3999 ) |
|
|
|
return(eval->Invalid("transaction too big")); |
|
|
|
if ( fixedAmount == 7 ) |
|
|
@ -375,19 +411,15 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & |
|
|
|
{ |
|
|
|
// tokens snapshot.
|
|
|
|
} |
|
|
|
// sanity check to make sure we got all the required info
|
|
|
|
// sanity check to make sure we got all the required info, skip for merge type tx
|
|
|
|
//fprintf(stderr, " allocations.size().%li scriptPubKeys.size.%li\n",allocations.size(), scriptPubKeys.size());
|
|
|
|
if ( allocations.size() == 0 || scriptPubKeys.size() == 0 || allocations.size() != scriptPubKeys.size() ) |
|
|
|
if ( (allocations.size() == 0 || scriptPubKeys.size() == 0 || allocations.size() != scriptPubKeys.size()) ) |
|
|
|
return(eval->Invalid("missing data cannot validate")); |
|
|
|
|
|
|
|
//fprintf(stderr, "totalallocations.%li checkallocations.%li\n",totalallocations, checkallocations);
|
|
|
|
if ( funcid == 'C' && totalallocations != checkallocations ) // only check for normal payments release.
|
|
|
|
return(eval->Invalid("allocation missmatch")); |
|
|
|
|
|
|
|
// make sure change is in vout 0 and is paying to the contract address.
|
|
|
|
if ( (change= IsPaymentsvout(cp,tx,0,coinaddr)) == 0 ) |
|
|
|
return(eval->Invalid("change is in wrong vout or is wrong tx type")); |
|
|
|
|
|
|
|
// Check vouts go to the right place and pay the right amounts.
|
|
|
|
int64_t amount = 0, checkamount; int32_t n = 0; |
|
|
|
checkamount = tx.GetValueOut() - change - PAYMENTS_TXFEE; |
|
|
@ -419,6 +451,11 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & |
|
|
|
fprintf(stderr, "vout.%i test.%li vs nVlaue.%li\n",i, test, tx.vout[i].nValue); |
|
|
|
return(eval->Invalid("amounts do not match")); |
|
|
|
} |
|
|
|
if ( test < minimum ) |
|
|
|
{ |
|
|
|
fprintf(stderr, "vout.%i test.%li vs minimum.%i\n",i, test, minimum); |
|
|
|
return(eval->Invalid("under minimum size")); |
|
|
|
} |
|
|
|
amount += tx.vout[i].nValue; |
|
|
|
n++; |
|
|
|
} |
|
|
@ -432,9 +469,9 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & |
|
|
|
fprintf(stderr, "does not meet minrelease amount.%li minrelease.%li\n",amount, (int64_t)minrelease*COIN ); |
|
|
|
return(eval->Invalid("amount is too small")); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
// Check vins
|
|
|
|
i = 0; |
|
|
|
i = 0; int32_t dust = 0; |
|
|
|
int32_t blocksleft; |
|
|
|
BOOST_FOREACH(const CTxIn& vin, tx.vin) |
|
|
|
{ |
|
|
@ -442,14 +479,16 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & |
|
|
|
if ( myGetTransaction(vin.prevout.hash,txin,blockhash) ) |
|
|
|
{ |
|
|
|
// check the vin comes from the CC address's
|
|
|
|
char destaddr[64]; |
|
|
|
char destaddr[64]; int32_t mergeoffset = 0; CScript opret; uint256 checktxid; |
|
|
|
Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey); |
|
|
|
if ( fIsMerge && txin.vout[vin.prevout.n].nValue < COIN ) |
|
|
|
dust++; |
|
|
|
if ( strcmp(destaddr,coinaddr) != 0 ) |
|
|
|
{ |
|
|
|
// if does not come from address its in the global payments adddress and we need to check the opreturn.
|
|
|
|
CScript opret; uint256 checktxid; int32_t opret_ind; |
|
|
|
uint256 checktxid; int32_t opret_ind; |
|
|
|
if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 ) |
|
|
|
opret = getCCopret(txin.vout[vin.prevout.n].scriptPubKey); // get op_return from CCvout,
|
|
|
|
getCCopret(txin.vout[vin.prevout.n].scriptPubKey,opret); // get op_return from CCvout,
|
|
|
|
else |
|
|
|
opret = txin.vout[opret_ind].scriptPubKey; |
|
|
|
if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) |
|
|
@ -458,11 +497,23 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & |
|
|
|
return(eval->Invalid("vin is not paymentsCC type")); |
|
|
|
} |
|
|
|
} |
|
|
|
else if ( fIsMerge && getCCopret(txin.vout[vin.prevout.n].scriptPubKey,opret) && opret.size() > 2 && DecodePaymentsMergeOpRet(opret,checktxid) == 'M' ) |
|
|
|
{ |
|
|
|
mergeoffset = PAYMENTS_MERGEOFSET; |
|
|
|
} |
|
|
|
fprintf(stderr, "mergeoffset.%i\n", mergeoffset); |
|
|
|
// check the chain depth vs locked blocks requirement.
|
|
|
|
if ( !payments_lockedblocks(blockhash, lockedblocks, blocksleft) ) |
|
|
|
if ( !payments_lockedblocks(blockhash, lockedblocks+mergeoffset, blocksleft) ) |
|
|
|
return(eval->Invalid("vin not elegible")); |
|
|
|
} else return(eval->Invalid("cant get vin transaction")); |
|
|
|
i++; |
|
|
|
} else return(eval->Invalid("cant get vin transaction")); |
|
|
|
} |
|
|
|
if ( fIsMerge ) |
|
|
|
{ |
|
|
|
if ( i < 2 ) |
|
|
|
return(eval->Invalid("must have at least 2 vins to carry out merge")); |
|
|
|
else if ( i == dust+1 ) |
|
|
|
return(eval->Invalid("cannot merge only dust")); |
|
|
|
} |
|
|
|
} else return(eval->Invalid("create transaction cannot decode")); |
|
|
|
} else return(eval->Invalid("Could not get contract transaction")); |
|
|
@ -474,7 +525,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & |
|
|
|
int64_t AddPaymentsInputs(bool fLockedBlocks,int8_t GetBalance,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey txidpk,int64_t total,int32_t maxinputs,uint256 createtxid,int32_t lockedblocks,int64_t minrelease,int32_t &blocksleft) |
|
|
|
{ |
|
|
|
char coinaddr[64]; CPubKey Paymentspk; int64_t nValue,threshold,price,totalinputs = 0; uint256 txid,checktxid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t iter,vout,ht,n = 0; |
|
|
|
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; |
|
|
|
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; CScript ccopret; |
|
|
|
std::vector<std::pair<int32_t,CAmount> > blocksleft_balance; |
|
|
|
if ( GetBalance == 0 ) |
|
|
|
{ |
|
|
@ -509,7 +560,7 @@ int64_t AddPaymentsInputs(bool fLockedBlocks,int8_t GetBalance,struct CCcontract |
|
|
|
if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 ) |
|
|
|
{ |
|
|
|
// get op_return from CCvout
|
|
|
|
opret = getCCopret(vintx.vout[vout].scriptPubKey); |
|
|
|
getCCopret(vintx.vout[vout].scriptPubKey,opret); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
@ -522,13 +573,15 @@ int64_t AddPaymentsInputs(bool fLockedBlocks,int8_t GetBalance,struct CCcontract |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
if ( (nValue= IsPaymentsvout(cp,vintx,vout,coinaddr)) > PAYMENTS_TXFEE && nValue >= threshold && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) |
|
|
|
if ( (nValue= IsPaymentsvout(cp,vintx,vout,coinaddr,ccopret)) > PAYMENTS_TXFEE && nValue >= threshold && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 ) |
|
|
|
{ |
|
|
|
int32_t tmpblocksleft = 0; |
|
|
|
if ( GetBalance == 0 && total != 0 && maxinputs != 0 ) |
|
|
|
if ( (GetBalance == 0 && total != 0 && maxinputs != 0) || GetBalance == 4 ) |
|
|
|
mtx.vin.push_back(CTxIn(txid,vout,CScript())); |
|
|
|
nValue = it->second.satoshis; |
|
|
|
if ( fLockedBlocks && !payments_lockedblocks(hashBlock, lockedblocks, tmpblocksleft) ) |
|
|
|
if ( nValue < COIN ) |
|
|
|
blocksleft++; // count dust with unused variable.
|
|
|
|
if ( fLockedBlocks && !payments_lockedblocks(hashBlock, lockedblocks+(GetBalance == 4 ? PAYMENTS_MERGEOFSET : 0), tmpblocksleft) ) |
|
|
|
{ |
|
|
|
blocksleft_balance.push_back(std::make_pair(tmpblocksleft,nValue)); |
|
|
|
continue; |
|
|
@ -636,7 +689,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
//int32_t latestheight,nextheight = komodo_nextheight();
|
|
|
|
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock,tokenid; |
|
|
|
CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease; int64_t newamount,inputsum,amount,CCchange=0,totalallocations=0,checkallocations=0,allocation; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector<uint256> txidoprets; |
|
|
|
int32_t top,bottom=0,blocksleft=0; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t funcid,fixedAmount=0; bool fFixedAmount = false; |
|
|
|
int32_t top,bottom=0,blocksleft=0,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t funcid,fixedAmount=0; bool fFixedAmount = false; |
|
|
|
mpz_t mpzTotalAllocations; mpz_init(mpzTotalAllocations); |
|
|
|
cJSON *params = payments_reparse(&n,jsonstr); |
|
|
|
mypk = pubkey2pk(Mypubkey()); |
|
|
@ -647,7 +700,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; |
|
|
|
if ( myGetTransaction(createtxid,tx,hashBlock) != 0 && tx.vout.size() > 0 ) |
|
|
|
{ |
|
|
|
if ( ((funcid= DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets)) == 'C' || (funcid= DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid)) == 'O') ) |
|
|
|
if ( ((funcid= DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets)) == 'C' || (funcid= DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid)) == 'O') ) |
|
|
|
{ |
|
|
|
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) ) |
|
|
|
{ |
|
|
@ -657,6 +710,9 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
free_json(params); |
|
|
|
return(result); |
|
|
|
} |
|
|
|
// set minimum size to 10k sat otherwise the tx will be invalid.
|
|
|
|
if ( minimum < 10000 ) |
|
|
|
minimum = 10000; |
|
|
|
//latestheight = (nextheight - lockedblocks - 1);
|
|
|
|
if ( amount < minrelease*COIN ) |
|
|
|
{ |
|
|
@ -817,13 +873,14 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
} |
|
|
|
//fprintf(stderr, "nValue.%li \n", mtx.vout[i+1].nValue);
|
|
|
|
mpz_clear(mpzValue); |
|
|
|
/*
|
|
|
|
replace this with default dust threshold of 10ksat |
|
|
|
if ( mtx.vout[i+1].nValue < PAYMENTS_TXFEE ) |
|
|
|
if ( mtx.vout[i+1].nValue < minimum ) |
|
|
|
{ |
|
|
|
newamount += (PAYMENTS_TXFEE - mtx.vout[i+1].nValue); |
|
|
|
mtx.vout[i+1].nValue = PAYMENTS_TXFEE; |
|
|
|
} */ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","value too small, try releasing a larger amount")); |
|
|
|
if ( params != 0 ) |
|
|
|
free_json(params); |
|
|
|
return(result); |
|
|
|
} |
|
|
|
totalamountsent += mtx.vout[i+1].nValue; |
|
|
|
} |
|
|
|
if ( totalamountsent < amount ) newamount = totalamountsent; |
|
|
@ -879,7 +936,7 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
{ |
|
|
|
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); |
|
|
|
CPubKey Paymentspk,mypk,txidpk; uint256 txid,hashBlock; int64_t amount,totalallocations; CScript opret; CTransaction tx; char txidaddr[64]; std::string rawtx; int32_t n,useopret = 0,lockedblocks,minrelease; std::vector<uint256> txidoprets; |
|
|
|
int32_t top,bottom; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
|
|
|
|
int32_t top,bottom,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
|
|
|
|
uint256 tokenid; int8_t fixedAmount; |
|
|
|
cJSON *params = payments_reparse(&n,jsonstr); |
|
|
|
mypk = pubkey2pk(Mypubkey()); |
|
|
@ -890,7 +947,7 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; |
|
|
|
if ( n == 3 ) |
|
|
|
useopret = jint(jitem(params,2),0) != 0; |
|
|
|
if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() == 1 || (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 && DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys) == 0 && DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 0) ) |
|
|
|
if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() == 1 || (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 && DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys) == 0 && DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 0) ) |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","invalid createtxid")); |
|
|
@ -942,6 +999,64 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
return(result); |
|
|
|
} |
|
|
|
|
|
|
|
UniValue PaymentsMerge(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
{ |
|
|
|
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); |
|
|
|
CPubKey Paymentspk,mypk,txidpk; uint256 createtxid,hashBlock; int64_t totalallocations,inputsum; CScript opret; CTransaction tx; char txidaddr[64],destaddr[64]; std::string rawtx; |
|
|
|
int32_t n,useopret = 0,lockedblocks,minrelease,top,bottom,minimum=10000,blocksleft; std::vector<uint256> txidoprets; |
|
|
|
std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
|
|
|
|
uint256 tokenid; int8_t fixedAmount; |
|
|
|
cJSON *params = payments_reparse(&n,jsonstr); |
|
|
|
mypk = pubkey2pk(Mypubkey()); |
|
|
|
Paymentspk = GetUnspendable(cp,0); |
|
|
|
if ( params != 0 && n == 1 ) |
|
|
|
{ |
|
|
|
createtxid = payments_juint256(jitem(params,0)); |
|
|
|
txidpk = CCtxidaddr(txidaddr,createtxid); |
|
|
|
if ( myGetTransaction(createtxid,tx,hashBlock) == 0 || tx.vout.size() == 1 || (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 && DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys) == 0 && DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 0) ) |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","invalid createtxid")); |
|
|
|
} |
|
|
|
else if ( (inputsum= AddPaymentsInputs(true,4,cp,mtx,txidpk,0,CC_MAXVINS,createtxid,lockedblocks,minrelease,blocksleft)) > 0 && mtx.vin.size() > 1 ) |
|
|
|
{ |
|
|
|
int32_t dust = blocksleft; |
|
|
|
if ( mtx.vin.size() != dust+1 ) |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","cannot merge only dust")); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// encode the checktxid into the end of the ccvout, along with 'M' to flag merge type tx.
|
|
|
|
opret = EncodePaymentsMergeOpRet(createtxid); |
|
|
|
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>(); |
|
|
|
if ( makeCCopret(opret, vData) ) |
|
|
|
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,inputsum-PAYMENTS_TXFEE,Paymentspk,&vData)); |
|
|
|
GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk); |
|
|
|
CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr); |
|
|
|
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); |
|
|
|
if ( params != 0 ) |
|
|
|
free_json(params); |
|
|
|
return(payments_rawtxresult(result,rawtx,1)); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","couldnt find enough funds")); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","parameters error")); |
|
|
|
} |
|
|
|
if ( params != 0 ) |
|
|
|
free_json(params); |
|
|
|
return(result); |
|
|
|
} |
|
|
|
|
|
|
|
UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
{ |
|
|
|
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); CPubKey mypk; std::string rawtx; |
|
|
@ -1062,7 +1177,7 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); |
|
|
|
UniValue result(UniValue::VOBJ); |
|
|
|
uint256 hashBlock; CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::string rawtx; |
|
|
|
int32_t lockedblocks,minrelease,top,bottom,n,i; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t fixedAmount; |
|
|
|
int32_t lockedblocks,minrelease,top,bottom,n,i,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t fixedAmount; |
|
|
|
if ( KOMODO_SNAPSHOT_INTERVAL == 0 ) |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
@ -1074,10 +1189,11 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
{ |
|
|
|
lockedblocks = juint(jitem(params,0),0); |
|
|
|
minrelease = juint(jitem(params,1),0); |
|
|
|
top = juint(jitem(params,2),0); |
|
|
|
bottom = juint(jitem(params,3),0); |
|
|
|
fixedAmount = juint(jitem(params,4),0); // fixed amount is a flag set to 0 or 1. It means allocations are equal rather than weighted by address balance.
|
|
|
|
if ( lockedblocks < 0 || minrelease < 0 || top <= 0 || bottom < 0 || fixedAmount < 0 || top > 3999 ) |
|
|
|
minimum = juint(jitem(params,2),0); |
|
|
|
top = juint(jitem(params,3),0); |
|
|
|
bottom = juint(jitem(params,4),0); |
|
|
|
fixedAmount = juint(jitem(params,5),0); // fixed amount is a flag, set to 7 does game mode, 0 normal snapshot, anything else fixed allocations.
|
|
|
|
if ( lockedblocks < 0 || minrelease < 0 || top <= 0 || bottom < 0 || minimum < 0 || fixedAmount < 0 || top > 3999 ) |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","negative parameter, or top over 3999")); |
|
|
@ -1085,15 +1201,15 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
free_json(params); |
|
|
|
return(result); |
|
|
|
} |
|
|
|
if ( n > 5 ) |
|
|
|
if ( n > 6 ) |
|
|
|
{ |
|
|
|
for (i=0; i<n-5; i++) |
|
|
|
for (i=0; i<n-6; i++) |
|
|
|
{ |
|
|
|
/* TODO: Change this RPC to take an address. Because a tokens airdrop needs its own RPC anyway.
|
|
|
|
CTxDestination destination = DecodeDestination(name_); |
|
|
|
CScript scriptPubKey = GetScriptForDestination(destination); |
|
|
|
*/ |
|
|
|
char *inputhex = jstri(params,3+i); |
|
|
|
char *inputhex = jstri(params,6+i); |
|
|
|
std::vector<uint8_t> scriptPubKey; |
|
|
|
int32_t len = strlen(inputhex)/2; |
|
|
|
scriptPubKey.resize(len); |
|
|
@ -1106,7 +1222,16 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
if ( AddNormalinputs(mtx,mypk,2*PAYMENTS_TXFEE,60) > 0 ) |
|
|
|
{ |
|
|
|
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,PAYMENTS_TXFEE,Paymentspk,Paymentspk)); |
|
|
|
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsSnapsShotOpRet(lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys)); |
|
|
|
CScript tempopret = EncodePaymentsSnapsShotOpRet(lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys); |
|
|
|
if ( tempopret.size() > 10000 ) // TODO: Check this!
|
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","op_return is too big, try with less exclude addresses.")); |
|
|
|
if ( params != 0 ) |
|
|
|
free_json(params); |
|
|
|
return(result); |
|
|
|
} |
|
|
|
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,tempopret); |
|
|
|
if ( params != 0 ) |
|
|
|
free_json(params); |
|
|
|
return(payments_rawtxresult(result,rawtx,1)); |
|
|
@ -1127,7 +1252,7 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
{ |
|
|
|
UniValue result(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx,txO; CPubKey Paymentspk,txidpk; int32_t i,j,n,flag=0,numoprets=0,lockedblocks,minrelease,blocksleft=0; std::vector<uint256> txidoprets; int64_t funds,fundsopret,elegiblefunds,totalallocations=0,allocation; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock; |
|
|
|
int32_t top,bottom; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
|
|
|
|
int32_t top,bottom,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
|
|
|
|
uint256 tokenid; int8_t fixedAmount; CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),komodo_nextheight()); |
|
|
|
cJSON *params = payments_reparse(&n,jsonstr); |
|
|
|
if ( params != 0 && n == 1 ) |
|
|
@ -1183,9 +1308,9 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
result.push_back(Pair("error","too many opreturns")); |
|
|
|
} else result.push_back(Pair("txidoprets",a)); |
|
|
|
} |
|
|
|
else if ( DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys) != 0 ) |
|
|
|
else if ( DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys) != 0 ) |
|
|
|
{ |
|
|
|
if ( lockedblocks < 0 || minrelease < 0 || top <= 0 || bottom < 0 || fixedAmount < 0 || top > 3999 ) |
|
|
|
if ( lockedblocks < 0 || minrelease < 0 || top <= 0 || bottom < 0 || fixedAmount < 0 || top > 3999 || minimum < 10000 ) |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","negative parameter")); |
|
|
@ -1199,6 +1324,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
result.push_back(Pair("plan_type","snapshot")); |
|
|
|
result.push_back(Pair("lockedblocks",(int64_t)lockedblocks)); |
|
|
|
result.push_back(Pair("minrelease",(int64_t)minrelease)); |
|
|
|
result.push_back(Pair("minimum",(int64_t)minimum)); |
|
|
|
result.push_back(Pair("bottom",(int64_t)bottom)); |
|
|
|
result.push_back(Pair("top",(int64_t)top)); |
|
|
|
result.push_back(Pair("fixedFlag",(int64_t)fixedAmount)); |
|
|
@ -1272,7 +1398,7 @@ UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
{ |
|
|
|
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; uint256 txid,hashBlock,tokenid; |
|
|
|
UniValue result(UniValue::VOBJ),a(UniValue::VARR); char markeraddr[64],str[65]; CPubKey Paymentspk; CTransaction tx; int32_t lockedblocks,minrelease; std::vector<uint256> txidoprets; int64_t totalallocations=0; |
|
|
|
int32_t top=0,bottom=0; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t fixedAmount = 0; |
|
|
|
int32_t top=0,bottom=0,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t fixedAmount = 0; |
|
|
|
Paymentspk = GetUnspendable(cp,0); |
|
|
|
GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk); |
|
|
|
SetCCtxids(addressIndex,markeraddr,true); |
|
|
@ -1281,9 +1407,9 @@ UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr) |
|
|
|
txid = it->first.txhash; |
|
|
|
if ( it->first.index == 0 && myGetTransaction(txid,tx,hashBlock) != 0 ) |
|
|
|
{ |
|
|
|
if ( tx.vout.size() > 0 && (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 'C' || DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys) == 'S' || DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 'O') ) |
|
|
|
if ( tx.vout.size() > 0 && (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 'C' || DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys) == 'S' || DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 'O') ) |
|
|
|
{ |
|
|
|
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) || bottom < 0 || fixedAmount < 0 ) |
|
|
|
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) || bottom < 0 || fixedAmount < 0 || minimum < 10000 ) |
|
|
|
{ |
|
|
|
result.push_back(Pair("result","error")); |
|
|
|
result.push_back(Pair("error","negative parameter")); |
|
|
|