Merge pull request #1 from jl777/FSM

Fsm
This commit is contained in:
Alrighttt
2019-05-19 22:22:31 +02:00
committed by GitHub
16 changed files with 415 additions and 277 deletions

View File

@@ -22,7 +22,7 @@
#include <key_io.h>
#define PAYMENTS_TXFEE 10000
#define PAYMENTS_MERGEOFSET 10 // 100?
#define PAYMENTS_MERGEOFSET 60 // 1H extra.
extern std::vector <std::pair<CAmount, CTxDestination>> vAddressSnapshot;
extern int32_t lastSnapShotHeight;
@@ -35,6 +35,7 @@ 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);
UniValue PaymentsAirdropTokens(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr);
UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr);

View File

@@ -251,7 +251,7 @@ void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, c
int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode);
bool IsCCInput(CScript const& scriptSig);
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime);
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime,int64_t &actualtxfee);
int32_t unstringbits(char *buf,uint64_t bits);
uint64_t stringbits(char *str);
uint256 revuint256(uint256 txid);

View File

@@ -150,7 +150,7 @@ bool IsCCInput(CScript const& scriptSig)
return true;
}
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime)
bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime, int64_t &actualtxfee)
{
LOCK(mempool.cs);
CCoinsView dummy;
@@ -159,9 +159,10 @@ bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
view.SetBackend(viewMemPool);
valuein = view.GetValueIn(height,&interest,tx,blocktime);
if ( valuein-tx.GetValueOut() > txfee )
actualtxfee = valuein-tx.GetValueOut();
if ( actualtxfee > txfee )
{
//fprintf(stderr, "txfee.%li vs txfee.%li\n", valuein-tx.GetValueOut(), txfee);
//fprintf(stderr, "actualtxfee.%li vs txfee.%li\n", actualtxfee, txfee);
return false;
}
return true;

View File

@@ -137,6 +137,26 @@ uint8_t DecodePaymentsMergeOpRet(CScript scriptPubKey,uint256 &checktxid)
return(0);
}
CScript EncodePaymentsReleaseOpRet(uint256 checktxid, int64_t amountReleased)
{
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'R' << checktxid << amountReleased);
return(opret);
}
uint8_t DecodePaymentsReleaseOpRet(CScript scriptPubKey,uint256 &checktxid,int64_t &amountReleased)
{
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 >> checktxid; ss >> amountReleased) != 0 )
{
if ( e == EVAL_PAYMENTS && f == 'R' )
return(f);
}
return(0);
}
CScript EncodePaymentsOpRet(int32_t lockedblocks,int32_t minrelease,int64_t totalallocations,std::vector<uint256> txidoprets)
{
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
@@ -160,13 +180,7 @@ uint8_t DecodePaymentsOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &
CScript EncodePaymentsSnapsShotOpRet(int32_t lockedblocks,int32_t minrelease,int32_t minimum,int32_t top,int32_t bottom,int8_t fixedAmount,std::vector<std::vector<uint8_t>> excludeScriptPubKeys)
{
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
if ( (strcmp(ASSETCHAINS_SYMBOL, "CFEKPAY") == 0) ) // exempt for now, remove this after game completed.
{
minimum = 10000;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << top << bottom << fixedAmount << excludeScriptPubKeys);
}
else
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << minimum << top << bottom << fixedAmount << excludeScriptPubKeys);
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << minimum << top << bottom << fixedAmount << excludeScriptPubKeys);
return(opret);
}
@@ -175,40 +189,27 @@ uint8_t DecodePaymentsSnapsShotOpRet(CScript scriptPubKey,int32_t &lockedblocks,
std::vector<uint8_t> vopret; uint8_t *script,e,f;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if ( (strcmp(ASSETCHAINS_SYMBOL, "CFEKPAY") == 0) ) // exempt for now, remove this after game completed.
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 )
{
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);
}
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 EncodePaymentsTokensOpRet(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,uint256 tokenid)
{
CScript opret; uint8_t evalcode = EVAL_PAYMENTS;
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'O' << lockedblocks << minrelease << top << excludeScriptPubKeys << tokenid);
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'O' << lockedblocks << minrelease << minimum << top << bottom << fixedAmount << 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)
uint8_t DecodePaymentsTokensOpRet(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, 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 ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minimum; ss >> top; ; ss >> bottom; ss >> fixedAmount; ss >> excludeScriptPubKeys; ss >> tokenid) != 0 )
{
if ( e == EVAL_PAYMENTS && f == 'O' )
return(f);
@@ -219,7 +220,6 @@ uint8_t DecodePaymentsTokensOpRet(CScript scriptPubKey,int32_t &lockedblocks,int
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 ( getCCopret(tx.vout[v].scriptPubKey, ccopret) )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && (cmpaddr[0] == 0 || strcmp(destaddr,cmpaddr) == 0) )
@@ -228,22 +228,6 @@ int64_t IsPaymentsvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t
return(0);
}
void pub2createtxid(char *str)
{
int i,n;
char *rev;
n = (int32_t)strlen(str);
rev = (char *)malloc(n + 1);
for (i=0; i<n; i+=2)
{
rev[n-2-i] = str[i];
rev[n-1-i] = str[i+1];
}
rev[n] = 0;
strcpy(str,rev);
free(rev);
}
bool payments_game(int32_t &top, int32_t &bottom)
{
uint64_t x;
@@ -255,7 +239,7 @@ bool payments_game(int32_t &top, int32_t &bottom)
if ( top < 50 ) top += 50;
bottom = (vAddressSnapshot.size()*bottom)/100;
top = (vAddressSnapshot.size()*top)/100;
fprintf(stderr, "bottom.%i top.%i\n",bottom,top);
//fprintf(stderr, "bottom.%i top.%i\n",bottom,top);
return true;
}
@@ -272,43 +256,71 @@ bool payments_lockedblocks(uint256 blockhash,int32_t lockedblocks,int32_t &block
return true;
}
int32_t payments_getallocations(int32_t top, int32_t bottom, const std::vector<std::vector<uint8_t>> &excludeScriptPubKeys, mpz_t &mpzTotalAllocations, std::vector<CScript> &scriptPubKeys, std::vector<int64_t> &allocations)
{
mpz_t mpzAllocation; int32_t i =0;
for (int32_t j = bottom; j < vAddressSnapshot.size(); j++)
{
auto &address = vAddressSnapshot[j];
CScript scriptPubKey = GetScriptForDestination(address.second);
bool skip = false;
// skip excluded addresses.
for ( auto skipkey : excludeScriptPubKeys )
{
if ( scriptPubKey == CScript(skipkey.begin(), skipkey.end()) )
skip = true;
}
if ( !skip )
{
mpz_init(mpzAllocation);
i++;
//fprintf(stderr, "address: %s nValue.%li \n", CBitcoinAddress(address.second).ToString().c_str(), address.first);
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 )
break; // we reached top amount to pay, it can be less than this, if less address exist on chain, return the number we got.
}
return(i);
}
int32_t payments_gettokenallocations(int32_t top, int32_t bottom, const std::vector<std::vector<uint8_t>> &excludeScriptPubKeys, uint256 tokenid, mpz_t &mpzTotalAllocations, std::vector<CScript> &scriptPubKeys, std::vector<int64_t> &allocations)
{
/*
- check tokenid exists.
- iterate tokenid address and extract all pubkeys, add to map.
- rewind to last notarized height for balances? see main.cpp: line# 660.
- convert balances to mpz_t and add up totalallocations
- sort the map into a vector, then convert to the correct output.
*/
return(0);
}
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
// one of two addresses
// change must go to 1of2 txidaddr
// 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]={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() == 1 )
char temp[128], txidaddr[64]={0}; std::string scriptpubkey; uint256 createtxid, blockhash, tokenid; CTransaction plantx; int8_t funcid=0, fixedAmount=0;
int32_t i,lockedblocks,minrelease,blocksleft,dust = 0, top,bottom=0,minimum=10000; int64_t change,totalallocations,actualtxfee,amountReleased=0; std::vector<uint256> txidoprets; bool fHasOpret = false,fIsMerge = false; CPubKey txidpk,Paymentspk;
std::vector<std::vector<uint8_t>> excludeScriptPubKeys; bool fFixedAmount = false; CScript ccopret;
mpz_t mpzTotalAllocations,mpzAllocation,mpzCheckamount;
mpz_init(mpzCheckamount); mpz_init(mpzTotalAllocations);
// Check change is in vout[0], and also fetch the ccopret to determine what type of tx this is. txidaddr is unknown, recheck this later.
if ( (change= IsPaymentsvout(cp,tx,0,txidaddr,ccopret)) != 0 && ccopret.size() > 2 )
{
if ( IsPaymentsvout(cp,tx,0,coinaddr,ccopret) != 0 && ccopret.size() > 2 && DecodePaymentsMergeOpRet(ccopret,createtxid) )
{
// get the checktxid and the amount released if doing release tx.
if ( DecodePaymentsMergeOpRet(ccopret,createtxid) == 'M' )
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);
if ( !fIsMerge )
{
strcpy(temp, scriptpubkey.c_str());
pub2createtxid(temp);
createtxid = Parseuint256(temp);
}
//printf("createtxid.%s\n",createtxid.ToString().c_str());
else if ( DecodePaymentsReleaseOpRet(ccopret,createtxid,amountReleased) != 'R' )
return(eval->Invalid("could not decode ccopret"));
mpz_set_si(mpzCheckamount,amountReleased);
} else return(eval->Invalid("could not decode ccopret"));
// 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,minimum,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,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid)) == 'O') )
{
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) )
return(eval->Invalid("negative values"));
@@ -316,25 +328,30 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
return(eval->Invalid("minimum must be over 10000"));
Paymentspk = GetUnspendable(cp,0);
txidpk = CCtxidaddr(txidaddr,createtxid);
GetCCaddress1of2(cp,coinaddr,Paymentspk,txidpk);
GetCCaddress1of2(cp,txidaddr,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) )
if ( !CheckTxFee(tx, PAYMENTS_TXFEE+1, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime, actualtxfee) )
return eval->Invalid("txfee is too high");
// make sure change is in vout 0 and is paying to the contract address.
if ( (change= IsPaymentsvout(cp,tx,0,coinaddr,ccopret)) == 0 )
return(eval->Invalid("change is in wrong vout or is wrong tx type"));
// Check that the change vout is playing the txid address.
if ( IsPaymentsvout(cp,tx,0,txidaddr,ccopret) == 0 )
return eval->Invalid("change pays wrong address");
if ( !fIsMerge )
{
if ( amountReleased < minrelease*COIN )
{
fprintf(stderr, "does not meet minrelease amount.%li minrelease.%li\n",amountReleased, (int64_t)minrelease*COIN);
return(eval->Invalid("amount is too small"));
}
// 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' )
{
// normal payment
for (const uint256& txidopret : txidoprets)
int64_t checkallocations = 0;
for ( auto txidopret : txidoprets)
{
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' )
@@ -360,10 +377,14 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
}
i++;
}
//fprintf(stderr, "totalallocations.%li checkallocations.%li\n",totalallocations, checkallocations);
if ( totalallocations != checkallocations )
return(eval->Invalid("allocation missmatch"));
mpz_set_si(mpzTotalAllocations,totalallocations);
}
else if ( funcid == 'S' )
else if ( funcid == 'S' || funcid == 'O' )
{
// snapshot payment
if ( KOMODO_SNAPSHOT_INTERVAL == 0 )
return(eval->Invalid("snapshots not activated on this chain"));
if ( vAddressSnapshot.size() == 0 )
@@ -379,132 +400,115 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
{
fFixedAmount = true;
}
for (int32_t j = bottom; j < vAddressSnapshot.size(); j++)
if ( funcid == 'S' )
payments_getallocations(top, bottom, excludeScriptPubKeys, mpzTotalAllocations, scriptPubKeys, allocations);
else
{
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;
// token snapshot
// payments_gettokenallocations(top, bottom, excludeScriptPubKeys, tokenid, mpzTotalAllocations, scriptPubKeys, allocations);
}
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, 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++)
int64_t amount = 0; int32_t n = 0;
// We place amount released into ccopret, so that these calcualtion are accurate!
// If you change the amount released in the RPC these calcs will be wrong, and validation will fail.
for (i = 1; i < (fHasOpret ? tx.vout.size()-1 : tx.vout.size()); i++)
{
int64_t test;
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);
if ( (top-bottom) > 0 )
test = amountReleased / (top-bottom);
else
return(eval->Invalid("top/bottom range is illegal"));
}
else
{
mpz_init(mpzAllocation);
mpz_set_si(mpzAllocation,allocations[n]);
mpz_mul(mpzAllocation,mpzAllocation,mpzCheckamount);
mpz_cdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations);
mpz_tdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations);
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 nValue.%li\n", i, test, tx.vout[i].nValue);
if ( 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"));
}
if ( test < minimum )
{
// prevent anyone being paid the 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++;
}
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 )
if ( allocations.size() > n )
{
fprintf(stderr, "does not meet minrelease amount.%li minrelease.%li\n",amount, (int64_t)minrelease*COIN );
return(eval->Invalid("amount is too small"));
// need to check that the next allocation was less than minimum, otherwise ppl can truncate the tx at any place not paying all elegible addresses.
mpz_init(mpzAllocation);
mpz_set_si(mpzAllocation,allocations[n+1]);
mpz_mul(mpzAllocation,mpzAllocation,mpzCheckamount);
mpz_tdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations);
int64_t test = mpz_get_si(mpzAllocation);
//fprintf(stderr, "check next vout pays under min: test.%li > minimuim.%i\n", test, minimum);
if ( test > minimum )
return(eval->Invalid("next allocation was not under minimum"));
}
mpz_clear(mpzTotalAllocations); mpz_clear(mpzCheckamount);
}
// Check vins
i = 0; int32_t dust = 0;
int32_t blocksleft;
BOOST_FOREACH(const CTxIn& vin, tx.vin)
i = 0;
for (auto vin : tx.vin)
{
CTransaction txin;
if ( myGetTransaction(vin.prevout.hash,txin,blockhash) )
{
// check the vin comes from the CC address's
char destaddr[64]; int32_t mergeoffset = 0; CScript opret; uint256 checktxid;
Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey);
char fromaddr[64]; int32_t mergeoffset = 0; CScript vinccopret; uint256 checktxid;
Getscriptaddress(fromaddr,txin.vout[vin.prevout.n].scriptPubKey);
if ( fIsMerge && txin.vout[vin.prevout.n].nValue < COIN )
dust++;
if ( strcmp(destaddr,coinaddr) != 0 )
if ( IsPaymentsvout(cp,txin,vin.prevout.n,cp->unspendableCCaddr,vinccopret) != 0 )
{
// if does not come from address its in the global payments adddress and we need to check the opreturn.
uint256 checktxid; int32_t opret_ind;
if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 )
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 )
// if from global payments address get ccopret to detemine pays correct plan.
uint256 checktxid;
if ( vinccopret.size() < 2 || DecodePaymentsFundOpRet(vinccopret,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 vout.%i\n", i, txin.GetHash().ToString().c_str(), vin.prevout.n);
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' )
else if ( IsPaymentsvout(cp,txin,vin.prevout.n,txidaddr,vinccopret) != 0 )
{
mergeoffset = PAYMENTS_MERGEOFSET;
}
//fprintf(stderr, "mergeoffset.%i\n", mergeoffset);
// if in txid address apply merge offset if applicable.
if ( fIsMerge && vinccopret.size() > 2 && DecodePaymentsMergeOpRet(vinccopret,checktxid) == 'M' )
{
// Apply merge offset to locked blocks, this prevents people spaming payments fund and payments merge to prevent release happening.
mergeoffset = PAYMENTS_MERGEOFSET;
}
}
else // not from global payments plan, or txid address.
return(eval->Invalid("utxo comes from incorrect address"));
// check the chain depth vs locked blocks requirement.
if ( !payments_lockedblocks(blockhash, lockedblocks+mergeoffset, blocksleft) )
{
fprintf(stderr, "vin.%i is not elegible for.%i blocks \n",i, blocksleft);
return(eval->Invalid("vin not elegible"));
}
i++;
} else return(eval->Invalid("cant get vin transaction"));
}
@@ -552,32 +556,23 @@ int64_t AddPaymentsInputs(bool fLockedBlocks,int8_t GetBalance,struct CCcontract
txid = it->first.txhash;
vout = (int32_t)it->first.index;
//fprintf(stderr,"iter.%d %s/v%d %s\n",iter,txid.GetHex().c_str(),vout,coinaddr);
if ( (vout == 0 || vout == 1) && GetTransaction(txid,vintx,hashBlock,false) != 0 )
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( iter == 0 )
{
CScript opret; uint256 checktxid; int32_t opret_ind;
if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 )
{
// get op_return from CCvout
getCCopret(vintx.vout[vout].scriptPubKey,opret);
}
else
{
// get op_return from the op_return
opret = vintx.vout[opret_ind].scriptPubKey;
}
if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid )
{
fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str());
continue;
}
}
if ( (nValue= IsPaymentsvout(cp,vintx,vout,coinaddr,ccopret)) > PAYMENTS_TXFEE && nValue >= threshold && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
int32_t offset = 0;
if ( ccopret.size() > 2 && DecodePaymentsMergeOpRet(ccopret,checktxid) == 'M' )
offset = PAYMENTS_MERGEOFSET;
if ( ccopret.size() > 2 )
{
if ( iter == 0 && (DecodePaymentsFundOpRet(ccopret,checktxid) != 'F' || checktxid != createtxid) )
{
// global address but not for this plan.
fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str());
continue;
}
// increase merge offset, if this is a merge tx, merging merged utxos.
if ( iter == 1 && GetBalance == 4 && DecodePaymentsMergeOpRet(ccopret,checktxid) == 'M' )
offset = PAYMENTS_MERGEOFSET;
}
int32_t tmpblocksleft = 0;
if ( fLockedBlocks && !payments_lockedblocks(hashBlock, lockedblocks+offset, tmpblocksleft) )
{
@@ -587,8 +582,10 @@ int64_t AddPaymentsInputs(bool fLockedBlocks,int8_t GetBalance,struct CCcontract
if ( (GetBalance == 0 && total != 0 && maxinputs != 0) || GetBalance == 4 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
if ( nValue < COIN )
if ( GetBalance == 4 && nValue < COIN )
blocksleft++; // count dust with unused variable.
if ( GetBalance == 2 || GetBalance == 1 )
blocksleft++; // count all utxos with unused variable.
totalinputs += nValue;
n++;
//fprintf(stderr,"iter.%d %s/v%d %s %.8f\n",iter,txid.GetHex().c_str(),vout,coinaddr,(double)nValue/COIN);
@@ -688,22 +685,23 @@ int32_t payments_parsehexdata(std::vector<uint8_t> &hexdata,cJSON *item,int32_t
UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
{
int32_t nextheight = komodo_nextheight();
//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,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t funcid,fixedAmount=0; bool fFixedAmount = false;
mpz_t mpzTotalAllocations; mpz_init(mpzTotalAllocations);
LOCK(cs_main);
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),komodo_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,ccopret; char txidaddr[64],destaddr[64]; std::vector<uint256> txidoprets;
int32_t top,bottom=0,blocksleft=0,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t funcid,fixedAmount=0,skipminimum=0; bool fFixedAmount = false;
mpz_t mpzTotalAllocations, mpzAllocation; mpz_init(mpzTotalAllocations);
cJSON *params = payments_reparse(&n,jsonstr);
mypk = pubkey2pk(Mypubkey());
Paymentspk = GetUnspendable(cp,0);
if ( params != 0 && n == 2 )
if ( params != 0 && n >= 2 )
{
createtxid = payments_juint256(jitem(params,0));
amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049;
if ( n == 3 )
skipminimum = juint(jitem(params,2),0);
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,minimum,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,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid)) == 'O') )
{
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) )
{
@@ -716,7 +714,6 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
// 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 )
{
result.push_back(Pair("result","error"));
@@ -728,11 +725,15 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
return(result);
}
txidpk = CCtxidaddr(txidaddr,createtxid);
mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk));
ccopret = EncodePaymentsReleaseOpRet(createtxid, amount);
std::vector<std::vector<unsigned char>> vData = std::vector<std::vector<unsigned char>>();
if ( makeCCopret(ccopret, vData) )
mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk,&vData));
//fprintf(stderr, "funcid.%i\n", funcid);
if ( funcid == 'C' )
{
// normal payments
m = txidoprets.size();
for (i=0; i<m; i++)
{
std::vector<uint8_t> scriptPubKey,opret;
@@ -783,7 +784,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
// set totalallocations to a mpz_t bignum, for amounts calculation later.
mpz_set_si(mpzTotalAllocations,totalallocations);
}
else if ( funcid == 'S' )
else if ( funcid == 'S' || funcid == 'O' )
{
// normal snapshot
if ( vAddressSnapshot.size() == 0 )
@@ -802,7 +803,6 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
free_json(params);
return(result);
}
i = 0;
if ( fixedAmount == 7 )
{
// game setting, randomise bottom and top values
@@ -812,38 +812,40 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
{
fFixedAmount = true;
}
for (int32_t j = bottom; j < vAddressSnapshot.size(); j++)
if ( (top-bottom) < 0 )
{
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_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);
mtx.vout.push_back(vout);
mpz_clear(mpzAllocation);
}
if ( i+bottom == top ) // we reached top amount to pay, it can be less than this!
break;
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid range top/bottom"));
if ( params != 0 )
free_json(params);
return(result);
}
std::vector<int64_t> allocations;
std::vector<CScript> scriptPubKeys;
if ( funcid == 'S' )
m = payments_getallocations(top, bottom, excludeScriptPubKeys, mpzTotalAllocations, scriptPubKeys, allocations);
else
{
// token snapshot
// payments_gettokenallocations(top, bottom, excludeScriptPubKeys, tokenid, mpzTotalAllocations, scriptPubKeys, allocations);
}
if ( (allocations.size() == 0 || scriptPubKeys.size() == 0 || allocations.size() != scriptPubKeys.size()) )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","mismatched allocations, scriptpubkeys"));
if ( params != 0 )
free_json(params);
return(result);
}
i = 0;
for ( auto allocation : allocations )
{
vout.nValue = allocation;
vout.scriptPubKey = scriptPubKeys[i];
mtx.vout.push_back(vout);
i++;
}
m = i; // this is the amount we got, either top, or all of the address on the chain.
}
else if ( funcid == 'O' )
{
// token snapshot
}
newamount = amount;
int64_t totalamountsent = 0;
@@ -852,15 +854,12 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
{
mpz_t mpzValue; mpz_init(mpzValue);
if ( fFixedAmount )
{
mtx.vout[i+1].nValue = amount / (top-bottom);
//fprintf(stderr, "amount.%li / top-bottom.%i = value.%li\n", amount, (top-bottom-2), mtx.vout[i+1].nValue);
}
else
{
mpz_set_si(mpzValue,mtx.vout[i+1].nValue);
mpz_mul(mpzValue,mpzValue,mpzAmount);
mpz_cdiv_q(mpzValue,mpzValue,mpzTotalAllocations);
mpz_tdiv_q(mpzValue,mpzValue,mpzTotalAllocations);
if ( mpz_fits_slong_p(mpzValue) )
mtx.vout[i+1].nValue = mpz_get_si(mpzValue);
else
@@ -872,20 +871,31 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
return(result);
}
}
//fprintf(stderr, "nValue.%li \n", mtx.vout[i+1].nValue);
mpz_clear(mpzValue);
//fprintf(stderr, "[%i] nValue.%li minimum.%i scriptpubkey.%s\n", i, mtx.vout[i+1].nValue, minimum, HexStr(mtx.vout[i+1].scriptPubKey.begin(),mtx.vout[i+1].scriptPubKey.end()).c_str());
if ( mtx.vout[i+1].nValue < minimum )
{
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);
if ( skipminimum == 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","value too small, try releasing a larger amount, or use skipminimum flag"));
if ( params != 0 )
free_json(params);
return(result);
}
else
{
// NOTE: should make this default behaviour.
// truncate off any vouts that are less than minimum.
mtx.vout.resize(i+1);
break;
}
}
totalamountsent += mtx.vout[i+1].nValue;
}
if ( totalamountsent < amount ) newamount = totalamountsent;
fprintf(stderr, "newamount.%li totalamountsent.%li\n", newamount, totalamountsent);
//int64_t temptst = mpz_get_si(mpzTotalAllocations);
//fprintf(stderr, "checkamount RPC.%li totalallocations.%li\n",totalamountsent, temptst);
mpz_clear(mpzAmount); mpz_clear(mpzTotalAllocations);
}
else
@@ -899,9 +909,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
if ( (inputsum= AddPaymentsInputs(true,0,cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,lockedblocks,minrelease,blocksleft)) >= 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));
mtx.vout[0].nValue = inputsum - newamount - PAYMENTS_TXFEE; // only 1 txfee, so the minimum in this vout is a tx fee.
GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk);
CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr);
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret);
@@ -936,19 +944,21 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr)
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;
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,broadcast=0,lockedblocks,minrelease; std::vector<uint256> txidoprets;
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());
Paymentspk = GetUnspendable(cp,0);
if ( params != 0 && n > 1 && n <= 3 )
if ( params != 0 && n > 1 && n <= 4 )
{
txid = payments_juint256(jitem(params,0));
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,minimum,top,bottom,fixedAmount,excludeScriptPubKeys) == 0 && DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 0) )
if ( n == 4 )
broadcast = jint(jitem(params,3),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,minimum,top,bottom,fixedAmount,excludeScriptPubKeys) == 0 && DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid) == 0) )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid createtxid"));
@@ -970,18 +980,14 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr)
}
else
{
mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk));
opret = EncodePaymentsFundOpRet(txid);
// Use the below one along with other FinalizeCCTx/return, to get the ccvout scriptpubkey
/*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) )
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,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());
if ( params != 0 )
free_json(params);
//return(payments_rawtxresult(result,rawtx,0)); // disable sending for CCvout, as we only need to decode the tx.
free_json(params);
return(payments_rawtxresult(result,rawtx,1));
}
else
@@ -1014,7 +1020,7 @@ UniValue PaymentsMerge(struct CCcontract_info *cp,char *jsonstr)
{
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) )
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,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid) == 0) )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid createtxid"));
@@ -1032,7 +1038,6 @@ UniValue PaymentsMerge(struct CCcontract_info *cp,char *jsonstr)
// 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>>();
// try to pay to diffrent pubkey here... change txidpk.
if ( makeCCopret(opret, vData) )
mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,inputsum-PAYMENTS_TXFEE,Paymentspk,txidpk,&vData));
GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk);
@@ -1125,6 +1130,7 @@ UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr)
for (i=0; i<txidoprets.size(); i++)
{
std::vector<uint8_t> scriptPubKey,opret; int64_t allocation;
//fprintf(stderr, "txid.%s\n",txidoprets[i].GetHex().c_str());
if ( myGetTransaction(txidoprets[i],tx,hashBlock) != 0 && tx.vout.size() > 1 && DecodePaymentsTxidOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
{
totalallocations += allocation;
@@ -1204,6 +1210,14 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr)
free_json(params);
return(result);
}
if ( top-bottom < 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid range, top/bottom"));
if ( params != 0 )
free_json(params);
return(result);
}
if ( n > 6 )
{
for (i=0; i<n-6; i++)
@@ -1258,6 +1272,87 @@ UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr)
return(result);
}
UniValue PaymentsAirdropTokens(struct CCcontract_info *cp,char *jsonstr)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
UniValue result(UniValue::VOBJ);
uint256 hashBlock, tokenid = zeroid; CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::string rawtx;
int32_t lockedblocks,minrelease,top,bottom,n,i,minimum=10000; std::vector<std::vector<uint8_t>> excludeScriptPubKeys; int8_t fixedAmount;
cJSON *params = payments_reparse(&n,jsonstr);
if ( params != 0 && n >= 6 )
{
tokenid = payments_juint256(jitem(params,0));
lockedblocks = juint(jitem(params,1),0);
minrelease = juint(jitem(params,2),0);
minimum = juint(jitem(params,3),0);
if ( minimum < 10000 ) minimum = 10000;
top = juint(jitem(params,4),0);
bottom = juint(jitem(params,5),0);
fixedAmount = juint(jitem(params,6),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 || tokenid == zeroid )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","negative parameter, or top over 3999"));
if ( params != 0 )
free_json(params);
return(result);
}
// TODO: lookup tokenid and make sure it exists.
if ( n > 7 )
{
for (i=0; i<n-7; i++)
{
// Change to pubkeys! tokens are owned by a pubkey not an address.
std::string address;
address.append(jstri(params,7+i));
CTxDestination destination = DecodeDestination(address);
if (!IsValidDestination(destination))
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","address is not valid."));
result.push_back(Pair("invalid_address",address));
if ( params != 0 )
free_json(params);
return(result);
}
std::vector<uint8_t> vscriptPubKey;
CScript scriptPubKey = GetScriptForDestination(destination);
vscriptPubKey.assign(scriptPubKey.begin(), scriptPubKey.end());
excludeScriptPubKeys.push_back(vscriptPubKey);
}
}
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));
CScript tempopret = EncodePaymentsTokensOpRet(lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid);
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 pubkeys."));
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,0));
}
result.push_back(Pair("result","error"));
result.push_back(Pair("error","not enough normal funds"));
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","parameters error"));
}
if ( params != 0 )
free_json(params);
return(result);
}
UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx,txO; CPubKey Paymentspk,txidpk; int32_t i,j,n,flag=0,numoprets=0,lockedblocks,minrelease,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;
@@ -1345,7 +1440,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
}
result.push_back(Pair("excludeAddresses",a));
}
else if ( DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) != 0 )
else if ( DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid) != 0 )
{
if ( lockedblocks < 0 || minrelease < 0 || top <= 0 )
{
@@ -1374,11 +1469,15 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
{
txidpk = CCtxidaddr(txidaddr,createtxid);
GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk);
blocksleft = 0;
funds = AddPaymentsInputs(false,2,cp,mtx,txidpk,0,CC_MAXVINS,createtxid,lockedblocks,minrelease,blocksleft);
result.push_back(Pair(fundsaddr,ValueFromAmount(funds)));
result.push_back(Pair("utxos", (int64_t)blocksleft));
blocksleft = 0;
GetCCaddress(cp,fundsopretaddr,Paymentspk);
fundsopret = AddPaymentsInputs(false,1,cp,mtx,txidpk,0,CC_MAXVINS,createtxid,lockedblocks,minrelease,blocksleft);
result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret)));
result.push_back(Pair("utxos", (int64_t)blocksleft));
result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret)));
// Blocks until minrelease can be released.
elegiblefunds = AddPaymentsInputs(true,3,cp,mtx,txidpk,0,CC_MAXVINS,createtxid,lockedblocks,minrelease,blocksleft);
@@ -1416,7 +1515,7 @@ UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr)
txid = it->first.txhash;
if ( it->first.index == 0 && myGetTransaction(txid,tx,hashBlock) != 0 )
{
if ( tx.vout.size() > 0 && (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 'C' || 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 ( 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,minimum,top,bottom,fixedAmount,excludeScriptPubKeys,tokenid) == 'O') )
{
if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) || bottom < 0 || fixedAmount < 0 || minimum < 10000 )
{

View File

@@ -1380,15 +1380,6 @@ int64_t prices_enumaddedbets(uint256 &batontxid, std::vector<OneBetData> &bets,
// pricesbet rpc impl: make betting tx
UniValue PricesBet(int64_t txfee, int64_t amount, int16_t leverage, std::vector<std::string> synthetic)
{
fprintf(stderr, "assetchains_contract.%i vs eval_prices.%i\n",ASSETCHAINS_EARLYTXIDCONTRACT, EVAL_PRICES);
if ( ASSETCHAINS_EARLYTXIDCONTRACT == EVAL_PRICES && KOMODO_EARLYTXID_SCRIPTPUB.size() == 0 )
{
// Lock here, as in validation we cannot call lock in the function itself.
// may not be needed as the validation call to update the global, is called in a LOCK already, and it can only update there and here.
LOCK(cs_main);
GetKomodoEarlytxidScriptPub();
}
/*
int32_t nextheight = komodo_nextheight();
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextheight); UniValue result(UniValue::VOBJ);
struct CCcontract_info *cp, C;
@@ -1439,7 +1430,6 @@ UniValue PricesBet(int64_t txfee, int64_t amount, int16_t leverage, std::vector<
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "not enough funds"));
return(result);
*/
}
// pricesaddfunding rpc impl: add yet another bet

