Browse Source

initial commit for payments merge RPC

z_createrawtransaction
blackjok3r 5 years ago
parent
commit
0d47cda145
  1. 2
      src/cc/CCPayments.h
  2. 2
      src/cc/CCinclude.h
  3. 2
      src/cc/CCtx.cpp
  4. 16
      src/cc/CCutils.cpp
  5. 6
      src/cc/customcc.cpp
  6. 480
      src/cc/payments.cpp
  7. 2
      src/main.h
  8. 1
      src/rpc/server.cpp
  9. 1
      src/rpc/server.h
  10. 15
      src/wallet/rpcwallet.cpp

2
src/cc/CCPayments.h

@ -21,6 +21,7 @@
#include <gmp.h>
#define PAYMENTS_TXFEE 10000
#define PAYMENTS_MERGEOFSET 10 // 100?
extern std::vector <std::pair<CAmount, CTxDestination>> vAddressSnapshot;
extern int32_t lastSnapShotHeight;
@ -29,6 +30,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
// CCcustom
UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsMerge(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr);

2
src/cc/CCinclude.h

@ -229,7 +229,7 @@ uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,i
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, std::vector<std::vector<unsigned char>>* vData = NULL);
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, std::vector<std::vector<unsigned char>>* vData = NULL);
int32_t has_opret(const CTransaction &tx, uint8_t evalcode);
CScript getCCopret(const CScript &scriptPubKey);
bool getCCopret(const CScript &scriptPubKey, CScript &opret);
bool makeCCopret(CScript &opret, std::vector<std::vector<unsigned char>> &vData);
CC *MakeCCcond1(uint8_t evalcode,CPubKey pk);
CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2);

2
src/cc/CCtx.cpp

@ -241,7 +241,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
{
char coinaddr[64];
GetCCaddress1of2(cp,coinaddr,globalpk,pubkeys[i]);
//fprintf(stderr,"%s + %s -> %s vs %s\n",HexStr(globalpk).c_str(),HexStr(pubkeys[i]).c_str(),coinaddr,destaddr);
fprintf(stderr,"%s + %s -> %s vs %s\n",HexStr(globalpk).c_str(),HexStr(pubkeys[i]).c_str(),coinaddr,destaddr);
if ( strcmp(destaddr,coinaddr) == 0 )
{
privkey = cp->CCpriv;

16
src/cc/CCutils.cpp

@ -70,16 +70,20 @@ int32_t has_opret(const CTransaction &tx, uint8_t evalcode)
return 0;
}
CScript getCCopret(const CScript &scriptPubKey)
bool getCCopret(const CScript &scriptPubKey, CScript &opret)
{
std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
CScript dummy; CScript opret;
if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() == 1 )
CScript dummy; bool ret = false;
if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) != 0 )
{
//fprintf(stderr, "vparams.%s\n", HexStr(vParams[0].begin(), vParams[0].end()).c_str());
opret = CScript(vParams[0].begin()+6, vParams[0].end());
ret = true;
if ( vParams.size() == 1)
{
opret = CScript(vParams[0].begin()+6, vParams[0].end());
//fprintf(stderr, "vparams.%s\n", HexStr(vParams[0].begin(), vParams[0].end()).c_str());
}
}
return opret;
return ret;
}
bool makeCCopret(CScript &opret, std::vector<std::vector<unsigned char>> &vData)

6
src/cc/customcc.cpp

@ -82,12 +82,12 @@ UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
{
char expectedaddress[64]; CPubKey pk;
CScript opret; int32_t numvout;
CScript opret; int32_t numvout = 0;
if ( has_opret(tx, EVAL_CUSTOM) == 0 )
{
std::vector<std::vector<unsigned char>> vParams = std::vector<std::vector<unsigned char>>();
opret = getCCopret(tx.vout[0].scriptPubKey);
numvout = 1;
if ( getCCopret(tx.vout[0].scriptPubKey,opret) )
numvout = 1;
}
else
{

480
src/cc/payments.cpp

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

2
src/main.h

@ -95,7 +95,7 @@ static const unsigned int MAX_TEMPFILE_SIZE = 0x1000000; // 16 MiB 0x8000000
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
/** Maximum number of script-checking threads allowed */
static const int MAX_SCRIPTCHECK_THREADS = 16;
/** -par default (number of script-checking threads, 0 = auto) */

1
src/rpc/server.cpp

@ -487,6 +487,7 @@ static const CRPCCommand vRPCCommands[] =
{ "payments", "paymentslist", &payments_list, true },
{ "payments", "paymentsinfo", &payments_info, true },
{ "payments", "paymentsfund", &payments_fund, true },
{ "payments", "paymentsmerge", &payments_merge, true },
{ "payments", "paymentsrelease", &payments_release, true },
{ "CClib", "cclibaddress", &cclibaddress, true },

1
src/rpc/server.h

@ -287,6 +287,7 @@ extern UniValue marmara_lock(const UniValue& params, bool fHelp);
extern UniValue paymentsaddress(const UniValue& params, bool fHelp);
extern UniValue payments_release(const UniValue& params, bool fHelp);
extern UniValue payments_fund(const UniValue& params, bool fHelp);
extern UniValue payments_merge(const UniValue& params, bool fHelp);
extern UniValue payments_txidopret(const UniValue& params, bool fHelp);
extern UniValue payments_create(const UniValue& params, bool fHelp);
extern UniValue payments_airdrop(const UniValue& params, bool fHelp);

15
src/wallet/rpcwallet.cpp

@ -5603,6 +5603,19 @@ UniValue payments_fund(const UniValue& params, bool fHelp)
return(PaymentsFund(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_merge(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 1 )
throw runtime_error("paymentsmerge \"[%22createtxid%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(PaymentsMerge(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_txidopret(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
@ -5633,7 +5646,7 @@ UniValue payments_airdrop(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 1 )
throw runtime_error("paymentsairdrop \"[lockedblocks,minamount,top,bottom,fixedFlag,%22excludeAddress%22,...,%22excludeAddressN%22]\"\n");
throw runtime_error("paymentsairdrop \"[lockedblocks,minamount,mintoaddress,top,bottom,fixedFlag,%22excludeAddress%22,...,%22excludeAddressN%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;

Loading…
Cancel
Save