From 36647d52f76d72cc88a82f0cd33d561fef8ab174 Mon Sep 17 00:00:00 2001 From: Michael Toutonghi Date: Mon, 9 Apr 2018 22:48:54 -0700 Subject: [PATCH] Added ac-eras parameter, which enables multiple reward eras by allowing other ac_reward releated parameters to accept comma separated lists of values, one for each era --- src/komodo_globals.h | 8 +- src/komodo_utils.h | 205 ++++++++++++++++++++++++++++++++++++------- src/main.cpp | 46 +--------- src/util.cpp | 34 +++++++ src/util.h | 11 +++ 5 files changed, 230 insertions(+), 74 deletions(-) diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 518d22cbd..53a2d80a8 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -54,7 +54,13 @@ char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; uint16_t ASSETCHAINS_PORT; uint32_t ASSETCHAIN_INIT; uint32_t ASSETCHAINS_MAGIC = 2387029918; -uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY = 10; +uint64_t ASSETCHAINS_SUPPLY = 10; +uint64_t ASSETCHAINS_COMMISSION; + +#define _MAX_ERAS 3 +int MAX_ERAS = _MAX_ERAS; +uint32_t ASSETCHAINS_ERAS = 1; +uint64_t ASSETCHAINS_ENDSUBSIDY[_MAX_ERAS],ASSETCHAINS_REWARD[_MAX_ERAS],ASSETCHAINS_HALVING[_MAX_ERAS],ASSETCHAINS_DECAY[_MAX_ERAS]; uint32_t KOMODO_INITDONE; char KMDUSERPASS[4096],BTCUSERPASS[4096]; uint16_t KMD_PORT = 7771,BITCOIND_PORT = 7771; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 999200c13..75c7c5663 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1498,6 +1498,121 @@ char *argv0names[] = (char *)"MNZ", (char *)"MNZ", (char *)"MNZ", (char *)"MNZ", (char *)"BTCH", (char *)"BTCH", (char *)"BTCH", (char *)"BTCH" }; +int64_t komodo_max_money() +{ + uint64_t max_money; + + if ( (baseid = komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 ) + max_money = komodo_maxallowed(baseid); + else + { + // figure out max_money by adding up supply and future block rewards, if no ac_END, max_money uses arbitrary 10,000,000 block end + max_money = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + (ASSETCHAINS_MAGIC & 0xffffff); + + // ASSETCHAINS_ERAS is zero based + for ( int j = 0; j <= ASSETCHAINS_ERAS && (j == 0 || ASSETCHAINS_ENDSUBSIDY[j - 1] != 0); j++ ) + { + uint64_t reward = ASSETCHAINS_REWARD[j]; + if ( reward > 0 ) + { + uint64_t lastEnd = j == 0 ? 0 : ASSETCHAINS_ENDSUBSIDY[j - 1]; + uint64_t curEnd = ASSETCHAINS_ENDSUBSIDY[j] == 0 ? 10000000 : : ASSETCHAINS_ENDSUBSIDY[j]; + uint64_t period = ASSETCHAINS_HALVING[j]; + uint64_t decay = ASSETCHAINS_DECAY[j]; + + // if exactly SATOSHIDEN, linear decay to zero or next era, same as: + // (next_era_reward + (starting reward - next_era_reward) / 2) * num_blocks + if ( decay == SATOSHIDEN ) + { + if ( j < ASSETCHAINS_ERAS ) + { + nextReward = ASSETCHAINS_REWARD[j + 1]; + } + else + nextReward = 0; + + // it can go either up or down if linear, swap to prevent underflow + if ( nextReward > reward ) + { + tmp = reward; + reward = nextReward; + nextReward = tmp; + } + max_money += ((nextReward + ((reward - nextReward + 1) >> 1)) * (curEnd - lastEnd); + } + else + { + for ( int k = 0; k < curEnd; k += period ) + { + max_money += period * reward; + // if zero, we do straight halving + reward = decay ? (reward * decay) / SATOSHIDEN : reward >> 1; + } + } + } + } + } + return((int64_t)max_money); +} + +uint64_t komodo_ac_block_subsidy(int nHeight) +{ + // we have to find our era, start from beginning reward, and determine current subsidy + uint64_t numerator, nSubsidy = 0; + int32_t numhalvings, curEra = 0; + static uint64_t cached_subsidy; static int32_t cached_numhalvings; static int cached_era; + + + // if we have zero end block with rewards or non-zero end-block, check further + if ( (ASSETCHAINS_ENDSUBSIDY[0] == 0 && ASSETCHAINS_REWARD[0] != 0) || ASSETCHAINS_ENDSUBSIDY[0] != 0 ) + { + // if we have an end block in the first era, find our current era + if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 ) + { + for ( curEra = 0; curEra <= ASSETCHAINS_ERAS; curEra++ ) + { + if ( ASSETCHAINS_ENDSUBSIDY[curEra] > nHeight || ASSETCHAINS_ENDSUBSIDY[curEra] == 0 ) + break; + } + } + if ( curEra <= ASSETCHAINS_ERAS ) + { + int nStart = curEra ? ASSETCHAINS_ENDSUBSIDY[curEra - 1] : 0; + nSubsidy = ASSETCHAINS_REWARD[curEra]; + if ( nSubsidy ) + { + if ( ASSETCHAINS_HALVING[curEra] != 0 ) + { + if ( (numhalvings = ((nHeight - nStart) / ASSETCHAINS_HALVING[curEra])) > 0 ) + { + if ( ASSETCHAINS_DECAY[curEra] == 0 ) + nSubsidy >>= numhalvings; + else if ( ASSETCHAINS_DECAY[curEra] == 100000000 && ASSETCHAINS_ENDSUBSIDY[curEra] != 0 ) + { + numerator = (ASSETCHAINS_ENDSUBSIDY[curEra] - nHeight); + nSubsidy = (nSubsidy * numerator) / (ASSETCHAINS_ENDSUBSIDY[curEra] - nStart); + } + else + { + if ( cached_subsidy > 0 && cached_era == curEra && cached_numhalvings == numhalvings ) + nSubsidy = cached_subsidy; + else + { + for (i=0; i < numhalvings && nSubsidy != 0; i++) + nSubsidy = (nSubsidy * ASSETCHAINS_DECAY[curEra]) / 100000000; + cached_subsidy = nSubsidy; + cached_numhalvings = numhalvings; + cached_era = curEra; + } + } + } + } + } + } + } + return(nSubsidy); +} + void komodo_args(char *argv0) { extern int64_t MAX_MONEY; @@ -1533,57 +1648,85 @@ void komodo_args(char *argv0) } if ( name.c_str()[0] != 0 ) { + ASSETCHAINS_ERAS = GetArg("-ac_eras",1) + if ( ASSETCHAINS_ERAS < 1 || ASSETCHAINS_ERAS > MAX_ERAS ) + { + ASSETCHAINS_ERAS = 1; + printf("ASSETCHAINS_ERAS, if specified, must be between 1 and %u. ASSETCHAINS_ERAS set to %u\n", MAX_ERAS, ASSETCHAINS_ERAS); + } + ASSETCHAINS_ERAS -= 1; + + SplitToi64(GetArg("-ac_end",""), &ASSETCHAINS_ENDSUBSIDY, 0); + SplitToi64(GetArg("-ac_reward",""), &ASSETCHAINS_REWARD, 0); + SplitToi64(GetArg("-ac_halving",""), &ASSETCHAINS_HALVING, 0); + SplitToi64(GetArg("-ac_decay",""), &ASSETCHAINS_DECAY, 0); + + for ( int i = 0; i < MAX_ERAS; i++ ) + { + if ( ASSETCHAINS_HALVING[i] != 0 && ASSETCHAINS_HALVING[i] < 1440 ) + { + ASSETCHAINS_HALVING[i] = 1440; + printf("ERA%u: ASSETCHAINS_HALVING must be at least 1440 blocks\n", i); + } + if ( ASSETCHAINS_DECAY[i] == 100000000 && ASSETCHAINS_ENDSUBSIDY == 0 ) + { + ASSETCHAINS_DECAY[i] = 0; + printf("ERA%u: ASSETCHAINS_DECAY of 100000000 means linear and that needs ASSETCHAINS_ENDSUBSIDY\n", i); + } + else if ( ASSETCHAINS_DECAY[i] > 100000000 ) + { + ASSETCHAINS_DECAY[i] = 0; + printf("ERA%u: ASSETCHAINS_DECAY cant be more than 100000000\n", i); + } + } + ASSETCHAINS_SUPPLY = GetArg("-ac_supply",10); - ASSETCHAINS_ENDSUBSIDY = GetArg("-ac_end",0); - ASSETCHAINS_REWARD = GetArg("-ac_reward",0); - ASSETCHAINS_HALVING = GetArg("-ac_halving",0); - ASSETCHAINS_DECAY = GetArg("-ac_decay",0); ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0); ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey",""); - if ( ASSETCHAINS_HALVING != 0 && ASSETCHAINS_HALVING < 1440 ) - { - ASSETCHAINS_HALVING = 1440; - printf("ASSETCHAINS_HALVING must be at least 1440 blocks\n"); - } - if ( ASSETCHAINS_DECAY == 100000000 && ASSETCHAINS_ENDSUBSIDY == 0 ) - { - ASSETCHAINS_DECAY = 0; - printf("ASSETCHAINS_DECAY of 100000000 means linear and that needs ASSETCHAINS_ENDSUBSIDY\n"); - } - else if ( ASSETCHAINS_DECAY > 100000000 ) - { - ASSETCHAINS_DECAY = 0; - printf("ASSETCHAINS_DECAY cant be more than 100000000\n"); - } + if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 && ASSETCHAINS_COMMISSION > 0 && ASSETCHAINS_COMMISSION <= 100000000 ) decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str()); else if ( ASSETCHAINS_COMMISSION != 0 ) { ASSETCHAINS_COMMISSION = 0; - printf("ASSETCHAINS_COMMISSION needs an ASETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n"); + printf("ASSETCHAINS_COMMISSION needs an ASSETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n"); } - if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_COMMISSION != 0 ) + + if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 ) { - printf("end.%llu reward.%llu halving.%llu decay.%llu perc.%llu\n",(long long)ASSETCHAINS_ENDSUBSIDY,(long long)ASSETCHAINS_REWARD,(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,(long long)ASSETCHAINS_COMMISSION); + printf("perc.%llu\n",(long long)ASSETCHAINS_COMMISSION); + extraptr = extrabuf; memcpy(extraptr,ASSETCHAINS_OVERRIDE_PUBKEY33,33), extralen = 33; - extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ENDSUBSIDY),(void *)&ASSETCHAINS_ENDSUBSIDY); - extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_REWARD),(void *)&ASSETCHAINS_REWARD); - extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_HALVING),(void *)&ASSETCHAINS_HALVING); - extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY),(void *)&ASSETCHAINS_DECAY); + + // if we have one era, this should create the same data structure as it used to, same if we increase _MAX_ERAS + for ( int i = 0; i <= ASSETCHAINS_ERAS; i++ ) + { + printf("ERA%u: end.%llu reward.%llu halving.%llu decay.%llu\n", i, + (long long)ASSETCHAINS_ENDSUBSIDY[i], + (long long)ASSETCHAINS_REWARD[i], + (long long)ASSETCHAINS_HALVING[i], + (long long)ASSETCHAINS_DECAY[i]); + + // TODO: Verify that we don't overrun extrabuf here, which is a 256 byte buffer + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ENDSUBSIDY[i]),(void *)&ASSETCHAINS_ENDSUBSIDY[i]); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_REWARD[i]),(void *)&ASSETCHAINS_REWARD[i]); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_HALVING[i]),(void *)&ASSETCHAINS_HALVING[i]); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY[i]),(void *)&ASSETCHAINS_DECAY[i]); + } extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_COMMISSION),(void *)&ASSETCHAINS_COMMISSION); } + addn = GetArg("-seednode",""); if ( strlen(addn.c_str()) > 0 ) ASSETCHAINS_SEED = 1; strncpy(ASSETCHAINS_SYMBOL,name.c_str(),sizeof(ASSETCHAINS_SYMBOL)-1); - if ( (baseid= komodo_baseid(ASSETCHAINS_SYMBOL)) >= 0 && baseid < 32 ) - MAX_MONEY = komodo_maxallowed(baseid); - else if ( ASSETCHAINS_REWARD == 0 ) - MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN; - else MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + ASSETCHAINS_REWARD * (ASSETCHAINS_ENDSUBSIDY==0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY); + + MAX_MONEY = komodo_max_money(); + //printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN); ASSETCHAINS_PORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen); + while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 ) { fprintf(stderr,"waiting for datadir\n"); diff --git a/src/main.cpp b/src/main.cpp index f45ad7bad..37242387a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1636,11 +1636,10 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) //uint64_t komodo_moneysupply(int32_t height); extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern uint32_t ASSETCHAINS_MAGIC; -extern uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; +extern uint64_t ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { - static uint64_t cached_subsidy; static int32_t cached_numhalvings; int32_t numhalvings,i; uint64_t numerator; CAmount nSubsidy = 3 * COIN; if ( ASSETCHAINS_SYMBOL[0] == 0 ) { @@ -1654,45 +1653,8 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { if ( nHeight == 1 ) return(ASSETCHAINS_SUPPLY * COIN + (ASSETCHAINS_MAGIC & 0xffffff)); - else if ( ASSETCHAINS_ENDSUBSIDY == 0 || nHeight < ASSETCHAINS_ENDSUBSIDY ) - { - if ( ASSETCHAINS_REWARD == 0 ) - return(10000); - else if ( ASSETCHAINS_ENDSUBSIDY != 0 && nHeight >= ASSETCHAINS_ENDSUBSIDY ) - return(0); - else - { - nSubsidy = ASSETCHAINS_REWARD; - if ( ASSETCHAINS_HALVING != 0 ) - { - if ( (numhalvings= (nHeight / ASSETCHAINS_HALVING)) > 0 ) - { - if ( numhalvings >= 64 && ASSETCHAINS_DECAY == 0 ) - return(0); - if ( ASSETCHAINS_DECAY == 0 ) - nSubsidy >>= numhalvings; - else if ( ASSETCHAINS_DECAY == 100000000 && ASSETCHAINS_ENDSUBSIDY != 0 ) - { - numerator = (ASSETCHAINS_ENDSUBSIDY - nHeight); - nSubsidy = (nSubsidy * numerator) / ASSETCHAINS_ENDSUBSIDY; - } - else - { - if ( cached_subsidy > 0 && cached_numhalvings == numhalvings ) - nSubsidy = cached_subsidy; - else - { - for (i=0; i>= halvings; - return nSubsidy; + //return nSubsidy; } bool IsInitialBlockDownload() diff --git a/src/util.cpp b/src/util.cpp index dd9b709a2..5f5b7d10d 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -18,6 +18,8 @@ #include "komodo_defs.h" #include +#include +#include #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) #include @@ -362,6 +364,38 @@ void ParseParameters(int argc, const char* const argv[]) } } +void SplitToi64(const std::string& strVal, int64_t[_MAX_ERAS] *outVals, const int64_t nDefault) +{ + istringstream ss(strVal); + vector vec; + + int64_t i, numVals = 0; + + while ( ss.peek() == ' ' ) + ss.ignore(); + + while ( ss >> i ) + { + outVals[numVals] = i; + numVals += 1; + + while ( ss.peek() == ' ' ) + ss.ignore(); + if ( ss.peek() == ',' ) + ss.ignore(); + while ( ss.peek() == ' ' ) + ss.ignore(); + } + + if ( numVals > 0 ) + nDefault = outVals[numVals - 1]; + + for ( i=numVals; i < MAX_ERAS; i++ ) + { + outVals[i] = nDefault; + } +} + std::string GetArg(const std::string& strArg, const std::string& strDefault) { if (mapArgs.count(strArg)) diff --git a/src/util.h b/src/util.h index faf741409..89cc94bbc 100644 --- a/src/util.h +++ b/src/util.h @@ -157,6 +157,17 @@ inline bool IsSwitchChar(char c) #endif } +/** + * Return string argument or default value + * + * @param strVal string to split + * @param outVals array of numbers from string or default + * if the string is null, nDefault is used for all array entries + * else if the string has fewer than _MAX_ERAS entries, then the last + * entry fills remaining entries + */ +void SplitToi64(const std::string& strVal, int64_t[_MAX_ERAS]& outVals, int64_t nDefault); + /** * Return string argument or default value *