From 2a0ae738743a250622b5d3f8266aa51b6878889c Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Mon, 29 Apr 2019 22:45:56 +0800 Subject: [PATCH] payments Airdrop. Working airdrop and syncs TESTHC chain. --- src/cc/CCPayments.h | 2 + src/cc/CCutils.cpp | 2 +- src/cc/eval.cpp | 9 + src/cc/payments.cpp | 541 +++++++++++++++++++++++++++++---------- src/main.cpp | 24 +- src/wallet/rpcwallet.cpp | 14 +- 6 files changed, 425 insertions(+), 167 deletions(-) diff --git a/src/cc/CCPayments.h b/src/cc/CCPayments.h index 3f5a10087..cff304a2e 100644 --- a/src/cc/CCPayments.h +++ b/src/cc/CCPayments.h @@ -18,6 +18,7 @@ #define CC_PAYMENTS_H #include "CCinclude.h" +#include #define PAYMENTS_TXFEE 10000 extern std::vector > vAddressSnapshot; @@ -34,3 +35,4 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr); UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr); #endif + diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 65b390c41..acf0da766 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -74,7 +74,7 @@ CScript getCCopret(const CScript &scriptPubKey) { std::vector> vParams = std::vector>(); CScript dummy; CScript opret; - if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) ) + if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() == 1 ) { //fprintf(stderr, "vparams.%s\n", HexStr(vParams[0].begin(), vParams[0].end()).c_str()); opret = CScript(vParams[0].begin()+6, vParams[0].end()); diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 62f020063..a23a7b16c 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -53,6 +53,15 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn) eval->state.GetRejectReason().data(), tx.vin[nIn].prevout.hash.GetHex().data()); if (eval->state.IsError()) fprintf(stderr, "Culprit: %s\n", EncodeHexTx(tx).data()); + CTransaction tmp; + if (mempool.lookup(tx.GetHash(), tmp)) + { + // This is to remove a payments airdrop if it gets stuck in the mempool. + // Miner will mine 1 invalid block, but doesnt stop them mining until a restart. + // This would almost never happen in normal use. + std::list dummy; + mempool.remove(tx,dummy,true); + } return false; } diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 569c4eb14..e72184719 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -16,6 +16,14 @@ #include "CCPayments.h" /* +192.168.0.139: RH side screen. + ./komodod -ac_name=TESTDP -ac_supply=10000000 -ac_reward=1000000000 -ac_nk=96,5 -ac_blocktime=20 -ac_cc=2 -addndoe=192.168.0.112 + - TESTDP.tar saved after distributing funds randomly. approx block 120. +LH screen: + ./komodod -ac_name=TESTDP -ac_supply=10000000 -ac_reward=1000000000 -ac_nk=96,5 -ac_blocktime=20 -ac_cc=2 -pubkey=0244a96824fa317433f0eaa6d5b1faf68e802b1958df273c24cb82bce1ef8e1aec -gen -genproclimit=1 + +./komodo-cli -ac_name=TESTDP paymentsairdrop '[10,2000,500,"76a9149758abb81ee168dd3824cb55e94df509b35462d788ac",76a9144cfd873dadbfbb4b9c03e77ecaa6cfb74a484f4888ac"]' + use notarizations DB to scan back from the correct height, then undo ALL blocks back to this notarized height! payments airdrop: - extra RPC to merge all payments inputs to a single utxo, this must be called first and be confirmed before payments release, @@ -144,12 +152,53 @@ uint8_t DecodePaymentsOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t & script = (uint8_t *)vopret.data(); if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> totalallocations; ss >> txidoprets) != 0 ) { - if ( e == EVAL_PAYMENTS && f == 'C' ) + if ( e == EVAL_PAYMENTS && f == 'C' && txidoprets.size() > 1 ) return(f); } return(0); } + +CScript EncodePaymentsSnapsShotOpRet(int32_t lockedblocks,int32_t minrelease,int32_t top,std::vector> excludeScriptPubKeys) +{ + CScript opret; uint8_t evalcode = EVAL_PAYMENTS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << top << excludeScriptPubKeys); + return(opret); +} + +uint8_t DecodePaymentsSnapsShotOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &top,std::vector> &excludeScriptPubKeys) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> top; ss >> excludeScriptPubKeys) != 0 ) + { + if ( e == EVAL_PAYMENTS && f == 'S' ) + return(f); + } + return(0); +} + +CScript EncodePaymentsTokensOpRet(int32_t lockedblocks,int32_t minrelease,int32_t top,std::vector> excludeScriptPubKeys, uint256 tokenid) +{ + CScript opret; uint8_t evalcode = EVAL_PAYMENTS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'O' << lockedblocks << minrelease << top << excludeScriptPubKeys << tokenid); + return(opret); +} + +uint8_t DecodePaymentsTokensOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &top,std::vector> &excludeScriptPubKeys, uint256 &tokenid) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> top; ss >> excludeScriptPubKeys; ss >> tokenid) != 0 ) + { + if ( e == EVAL_PAYMENTS && f == 'O' ) + return(f); + } + return(0); +} + int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr) { char destaddr[64]; @@ -184,8 +233,10 @@ 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; CTransaction tmptx; + char temp[128], coinaddr[64], txidaddr[64]; std::string scriptpubkey; uint256 createtxid, blockhash, tokenid; CTransaction plantx; uint8_t funcid = 0; int32_t i,lockedblocks,minrelease; int64_t change,totalallocations; std::vector txidoprets; bool fHasOpret = false; CPubKey txidpk,Paymentspk; + int32_t top; std::vector> excludeScriptPubKeys; + 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")); @@ -200,13 +251,15 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & //printf("createtxid.%s\n",createtxid.ToString().c_str()); // use the createtxid to fetch the tx and all of the plans info. - if ( myGetTransaction(createtxid,tmptx,blockhash) != 0 ) - { - if ( tmptx.vout.size() > 0 && DecodePaymentsOpRet(tmptx.vout[tmptx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 ) + 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,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(plantx.vout[plantx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid)) == 'O') ) { - if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) + if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 ) return(eval->Invalid("negative values")); 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"); @@ -215,65 +268,101 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & std::vector scriptPubKeys; int64_t checkallocations = 0; i = 0; - BOOST_FOREACH(const uint256& txidopret, txidoprets) + if ( funcid == 'C' ) { - CTransaction tx0; std::vector scriptPubKey,opret; int64_t allocation; - if ( myGetTransaction(txidopret,tx0,blockhash) != 0 && tx0.vout.size() > 1 && DecodePaymentsTxidOpRet(tx0.vout[tx0.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) + // normal payment + for (const uint256& txidopret : txidoprets) { - scriptPubKeys.push_back(CScript(scriptPubKey.begin(), scriptPubKey.end())); - allocations.push_back(allocation); - //fprintf(stderr, "i.%i scriptpubkey.%s allocation.%li\n",i,scriptPubKeys[i].ToString().c_str(),allocation); - checkallocations += allocation; - // if we have an op_return to pay to need to check it exists and is paying the correct opret. - if ( !opret.empty() ) + CTransaction tx0; std::vector scriptPubKey,opret; int64_t allocation; + if ( myGetTransaction(txidopret,tx0,blockhash) != 0 && tx0.vout.size() > 1 && DecodePaymentsTxidOpRet(tx0.vout[tx0.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) { - if ( !fHasOpret ) + scriptPubKeys.push_back(CScript(scriptPubKey.begin(), scriptPubKey.end())); + allocations.push_back(allocation); + //fprintf(stderr, "i.%i scriptpubkey.%s allocation.%li\n",i,scriptPubKeys[i].ToString().c_str(),allocation); + checkallocations += allocation; + // if we have an op_return to pay to need to check it exists and is paying the correct opret. + if ( !opret.empty() ) { - fprintf(stderr, "missing opret.%s in payments release.\n",HexStr(opret.begin(), opret.end()).c_str()); - return(eval->Invalid("missing opret in payments release")); - } - else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey ) - { - fprintf(stderr, "opret.%s vs opret.%s\n",HexStr(opret.begin(), opret.end()).c_str(), HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin(), tx.vout[tx.vout.size()-1].scriptPubKey.end()).c_str()); - return(eval->Invalid("pays incorrect opret")); + if ( !fHasOpret ) + { + fprintf(stderr, "missing opret.%s in payments release.\n",HexStr(opret.begin(), opret.end()).c_str()); + return(eval->Invalid("missing opret in payments release")); + } + else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey ) + { + fprintf(stderr, "opret.%s vs opret.%s\n",HexStr(opret.begin(), opret.end()).c_str(), HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin(), tx.vout[tx.vout.size()-1].scriptPubKey.end()).c_str()); + return(eval->Invalid("pays incorrect opret")); + } } } + i++; } - i++; + mpz_set_si(mpzTotalAllocations,totalallocations); + } + else if ( funcid == 'S' ) + { + // need time for TX to me mined before the next snapshot. + if ( top > 5000 ) + return(eval->Invalid("transaction too big")); + for ( auto address : vAddressSnapshot ) + { + CScript scriptPubKey = GetScriptForDestination(address.second); + for ( auto skipkey : excludeScriptPubKeys ) + { + //fprintf(stderr, "scriptpubkey.%s\n skipkey.%s", HexStr(scriptPubKey).c_str(), HexStr(CScript(skipkey.begin(), skipkey.end())).c_str()); + if ( scriptPubKey != CScript(skipkey.begin(), skipkey.end()) ) + { + mpz_init(mpzAllocation); + i++; + scriptPubKeys.push_back(scriptPubKey); + allocations.push_back(address.first); + mpz_set_si(mpzAllocation,address.first); + mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation); + mpz_clear(mpzAllocation); + } + } + if ( i == top ) // we reached top amount to pay, it can be less than this! + break; + } + if ( i != tx.vout.size()-2 ) + return(eval->Invalid("pays wrong amount of recipients")); + } + else if ( funcid == 'O' ) + { + // tokens snapshot. } - // sanity check to make sure we got all the required info + //fprintf(stderr, " allocations.size().%li scriptPubKeys.size.%li\n",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 ( totalallocations != checkallocations ) + if ( funcid == 'C' && totalallocations != checkallocations ) // only check for normal payments release. return(eval->Invalid("allocation missmatch")); - - txidpk = CCtxidaddr(txidaddr,createtxid); - GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk); - //fprintf(stderr, "coinaddr.%s\n", coinaddr); - + // 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; + int64_t amount = 0, checkamount; int32_t n = 0; checkamount = tx.GetValueOut() - change - PAYMENTS_TXFEE; + mpz_t mpzCheckamount; mpz_init(mpzCheckamount); mpz_set_si(mpzCheckamount,checkamount); for (i = 1; i < (fHasOpret ? tx.vout.size()-2 : tx.vout.size()-1); i++) { - std::string destscriptPubKey = HexStr(scriptPubKeys[n].begin(),scriptPubKeys[n].end()); - std::string voutscriptPubKey = HexStr(tx.vout[i].scriptPubKey.begin(),tx.vout[i].scriptPubKey.end()); - if ( destscriptPubKey != voutscriptPubKey ) + if ( scriptPubKeys[n] != tx.vout[i].scriptPubKey ) { - fprintf(stderr, "pays wrong destination destscriptPubKey.%s voutscriptPubKey.%s\n", destscriptPubKey.c_str(), voutscriptPubKey.c_str()); + fprintf(stderr, "pays wrong destination destscriptPubKey.%s voutscriptPubKey.%s\n", HexStr(scriptPubKeys[n].begin(),scriptPubKeys[n].end()).c_str(), HexStr(tx.vout[i].scriptPubKey.begin(),tx.vout[i].scriptPubKey.end()).c_str()); return(eval->Invalid("pays wrong address")); } - int64_t test = allocations[n]; - test *= checkamount; - test /= totalallocations; - if ( test != tx.vout[i].nValue && test != tx.vout[i].nValue-1 ) + mpz_init(mpzAllocation); + mpz_set_si(mpzAllocation,allocations[n]); + mpz_mul(mpzAllocation,mpzAllocation,mpzCheckamount); + mpz_cdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations); + int64_t test = mpz_get_si(mpzAllocation); + mpz_clear(mpzAllocation); + // Vairance of 1 sat is allowed, for rounding errors. + if ( test >= tx.vout[i].nValue+1 && test <= tx.vout[i].nValue-1 ) { fprintf(stderr, "vout.%i test.%li vs nVlaue.%li\n",i, test, tx.vout[i].nValue); return(eval->Invalid("amounts do not match")); @@ -281,6 +370,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & amount += tx.vout[i].nValue; n++; } + mpz_clear(mpzTotalAllocations); // This is a backup check to make sure there are no extra vouts paying something else! if ( checkamount != amount ) return(eval->Invalid("amounts do not match")); @@ -291,6 +381,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return(eval->Invalid("amount is too small")); } + // Check vins i = 0; int32_t ht = chainActive.LastTip()->GetHeight(); BOOST_FOREACH(const CTxIn& vin, tx.vin) @@ -303,17 +394,12 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey); 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; if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 ) - { - // get op_return from CCvout, - opret = getCCopret(txin.vout[vin.prevout.n].scriptPubKey); - } + opret = getCCopret(txin.vout[vin.prevout.n].scriptPubKey); // get op_return from CCvout, else - { - // get op_return from the op_return - opret = txin.vout[opret_ind].scriptPubKey; - } + opret = txin.vout[opret_ind].scriptPubKey; if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str()); @@ -404,6 +490,7 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) break; } //else fprintf(stderr,"nValue %.8f vs threshold %.8f\n",(double)nValue/COIN,(double)threshold/COIN); + iter++; } } } @@ -482,8 +569,10 @@ int32_t payments_parsehexdata(std::vector &hexdata,cJSON *item,int32_t 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; - CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease; int64_t newamount,inputsum,amount,CCchange=0,totalallocations,checkallocations=0,allocation; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector txidoprets; + 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 txidoprets; + int32_t top; std::vector> excludeScriptPubKeys; int8_t funcid; + mpz_t mpzTotalAllocations; mpz_init(mpzTotalAllocations); cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); Paymentspk = GetUnspendable(cp,0); @@ -491,14 +580,16 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) { createtxid = payments_juint256(jitem(params,0)); amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; - if ( myGetTransaction(createtxid,tx,hashBlock) != 0 ) + if ( myGetTransaction(createtxid,tx,hashBlock) != 0 && tx.vout.size() > 0 ) { - if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 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,excludeScriptPubKeys)) == 'S' || (funcid= DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid)) == 'O') ) { - if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) + if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","negative parameter")); + if ( params != 0 ) + free_json(params); return(result); } latestheight = (nextheight - lockedblocks - 1); @@ -508,94 +599,163 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) result.push_back(Pair("error","amount too smal")); result.push_back(Pair("amount",ValueFromAmount(amount))); result.push_back(Pair("minrelease",ValueFromAmount(minrelease*COIN))); + if ( params != 0 ) + free_json(params); return(result); } txidpk = CCtxidaddr(txidaddr,createtxid); mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk)); - m = txidoprets.size(); - for (i=0; i scriptPubKey,opret; - vout.nValue = 0; - if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) + // normal payments + for (i=0; i 0 ) + std::vector scriptPubKey,opret; + vout.nValue = 0; + if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) { - onlyopret.resize(opret.size()); - memcpy(&onlyopret[0],&opret[0],opret.size()); - numoprets++; + vout.nValue = allocation; + vout.scriptPubKey.resize(scriptPubKey.size()); + memcpy(&vout.scriptPubKey[0],&scriptPubKey[0],scriptPubKey.size()); + checkallocations += allocation; + if ( opret.size() > 0 ) + { + onlyopret.resize(opret.size()); + memcpy(&onlyopret[0],&opret[0],opret.size()); + numoprets++; + } + } else break; + mtx.vout.push_back(vout); + } + result.push_back(Pair("numoprets",(int64_t)numoprets)); + if ( i != m ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid txidoprets[i]")); + result.push_back(Pair("txi",(int64_t)i)); + if ( params != 0 ) + free_json(params); + return(result); + } + else if ( checkallocations != totalallocations ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","totalallocations mismatch")); + result.push_back(Pair("checkallocations",(int64_t)checkallocations)); + result.push_back(Pair("totalallocations",(int64_t)totalallocations)); + if ( params != 0 ) + free_json(params); + return(result); + } + else if ( numoprets > 1 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","too many oprets")); + if ( params != 0 ) + free_json(params); + return(result); + } + // set totalallocations to a mpz_t bignum, for amounts calculation later. + mpz_set_si(mpzTotalAllocations,totalallocations); + } + else if ( funcid = 'S' ) + { + // normal snapshot + i = 0; + if ( top > 5000 ) + { + // need to test the maximum number, this is an estimate. + result.push_back(Pair("result","error")); + result.push_back(Pair("error","cannot pay more than 5000 addresses")); + if ( params != 0 ) + free_json(params); + return(result); + } + for ( auto address : vAddressSnapshot ) + { + CScript scriptPubKey = GetScriptForDestination(address.second); + for ( auto skipkey : excludeScriptPubKeys ) + { + if ( scriptPubKey != CScript(skipkey.begin(), skipkey.end()) ) + { + mpz_t mpzAllocation; mpz_init(mpzAllocation); + i++; + //fprintf(stderr, "address: %s nValue.%li \n", CBitcoinAddress(address.second).ToString().c_str(), address.first); + vout.nValue = address.first; + vout.scriptPubKey = scriptPubKey; + mpz_set_si(mpzAllocation,address.first); + mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation); //totalallocations += address.first; + mtx.vout.push_back(vout); + mpz_clear(mpzAllocation); + } else fprintf(stderr, "SKIPPED::: %s\n", CBitcoinAddress(address.second).ToString().c_str()); } - } else break; - mtx.vout.push_back(vout); + if ( i == top ) // we reached top amount to pay, it can be less than this! + break; + } + m = i; // this is the amount we got, either top, or all of the address on the chain. } - result.push_back(Pair("numoprets",(int64_t)numoprets)); - if ( i != m ) + else if ( funcid = 'O' ) { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","invalid txidoprets[i]")); - result.push_back(Pair("txi",(int64_t)i)); - if ( params != 0 ) - free_json(params); - return(result); - } - else if ( checkallocations != totalallocations ) - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","totalallocations mismatch")); - result.push_back(Pair("checkallocations",(int64_t)checkallocations)); - result.push_back(Pair("totalallocations",(int64_t)totalallocations)); - if ( params != 0 ) - free_json(params); - return(result); - } - else if ( numoprets > 1 ) - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","too many oprets")); - if ( params != 0 ) - free_json(params); - return(result); + // token snapshot } newamount = amount; + int64_t totalamountsent = 0; + mpz_t mpzAmount; mpz_init(mpzAmount); mpz_set_si(mpzAmount,amount); for (i=0; i= newamount+2*PAYMENTS_TXFEE ) - { - std::string rawtx; - if ( (CCchange= (inputsum - newamount - 2*PAYMENTS_TXFEE)) >= PAYMENTS_TXFEE ) - mtx.vout[0].nValue = CCchange; - mtx.vout.push_back(CTxOut(PAYMENTS_TXFEE,CScript() << ParseHex(HexStr(txidpk)) << OP_CHECKSIG)); - GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk); - CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret); - if ( params != 0 ) - free_json(params); - result.push_back(Pair("amount",ValueFromAmount(amount))); - result.push_back(Pair("newamount",ValueFromAmount(newamount))); - return(payments_rawtxresult(result,rawtx,1)); - } - else - { - result.push_back(Pair("result","error")); - result.push_back(Pair("error","couldnt find enough locked funds")); - } + //fprintf(stderr, "newamount.%li totalamountsent.%li\n", newamount, totalamountsent); + mpz_clear(mpzAmount); mpz_clear(mpzTotalAllocations); } else { result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt decode paymentscreate txid opret")); + if ( params != 0 ) + free_json(params); + return(result); + } + if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE ) + { + std::string rawtx; + if ( (CCchange= (inputsum - newamount - 2*PAYMENTS_TXFEE)) >= PAYMENTS_TXFEE ) + mtx.vout[0].nValue = CCchange; + mtx.vout.push_back(CTxOut(PAYMENTS_TXFEE,CScript() << ParseHex(HexStr(txidpk)) << OP_CHECKSIG)); + GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk); + CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret); + if ( params != 0 ) + free_json(params); + result.push_back(Pair("amount",ValueFromAmount(amount))); + result.push_back(Pair("newamount",ValueFromAmount(newamount))); + return(payments_rawtxresult(result,rawtx,0)); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt find enough locked funds")); } } else @@ -618,6 +778,8 @@ 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 txidoprets; + int32_t top; std::vector> excludeScriptPubKeys; // snapshot + uint256 tokenid; cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); Paymentspk = GetUnspendable(cp,0); @@ -627,14 +789,14 @@ 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 ) + 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,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 ( AddNormalinputs(mtx,mypk,amount+PAYMENTS_TXFEE,60) > 0 ) { - if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) + if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","negative parameter")); @@ -650,13 +812,13 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) else { mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk)); + opret = EncodePaymentsFundOpRet(txid); // Use the below one along with other FinalizeCCTx/return, to get the ccvout scriptpubkey - /*opret = EncodePaymentsFundOpRet(txid); - std::vector> vData = std::vector>(); + /*std::vector> vData = std::vector>(); if ( makeCCopret(opret, vData) ) mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); */ } - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsFundOpRet(txid)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret); //rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); // use this one to get ccvout scriptpubkey. if ( params != 0 ) free_json(params); @@ -796,22 +958,73 @@ UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) { - uint64_t start = time(NULL); - - return(time(NULL)-start); + 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,n,i; std::vector> excludeScriptPubKeys; + cJSON *params = payments_reparse(&n,jsonstr); + if ( params != 0 && n >= 4 ) + { + lockedblocks = juint(jitem(params,0),0); + minrelease = juint(jitem(params,1),0); + top = juint(jitem(params,2),0); + if ( lockedblocks < 0 || minrelease < 0 || top < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + if ( params != 0 ) + free_json(params); + return(result); + } + for (i=0; i scriptPubKey; + int32_t len = strlen(inputhex)/2; + scriptPubKey.resize(len); + decode_hex((uint8_t *)scriptPubKey.data(),len,(char *)inputhex); + excludeScriptPubKeys.push_back(scriptPubKey); + } + mypk = pubkey2pk(Mypubkey()); + Paymentspk = GetUnspendable(cp,0); + 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,excludeScriptPubKeys)); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,0)); + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough normal funds")); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","parameters error")); + } + if ( params != 0 ) + free_json(params); + return(result); } 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; std::vector txidoprets; int64_t funds,fundsopret,totalallocations=0,allocation; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock; + int32_t top; std::vector> excludeScriptPubKeys; // snapshot + uint256 tokenid; cJSON *params = payments_reparse(&n,jsonstr); if ( params != 0 && n == 1 ) { Paymentspk = GetUnspendable(cp,0); createtxid = payments_juint256(jitem(params,0)); - if ( myGetTransaction(createtxid,tx,hashBlock) != 0 ) + if ( myGetTransaction(createtxid,tx,hashBlock) != 0 && tx.vout.size() > 0 ) { - if ( tx.vout.size() > 0 && DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 ) + if ( DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 ) { if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) { @@ -821,6 +1034,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) free_json(params); return(result); } + result.push_back(Pair("plan_type","payments")); result.push_back(Pair("lockedblocks",(int64_t)lockedblocks)); result.push_back(Pair("totalallocations",(int64_t)totalallocations)); result.push_back(Pair("minrelease",(int64_t)minrelease)); @@ -849,29 +1063,71 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) } else fprintf(stderr,"error decoding voutsize.%d\n",(int32_t)txO.vout.size()); a.push_back(obj); } - flag++; result.push_back(Pair("numoprets",(int64_t)numoprets)); if ( numoprets > 1 ) { + flag++; result.push_back(Pair("result","error")); result.push_back(Pair("error","too many opreturns")); - } - else + } else result.push_back(Pair("txidoprets",a)); + } + else if ( DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys) != 0 ) + { + if ( lockedblocks < 0 || minrelease < 0 || top <= 0 ) { - result.push_back(Pair("txidoprets",a)); - txidpk = CCtxidaddr(txidaddr,createtxid); - GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk); - funds = CCaddress_balance(fundsaddr,1); - result.push_back(Pair(fundsaddr,ValueFromAmount(funds))); - GetCCaddress(cp,fundsopretaddr,Paymentspk); - fundsopret = CCaddress_balance(fundsopretaddr,1); // Shows balance for ALL payments plans, not just the one asked for! - result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret))); - result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret))); - result.push_back(Pair("result","success")); + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + if ( params != 0 ) + free_json(params); + return(result); } + 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("top",(int64_t)top)); + for ( auto scriptPubKey : excludeScriptPubKeys ) + a.push_back(HexStr(scriptPubKey.begin(),scriptPubKey.end())); + result.push_back(Pair("excludeScriptPubkeys",a)); + } + else if ( DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) != 0 ) + { + if ( lockedblocks < 0 || minrelease < 0 || top <= 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","negative parameter")); + if ( params != 0 ) + free_json(params); + return(result); + } + result.push_back(Pair("plan_type","token snapshot")); + result.push_back(Pair("lockedblocks",(int64_t)lockedblocks)); + result.push_back(Pair("minrelease",(int64_t)minrelease)); + result.push_back(Pair("top",(int64_t)top)); + result.push_back(Pair("tokenid",tokenid.ToString())); + for ( auto scriptPubKey : excludeScriptPubKeys ) + a.push_back(HexStr(scriptPubKey.begin(),scriptPubKey.end())); + result.push_back(Pair("excludeScriptPubkeys",a)); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt decode valid payments create txid opreturn")); + } + if ( flag == 0 ) + { + txidpk = CCtxidaddr(txidaddr,createtxid); + GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk); + funds = CCaddress_balance(fundsaddr,1); + result.push_back(Pair(fundsaddr,ValueFromAmount(funds))); + GetCCaddress(cp,fundsopretaddr,Paymentspk); + // TODO: Shows balance for ALL payments plans, not just the one asked for! Needs to be reworked. + fundsopret = CCaddress_balance(fundsopretaddr,1); + result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret))); + result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret))); + result.push_back(Pair("result","success")); } } - if ( flag == 0 ) + else { result.push_back(Pair("result","error")); result.push_back(Pair("error","couldnt find valid payments create txid")); @@ -889,8 +1145,9 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr) { - std::vector > addressIndex; uint256 txid,hashBlock; + std::vector > 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 txidoprets; int64_t totalallocations; + int32_t top; std::vector> excludeScriptPubKeys; Paymentspk = GetUnspendable(cp,0); GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk); SetCCtxids(addressIndex,markeraddr,true); @@ -899,7 +1156,7 @@ 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' ) + 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,excludeScriptPubKeys) == 'S' || DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 'O') ) { if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) { diff --git a/src/main.cpp b/src/main.cpp index 8bace2cb0..3168b773c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -656,6 +656,7 @@ std::vector > vAddressSnapshot; bool komodo_dailysnapshot(int32_t height) { + int reorglimit = 10; // CHANGE BACK TO 100 AFTER TESTING! uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,undo_height,extraoffset; if ( (extraoffset= height % KOMODO_SNAPSHOT_INTERVAL) != 0 ) { @@ -663,25 +664,16 @@ bool komodo_dailysnapshot(int32_t height) // use the notarizationsDB to scan back from the consesnus height to get the offset we need. std::string symbol; Notarisation nota; symbol.assign(ASSETCHAINS_SYMBOL); - ScanNotarisationsDB(height-extraoffset, symbol, 100, nota); - undo_height = nota.second.height; - if ( undo_height == 0 ) undo_height = height-extraoffset-100; - fprintf(stderr, "height.%i-extraoffset.%i = startscanfrom.%i to get undo_height.%i\n", height, extraoffset, height-extraoffset, undo_height); + if ( ScanNotarisationsDB(height-extraoffset, symbol, 100, nota) == 0 ) + undo_height = height-extraoffset-reorglimit; + else undo_height = nota.second.height; + //fprintf(stderr, "height.%i-extraoffset.%i = startscanfrom.%i to get undo_height.%i\n", height, extraoffset, height-extraoffset, undo_height); } else { // we are at the right height in connect block to scan back to last notarized height. notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); - if ( notarized_height > height-100 ) - { - // notarized height is higher than 100 blocks before this height, so snapshot the notarized height. - undo_height = notarized_height; - } - else - { - //snapshot 100 blocks ago. Could still be reorged but very unlikley and expensive to carry out constantly. - undo_height = height-100; - } + notarized_height > height-100 ? undo_height = notarized_height : undo_height = height-reorglimit; } fprintf(stderr, "doing snapshot for height.%i undo_height.%i\n", height, undo_height); // if we already did this height dont bother doing it again, this is just a reorg. The actual snapshot height cannot be reorged. @@ -702,9 +694,7 @@ bool komodo_dailysnapshot(int32_t height) for (int32_t i = block.vtx.size() - 1; i >= 0; i--) { const CTransaction &tx = block.vtx[i]; - uint256 hash = tx.GetHash(); CTxDestination vDest; - //fprintf(stderr, "undong tx.%s\n",hash.GetHex().c_str()); // loop vouts reverse order, remove value recieved. for (unsigned int k = tx.vout.size(); k-- > 0;) { @@ -721,7 +711,7 @@ bool komodo_dailysnapshot(int32_t height) for (unsigned int j = tx.vin.size(); j-- > 0;) { uint256 blockhash; CTransaction txin; - if ( !tx.IsCoinImport() && !tx.IsCoinBase() && myGetTransaction(tx.vin[j].prevout.hash,txin,blockhash) ) // myGetTransaction! + if ( !tx.IsCoinImport() && !tx.IsCoinBase() && myGetTransaction(tx.vin[j].prevout.hash,txin,blockhash) ) { int vout = tx.vin[j].prevout.n; if ( ExtractDestination(txin.vout[vout].scriptPubKey, vDest) ) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 66c534f11..8733b2894 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5632,14 +5632,14 @@ UniValue payments_create(const UniValue& params, bool fHelp) UniValue payments_airdrop(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; - //if ( fHelp || params.size() != 1 ) - // throw runtime_error("paymentscreate \"[lockedblocks,minamount,%22paytxid0%22,...,%22paytxidN%22]\"\n"); - //if ( ensure_CCrequirements(EVAL_PAYMENTS) < 0 ) - // 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; + if ( fHelp || params.size() != 1 ) + throw runtime_error("paymentsairdrop \"[lockedblocks,minamount,top,%22paytxid0%22,...,%22paytxidN%22]\"\n"); + if ( ensure_CCrequirements(EVAL_PAYMENTS) < 0 ) + 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); - //cp = CCinit(&C,EVAL_PAYMENTS); - return(PaymentsAirdrop(0,(char *)params[0].get_str().c_str())); + cp = CCinit(&C,EVAL_PAYMENTS); + return(PaymentsAirdrop(cp,(char *)params[0].get_str().c_str())); } UniValue payments_info(const UniValue& params, bool fHelp)