View File

@@ -195,6 +195,7 @@ bool RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransactio
bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx;
int64_t dummy;
numvins = tx.vin.size();
numvouts = tx.vout.size();
preventCCvins = preventCCvouts = -1;
@@ -255,7 +256,7 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
return eval->Invalid("unexpected normal vin for unlock");
}
if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) )
if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime, dummy) )
return eval->Invalid("txfee is too high");
amount = vinTx.vout[0].nValue;
reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit);

View File

@@ -24,7 +24,7 @@
// * Shut down WEEKS_UNTIL_DEPRECATION weeks' worth of blocks after the estimated release block height.
// * A warning is shown during the DEPRECATION_WARN_LIMIT worth of blocks prior to shut down.
static const int WEEKS_UNTIL_DEPRECATION = 52;
static const int DEPRECATION_HEIGHT = 1600000;
static const int DEPRECATION_HEIGHT = 2200000;
static const int APPROX_RELEASE_HEIGHT = DEPRECATION_HEIGHT - (WEEKS_UNTIL_DEPRECATION * 7 * 24 * 60);
// Number of blocks before deprecation to warn users

View File

@@ -2017,8 +2017,10 @@ int32_t get_stockprices(uint32_t now,uint32_t *prices,std::vector<std::string> s
{
char url[32768],*symbol,*timestr; cJSON *json,*obj; int32_t i,n=0,retval=-1; uint32_t uprice,timestamp;
sprintf(url,"https://api.iextrading.com/1.0/tops/last?symbols=%s",GetArg("-ac_stocks","").c_str());
fprintf(stderr,"url.(%s)\n",url);
if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"iex")) != 0 ) //
{
fprintf(stderr,"stocks.(%s)\n",jprint(json,0));
if ( (n= cJSON_GetArraySize(json)) > 0 )
{
retval = n;

View File

@@ -1,6 +1,9 @@
#ifndef KOMODO_NK_H
#define KOMODO_NK_H
//#define ASSETCHAINS_N 77
//#define ASSETCHAINS_K 3
#define ASSETCHAINS_N 96
#define ASSETCHAINS_K 5

View File

@@ -656,8 +656,12 @@ std::vector <std::pair<CAmount, CTxDestination>> vAddressSnapshot;
bool komodo_dailysnapshot(int32_t height)
{
int reorglimit = 10; // CHANGE BACK TO 100 AFTER TESTING!
int reorglimit = 100;
uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,undo_height,extraoffset;
// NOTE: To make this 100% safe under all sync conditions, it should be using a notarized notarization, from the DB.
// Under heavy reorg attack, its possible `komodo_notarized_height` can return a height that can't be found on chain sync.
// However, the DB can reorg the last notarization. By using 2 deep, we know 100% that the previous notarization cannot be reorged by online nodes,
// and as such will always be notarizing the same height. May need to check heights on scan back to make sure they are confirmed in correct order.
if ( (extraoffset= height % KOMODO_SNAPSHOT_INTERVAL) != 0 )
{
// we are on chain init, and need to scan all the way back to the correct height, other wise our node will have a diffrent snapshot to online nodes.
@@ -1369,9 +1373,10 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState
}
}
int32_t komodo_isnotaryvout(char *coinaddr) // from ac_private chains only
int32_t komodo_isnotaryvout(char *coinaddr,uint32_t tiptime) // from ac_private chains only
{
static int32_t didinit; static char notaryaddrs[sizeof(Notaries_elected1)/sizeof(*Notaries_elected1) + 1][64];
//use normal notary functions
int32_t i;
if ( didinit == 0 )
{
@@ -1480,7 +1485,7 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio
//
char destaddr[65];
Getscriptaddress(destaddr,txout.scriptPubKey);
if ( komodo_isnotaryvout(destaddr) == 0 )
if ( komodo_isnotaryvout(destaddr,tiptime) == 0 )
{
invalid_private_taddr = 1;
//return state.DoS(100, error("CheckTransaction(): this is a private chain, no public allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain");
@@ -6469,7 +6474,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
try {
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
//CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION);
CBufferedFile blkdat(fileIn, 32*MAX_BLOCK_SIZE(10000000), MAX_BLOCK_SIZE(10000000)+8, SER_DISK, CLIENT_VERSION);
CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE(10000000), MAX_BLOCK_SIZE(10000000)+8, SER_DISK, CLIENT_VERSION);
uint64_t nRewind = blkdat.GetPos();
while (!blkdat.eof()) {
boost::this_thread::interruption_point();
@@ -6503,7 +6508,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
blkdat.SetPos(nBlockPos);
CBlock block;
blkdat >> block;
nRewind = blkdat.GetPos();
nRewind = blkdat.GetPos();
// detect out of order blocks, and store them for later
uint256 hash = block.GetHash();

View File

@@ -48,6 +48,7 @@
using namespace std;
extern int32_t KOMODO_INSYNC;
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
#include "komodo_defs.h"
@@ -1689,6 +1690,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("synced", KOMODO_INSYNC!=0));
obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->GetHeight() : -1));
obj.push_back(Pair("bestblockhash", chainActive.LastTip()->GetBlockHash().GetHex()));
obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty()));
@@ -2082,4 +2084,4 @@ void RegisterBlockchainRPCCommands(CRPCTable &tableRPC)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
}

