diff --git a/README.md b/README.md index c962b52ef42..3905eac3eae 100755 --- a/README.md +++ b/README.md @@ -19,17 +19,17 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers. ## Introduction -X-CASH is a cryptocurrency built using the Cryptonight v8 (CNv2) algorithm, with the aim to become and standard in digital payment and transaction settlement. We believe privacy is very important when it comes to managing personal finances, but at the same time banks and institutions need to know the source of the funds for KYC purposes. Therefore, we plan on leaving the users the choice of whether or not they want their transaction to be public. Because we are implementing a worldwide network of dedicated servers, we hope to make the synchronization of the blockchain faster than other cryptocurrencies as well as reducing transaction latency. We believe this network will be a key component in the deployment of the future improvements we plan on adding to the core code. The main characteristics of X-CASH are detailed below: +X-CASH is a cryptocurrency built using the Cryptonight v8 (CNv2) algorithm, using a variation called CN/DOUBLE, with the aim to become and standard in digital payment and transaction settlement. We believe privacy is very important when it comes to managing personal finances, but at the same time banks and institutions need to know the source of the funds for KYC purposes. Therefore, we plan on leaving the users the choice of whether or not they want their transaction to be public. Because we are implementing a worldwide network of dedicated servers, we hope to make the synchronization of the blockchain faster than other cryptocurrencies as well as reducing transaction latency. We believe this network will be a key component in the deployment of the future improvements we plan on adding to the core code. The main characteristics of X-CASH are detailed below: - Total Supply: 100,000,000,000 -- Block Time: 1 minute +- Block Time: 2 minute -- Algorithm: Cryptonight v8 (CNv2) +- Algorithm: CN/DOUBLE (Cryptonight v8 (scratchpad of 2MB) with double the iterations, and some minor changes) - Reward: ~100,000 XCA at inception -- Emission structure: logarithmic until max supply is reached in 2020. For more information: https://www.x-cash.org +- Emission structure: logarithmic until max supply is reached in 2022. For more information: https://www.x-cash.org We developed the FlexPrivacy feature, giving the opportunity to the user to chose between sending their transaction privately or publicly, from the same account, on the same blockchain, and on a per transaction basis. This is the first Cryptonight coin showing this hybrid feature, resembling the current cash system: - make a transaction using a check, credit card, bank transfer etc… and leave a transaction trail (public transaction) @@ -54,6 +54,7 @@ If you want to help out, see [CONTRIBUTING](CONTRIBUTING.md) for a set of guidel | 106000 | 16-10-2018 | v9 | Adjusting the new difficulty algorithm | | 136000 | 06-11-2018 | v10 | Adding public transactions, bullet proofs, fixed ring size of 21 and more! | | 137000 | 07-11-2018 | v11 | This version makes sure that all non bullet proof transactions are confirmed before bullet proofs transactions are required. | +| 281000 | 15-02-2019 | v12 | This version changes the proof of work algorithm to CN/DOUBLE, and changes the block time to 2 minutes. | Note future releases block heights and dates may change, so make sure to frequently check github, our website, the forums, etc. for the most up to date information. diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index f99949525d1..059f31a5255 100755 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -41,7 +41,7 @@ #include "variant2_int_sqrt.h" #define MEMORY (1 << 21) // 2MB scratchpad -#define ITER (1 << 20) +#define ITER(variant) (variant >= 3 ? (1 << 21) : (1 << 20)) #define AES_BLOCK_SIZE 16 #define AES_KEY_SIZE 32 #define INIT_SIZE_BLK 8 @@ -109,8 +109,16 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp memcpy(b + AES_BLOCK_SIZE, state.hs.b + 64, AES_BLOCK_SIZE); \ xor64(b + AES_BLOCK_SIZE, state.hs.b + 80); \ xor64(b + AES_BLOCK_SIZE + 8, state.hs.b + 88); \ - division_result = state.hs.w[12]; \ - sqrt_result = state.hs.w[13]; \ + if (variant == 2) \ + { \ + division_result = state.hs.w[12]; \ + sqrt_result = state.hs.w[13]; \ + } \ + else if (variant == 3) \ + { \ + division_result = SWAP64LE(state.hs.w[12]); \ + sqrt_result = SWAP64LE(state.hs.w[13]); \ + } \ } while (0) #define VARIANT2_SHUFFLE_ADD_SSE2(base_ptr, offset) \ @@ -145,30 +153,66 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp const uint64_t chunk1_old[2] = { chunk1[0], chunk1[1] }; \ \ uint64_t b1[2]; \ - memcpy(b1, b + 16, 16); \ - chunk1[0] = chunk3[0] + b1[0]; \ - chunk1[1] = chunk3[1] + b1[1]; \ - \ - uint64_t a0[2]; \ - memcpy(a0, a, 16); \ - chunk3[0] = chunk2[0] + a0[0]; \ - chunk3[1] = chunk2[1] + a0[1]; \ - \ - uint64_t b0[2]; \ - memcpy(b0, b, 16); \ - chunk2[0] = chunk1_old[0] + b0[0]; \ - chunk2[1] = chunk1_old[1] + b0[1]; \ + if (variant == 2) \ + { \ + memcpy(b1, b + 16, 16); \ + chunk1[0] = chunk3[0] + b1[0]; \ + chunk1[1] = chunk3[1] + b1[1]; \ + \ + uint64_t a0[2]; \ + memcpy(a0, a, 16); \ + chunk3[0] = chunk2[0] + a0[0]; \ + chunk3[1] = chunk2[1] + a0[1]; \ + \ + uint64_t b0[2]; \ + memcpy(b0, b, 16); \ + chunk2[0] = chunk1_old[0] + b0[0]; \ + chunk2[1] = chunk1_old[1] + b0[1]; \ + } \ + else if (variant == 3) \ + { \ + memcpy_swap64le(b1, b + 16, 2); \ + chunk1[0] = SWAP64LE(SWAP64LE(chunk3[0]) + b1[0]); \ + chunk1[1] = SWAP64LE(SWAP64LE(chunk3[1]) + b1[1]); \ + \ + uint64_t a0[2]; \ + memcpy_swap64le(a0, a, 2); \ + chunk3[0] = SWAP64LE(SWAP64LE(chunk2[0]) + a0[0]); \ + chunk3[1] = SWAP64LE(SWAP64LE(chunk2[1]) + a0[1]); \ + \ + uint64_t b0[2]; \ + memcpy_swap64le(b0, b, 2); \ + chunk2[0] = SWAP64LE(SWAP64LE(chunk1_old[0]) + b0[0]); \ + chunk2[1] = SWAP64LE(SWAP64LE(chunk1_old[1]) + b0[1]); \ + } \ } while (0) #define VARIANT2_INTEGER_MATH_DIVISION_STEP(b, ptr) \ - ((uint64_t*)(b))[0] ^= division_result ^ (sqrt_result << 32); \ + uint64_t sqrt_input_result = 0; \ + if (variant <= 2) \ { \ - const uint64_t dividend = ((uint64_t*)(ptr))[1]; \ - const uint32_t divisor = (((uint64_t*)(ptr))[0] + (uint32_t)(sqrt_result << 1)) | 0x80000001UL; \ - division_result = ((uint32_t)(dividend / divisor)) + \ + ((uint64_t*)(b))[0] ^= division_result ^ (sqrt_result << 32); \ + { \ + const uint64_t dividend = ((uint64_t*)(ptr))[1]; \ + const uint32_t divisor = (((uint64_t*)(ptr))[0] + (uint32_t)(sqrt_result << 1)) | 0x80000001UL; \ + division_result = ((uint32_t)(dividend / divisor)) + \ (((uint64_t)(dividend % divisor)) << 32); \ + } \ + sqrt_input_result = ((uint64_t*)(ptr))[0] + division_result; \ } \ - const uint64_t sqrt_input = ((uint64_t*)(ptr))[0] + division_result + else if (variant == 3) \ + { \ + uint64_t tmpx = division_result ^ (sqrt_result << 32); \ + ((uint64_t*)(b))[0] ^= SWAP64LE(tmpx); \ + { \ + const uint64_t dividend = SWAP64LE(((uint64_t*)(ptr))[1]); \ + const uint32_t divisor = (SWAP64LE(((uint64_t*)(ptr))[0]) + (uint32_t)(sqrt_result << 1)) | 0x80000001UL; \ + division_result = ((uint32_t)(dividend / divisor)) + \ + (((uint64_t)(dividend % divisor)) << 32); \ + } \ + sqrt_input_result = SWAP64LE(((uint64_t*)(ptr))[0]) + division_result; \ + } \ + const uint64_t sqrt_input = sqrt_input_result #define VARIANT2_INTEGER_MATH_SSE2(b, ptr) \ do if (variant >= 2) \ @@ -205,12 +249,19 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp } #define VARIANT2_2() \ - do if (variant >= 2) \ + do if (variant == 2) \ { \ *U64(hp_state + (j ^ 0x10)) ^= hi; \ *(U64(hp_state + (j ^ 0x10)) + 1) ^= lo; \ hi ^= *U64(hp_state + (j ^ 0x20)); \ lo ^= *(U64(hp_state + (j ^ 0x20)) + 1); \ + } while (0); \ + do if (variant == 3) \ + { \ + *U64(hp_state + (j ^ 0x10)) ^= SWAP64LE(hi); \ + *(U64(hp_state + (j ^ 0x10)) + 1) ^= SWAP64LE(lo); \ + hi ^= SWAP64LE(*U64(hp_state + (j ^ 0x20))); \ + lo ^= SWAP64LE(*(U64(hp_state + (j ^ 0x20)) + 1)); \ } while (0) @@ -772,7 +823,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int // the useAes test is only performed once, not every iteration. if(useAes) { - for(i = 0; i < ITER / 2; i++) + for(i = 0; i < ITER(variant) / 2; i++) { pre_aes(); _c = _mm_aesenc_si128(_c, _a); @@ -781,7 +832,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int } else { - for(i = 0; i < ITER / 2; i++) + for(i = 0; i < ITER(variant) / 2; i++) { pre_aes(); aesb_single_round((uint8_t *) &_c, (uint8_t *) &_c, (uint8_t *) &_a); @@ -1124,7 +1175,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int _b = vld1q_u8((const uint8_t *)b); _b1 = vld1q_u8(((const uint8_t *)b) + AES_BLOCK_SIZE); - for(i = 0; i < ITER / 2; i++) + for(i = 0; i < ITER(variant) / 2; i++) { pre_aes(); _c = vaeseq_u8(_c, zero); @@ -1331,7 +1382,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int U64(b)[0] = U64(&state.k[16])[0] ^ U64(&state.k[48])[0]; U64(b)[1] = U64(&state.k[16])[1] ^ U64(&state.k[48])[1]; - for(i = 0; i < ITER / 2; i++) + for(i = 0; i < ITER(variant) / 2; i++) { #define MASK ((uint32_t)(((MEMORY / AES_BLOCK_SIZE) - 1) << 4)) #define state_index(x) ((*(uint32_t *) x) & MASK) @@ -1412,6 +1463,7 @@ extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expa extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey); static size_t e2i(const uint8_t* a, size_t count) { return (*((uint64_t*)a) / AES_BLOCK_SIZE) & (count - 1); } +static size_t e2i_3(const uint8_t* a, size_t count) { return (SWAP64LE(*((uint64_t*)a)) / AES_BLOCK_SIZE) & (count - 1); } static void mul(const uint8_t* a, const uint8_t* b, uint8_t* res) { uint64_t a0, b0; @@ -1521,22 +1573,43 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int b[i] = state.k[AES_BLOCK_SIZE + i] ^ state.k[AES_BLOCK_SIZE * 3 + i]; } - for (i = 0; i < ITER / 2; i++) { + for (i = 0; i < ITER(variant) / 2; i++) { /* Dependency chain: address -> read value ------+ * written value <-+ hard function (AES or MUL) <+ * next address <-+ */ /* Iteration 1 */ - j = e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; + if (variant <= 2) + { + j = e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; + } + else if (variant == 3) + { + j = e2i_3(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; + } copy_block(c1, &long_state[j]); aesb_single_round(c1, c1, a); VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j); copy_block(&long_state[j], c1); xor_blocks(&long_state[j], b); - assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE); + if (variant <= 2) + { + assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE); + } + else if (variant == 3) + { + assert(j == e2i_3(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE); + } VARIANT1_1(&long_state[j]); /* Iteration 2 */ - j = e2i(c1, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; + if (variant <= 2) + { + j = e2i(c1, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; + } + else if (variant == 3) + { + j = e2i_3(c1, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; + } copy_block(c2, &long_state[j]); VARIANT2_PORTABLE_INTEGER_MATH(c2, c1); mul(c1, c2, d); @@ -1548,7 +1621,14 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int xor_blocks(c1, c2); VARIANT1_2(c2 + 8); copy_block(&long_state[j], c2); - assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE); + if (variant <= 2) + { + assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE); + } + else if (variant == 3) + { + assert(j == e2i_3(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE); + } if (variant >= 2) { copy_block(b + AES_BLOCK_SIZE, b); } diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index 82285819dce..98ed329f77d 100755 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -87,9 +87,9 @@ namespace cryptonote { } //----------------------------------------------------------------------------------------------- bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version, uint64_t height) { - static_assert(DIFFICULTY_TARGET_V2%60==0&&DIFFICULTY_TARGET_V1%60==0,"difficulty targets must be a multiple of 60"); - const int target = version < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2; - const int target_minutes = target / 60; + static_assert(DIFFICULTY_TARGET_V1%60==0&&DIFFICULTY_TARGET_V2%60==0&&DIFFICULTY_TARGET_V8%60==0&&DIFFICULTY_TARGET_V9%60==0&&DIFFICULTY_TARGET_V10%60==0&&DIFFICULTY_TARGET_V12%60==0,"difficulty targets must be a multiple of 60"); + const int target = version < HF_VERSION_TWO_MINUTE_BLOCK_TIME ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V12; + const int target_minutes = 1; // set it to always 1, so we dont increase the block reward when changing the block time const int emission_speed_factor = EMISSION_SPEED_FACTOR_PER_MINUTE - (target_minutes-1); uint64_t base_reward; diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 08bdc804741..5d502bbd788 100755 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -1033,10 +1033,14 @@ namespace cryptonote { cn_variant = 1; } - else + else if (b.major_version == 10 || b.major_version == 11) { cn_variant = 2; } + else + { + cn_variant = 3; + } crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant); return true; } diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp index 33a6693ace4..a8ac14fb425 100755 --- a/src/cryptonote_basic/difficulty.cpp +++ b/src/cryptonote_basic/difficulty.cpp @@ -369,4 +369,78 @@ difficulty_type next_difficulty_V10(std::vector timestamps, std:: return next_difficulty; } + + + + + + + + +// LWMA difficulty algorithm +// Background: https://github.com/zawy12/difficulty-algorithms/issues/3 +// Copyright (c) 2017-2018 Zawy (pseudocode) +// MIT license http://www.opensource.org/licenses/mit-license.php +// Copyright (c) 2018 The Stellite Project +// Copyright (c) 2018 The Masari Project (10x for quicker recoveries, minimum to be symmetric with FTL) +// Copyright (c) 2018 Wownero Inc., a Monero Enterprise Alliance partner company +// Copyright (c) 2018 The Karbowanec developers (initial code) +// Copyright (c) 2018 Haven Protocol (refinements) +// Degnr8, Karbowanec, Masari, Bitcoin Gold, Bitcoin Candy, and Haven have contributed. +// This algorithm is: next_difficulty = harmonic_mean(Difficulties) * T / LWMA(Solvetimes) +// The harmonic_mean(Difficulties) = 1/average(Targets) so it is also: +// next_target = avg(Targets) * LWMA(Solvetimes) / T. +// This is "the best algorithm" because it has lowest root-mean-square error between +// needed & actual difficulty during hash attacks while having the lowest standard +// deviation during stable hashrate. That is, it's the fastest for a given stability and vice versa. +// Do not use "if solvetime < 1 then solvetime = 1" which allows a catastrophic exploit. +// Do not sort timestamps. "Solvetimes" and "LWMA" variables must allow negatives. +// Do not use MTP as most recent block. Do not use (POW)Limits, filtering, or tempering. +// Do not forget to set N (aka DIFFICULTY_WINDOW in Cryptonote) to recommendation below. +// The nodes' future time limit (FTL) aka CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT needs to +// be reduced from 60*60*2 to 500 seconds to prevent timestamp manipulation from miner's with +// > 50% hash power. If this is too small, it can be increased to 1000 at a cost in protection. +difficulty_type next_difficulty_V12(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds) { + const int64_t T = static_cast(target_seconds); + size_t N = DIFFICULTY_WINDOW_V12; + // Return a difficulty of 1 for first 3 blocks if it's the start of the chain. + if (timestamps.size() < 4) { + return 1; + } + // Otherwise, use a smaller N if the start of the chain is less than N+1. + else if ( timestamps.size() < N+1 ) { + N = timestamps.size() - 1; + } + // Otherwise make sure timestamps and cumulative_difficulties are correct size. + else { + timestamps.resize(N+1); + cumulative_difficulties.resize(N+1); + } + // To get an average solvetime to within +/- ~0.1%, use an adjustment factor. + // adjust=0.998 for N = 60 + const double adjust = 0.998; + // The divisor k normalizes the LWMA sum to a standard LWMA. + const double k = N * (N + 1) / 2; + double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0); + int64_t solveTime(0); + uint64_t difficulty(0), next_difficulty(0); + // Loop through N most recent blocks. N is most recently solved block. + for (size_t i = 1; i <= N; i++) { + solveTime = static_cast(timestamps[i]) - static_cast(timestamps[i - 1]); + solveTime = std::min((T * 10), solveTime); + difficulty = cumulative_difficulties[i] - cumulative_difficulties[i - 1]; + LWMA += (int64_t)(solveTime * i) / k; + sum_inverse_D += 1 / static_cast(difficulty); + } + harmonic_mean_D = N / sum_inverse_D; + // Limit LWMA same as Bitcoin's 1/4 in case something unforeseen occurs. + if (static_cast(boost::math::round(LWMA)) < T / 4) + LWMA = static_cast(T / 4); + nextDifficulty = harmonic_mean_D * T / LWMA * adjust; + // No limits should be employed, but this is correct way to employ a 20% symmetrical limit: + // nextDifficulty=max(previous_Difficulty*0.8,min(previous_Difficulty/0.8, next_Difficulty)); + next_difficulty = static_cast(nextDifficulty); + return next_difficulty; +} + } diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h index 09d48c50891..455f789bb22 100755 --- a/src/cryptonote_basic/difficulty.h +++ b/src/cryptonote_basic/difficulty.h @@ -56,4 +56,5 @@ namespace cryptonote difficulty_type next_difficulty_V8(std::vector timestamps,std::vector cumulative_difficulties, uint64_t block_height); difficulty_type next_difficulty_V9(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); difficulty_type next_difficulty_V10(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); + difficulty_type next_difficulty_V12(std::vector timestamps, std::vector cumulative_difficulties, size_t target_seconds); } diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 0c79a1c4418..4406a26cf2d 100755 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -111,9 +111,17 @@ #define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V10 11 #define DIFFICULTY_TARGET_V10 60 // seconds +// LWMA difficulty V12 +#define DIFFICULTY_WINDOW_V12 120 +#define DIFFICULTY_BLOCKS_COUNT_V12 121 +#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V12 60*4 +#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V12 11 +#define DIFFICULTY_TARGET_V12 120 // seconds + #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 DIFFICULTY_TARGET_V1 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 DIFFICULTY_TARGET_V2 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS +#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V12 120 // seconds #define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS 1 @@ -167,6 +175,9 @@ #define HF_VERSION_BULLETPROOFS 10 #define HF_VERSION_MIN_MIXIN_20 10 #define HF_VERSION_PER_BYTE_FEE 10 +#define HF_VERSION_TWO_MINUTE_BLOCK_TIME 12 +#define HF_BLOCK_HEIGHT_TWO_MINUTE_BLOCK_TIME 281000 +#define HF_TIME_TWO_MINUTE_BLOCK_TIME 1550241230 #define BLOCKCHAIN_DEFAULT_MIXIN 20 diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index e05cd8092cc..13e3ceb32b6 100755 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -98,7 +98,7 @@ static const struct { // version 8 starts from block 95085, which is on or around Oct 8, 2018. This version includes a new difficulty algorithm. { 8, 95085, 0, 1538524800 }, - + // version 9 starts from block 106000, which is on or around Oct 16, 2018. This version includes a change to the new difficulty algorithm. { 9, 106000, 0, 1539550195 }, @@ -107,6 +107,9 @@ static const struct { // version 11 starts from block 137000, which is on or around Nov 7, 2018. This version makes sure that all non bullet proof transactions are confirmed before bullet proofs transactions are required. { 11, 137000, 0, 1540146330 }, + + // version 12 starts from block 281000, which is on or around Feb 15, 2019. This version changes the proof of work algorithm to Cryptonight HeavyX and changes the block time to 2 minutes. + { 12, 281000, 0, 1549310115 }, }; static const uint64_t mainnet_hard_fork_version_1_till = 1; @@ -133,6 +136,9 @@ static const struct { // version 11 starts from block 137000, which is on or around Nov 7, 2018. This version makes sure that all non bullet proof transactions are confirmed before bullet proofs transactions are required. { 11, 137000, 0, 1540146330 }, + + // version 12 starts from block 281000, which is on or around Feb 15, 2019. This version changes the proof of work algorithm to CN/DOUBLE and changes the block time to 2 minutes. + { 12, 281000, 0, 1549310115 }, }; static const uint64_t testnet_hard_fork_version_1_till = 1; @@ -819,9 +825,12 @@ difficulty_type Blockchain::get_difficulty_for_next_block() else if(version == 9){ difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V9; } - else{ + else if(version == 10 || version == 11){ difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V10; } + else{ + difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V12; + } LOG_PRINT_L3("Blockchain::" << __func__); @@ -883,20 +892,28 @@ difficulty_type Blockchain::get_difficulty_for_next_block() m_timestamps = timestamps; m_difficulties = difficulties; } - size_t target = DIFFICULTY_TARGET_V10; + size_t target; difficulty_type diff; if(version <= 7){ - diff = next_difficulty(timestamps, difficulties, target); + target = DIFFICULTY_TARGET_V10; + diff = next_difficulty(timestamps, difficulties, target); } else if(version == 8){ + target = DIFFICULTY_TARGET_V10; diff = next_difficulty_V8(timestamps, difficulties, block_height); } else if(version == 9){ + target = DIFFICULTY_TARGET_V10; diff = next_difficulty_V9(timestamps, difficulties, target); } - else{ + else if(version == 10 || version == 11){ + target = DIFFICULTY_TARGET_V10; diff = next_difficulty_V10(timestamps, difficulties, target); } + else{ + target = DIFFICULTY_TARGET_V12; + diff = next_difficulty_V12(timestamps, difficulties, target); + } CRITICAL_REGION_LOCAL1(m_difficulty_lock); m_difficulty_for_next_block_top_hash = top_hash; @@ -1064,9 +1081,12 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: else if(version == 9){ difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V9; } - else{ + else if(version == 10 || version == 11){ difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V10; } + else{ + difficulty_blocks_count = DIFFICULTY_BLOCKS_COUNT_V12; + } LOG_PRINT_L3("Blockchain::" << __func__); std::vector timestamps; @@ -1123,19 +1143,27 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: } // FIXME: This will fail if fork activation heights are subject to voting - size_t target = DIFFICULTY_TARGET_V10; + size_t target; if(version <= 7){ + target = DIFFICULTY_TARGET_V10; return next_difficulty(timestamps, cumulative_difficulties, target); } else if(version == 8){ + target = DIFFICULTY_TARGET_V10; return next_difficulty_V8(timestamps, cumulative_difficulties, block_height); } else if(version == 9){ + target = DIFFICULTY_TARGET_V10; return next_difficulty_V9(timestamps, cumulative_difficulties, target); } - else{ + else if(version == 10 || version == 11){ + target = DIFFICULTY_TARGET_V10; return next_difficulty_V10(timestamps, cumulative_difficulties, target); } + else{ + target = DIFFICULTY_TARGET_V12; + return next_difficulty_V12(timestamps, cumulative_difficulties, target); + } } //------------------------------------------------------------------ // This function does a sanity check on basic things that all miner @@ -3082,7 +3110,7 @@ bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const { //interpret as time uint64_t current_time = static_cast(time(NULL)); - if(current_time + (get_current_hard_fork_version() < 2 ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2) >= unlock_time) + if(current_time + (get_current_hard_fork_version() < HF_VERSION_TWO_MINUTE_BLOCK_TIME ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V12) >= unlock_time) return true; else return false; @@ -3197,9 +3225,13 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons cryptonote_block_future_time_limit = CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V9; blockchain_timestamp_check_window = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V9; } + else if(version == 10 || version == 11){ + cryptonote_block_future_time_limit = CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V10; + blockchain_timestamp_check_window = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V10; + } else{ - cryptonote_block_future_time_limit = CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V10; - blockchain_timestamp_check_window = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V10; + cryptonote_block_future_time_limit = CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V12; + blockchain_timestamp_check_window = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V12; } LOG_PRINT_L3("Blockchain::" << __func__); if(b.timestamp > get_adjusted_time() + cryptonote_block_future_time_limit) @@ -4422,7 +4454,7 @@ bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, ui uint64_t Blockchain::get_difficulty_target() const { - return get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2; + return get_current_hard_fork_version() < HF_VERSION_TWO_MINUTE_BLOCK_TIME ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V12; } std::map> Blockchain:: get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count) const diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 158ba87d6e2..5f4ecc51f99 100755 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -302,10 +302,10 @@ namespace cryptonote int64_t diff = static_cast(hshd.current_height) - static_cast(m_core.get_current_blockchain_height()); uint64_t abs_diff = std::abs(diff); uint64_t max_block_height = std::max(hshd.current_height,m_core.get_current_blockchain_height()); - uint64_t last_block_v1 = m_core.get_nettype() == TESTNET ? 624633 : m_core.get_nettype() == MAINNET ? 1009826 : (uint64_t)-1; + uint64_t last_block_v1 = m_core.get_nettype() == TESTNET ? HF_BLOCK_HEIGHT_TWO_MINUTE_BLOCK_TIME-1 : m_core.get_nettype() == MAINNET ? HF_BLOCK_HEIGHT_TWO_MINUTE_BLOCK_TIME-1 : (uint64_t)-1; uint64_t diff_v2 = max_block_height > last_block_v1 ? std::min(abs_diff, max_block_height - last_block_v1) : 0; MCLOG(is_inital ? el::Level::Info : el::Level::Debug, "global", context << "Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height - << " [Your node is " << abs_diff << " blocks (" << ((abs_diff - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V2)) << " days) " + << " [Your node is " << abs_diff << " blocks (" << ((abs_diff - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V12)) << " days) " << (0 <= diff ? std::string("behind") : std::string("ahead")) << "] " << ENDL << "SYNCHRONIZATION started"); if (hshd.current_height >= m_core.get_current_blockchain_height() + 5) // don't switch to unsafe mode just for a few blocks diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 626426b20b9..d5d203f4a8e 100755 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -1018,7 +1018,7 @@ bool t_rpc_command_executor::print_transaction_pool_stats() { else { uint64_t backlog = (res.pool_stats.bytes_total + full_reward_zone - 1) / full_reward_zone; - backlog_message = (boost::format("estimated %u block (%u minutes) backlog") % backlog % (backlog * DIFFICULTY_TARGET_V2 / 60)).str(); + backlog_message = ires.height >= HF_BLOCK_HEIGHT_TWO_MINUTE_BLOCK_TIME ? (boost::format("estimated %u block (%u minutes) backlog") % backlog % (backlog * DIFFICULTY_TARGET_V12 / 60)).str() : (boost::format("estimated %u block (%u minutes) backlog") % backlog % (backlog * DIFFICULTY_TARGET_V2 / 60)).str(); } tools::msg_writer() << n_transactions << " tx(es), " << res.pool_stats.bytes_total << " bytes total (min " << res.pool_stats.bytes_min << ", max " << res.pool_stats.bytes_max << ", avg " << avg_bytes << ", median " << res.pool_stats.bytes_med << ")" << std::endl diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 90fe9c0b254..570ac7a352e 100755 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1581,7 +1581,7 @@ namespace cryptonote res.top_block_hash = string_tools::pod_to_hex(top_hash); res.target_height = m_core.get_target_blockchain_height(); res.difficulty = m_core.get_blockchain_storage().get_difficulty_for_next_block(); - res.target = m_core.get_blockchain_storage().get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2; + res.target = m_core.get_blockchain_storage().get_current_hard_fork_version() < HF_VERSION_TWO_MINUTE_BLOCK_TIME ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V12; res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase res.tx_pool_size = m_core.get_pool_transactions_count(); res.alt_blocks_count = m_core.get_blockchain_storage().get_alternative_blocks_count(); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index b47a8e79587..af70d205b45 100755 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -823,7 +823,8 @@ bool simple_wallet::print_fee_info(const std::vector &args/* = std: std::string msg; if (priority == m_wallet->get_default_priority() || (m_wallet->get_default_priority() == 0 && priority == 2)) msg = tr(" (current)"); - uint64_t minutes_low = nblocks_low * DIFFICULTY_TARGET_V2 / 60, minutes_high = nblocks_high * DIFFICULTY_TARGET_V2 / 60; + uint64_t minutes_low = m_wallet->use_fork_rules(HF_VERSION_TWO_MINUTE_BLOCK_TIME, 0) ? nblocks_low * DIFFICULTY_TARGET_V12 / 60 : nblocks_low * DIFFICULTY_TARGET_V2 / 60; + uint64_t minutes_high = m_wallet->use_fork_rules(HF_VERSION_TWO_MINUTE_BLOCK_TIME, 0) ? nblocks_high * DIFFICULTY_TARGET_V12 / 60 : nblocks_high * DIFFICULTY_TARGET_V2 / 60; if (nblocks_high == nblocks_low) message_writer() << (boost::format(tr("%u block (%u minutes) backlog at priority %u%s")) % nblocks_low % minutes_low % priority % msg).str(); else @@ -7950,7 +7951,7 @@ bool simple_wallet::show_transfer(const std::vector &args) else { uint64_t current_time = static_cast(time(NULL)); - uint64_t threshold = current_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1); + uint64_t threshold = current_time + (m_wallet->use_fork_rules(HF_VERSION_TWO_MINUTE_BLOCK_TIME, 10) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V12 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1); if (threshold >= pd.m_unlock_time) success_msg_writer() << "unlocked for " << get_human_readable_timespan(std::chrono::seconds(threshold - pd.m_unlock_time)); else diff --git a/src/version.cpp.in b/src/version.cpp.in index ef8795681b7..2635c51de35 100755 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_XCASH_VERSION_TAG "@VERSIONTAG@" -#define DEF_XCASH_VERSION "1.4.2" +#define DEF_XCASH_VERSION "1.5.0" #define DEF_XCASH_RELEASE_NAME "" #define DEF_XCASH_VERSION_FULL DEF_XCASH_VERSION "-" DEF_XCASH_VERSION_TAG diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1b15693eb94..2fdaca42e6e 100755 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3771,11 +3771,9 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip uint64_t wallet2::estimate_blockchain_height() { - // -1 month for fluctuations in block time and machine date/time setup. - // avg seconds per block - const int seconds_per_block = DIFFICULTY_TARGET_V2; + // -1 month for fluctuations in block time and machine date/time setup. // ~num blocks per month - const uint64_t blocks_per_month = 60*60*24*30/seconds_per_block; + const uint64_t blocks_per_month = use_fork_rules(HF_VERSION_TWO_MINUTE_BLOCK_TIME, 0) ? 21600 : 43200; // 720 blocks per day if 2 minute block times, 1440 blocks per day if 1 minute block times // try asking the daemon first std::string err; @@ -10174,14 +10172,12 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err) uint64_t wallet2::get_approximate_blockchain_height() const { - // time of v2 fork - const time_t fork_time = m_nettype == TESTNET ? 1448285909 : m_nettype == STAGENET ? 1520937818 : 1458748658; - // v2 fork block - const uint64_t fork_block = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827; + // get the current time + const uint64_t current_time = (uint64_t)time(NULL); // avg seconds per block - const int seconds_per_block = DIFFICULTY_TARGET_V2; + const int seconds_per_block = current_time > HF_TIME_TWO_MINUTE_BLOCK_TIME ? DIFFICULTY_TARGET_V12 : DIFFICULTY_TARGET_V2; // Calculated blockchain height - uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block; + uint64_t approx_blockchain_height = HF_BLOCK_HEIGHT_TWO_MINUTE_BLOCK_TIME + (current_time - HF_TIME_TWO_MINUTE_BLOCK_TIME)/seconds_per_block; // testnet got some huge rollbacks, so the estimation is way off static const uint64_t approximate_testnet_rolled_back_blocks = 303967; if (m_nettype == TESTNET && approx_blockchain_height > approximate_testnet_rolled_back_blocks)