payments Airdrop. Working airdrop and syncs TESTHC chain.

This commit is contained in:
blackjok3r
2019-04-29 22:45:56 +08:00
parent 8b70bbf307
commit 2a0ae73874
6 changed files with 425 additions and 167 deletions

View File

@@ -18,6 +18,7 @@
#define CC_PAYMENTS_H #define CC_PAYMENTS_H
#include "CCinclude.h" #include "CCinclude.h"
#include <gmp.h>
#define PAYMENTS_TXFEE 10000 #define PAYMENTS_TXFEE 10000
extern std::vector <std::pair<CAmount, CTxDestination>> vAddressSnapshot; extern std::vector <std::pair<CAmount, CTxDestination>> vAddressSnapshot;
@@ -34,3 +35,4 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr); UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr);
#endif #endif

View File

@@ -74,7 +74,7 @@ CScript getCCopret(const CScript &scriptPubKey)
{ {
std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>(); std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
CScript dummy; CScript opret; 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()); //fprintf(stderr, "vparams.%s\n", HexStr(vParams[0].begin(), vParams[0].end()).c_str());
opret = CScript(vParams[0].begin()+6, vParams[0].end()); opret = CScript(vParams[0].begin()+6, vParams[0].end());

View File

@@ -53,6 +53,15 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
eval->state.GetRejectReason().data(), eval->state.GetRejectReason().data(),
tx.vin[nIn].prevout.hash.GetHex().data()); tx.vin[nIn].prevout.hash.GetHex().data());
if (eval->state.IsError()) fprintf(stderr, "Culprit: %s\n", EncodeHexTx(tx).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<CTransaction> dummy;
mempool.remove(tx,dummy,true);
}
return false; return false;
} }

View File