View File

@@ -1420,6 +1420,7 @@ UniValue getwalletburntransactions(const UniValue& params, bool fHelp)
UnmarshalBurnTx(*pwtx, targetSymbol, &targetCCid, payoutsHash, rawproof)) {
UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("txid", pwtx->GetHash().GetHex()));
if (vopret.begin()[0] == EVAL_TOKENS) {
// get burned token value
std::vector<std::pair<uint8_t, vscript_t>> oprets;
@@ -1460,6 +1461,12 @@ UniValue getwalletburntransactions(const UniValue& params, bool fHelp)
}
else
entry.push_back(Pair("burnedAmount", ValueFromAmount(pwtx->vout.back().nValue))); // coins
// check for corrupted strings (look for non-printable chars) from some older versions
// which caused "couldn't parse reply from server" error on client:
if (std::find_if(targetSymbol.begin(), targetSymbol.end(), [](int c) {return !std::isprint(c);}) != targetSymbol.end())
targetSymbol = "<value corrupted>";
entry.push_back(Pair("targetSymbol", targetSymbol));
entry.push_back(Pair("targetCCid", std::to_string(targetCCid)));
if (mytxid_inmempool(pwtx->GetHash()))

View File

@@ -69,7 +69,7 @@ bool komodo_txnotarizedconfirmed(uint256 txid);
uint32_t komodo_chainactive_timestamp();
int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp);
extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE;
extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN,IS_STAKED_NOTARY,IS_KOMODO_NOTARY,STAKED_ERA;
extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN,IS_STAKED_NOTARY,IS_KOMODO_NOTARY,STAKED_ERA,KOMODO_INSYNC;
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
uint32_t komodo_segid32(char *coinaddr);
int64_t komodo_coinsupply(int64_t *zfundsp,int64_t *sproutfundsp,int32_t height);
@@ -237,6 +237,7 @@ UniValue getinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
obj.push_back(Pair("KMDversion", KOMODO_VERSION));
obj.push_back(Pair("synced", KOMODO_INSYNC!=0));
//obj.push_back(Pair("VRSCversion", VERUS_VERSION));
obj.push_back(Pair("notarized", notarized_height));
obj.push_back(Pair("prevMoMheight", prevMoMheight));
@@ -1383,9 +1384,13 @@ UniValue getsnapshot(const UniValue& params, bool fHelp)
if (params.size() > 0 && !params[0].isNull()) {
top = atoi(params[0].get_str().c_str());
if (top < 0)
//throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, top must be a positive integer");
top = -1;
if ( top < 0 )
{
if ( KOMODO_SNAPSHOT_INTERVAL == 0 )
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, top must be a positive integer");
else
top = -1;
}
}
if ( fHelp || params.size() > 1)
@@ -1432,7 +1437,7 @@ UniValue getsnapshot(const UniValue& params, bool fHelp)
UniValue getaddresstxids(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 2)
if (fHelp || params.size() > 2 || params.size() < 1)
throw runtime_error(
"getaddresstxids (ccvout)\n"
"\nReturns the txids for an address(es) (requires addressindex to be enabled).\n"

View File

@@ -492,6 +492,7 @@ static const CRPCCommand vRPCCommands[] =
{ "payments", "paymentstxidopret", &payments_txidopret, true },
{ "payments", "paymentscreate", &payments_create, true },
{ "payments", "paymentsairdrop", &payments_airdrop, true },
{ "payments", "paymentsairdroptokens", &payments_airdroptokens, true },
{ "payments", "paymentslist", &payments_list, true },
{ "payments", "paymentsinfo", &payments_info, true },
{ "payments", "paymentsfund", &payments_fund, true },

View File

@@ -292,6 +292,7 @@ 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);
extern UniValue payments_airdroptokens(const UniValue& params, bool fHelp);
extern UniValue payments_info(const UniValue& params, bool fHelp);
extern UniValue payments_list(const UniValue& params, bool fHelp);

