diff --git a/src/cc/CCPayments.h b/src/cc/CCPayments.h index cff304a2e..c45fbab9e 100644 --- a/src/cc/CCPayments.h +++ b/src/cc/CCPayments.h @@ -22,6 +22,7 @@ #define PAYMENTS_TXFEE 10000 extern std::vector > vAddressSnapshot; +extern int32_t lastSnapShotHeight; bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index e72184719..7ab3e8202 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -16,27 +16,6 @@ #include "CCPayments.h" /* -192.168.0.139: RH side screen. - ./komodod -ac_name=TESTDP -ac_supply=10000000 -ac_reward=1000000000 -ac_nk=96,5 -ac_blocktime=20 -ac_cc=2 -addndoe=192.168.0.112 - - TESTDP.tar saved after distributing funds randomly. approx block 120. -LH screen: - ./komodod -ac_name=TESTDP -ac_supply=10000000 -ac_reward=1000000000 -ac_nk=96,5 -ac_blocktime=20 -ac_cc=2 -pubkey=0244a96824fa317433f0eaa6d5b1faf68e802b1958df273c24cb82bce1ef8e1aec -gen -genproclimit=1 - -./komodo-cli -ac_name=TESTDP paymentsairdrop '[10,2000,500,"76a9149758abb81ee168dd3824cb55e94df509b35462d788ac",76a9144cfd873dadbfbb4b9c03e77ecaa6cfb74a484f4888ac"]' - -use notarizations DB to scan back from the correct height, then undo ALL blocks back to this notarized height! -payments airdrop: - - extra RPC to merge all payments inputs to a single utxo, this must be called first and be confirmed before payments release, - or tx will be too big, we can check add payments inputs is only 1 input, at RPC and in validation very early on. - - do getsnapshot2 every 1440 blocks and save the result into some global sorted vector. - -this allows any address balance to be calculated by only iterating each 1439 blocks maximum. - - calculate scriptpubkey to pay from each address, set allocations from balance of each address. allocation = balance? - -payments airdrop paying a token: - - tokenid, top number of tokens to pay, list of pubkeys to exclude as optional param - - token airdrop code should be the same as normal snapshot, but call a diffrent snapshot function that only fetches the info for a specific tokenid given. - this should be fine to work in validation/rpc level rather than a global saved result, as a single token id doesnt require iterating the whole DB. - 0) txidopret <- allocation, scriptPubKey, opret 1) create <- locked_blocks, minrelease, list of txidopret @@ -138,6 +117,26 @@ uint8_t DecodePaymentsFundOpRet(CScript scriptPubKey,uint256 &checktxid) return(0); } +CScript EncodePaymentsMergeOpRet(uint256 checktxid) +{ + CScript opret; uint8_t evalcode = EVAL_PAYMENTS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'M' << checktxid); + return(opret); +} + +uint8_t DecodePaymentsMergeOpRet(CScript scriptPubKey,uint256 &checktxid) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> checktxid) != 0 ) + { + if ( e == EVAL_PAYMENTS && f == 'M' ) + return(f); + } + return(0); +} + CScript EncodePaymentsOpRet(int32_t lockedblocks,int32_t minrelease,int64_t totalallocations,std::vector txidoprets) { CScript opret; uint8_t evalcode = EVAL_PAYMENTS; @@ -158,20 +157,19 @@ uint8_t DecodePaymentsOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t & return(0); } - -CScript EncodePaymentsSnapsShotOpRet(int32_t lockedblocks,int32_t minrelease,int32_t top,std::vector> excludeScriptPubKeys) +CScript EncodePaymentsSnapsShotOpRet(int32_t lockedblocks,int32_t minrelease,int32_t top,int32_t bottom,int8_t fixedAmount,std::vector> excludeScriptPubKeys) { CScript opret; uint8_t evalcode = EVAL_PAYMENTS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << top << excludeScriptPubKeys); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << lockedblocks << minrelease << top << bottom << fixedAmount << excludeScriptPubKeys); return(opret); } -uint8_t DecodePaymentsSnapsShotOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &top,std::vector> &excludeScriptPubKeys) +uint8_t DecodePaymentsSnapsShotOpRet(CScript scriptPubKey,int32_t &lockedblocks,int32_t &minrelease,int32_t &top,int32_t &bottom,int8_t &fixedAmount,std::vector> &excludeScriptPubKeys) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> lockedblocks; ss >> minrelease; ss >> top; ss >> excludeScriptPubKeys) != 0 ) + if ( 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); @@ -233,9 +231,9 @@ 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; uint8_t funcid = 0; + 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 txidoprets; bool fHasOpret = false; CPubKey txidpk,Paymentspk; - int32_t top; std::vector> excludeScriptPubKeys; + int32_t top,bottom=0; std::vector> excludeScriptPubKeys; bool fFixedAmount = false; mpz_t mpzTotalAllocations, mpzAllocation;; mpz_init(mpzTotalAllocations); // user marker vout to get the createtxid if ( tx.vout.size() < 2 ) @@ -253,9 +251,9 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & // 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,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,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 ) + if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) ) return(eval->Invalid("negative values")); Paymentspk = GetUnspendable(cp,0); txidpk = CCtxidaddr(txidaddr,createtxid); @@ -301,32 +299,60 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & } 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 > 5000 ) + if ( top > 3999 ) return(eval->Invalid("transaction too big")); - for ( auto address : vAddressSnapshot ) + if ( fixedAmount == 7 ) { - CScript scriptPubKey = GetScriptForDestination(address.second); - for ( auto skipkey : excludeScriptPubKeys ) + // game setting, randomise bottom and top values + uint64_t x; + uint256 tmphash = chainActive[lastSnapShotHeight]->GetBlockHash(); + memcpy(&x,&tmphash,sizeof(x)); + bottom = ((x & 0xff) % 50); + if ( bottom == 0 ) bottom = 1; + top = (((x>>8) & 0xff) % 100); + if ( top < 50 ) top += 50; + bottom = (vAddressSnapshot.size()*bottom)/100; + top = (vAddressSnapshot.size()*top)/100; + fprintf(stderr, "bottom.%i top.%i\n",bottom,top); + fFixedAmount = true; + } + 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 ) { - //fprintf(stderr, "scriptpubkey.%s\n skipkey.%s", HexStr(scriptPubKey).c_str(), HexStr(CScript(skipkey.begin(), skipkey.end())).c_str()); - if ( scriptPubKey != CScript(skipkey.begin(), skipkey.end()) ) + if ( scriptPubKey == CScript(skipkey.begin(), skipkey.end()) ) { - mpz_init(mpzAllocation); - i++; - scriptPubKeys.push_back(scriptPubKey); - allocations.push_back(address.first); - mpz_set_si(mpzAllocation,address.first); - mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation); - mpz_clear(mpzAllocation); - } + skip = true; + //fprintf(stderr, "SKIPPED::: %s\n", CBitcoinAddress(address.second).ToString().c_str()); + } } - if ( i == top ) // we reached top amount to pay, it can be less than this! + 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 ( funcid == 'O' ) { // tokens snapshot. @@ -355,12 +381,20 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & 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")); } - mpz_init(mpzAllocation); - mpz_set_si(mpzAllocation,allocations[n]); - mpz_mul(mpzAllocation,mpzAllocation,mpzCheckamount); - mpz_cdiv_q(mpzAllocation,mpzAllocation,mpzTotalAllocations); - int64_t test = mpz_get_si(mpzAllocation); - mpz_clear(mpzAllocation); + int64_t test; + if ( fFixedAmount ) + { + test = checkamount / (top-bottom); + } + else + { + 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); + } // Vairance of 1 sat is allowed, for rounding errors. if ( test >= tx.vout[i].nValue+1 && test <= tx.vout[i].nValue-1 ) { @@ -571,7 +605,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 txidoprets; - int32_t top; std::vector> excludeScriptPubKeys; int8_t funcid; + int32_t top,bottom=0; std::vector> excludeScriptPubKeys; int8_t funcid,fixedAmount=0; bool fFixedAmount = false; mpz_t mpzTotalAllocations; mpz_init(mpzTotalAllocations); cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); @@ -582,9 +616,9 @@ 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,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,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 ) + if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","negative parameter")); @@ -605,7 +639,8 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) } txidpk = CCtxidaddr(txidaddr,createtxid); mtx.vout.push_back(MakeCC1of2vout(EVAL_PAYMENTS,0,Paymentspk,txidpk)); - if ( funcid = 'C' ) + //fprintf(stderr, "funcid.%i\n", funcid); + if ( funcid == 'C' ) { // normal payments for (i=0; i 5000 ) + if ( vAddressSnapshot.size() == 0 ) { - // need to test the maximum number, this is an estimate. result.push_back(Pair("result","error")); - result.push_back(Pair("error","cannot pay more than 5000 addresses")); + result.push_back(Pair("error","first snapshot has not happened yet")); if ( params != 0 ) free_json(params); return(result); } - for ( auto address : vAddressSnapshot ) + if ( top > 3999 ) { - CScript scriptPubKey = GetScriptForDestination(address.second); - for ( auto skipkey : excludeScriptPubKeys ) + result.push_back(Pair("result","error")); + result.push_back(Pair("error","cannot pay more than 3999 addresses")); + if ( params != 0 ) + free_json(params); + return(result); + } + i = 0; + //for ( auto address : vAddressSnapshot ) + if ( fixedAmount == 7 ) + { + // game setting, randomise bottom and top values + uint64_t x; + uint256 tmphash = chainActive[lastSnapShotHeight]->GetBlockHash(); + memcpy(&x,&tmphash,sizeof(x)); + bottom = ((x & 0xff) % 50); + if ( bottom == 0 ) bottom = 1; + top = (((x>>8) & 0xff) % 100); + if ( top < 50 ) top += 50; + bottom = (vAddressSnapshot.size()*bottom)/100; + top = (vAddressSnapshot.size()*top)/100; + fprintf(stderr, "bottom.%i top.%i\n",bottom,top); + fFixedAmount = true; + } + 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()) ) + if ( scriptPubKey == CScript(skipkey.begin(), skipkey.end()) ) { - mpz_t mpzAllocation; mpz_init(mpzAllocation); - i++; - //fprintf(stderr, "address: %s nValue.%li \n", CBitcoinAddress(address.second).ToString().c_str(), address.first); - vout.nValue = address.first; - vout.scriptPubKey = scriptPubKey; - mpz_set_si(mpzAllocation,address.first); - mpz_add(mpzTotalAllocations,mpzTotalAllocations,mpzAllocation); //totalallocations += address.first; - mtx.vout.push_back(vout); - mpz_clear(mpzAllocation); - } else fprintf(stderr, "SKIPPED::: %s\n", CBitcoinAddress(address.second).ToString().c_str()); + skip = true; + //fprintf(stderr, "SKIPPED::: %s\n", CBitcoinAddress(address.second).ToString().c_str()); + } } - if ( i == top ) // we reached top amount to pay, it can be less than this! + 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; } m = i; // this is the amount we got, either top, or all of the address on the chain. } - else if ( funcid = 'O' ) + else if ( funcid == 'O' ) { // token snapshot } newamount = amount; int64_t totalamountsent = 0; mpz_t mpzAmount; mpz_init(mpzAmount); mpz_set_si(mpzAmount,amount); + fprintf(stderr, "m.%i\n",m); for (i=0; i txidoprets; - int32_t top; std::vector> excludeScriptPubKeys; // snapshot - uint256 tokenid; + int32_t top,bottom; std::vector> excludeScriptPubKeys; // snapshot + uint256 tokenid; int8_t fixedAmount; cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); Paymentspk = GetUnspendable(cp,0); @@ -789,14 +869,14 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) amount = jdouble(jitem(params,1),0) * SATOSHIDEN + 0.0000000049; if ( n == 3 ) useopret = jint(jitem(params,2),0) != 0; - if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() == 1 || (DecodePaymentsOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) == 0 && DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys) == 0 && DecodePaymentsTokensOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,excludeScriptPubKeys,tokenid) == 0) ) + 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) ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","invalid createtxid")); } else if ( AddNormalinputs(mtx,mypk,amount+PAYMENTS_TXFEE,60) > 0 ) { - if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 ) + if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","negative parameter")); @@ -961,43 +1041,54 @@ 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,n,i; std::vector> excludeScriptPubKeys; + int32_t lockedblocks,minrelease,top,bottom,n,i; std::vector> excludeScriptPubKeys; int8_t fixedAmount; + if ( KOMODO_SNAPSHOT_INTERVAL == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","cannot use airdrop wihtout -ac_snapshot set.")); + return(result); + } cJSON *params = payments_reparse(&n,jsonstr); - if ( params != 0 && n >= 4 ) + if ( params != 0 && n >= 5 ) { lockedblocks = juint(jitem(params,0),0); minrelease = juint(jitem(params,1),0); top = juint(jitem(params,2),0); - if ( lockedblocks < 0 || minrelease < 0 || top < 0 ) + 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 ) { result.push_back(Pair("result","error")); - result.push_back(Pair("error","negative parameter")); + result.push_back(Pair("error","negative parameter, or top over 3999")); if ( params != 0 ) free_json(params); return(result); } - for (i=0; i 5 ) { - /* TODO: Change this RPC to take an address. Because a tokens airdrop needs its own RPC anyway. - CTxDestination destination = DecodeDestination(name_); - CScript scriptPubKey = GetScriptForDestination(destination); - */ - char *inputhex = jstri(params,3+i); - std::vector scriptPubKey; - int32_t len = strlen(inputhex)/2; - scriptPubKey.resize(len); - decode_hex((uint8_t *)scriptPubKey.data(),len,(char *)inputhex); - excludeScriptPubKeys.push_back(scriptPubKey); + for (i=0; i scriptPubKey; + int32_t len = strlen(inputhex)/2; + scriptPubKey.resize(len); + decode_hex((uint8_t *)scriptPubKey.data(),len,(char *)inputhex); + excludeScriptPubKeys.push_back(scriptPubKey); + } } mypk = pubkey2pk(Mypubkey()); Paymentspk = GetUnspendable(cp,0); if ( AddNormalinputs(mtx,mypk,2*PAYMENTS_TXFEE,60) > 0 ) { mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,PAYMENTS_TXFEE,Paymentspk,Paymentspk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsSnapsShotOpRet(lockedblocks,minrelease,top,excludeScriptPubKeys)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsSnapsShotOpRet(lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys)); if ( params != 0 ) free_json(params); - return(payments_rawtxresult(result,rawtx,0)); + return(payments_rawtxresult(result,rawtx,1)); } result.push_back(Pair("result","error")); result.push_back(Pair("error","not enough normal funds")); @@ -1015,8 +1106,8 @@ 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; std::vector txidoprets; int64_t funds,fundsopret,totalallocations=0,allocation; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock; - int32_t top; std::vector> excludeScriptPubKeys; // snapshot - uint256 tokenid; + int32_t top,bottom; std::vector> excludeScriptPubKeys; // snapshot + uint256 tokenid; int8_t fixedAmount; cJSON *params = payments_reparse(&n,jsonstr); if ( params != 0 && n == 1 ) { @@ -1071,9 +1162,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,excludeScriptPubKeys) != 0 ) + else if ( DecodePaymentsSnapsShotOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,top,bottom,fixedAmount,excludeScriptPubKeys) != 0 ) { - if ( lockedblocks < 0 || minrelease < 0 || top <= 0 ) + if ( lockedblocks < 0 || minrelease < 0 || top <= 0 || bottom < 0 || fixedAmount < 0 || top > 3999 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","negative parameter")); @@ -1085,6 +1176,9 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) result.push_back(Pair("lockedblocks",(int64_t)lockedblocks)); result.push_back(Pair("minrelease",(int64_t)minrelease)); result.push_back(Pair("top",(int64_t)top)); + result.push_back(Pair("bottom",(int64_t)bottom)); + result.push_back(Pair("fixedFlag",(int64_t)fixedAmount)); + // TODO: convert to show addresses instead of scriptpubkey. for ( auto scriptPubKey : excludeScriptPubKeys ) a.push_back(HexStr(scriptPubKey.begin(),scriptPubKey.end())); result.push_back(Pair("excludeScriptPubkeys",a)); @@ -1104,6 +1198,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) result.push_back(Pair("minrelease",(int64_t)minrelease)); result.push_back(Pair("top",(int64_t)top)); result.push_back(Pair("tokenid",tokenid.ToString())); + // TODO: show pubkeys instead of scriptpubkeys for ( auto scriptPubKey : excludeScriptPubKeys ) a.push_back(HexStr(scriptPubKey.begin(),scriptPubKey.end())); result.push_back(Pair("excludeScriptPubkeys",a)); @@ -1146,8 +1241,8 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr) { std::vector > addressIndex; uint256 txid,hashBlock,tokenid; - UniValue result(UniValue::VOBJ),a(UniValue::VARR); char markeraddr[64],str[65]; CPubKey Paymentspk; CTransaction tx; int32_t lockedblocks,minrelease; std::vector txidoprets; int64_t totalallocations; - int32_t top; std::vector> excludeScriptPubKeys; + UniValue result(UniValue::VOBJ),a(UniValue::VARR); char markeraddr[64],str[65]; CPubKey Paymentspk; CTransaction tx; int32_t lockedblocks,minrelease; std::vector txidoprets; int64_t totalallocations=0; + int32_t top=0,bottom=0; std::vector> excludeScriptPubKeys; int8_t fixedAmount = 0; Paymentspk = GetUnspendable(cp,0); GetCCaddress1of2(cp,markeraddr,Paymentspk,Paymentspk); SetCCtxids(addressIndex,markeraddr,true); @@ -1156,9 +1251,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,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,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 || txidoprets.size() < 2 ) + if ( lockedblocks < 0 || minrelease < 0 || (totalallocations <= 0 && top <= 0 ) || bottom < 0 || fixedAmount < 0 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","negative parameter")); @@ -1169,6 +1264,6 @@ UniValue PaymentsList(struct CCcontract_info *cp,char *jsonstr) } } result.push_back(Pair("result","success")); - result.push_back(Pair("createtxids",a)); - return(result); + result.push_back(Pair("createtxids",a)); + return(result); } diff --git a/src/init.cpp b/src/init.cpp index 4003f9ced..bab2aba77 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -35,6 +35,7 @@ #include "httprpc.h" #include "key.h" #include "notarisationdb.h" + #ifdef ENABLE_MINING #include "key_io.h" #endif @@ -55,6 +56,7 @@ #ifdef ENABLE_WALLET #include "wallet/wallet.h" #include "wallet/walletdb.h" + #endif #include #include @@ -89,9 +91,11 @@ using namespace std; extern void ThreadSendAlert(); +extern bool komodo_dailysnapshot(int32_t height); extern int32_t KOMODO_LOADINGBLOCKS; extern bool VERUS_MINTBLOCKS; extern char ASSETCHAINS_SYMBOL[]; +extern int32_t KOMODO_SNAPSHOT_INTERVAL; ZCJoinSplit* pzcashParams = NULL; @@ -1622,6 +1626,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain"); break; } + + if ( ASSETCHAINS_CC != 0 && KOMODO_SNAPSHOT_INTERVAL != 0 && chainActive.Height() > KOMODO_SNAPSHOT_INTERVAL ) + { + if ( !komodo_dailysnapshot(chainActive.Height()) ) + { + strLoadError = _("daily snapshot failed, please reindex your chain."); + break; + } + } if (!fReindex) { uiInterface.InitMessage(_("Rewinding blocks if needed...")); diff --git a/src/komodo_defs.h b/src/komodo_defs.h index a9df99c0e..a3bde708b 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -20,7 +20,6 @@ #define ASSETCHAINS_MINHEIGHT 128 #define ASSETCHAINS_MAX_ERAS 3 #define KOMODO_ELECTION_GAP 2000 -#define KOMODO_SNAPSHOT_INTERVAL 1440 // 1440 is approx 1 day. Maybe this can be -ac param to allow for diffrent block times etc.? #define ROUNDROBIN_DELAY 61 #define KOMODO_ASSETCHAIN_MAXLEN 65 #define KOMODO_LIMITED_NETWORKSIZE 4 @@ -79,7 +78,7 @@ extern std::string DONATION_PUBKEY; extern uint8_t ASSETCHAINS_PRIVATE; extern int32_t USE_EXTERNAL_PUBKEY; extern char NOTARYADDRS[64][64]; -extern int32_t KOMODO_TESTNODE; +extern int32_t KOMODO_TESTNODE, KOMODO_SNAPSHOT_INTERVAL; int tx_height( const uint256 &hash ); extern std::vector vWhiteListAddress; void komodo_netevent(std::vector payload); diff --git a/src/komodo_globals.h b/src/komodo_globals.h index dc8cbda35..8d440cbaf 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -109,7 +109,7 @@ uint64_t PENDING_KOMODO_TX; extern int32_t KOMODO_LOADINGBLOCKS; unsigned int MAX_BLOCK_SIGOPS = 20000; -int32_t KOMODO_TESTNODE; +int32_t KOMODO_TESTNODE, KOMODO_SNAPSHOT_INTERVAL; struct komodo_kv *KOMODO_KV; pthread_mutex_t KOMODO_KV_mutex,KOMODO_CC_mutex; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index cfb133a9d..137bace4c 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1752,6 +1752,7 @@ void komodo_args(char *argv0) ASSETCHAINS_BLOCKTIME = GetArg("-ac_blocktime",60); ASSETCHAINS_PUBLIC = GetArg("-ac_public",0); ASSETCHAINS_PRIVATE = GetArg("-ac_private",0); + KOMODO_SNAPSHOT_INTERVAL = GetArg("-ac_snapshot",0); Split(GetArg("-ac_nk",""), ASSETCHAINS_NK, 0); if ( (KOMODO_REWIND= GetArg("-rewind",0)) != 0 ) { @@ -2012,7 +2013,7 @@ void komodo_args(char *argv0) fprintf(stderr,"-ac_script and -ac_marmara are mutually exclusive\n"); StartShutdown(); } - if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 || ASSETCHAINS_CBOPRET != 0 || Mineropret.size() != 0 || (ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0) ) + if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 || ASSETCHAINS_CBOPRET != 0 || Mineropret.size() != 0 || (ASSETCHAINS_NK[0] != 0 && ASSETCHAINS_NK[1] != 0) || KOMODO_SNAPSHOT_INTERVAL != 0 ) { fprintf(stderr,"perc %.4f%% ac_pub=[%02x%02x%02x...] acsize.%d\n",dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0],ASSETCHAINS_OVERRIDE_PUBKEY33[1],ASSETCHAINS_OVERRIDE_PUBKEY33[2],(int32_t)ASSETCHAINS_SCRIPTPUB.size()); extraptr = extrabuf; @@ -2148,6 +2149,11 @@ void komodo_args(char *argv0) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_NK[0]),(void *)&ASSETCHAINS_NK[0]); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_NK[1]),(void *)&ASSETCHAINS_NK[1]); } + if ( KOMODO_SNAPSHOT_INTERVAL != 0 ) + { + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(KOMODO_SNAPSHOT_INTERVAL),(void *)&KOMODO_SNAPSHOT_INTERVAL); + fprintf(stderr, "snapshot interval.%i\n",KOMODO_SNAPSHOT_INTERVAL); + } } addn = GetArg("-seednode",""); diff --git a/src/main.cpp b/src/main.cpp index 3168b773c..ef1a1a40b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -673,7 +673,7 @@ bool komodo_dailysnapshot(int32_t height) { // we are at the right height in connect block to scan back to last notarized height. notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); - notarized_height > height-100 ? undo_height = notarized_height : undo_height = height-reorglimit; + notarized_height > height-reorglimit ? undo_height = notarized_height : undo_height = height-reorglimit; } fprintf(stderr, "doing snapshot for height.%i undo_height.%i\n", height, undo_height); // if we already did this height dont bother doing it again, this is just a reorg. The actual snapshot height cannot be reorged. @@ -732,7 +732,7 @@ bool komodo_dailysnapshot(int32_t height) //for (int j = 0; j < 50; j++) // fprintf(stderr, "j.%i address.%s nValue.%li\n",j, CBitcoinAddress(vAddressSnapshot[j].second).ToString().c_str(), vAddressSnapshot[j].first ); // include only top 5000 address. - if ( vAddressSnapshot.size() > 5000 ) vAddressSnapshot.resize(5000); + if ( vAddressSnapshot.size() > 3999 ) vAddressSnapshot.resize(3999); lastSnapShotHeight = undo_height; fprintf(stderr, "vAddressSnapshot.size.%li\n", vAddressSnapshot.size()); return true; @@ -3592,8 +3592,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin fprintf(stderr,"valueout %.8f too big\n",(double)valueout/COIN); return state.DoS(100, error("ConnectBlock(): GetValueOut too big"),REJECT_INVALID,"tx valueout is too big"); } - prevsum = voutsum; - voutsum += valueout; + //prevsum = voutsum; + //voutsum += valueout; /*if ( KOMODO_VALUETOOBIG(voutsum) != 0 ) { fprintf(stderr,"voutsum %.8f too big\n",(double)voutsum/COIN); @@ -4251,7 +4251,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * komodo_pricesupdate(pindexNew->GetHeight(),pblock); if ( ASSETCHAINS_SAPLING <= 0 && pindexNew->nTime > KOMODO_SAPLING_ACTIVATION - 24*3600 ) komodo_activate_sapling(pindexNew); - if ( ASSETCHAINS_CC != 0 && (pindexNew->GetHeight() % KOMODO_SNAPSHOT_INTERVAL) == 0 ) + if ( ASSETCHAINS_CC != 0 && KOMODO_SNAPSHOT_INTERVAL != 0 && (pindexNew->GetHeight() % KOMODO_SNAPSHOT_INTERVAL) == 0 && pindexNew->GetHeight() > KOMODO_SNAPSHOT_INTERVAL ) { uint64_t start = time(NULL); if ( !komodo_dailysnapshot(pindexNew->GetHeight()) ) @@ -6198,12 +6198,6 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->GetHeight(), nGoodTransactions); - if ( ASSETCHAINS_CC != 0 && chainActive.Height() > KOMODO_SNAPSHOT_INTERVAL ) - { - if ( !komodo_dailysnapshot(chainActive.Height()) ) - fprintf(stderr, "daily snapshot failed, please reindex your chain\n"); // maybe force shutdown here? - } - return true; } diff --git a/src/miner.cpp b/src/miner.cpp index a2ff8c933..810607d5a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -291,9 +291,9 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 txvalue = tx.GetValueOut(); if ( KOMODO_VALUETOOBIG(txvalue) != 0 ) continue; - if ( KOMODO_VALUETOOBIG(txvalue + voutsum) != 0 ) - continue; - voutsum += txvalue; + //if ( KOMODO_VALUETOOBIG(txvalue + voutsum) != 0 ) // has been commented from main.cpp ? + // continue; + //voutsum += txvalue; if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,0) < 0 ) { //fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure nHeight.%d nTime.%u vs locktime.%u\n",nHeight,(uint32_t)pblock->nTime,(uint32_t)tx.nLockTime); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8733b2894..8a671b322 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5633,7 +5633,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,%22paytxid0%22,...,%22paytxidN%22]\"\n"); + throw runtime_error("paymentsairdrop \"[lockedblocks,minamount,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;