@@ -16,6 +16,14 @@
#include "CCPayments.h" #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! use notarizations DB to scan back from the correct height, then undo ALL blocks back to this notarized height!
payments airdrop: payments airdrop:
- extra RPC to merge all payments inputs to a single utxo, this must be called first and be confirmed before payments release, - 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(); 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 ( 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(f);
} }
return(0); return(0);
} }
CScript EncodePaymentsSnapsShotOpRet(int32_t lockedblocks,int32_t minrelease,int32_t top,std::vector<std::vector<uint8_t>> 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<std::vector<uint8_t>> &excludeScriptPubKeys)
{
std::vector<uint8_t> 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<std::vector<uint8_t>> 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<std::vector<uint8_t>> &excludeScriptPubKeys, uint256 &tokenid)
{
std::vector<uint8_t> 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) int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr)
{ {
char destaddr[64]; char destaddr[64];
@@ -184,8 +233,10 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
// change is/must be in vout[0] // change is/must be in vout[0]
// only 'F' or 1of2 txidaddr can be spent // only 'F' or 1of2 txidaddr can be spent
// all vouts must match exactly // 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<uint256> txidoprets; bool fHasOpret = false; CPubKey txidpk,Paymentspk; int32_t i,lockedblocks,minrelease; int64_t change,totalallocations; std::vector<uint256> txidoprets; bool fHasOpret = false; CPubKey txidpk,Paymentspk;
int32_t top; std::vector<std::vector<uint8_t>> excludeScriptPubKeys;
mpz_t mpzTotalAllocations, mpzAllocation;; mpz_init(mpzTotalAllocations);
// user marker vout to get the createtxid // user marker vout to get the createtxid
if ( tx.vout.size() < 2 ) if ( tx.vout.size() < 2 )
return(eval->Invalid("not enough vouts")); 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()); //printf("createtxid.%s\n",createtxid.ToString().c_str());
// use the createtxid to fetch the tx and all of the plans info. // use the createtxid to fetch the tx and all of the plans info.
if ( myGetTransaction(createtxid,tmptx,blockhash) != 0 ) if ( myGetTransaction(createtxid,plantx,blockhash) != 0 && plantx.vout.size() > 0 )
{ {
if ( tmptx.vout.size() > 0 && DecodePaymentsOpRet(tmptx.vout[tmptx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 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")); return(eval->Invalid("negative values"));
Paymentspk = GetUnspendable(cp,0); 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() ); //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) ) if ( !CheckTxFee(tx, PAYMENTS_TXFEE+1, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) )
return eval->Invalid("txfee is too high"); return eval->Invalid("txfee is too high");
@@ -215,65 +268,101 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
std::vector<CScript> scriptPubKeys; std::vector<CScript> scriptPubKeys;
int64_t checkallocations = 0; int64_t checkallocations = 0;
i = 0; i = 0;
BOOST_FOREACH(const uint256& txidopret, txidoprets) if ( funcid == 'C' )
{ {
CTransaction tx0; std::vector<uint8_t> scriptPubKey,opret; int64_t allocation; // normal payment
if ( myGetTransaction(txidopret,tx0,blockhash) != 0 && tx0.vout.size() > 1 && DecodePaymentsTxidOpRet(tx0.vout[tx0.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) for (const uint256& txidopret : txidoprets)
{ {
scriptPubKeys.push_back(CScript(scriptPubKey.begin(), scriptPubKey.end())); CTransaction tx0; std::vector<uint8_t> scriptPubKey,opret; int64_t allocation;
allocations.push_back(allocation); if ( myGetTransaction(txidopret,tx0,blockhash) != 0 && tx0.vout.size() > 1 && DecodePaymentsTxidOpRet(tx0.vout[tx0.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
//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() )
{ {
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()); if ( !fHasOpret )
return(eval->Invalid("missing opret in payments release")); {
} fprintf(stderr, "missing opret.%s in payments release.\n",HexStr(opret.begin(), opret.end()).c_str());
else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey ) return(eval->Invalid("missing opret in payments release"));
{ }
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()); else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey )
return(eval->Invalid("pays incorrect opret")); {
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 // 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() ) if ( allocations.size() == 0 || scriptPubKeys.size() == 0 || allocations.size() != scriptPubKeys.size() )
return(eval->Invalid("missing data cannot validate")); return(eval->Invalid("missing data cannot validate"));
//fprintf(stderr, "totalallocations.%li checkallocations.%li\n",totalallocations, checkallocations); //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")); 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. // make sure change is in vout 0 and is paying to the contract address.
if ( (change= IsPaymentsvout(cp,tx,0,coinaddr)) == 0 ) if ( (change= IsPaymentsvout(cp,tx,0,coinaddr)) == 0 )
return(eval->Invalid("change is in wrong vout or is wrong tx type")); 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. // 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; 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++) for (i = 1; i < (fHasOpret ? tx.vout.size()-2 : tx.vout.size()-1); i++)
{ {
std::string destscriptPubKey = HexStr(scriptPubKeys[n].begin(),scriptPubKeys[n].end()); if ( scriptPubKeys[n] != tx.vout[i].scriptPubKey )
std::string voutscriptPubKey = HexStr(tx.vout[i].scriptPubKey.begin(),tx.vout[i].scriptPubKey.end());
if ( destscriptPubKey != voutscriptPubKey )
{ {
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")); return(eval->Invalid("pays wrong address"));
} }
int64_t test = allocations[n]; mpz_init(mpzAllocation);
test *= checkamount; mpz_set_si(mpzAllocation,allocations[n]);
test /= totalallocations; mpz_mul(mpzAllocation,mpzAllocation,mpzCheckamount);
if ( test != tx.vout[i].nValue && test != tx.vout[i].nValue-1 ) 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); fprintf(stderr, "vout.%i test.%li vs nVlaue.%li\n",i, test, tx.vout[i].nValue);
return(eval->Invalid("amounts do not match")); 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; amount += tx.vout[i].nValue;
n++; n++;
} }
mpz_clear(mpzTotalAllocations);
// This is a backup check to make sure there are no extra vouts paying something else! // This is a backup check to make sure there are no extra vouts paying something else!
if ( checkamount != amount ) if ( checkamount != amount )
return(eval->Invalid("amounts do not match")); 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")); return(eval->Invalid("amount is too small"));
} }
// Check vins
i = 0; i = 0;
int32_t ht = chainActive.LastTip()->GetHeight(); int32_t ht = chainActive.LastTip()->GetHeight();
BOOST_FOREACH(const CTxIn& vin, tx.vin) 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); Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey);
if ( strcmp(destaddr,coinaddr) != 0 ) 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; CScript opret; uint256 checktxid; int32_t opret_ind;
if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 ) if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 )
{ opret = getCCopret(txin.vout[vin.prevout.n].scriptPubKey); // get op_return from CCvout,
// get op_return from CCvout,
opret = getCCopret(txin.vout[vin.prevout.n].scriptPubKey);
}
else else
{ opret = txin.vout[opret_ind].scriptPubKey;
// get op_return from the op_return
opret = txin.vout[opret_ind].scriptPubKey;
}
if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) 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()); 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) ) if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break; break;
} //else fprintf(stderr,"nValue %.8f vs threshold %.8f\n",(double)nValue/COIN,(double)threshold/COIN); } //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<uint8_t> &hexdata,cJSON *item,int32_t
UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
{ {
int32_t latestheight,nextheight = komodo_nextheight(); int32_t latestheight,nextheight = komodo_nextheight();
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock; 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,checkallocations=0,allocation; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector<uint256> txidoprets; 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; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t funcid;
mpz_t mpzTotalAllocations; mpz_init(mpzTotalAllocations);
cJSON *params = payments_reparse(&n,jsonstr); cJSON *params = payments_reparse(&n,jsonstr);
mypk = pubkey2pk(Mypubkey()); mypk = pubkey2pk(Mypubkey());
Paymentspk = GetUnspendable(cp,0); Paymentspk = GetUnspendable(cp,0);
@@ -491,14 +580,16 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
{ {
createtxid = payments_juint256(jitem(params,0)); createtxid = payments_juint256(jitem(params,0));
amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; 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("result","error"));
result.push_back(Pair("error","negative parameter")); result.push_back(Pair("error","negative parameter"));
if ( params != 0 )
free_json(params);
return(result); return(result);
} }
latestheight = (nextheight - lockedblocks - 1); 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("error","amount too smal"));
result.push_back(Pair("amount",ValueFromAmount(amount))); result.push_back(Pair("amount",ValueFromAmount(amount)));
result.push_back(Pair("minrelease",ValueFromAmount(minrelease*COIN))); result.push_back(Pair("minrelease",ValueFromAmount(minrelease*COIN)));
if ( params != 0 )
free_json(params);
return(result); return(result);
} }
txidpk = CCtxidaddr(txidaddr,createtxid); txidpk = CCtxidaddr(txidaddr,createtxid);
mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk)); mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk));
m = txidoprets.size(); if ( funcid = 'C' )
for (i=0; i<m; i++)
{ {
std::vector<uint8_t> scriptPubKey,opret; // normal payments
vout.nValue = 0; for (i=0; i<m; i++)
if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
{ {
vout.nValue = allocation; std::vector<uint8_t> scriptPubKey,opret;
vout.scriptPubKey.resize(scriptPubKey.size()); vout.nValue = 0;
memcpy(&vout.scriptPubKey[0],&scriptPubKey[0],scriptPubKey.size()); if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
checkallocations += allocation;
if ( opret.size() > 0 )
{ {
onlyopret.resize(opret.size()); vout.nValue = allocation;
memcpy(&onlyopret[0],&opret[0],opret.size()); vout.scriptPubKey.resize(scriptPubKey.size());
numoprets++; 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; if ( i == top ) // we reached top amount to pay, it can be less than this!
mtx.vout.push_back(vout); 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)); else if ( funcid = 'O' )
if ( i != m )
{ {
result.push_back(Pair("result","error")); // token snapshot
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);
} }
newamount = amount; newamount = amount;
int64_t totalamountsent = 0;
mpz_t mpzAmount; mpz_init(mpzAmount); mpz_set_si(mpzAmount,amount);
for (i=0; i<m; i++) for (i=0; i<m; i++)
{ {
mtx.vout[i+1].nValue *= amount; mpz_t mpzValue; mpz_init(mpzValue);
mtx.vout[i+1].nValue /= totalallocations; mpz_set_si(mpzValue,mtx.vout[i+1].nValue);
mpz_mul(mpzValue,mpzValue,mpzAmount);
mpz_cdiv_q(mpzValue,mpzValue,mpzTotalAllocations);
if ( mpz_fits_slong_p(mpzValue) )
mtx.vout[i+1].nValue = mpz_get_si(mpzValue);
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","value too big, try releasing a smaller amount"));
if ( params != 0 )
free_json(params);
return(result);
}
//fprintf(stderr, "nValue.%li \n", mtx.vout[i+1].nValue);
mpz_clear(mpzValue);
if ( mtx.vout[i+1].nValue < PAYMENTS_TXFEE ) if ( mtx.vout[i+1].nValue < PAYMENTS_TXFEE )
{ {
newamount += (PAYMENTS_TXFEE - mtx.vout[i+1].nValue); newamount += (PAYMENTS_TXFEE - mtx.vout[i+1].nValue);
mtx.vout[i+1].nValue = PAYMENTS_TXFEE; mtx.vout[i+1].nValue = PAYMENTS_TXFEE;
} }
totalamountsent += mtx.vout[i+1].nValue;
} }
if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE ) //fprintf(stderr, "newamount.%li totalamountsent.%li\n", newamount, totalamountsent);
{ mpz_clear(mpzAmount); mpz_clear(mpzTotalAllocations);
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"));
}
} }
else else
{ {
result.push_back(Pair("result","error")); result.push_back(Pair("result","error"));
result.push_back(Pair("error","couldnt decode paymentscreate txid opret")); 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 else
@@ -618,6 +778,8 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr)
{ {
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); 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; 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; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
uint256 tokenid;
cJSON *params = payments_reparse(&n,jsonstr); cJSON *params = payments_reparse(&n,jsonstr);
mypk = pubkey2pk(Mypubkey()); mypk = pubkey2pk(Mypubkey());
Paymentspk = GetUnspendable(cp,0); 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; amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049;
if ( n == 3 ) if ( n == 3 )
useopret = jint(jitem(params,2),0) != 0; 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("result","error"));
result.push_back(Pair("error","invalid createtxid")); result.push_back(Pair("error","invalid createtxid"));
} }
else if ( AddNormalinputs(mtx,mypk,amount+PAYMENTS_TXFEE,60) > 0 ) 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("result","error"));
result.push_back(Pair("error","negative parameter")); result.push_back(Pair("error","negative parameter"));
@@ -650,13 +812,13 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr)
else else
{ {
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk)); 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 // Use the below one along with other FinalizeCCTx/return, to get the ccvout scriptpubkey
/*opret = EncodePaymentsFundOpRet(txid); /*std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
if ( makeCCopret(opret, vData) ) if ( makeCCopret(opret, vData) )
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&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. //rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); // use this one to get ccvout scriptpubkey.
if ( params != 0 ) if ( params != 0 )
free_json(params); free_json(params);
@@ -796,22 +958,73 @@ UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr)
UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr)
{ {
uint64_t start = time(NULL); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
UniValue result(UniValue::VOBJ);
return(time(NULL)-start); uint256 hashBlock; CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::string rawtx;
int32_t lockedblocks,minrelease,top,n,i; std::vector<std::vector<uint8_t>> 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<n-3; 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);
std::vector<uint8_t> 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 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<uint256> txidoprets; int64_t funds,fundsopret,totalallocations=0,allocation; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock; 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<uint256> txidoprets; int64_t funds,fundsopret,totalallocations=0,allocation; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock;
int32_t top; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; // snapshot
uint256 tokenid;
cJSON *params = payments_reparse(&n,jsonstr); cJSON *params = payments_reparse(&n,jsonstr);
if ( params != 0 && n == 1 ) if ( params != 0 && n == 1 )
{ {
Paymentspk = GetUnspendable(cp,0); Paymentspk = GetUnspendable(cp,0);
createtxid = payments_juint256(jitem(params,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 ) 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); free_json(params);
return(result); return(result);
} }
result.push_back(Pair("plan_type","payments"));
result.push_back(Pair("lockedblocks",(int64_t)lockedblocks)); result.push_back(Pair("lockedblocks",(int64_t)lockedblocks));
result.push_back(Pair("totalallocations",(int64_t)totalallocations)); result.push_back(Pair("totalallocations",(int64_t)totalallocations));
result.push_back(Pair("minrelease",(int64_t)minrelease)); 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()); } else fprintf(stderr,"error decoding voutsize.%d\n",(int32_t)txO.vout.size());
a.push_back(obj); a.push_back(obj);
} }
flag++;
result.push_back(Pair("numoprets",(int64_t)numoprets)); result.push_back(Pair("numoprets",(int64_t)numoprets));
if ( numoprets > 1 ) if ( numoprets > 1 )
{ {
flag++;
result.push_back(Pair("result","error")); result.push_back(Pair("result","error"));
result.push_back(Pair("error","too many opreturns")); result.push_back(Pair("error","too many opreturns"));
} } else result.push_back(Pair("txidoprets",a));
else }
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)); result.push_back(Pair("result","error"));
txidpk = CCtxidaddr(txidaddr,createtxid); result.push_back(Pair("error","negative parameter"));
GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk); if ( params != 0 )
funds = CCaddress_balance(fundsaddr,1); free_json(params);
result.push_back(Pair(fundsaddr,ValueFromAmount(funds))); return(result);
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("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("result","error"));
result.push_back(Pair("error","couldnt find valid payments create txid")); 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) UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr)
{ {
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; uint256 txid,hashBlock; 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; 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;
int32_t top; std::vector<std::vector<uint8_t>> excludeScriptPubKeys;
Paymentspk = GetUnspendable(cp,0); Paymentspk = GetUnspendable(cp,0);
GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk); GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk);
SetCCtxids(addressIndex,markeraddr,true); SetCCtxids(addressIndex,markeraddr,true);
@@ -899,7 +1156,7 @@ UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr)
txid = it->first.txhash; txid = it->first.txhash;
if ( it->first.index == 0 && myGetTransaction(txid,tx,hashBlock) != 0 ) 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 ) if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 )
{ {

View File

@@ -656,6 +656,7 @@ std::vector <std::pair<CAmount, CTxDestination>> vAddressSnapshot;
bool komodo_dailysnapshot(int32_t height) 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; uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,undo_height,extraoffset;
if ( (extraoffset= height % KOMODO_SNAPSHOT_INTERVAL) != 0 ) 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. // use the notarizationsDB to scan back from the consesnus height to get the offset we need.
std::string symbol; Notarisation nota; std::string symbol; Notarisation nota;
symbol.assign(ASSETCHAINS_SYMBOL); symbol.assign(ASSETCHAINS_SYMBOL);
ScanNotarisationsDB(height-extraoffset, symbol, 100, nota); if ( ScanNotarisationsDB(height-extraoffset, symbol, 100, nota) == 0 )
undo_height = nota.second.height; undo_height = height-extraoffset-reorglimit;
if ( undo_height == 0 ) undo_height = height-extraoffset-100; 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); //fprintf(stderr, "height.%i-extraoffset.%i = startscanfrom.%i to get undo_height.%i\n", height, extraoffset, height-extraoffset, undo_height);
} }
else else
{ {
// we are at the right height in connect block to scan back to last notarized height. // we are at the right height in connect block to scan back to last notarized height.
notarized_height = komodo_notarized_height(&prevMoMheight,&notarized_hash,&notarized_desttxid); notarized_height = komodo_notarized_height(&prevMoMheight,&notarized_hash,&notarized_desttxid);
if ( notarized_height > height-100 ) notarized_height > height-100 ? undo_height = notarized_height : undo_height = height-reorglimit;
{
// 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;
}
} }
fprintf(stderr, "doing snapshot for height.%i undo_height.%i\n", height, undo_height); 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. // 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--) for (int32_t i = block.vtx.size() - 1; i >= 0; i--)
{ {
const CTransaction &tx = block.vtx[i]; const CTransaction &tx = block.vtx[i];
uint256 hash = tx.GetHash();
CTxDestination vDest; CTxDestination vDest;
//fprintf(stderr, "undong tx.%s\n",hash.GetHex().c_str());
// loop vouts reverse order, remove value recieved. // loop vouts reverse order, remove value recieved.
for (unsigned int k = tx.vout.size(); k-- > 0;) 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;) for (unsigned int j = tx.vin.size(); j-- > 0;)
{ {
uint256 blockhash; CTransaction txin; 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; int vout = tx.vin[j].prevout.n;
if ( ExtractDestination(txin.vout[vout].scriptPubKey, vDest) ) if ( ExtractDestination(txin.vout[vout].scriptPubKey, vDest) )

View File

@@ -5632,14 +5632,14 @@ UniValue payments_create(const UniValue& params, bool fHelp)
UniValue payments_airdrop(const UniValue& params, bool fHelp) UniValue payments_airdrop(const UniValue& params, bool fHelp)
{ {
struct CCcontract_info *cp,C; struct CCcontract_info *cp,C;
//if ( fHelp || params.size() != 1 ) if ( fHelp || params.size() != 1 )
// throw runtime_error("paymentscreate \"[lockedblocks,minamount,%22paytxid0%22,...,%22paytxidN%22]\"\n"); throw runtime_error("paymentsairdrop \"[lockedblocks,minamount,top,%22paytxid0%22,...,%22paytxidN%22]\"\n");
//if ( ensure_CCrequirements(EVAL_PAYMENTS) < 0 ) 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"); 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; const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
//cp = CCinit(&C,EVAL_PAYMENTS); cp = CCinit(&C,EVAL_PAYMENTS);
return(PaymentsAirdrop(0,(char *)params[0].get_str().c_str())); return(PaymentsAirdrop(cp,(char *)params[0].get_str().c_str()));
} }
UniValue payments_info(const UniValue& params, bool fHelp) UniValue payments_info(const UniValue& params, bool fHelp)