View File

@@ -70,9 +70,10 @@ extern std::string ASSETCHAINS_OVERRIDE_PUBKEY;
const std::string ADDR_TYPE_SPROUT = "sprout";
const std::string ADDR_TYPE_SAPLING = "sapling";
extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
extern int32_t KOMODO_INSYNC;
uint32_t komodo_segid32(char *coinaddr);
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
int32_t komodo_isnotaryvout(char *coinaddr); // from ac_private chains only
int32_t komodo_isnotaryvout(char *coinaddr,uint32_t tiptime); // from ac_private chains only
CBlockIndex *komodo_getblockindex(uint256 hash);
int64_t nWalletUnlockTime;
@@ -84,6 +85,7 @@ UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
#define PLAN_NAME_MAX 8
#define VALID_PLAN_NAME(x) (strlen(x) <= PLAN_NAME_MAX)
#define THROW_IF_SYNCING(INSYNC) if (INSYNC == 0) { throw runtime_error(strprintf("%s: Chain still syncing at height %d, aborting to prevent linkability analysis!",__FUNCTION__,chainActive.Tip()->GetHeight())); }
int tx_height( const uint256 &hash );
@@ -461,7 +463,6 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
int32_t komodo_isnotaryvout(char *coinaddr);
UniValue sendtoaddress(const UniValue& params, bool fHelp)
{
@@ -494,7 +495,7 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
if ( ASSETCHAINS_PRIVATE != 0 && AmountFromValue(params[1]) > 0 )
{
if ( komodo_isnotaryvout((char *)params[0].get_str().c_str()) == 0 )
if ( komodo_isnotaryvout((char *)params[0].get_str().c_str(),chainActive.LastTip()->nTime) == 0 )
{
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid " + strprintf("%s",komodo_chainname()) + " address");
}
@@ -4248,6 +4249,8 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
+ HelpExampleRpc("z_sendmany", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", [{\"address\": \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\" ,\"amount\": 5.0}]")
);
THROW_IF_SYNCING(KOMODO_INSYNC);
LOCK2(cs_main, pwalletMain->cs_wallet);
// Check that the from address is valid.
@@ -4557,6 +4560,8 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
+ HelpExampleRpc("z_shieldcoinbase", "\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\", \"zs14d8tc0hl9q0vg5l28uec5vk6sk34fkj2n8s7jalvw5fxpy6v39yn4s2ga082lymrkjk0x2nqg37\"")
);
THROW_IF_SYNCING(KOMODO_INSYNC);
LOCK2(cs_main, pwalletMain->cs_wallet);
// Validate the from address
@@ -4817,6 +4822,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
}
THROW_IF_SYNCING(KOMODO_INSYNC);
LOCK2(cs_main, pwalletMain->cs_wallet);
bool useAnyUTXO = false;
@@ -5582,7 +5589,7 @@ UniValue payments_release(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 1 )
throw runtime_error("paymentsrelease \"[%22createtxid%22,amount]\"\n");
throw runtime_error("paymentsrelease \"[%22createtxid%22,amount,(skipminimum)]\"\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;
@@ -5656,6 +5663,19 @@ UniValue payments_airdrop(const UniValue& params, bool fHelp)
return(PaymentsAirdrop(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_airdroptokens(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
if ( fHelp || params.size() != 1 )
throw runtime_error("payments_airdroptokens \"[%22tokenid%22,lockedblocks,minamount,mintoaddress,top,bottom,fixedFlag,%22excludePubKey%22,...,%22excludePubKeyN%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(PaymentsAirdropTokens(cp,(char *)params[0].get_str().c_str()));
}
UniValue payments_info(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;